gc tweaking to gain a few percent of performance

This commit is contained in:
Araq 2011-05-07 22:13:24 +02:00
commit 73c3551766
13 changed files with 183 additions and 153 deletions

View file

@ -677,8 +677,8 @@ proc genProcAux(m: BModule, prc: PSym) =
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
appf(generatedProc, appf(generatedProc,
"profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n", "profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n",
[toRope(prc.loc.a)]) [toRope(prc.loc.a)])
app(generatedProc, returnStmt) app(generatedProc, returnStmt)
app(generatedProc, '}' & tnl) app(generatedProc, '}' & tnl)
app(m.s[cfsProcs], generatedProc) app(m.s[cfsProcs], generatedProc)

View file

@ -100,19 +100,16 @@ proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
proc crcFromFile(filename: string): TCrc32 = proc crcFromFile(filename: string): TCrc32 =
const const
bufSize = 8 * 1024 bufSize = 8000 # don't use 8K for the memory allocator!
var var
bin: tfile bin: tfile
buf: Pointer
readBytes: int
p: PByteArray
result = InitCrc32 result = InitCrc32
if not open(bin, filename): if not open(bin, filename):
return # not equal if file does not exist return # not equal if file does not exist
buf = alloc(BufSize) var buf = alloc(BufSize)
p = cast[PByteArray](buf) var p = cast[PByteArray](buf)
while true: while true:
readBytes = readBuffer(bin, buf, bufSize) var readBytes = readBuffer(bin, buf, bufSize)
for i in countup(0, readBytes - 1): result = updateCrc32(p[i], result) for i in countup(0, readBytes - 1): result = updateCrc32(p[i], result)
if readBytes != bufSize: break if readBytes != bufSize: break
dealloc(buf) dealloc(buf)

View file

@ -50,7 +50,7 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
rawMessage(errArgsNeedRunOption, []) rawMessage(errArgsNeedRunOption, [])
proc HandleCmdLine() = proc HandleCmdLine() =
var start = getTime() var start = epochTime()
if paramCount() == 0: if paramCount() == 0:
writeCommandLineUsage() writeCommandLineUsage()
else: else:
@ -73,7 +73,8 @@ proc HandleCmdLine() =
if gCmd == cmdRun: if gCmd == cmdRun:
tccgen.run() tccgen.run()
if gCmd notin {cmdInterpret, cmdRun}: if gCmd notin {cmdInterpret, cmdRun}:
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start)]) rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - start, ffDecimal, 3)])
if optRun in gGlobalOptions: if optRun in gGlobalOptions:
when defined(unix): when defined(unix):
var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, "")) var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, ""))
@ -81,6 +82,7 @@ proc HandleCmdLine() =
var prog = quoteIfContainsWhite(changeFileExt(filename, "")) var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
execExternalProgram(prog & ' ' & arguments) execExternalProgram(prog & ' ' & arguments)
#GC_disableMarkAndSweep()
cmdLineInfo = newLineInfo("command line", -1, -1) cmdLineInfo = newLineInfo("command line", -1, -1)
condsyms.InitDefines() condsyms.InitDefines()
HandleCmdLine() HandleCmdLine()

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2008 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -12,13 +12,7 @@
import import
nhashes, ast, astalgo, types nhashes, ast, astalgo, types
proc NodeTableGet*(t: TNodeTable, key: PNode): int
proc NodeTablePut*(t: var TNodeTable, key: PNode, val: int)
proc NodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int
# implementation
proc hashTree(n: PNode): THash = proc hashTree(n: PNode): THash =
result = 0
if n == nil: return if n == nil: return
result = ord(n.kind) result = ord(n.kind)
case n.kind case n.kind
@ -41,7 +35,6 @@ proc hashTree(n: PNode): THash =
result = concHash(result, hashTree(n.sons[i])) result = concHash(result, hashTree(n.sons[i]))
proc TreesEquivalent(a, b: PNode): bool = proc TreesEquivalent(a, b: PNode): bool =
result = false
if a == b: if a == b:
result = true result = true
elif (a != nil) and (b != nil) and (a.kind == b.kind): elif (a != nil) and (b != nil) and (a.kind == b.kind):
@ -60,36 +53,31 @@ proc TreesEquivalent(a, b: PNode): bool =
if result: result = sameTypeOrNil(a.typ, b.typ) if result: result = sameTypeOrNil(a.typ, b.typ)
proc NodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int = proc NodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int =
var h: THash var h: THash = k and high(t.data)
h = k and high(t.data)
while t.data[h].key != nil: while t.data[h].key != nil:
if (t.data[h].h == k) and TreesEquivalent(t.data[h].key, key): if (t.data[h].h == k) and TreesEquivalent(t.data[h].key, key):
return h return h
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = - 1 result = -1
proc NodeTableGet(t: TNodeTable, key: PNode): int = proc NodeTableGet*(t: TNodeTable, key: PNode): int =
var index: int var index = NodeTableRawGet(t, hashTree(key), key)
index = NodeTableRawGet(t, hashTree(key), key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = low(int) else: result = low(int)
proc NodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode, val: int) = proc NodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode,
var h: THash val: int) =
h = k and high(data) var h: THash = k and high(data)
while data[h].key != nil: h = nextTry(h, high(data)) while data[h].key != nil: h = nextTry(h, high(data))
assert(data[h].key == nil) assert(data[h].key == nil)
data[h].h = k data[h].h = k
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
proc NodeTablePut(t: var TNodeTable, key: PNode, val: int) = proc NodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
var var n: TNodePairSeq
index: int var k: THash = hashTree(key)
n: TNodePairSeq var index = NodeTableRawGet(t, k, key)
k: THash
k = hashTree(key)
index = NodeTableRawGet(t, k, key)
if index >= 0: if index >= 0:
assert(t.data[index].key != nil) assert(t.data[index].key != nil)
t.data[index].val = val t.data[index].val = val
@ -103,13 +91,10 @@ proc NodeTablePut(t: var TNodeTable, key: PNode, val: int) =
NodeTableRawInsert(t.data, k, key, val) NodeTableRawInsert(t.data, k, key, val)
inc(t.counter) inc(t.counter)
proc NodeTableTestOrSet(t: var TNodeTable, key: PNode, val: int): int = proc NodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int =
var var n: TNodePairSeq
index: int var k: THash = hashTree(key)
n: TNodePairSeq var index = NodeTableRawGet(t, k, key)
k: THash
k = hashTree(key)
index = NodeTableRawGet(t, k, key)
if index >= 0: if index >= 0:
assert(t.data[index].key != nil) assert(t.data[index].key != nil)
result = t.data[index].val result = t.data[index].val

View file

@ -157,10 +157,8 @@ proc cleanAux(dir: string) =
of "nimcache": of "nimcache":
echo "removing dir: ", path echo "removing dir: ", path
removeDir(path) removeDir(path)
of "dist", ".git": of "dist", ".git": nil
nil else: cleanAux(path)
else:
cleanAux(path)
else: nil else: nil
proc removePattern(pattern: string) = proc removePattern(pattern: string) =

View file

@ -13,60 +13,60 @@
## .. include:: ../doc/astspec.txt ## .. include:: ../doc/astspec.txt
type type
TNimrodNodeKind* = enum TNimrodNodeKind* = enum
nnkNone, nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkEmpty, nnkIdent, nnkSym,
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit, nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit, nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit,
nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit, nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit,
nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall, nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall,
nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr, nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr,
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix, nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix,
nnkPrefix, nnkPostfix, nnkPar, nnkCurly, nnkPrefix, nnkPostfix, nnkPar, nnkCurly,
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
nnkElifExpr, nnkElseExpr, nnkLambda, nnkAccQuoted, nnkElifExpr, nnkElseExpr, nnkLambda, nnkAccQuoted,
nnkTableConstr, nnkBind, nnkSymChoice, nnkHiddenStdConv, nnkTableConstr, nnkBind, nnkSymChoice, nnkHiddenStdConv,
nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast,
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkAsgn, nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkAsgn,
nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef, nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt, nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt, nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection, nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef, nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy, nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy, nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
TNimNodeKinds* = set[TNimrodNodeKind] TNimNodeKinds* = set[TNimrodNodeKind]
TNimrodTypeKind* = enum TNimrodTypeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmpty, ntyNone, ntyBool, ntyChar, ntyEmpty,
ntyArrayConstr, ntyNil, ntyExpr, ntyStmt, ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst, ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal, ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
ntyArray, ntyObject, ntyTuple, ntySet, ntyArray, ntyObject, ntyTuple, ntySet,
ntyRange, ntyPtr, ntyRef, ntyVar, ntyRange, ntyPtr, ntyRef, ntyVar,
ntySequence, ntyProc, ntyPointer, ntyOpenArray, ntySequence, ntyProc, ntyPointer, ntyOpenArray,
ntyString, ntyCString, ntyForward, ntyInt, ntyString, ntyCString, ntyForward, ntyInt,
ntyInt8, ntyInt16, ntyInt32, ntyInt64, ntyInt8, ntyInt16, ntyInt32, ntyInt64,
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128 ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
TNimTypeKinds* = set[TNimrodTypeKind] TNimTypeKinds* = set[TNimrodTypeKind]
TNimrodSymKind* = enum TNimrodSymKind* = enum
nskUnknown, nskConditional, nskDynLib, nskParam, nskUnknown, nskConditional, nskDynLib, nskParam,
nskGenericParam, nskTemp, nskType, nskConst, nskGenericParam, nskTemp, nskType, nskConst,
nskVar, nskProc, nskMethod, nskIterator, nskVar, nskProc, nskMethod, nskIterator,
nskConverter, nskMacro, nskTemplate, nskField, nskConverter, nskMacro, nskTemplate, nskField,
nskEnumField, nskForVar, nskModule, nskLabel, nskEnumField, nskForVar, nskModule, nskLabel,
nskStub nskStub
TNimSymKinds* = set[TNimrodSymKind] TNimSymKinds* = set[TNimrodSymKind]
type type
TNimrodIdent* = object of TObject TNimrodIdent* = object of TObject
@ -88,7 +88,7 @@ type
# Nodes should be reference counted to make the `copy` operation very fast! # Nodes should be reference counted to make the `copy` operation very fast!
# However, this is difficult to achieve: modify(n[0][1]) should propagate to # However, this is difficult to achieve: modify(n[0][1]) should propagate to
# its father. How to do this without back references? Hm, BS, it works without # its father. How to do this without back references? Hm, BS, it works without
# them. # them.
proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".} proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
@ -105,7 +105,7 @@ proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.} proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
## compares two Nimrod identifiers ## compares two Nimrod identifiers
proc `==`* (a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.} proc `==`* (a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nimrod nodes ## compares two Nimrod nodes

View file

@ -100,7 +100,7 @@ when defined(Windows):
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".} stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
proc WaitForSingleObject(hHandle: THANDLE, dwMilliseconds: int32): int32 {. proc WaitForSingleObject(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".} stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {. proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "TerminateThread".} stdcall, dynlib: "kernel32", importc: "TerminateThread".}

View file

@ -216,9 +216,16 @@ proc `[]=`*[A, B](t: TOrderedHashTable[A, B], key: A, val: B) =
inc(t.counter) inc(t.counter)
proc del*[A, B](t: TOrderedHashTable[A, B], key: A) = proc del*[A, B](t: TOrderedHashTable[A, B], key: A) =
## deletes `key` from hash table `t`. ## deletes `key` from hash table `t`. Warning: It's inefficient for ordered
## tables: O(n).
var index = RawGet(t, key) var index = RawGet(t, key)
if index >= 0: if index >= 0:
var i = t.first
while i >= 0:
var nxt = t.data[i].next
if nxt == index: XXX
i = nxt
t.data[index].slot = seDeleted t.data[index].slot = seDeleted
dec(t.counter) dec(t.counter)

View file

@ -23,28 +23,39 @@ proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.} proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.}
# Support for thread local storage: # Support for thread local storage:
when false: when defined(windows):
when defined(windows): type
proc TlsAlloc(): int32 {.importc: "TlsAlloc", stdcall, dynlib: "kernel32".} TThreadVarSlot {.compilerproc.} = distinct int32
proc TlsSetValue(dwTlsIndex: int32, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc TlsGetValue(dwTlsIndex: int32): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
else:
type
Tpthread_key {.importc: "pthread_key_t", header: "<sys/types.h>".} = int
proc pthread_getspecific(a1: Tpthread_key): pointer {. proc TlsAlloc(): TThreadVarSlot {.
importc: "pthread_getspecific", header: "<pthread.h>".} importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc pthread_key_create(a1: ptr Tpthread_key, proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
a2: proc (x: pointer) {.noconv.}): int32 {. importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
importc: "pthread_key_create", header: "<pthread.h>".} proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
proc pthread_key_delete(a1: Tpthread_key): int32 {. importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
importc: "pthread_key_delete", header: "<pthread.h>".}
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
result = TlsAlloc()
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.compilerproc.} =
TlsSetValue(s, value)
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc.} =
result = TlsGetValue(s)
else:
type
Tpthread_key {.importc: "pthread_key_t",
header: "<sys/types.h>".} = distinct int
TThreadVarSlot {.compilerproc.} = Tpthread_key
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {. proc pthread_getspecific(a1: Tpthread_key): pointer {.
importc: "pthread_setspecific", header: "<pthread.h>".} importc: "pthread_getspecific", header: "<pthread.h>".}
proc pthread_key_create(a1: ptr Tpthread_key,
destruct: proc (x: pointer) {.noconv.}): int32 {.
importc: "pthread_key_create", header: "<pthread.h>".}
proc pthread_key_delete(a1: Tpthread_key): int32 {.
importc: "pthread_key_delete", header: "<pthread.h>".}
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -21,8 +21,6 @@ proc rawWrite(f: TFile, s: string) =
proc nimLoadLibraryError(path: string) = proc nimLoadLibraryError(path: string) =
# carefully written to avoid memory allocation: # carefully written to avoid memory allocation:
#stdout.write("could not load: ")
#quit(path)
stdout.rawWrite("could not load: ") stdout.rawWrite("could not load: ")
stdout.rawWrite(path) stdout.rawWrite(path)
stdout.rawWrite("\n") stdout.rawWrite("\n")

View file

@ -23,7 +23,7 @@
const const
CycleIncrease = 2 # is a multiplicative increase CycleIncrease = 2 # is a multiplicative increase
InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
ZctThreshold = 256 # we collect garbage if the ZCT's size ZctThreshold = 500 # we collect garbage if the ZCT's size
# reaches this threshold # reaches this threshold
# this seems to be a good value # this seems to be a good value
@ -294,31 +294,32 @@ proc initGC() =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
var d = cast[TAddress](dest) var d = cast[TAddress](dest)
case n.kind case n.kind
of nkNone: assert(false)
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
of nkList: of nkList:
for i in 0..n.len-1: forAllSlotsAux(dest, n.sons[i], op) for i in 0..n.len-1: forAllSlotsAux(dest, n.sons[i], op)
of nkCase: of nkCase:
var m = selectBranch(dest, n) var m = selectBranch(dest, n)
if m != nil: forAllSlotsAux(dest, m, op) if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: assert(false)
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) = proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
var d = cast[TAddress](dest) var d = cast[TAddress](dest)
if dest == nil: return # nothing to do if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags: if ntfNoRefs notin mt.flags:
case mt.Kind case mt.Kind
of tyArray, tyArrayConstr, tyOpenArray:
for i in 0..(mt.size div mt.base.size)-1:
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
of tyRef, tyString, tySequence: # leaf: of tyRef, tyString, tySequence: # leaf:
doOperation(cast[ppointer](d)[], op) doOperation(cast[ppointer](d)[], op)
of tyObject, tyTuple, tyPureObject: of tyObject, tyTuple, tyPureObject:
forAllSlotsAux(dest, mt.node, op) forAllSlotsAux(dest, mt.node, op)
of tyArray, tyArrayConstr, tyOpenArray:
for i in 0..(mt.size div mt.base.size)-1:
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: nil else: nil
proc forAllChildren(cell: PCell, op: TWalkOp) = proc forAllChildren(cell: PCell, op: TWalkOp) =
assert(cell != nil) assert(cell != nil)
assert(cell.typ != nil) assert(cell.typ != nil)
assert cell.typ.kind in {tyRef, tySequence, tyString}
case cell.typ.Kind case cell.typ.Kind
of tyRef: # common case of tyRef: # common case
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
@ -329,14 +330,57 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
for i in 0..s.len-1: for i in 0..s.len-1:
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
GenericSeqSize), cell.typ.base, op) GenericSeqSize), cell.typ.base, op)
of tyString: nil else: nil
else: assert(false)
proc checkCollection {.inline.} = proc checkCollection {.inline.} =
# checks if a collection should be done # checks if a collection should be done
if recGcLock == 0: if recGcLock == 0:
collectCT(gch) collectCT(gch)
proc addNewObjToZCT(res: PCell) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused.
# In 63% of all cases we succeed here! But we have to optimize the heck
# out of this small linear search so that ``newObj`` is not slowed down.
#
# Slots to try cache hit
# 1 32%
# 4 59%
# 8 63%
# 16 66%
# all slots 68%
var L = gch.zct.len
var d = gch.zct.d
when true:
# loop unrolled for performance:
template replaceZctEntry(i: expr) =
c = d[i]
if c.refcount >=% rcIncrement:
c.refcount = c.refcount and not colorMask
d[i] = res
return
if L > 8:
var c: PCell
replaceZctEntry(L-1)
replaceZctEntry(L-2)
replaceZctEntry(L-3)
replaceZctEntry(L-4)
replaceZctEntry(L-5)
replaceZctEntry(L-6)
replaceZctEntry(L-7)
replaceZctEntry(L-8)
add(gch.zct, res)
else:
d[L] = res
inc(gch.zct.len)
else:
for i in countdown(L-1, max(0, L-8)):
var c = d[i]
if c.refcount >=% rcIncrement:
c.refcount = c.refcount and not colorMask
d[i] = res
return
add(gch.zct, res)
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
# generates a new object and sets its reference counter to 0 # generates a new object and sets its reference counter to 0
aquire(gch) aquire(gch)
@ -354,18 +398,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT
assert(isAllocatedPtr(allocator, res)) assert(isAllocatedPtr(allocator, res))
# its refcount is zero, so add it to the ZCT: # its refcount is zero, so add it to the ZCT:
block addToZCT: addNewObjToZCT(res)
# we check the last 8 entries (cache line) for a slot
# that could be reused
var L = gch.zct.len
var d = gch.zct.d
for i in countdown(L-1, max(0, L-8)):
var c = d[i]
if c.refcount >=% rcIncrement:
c.refcount = c.refcount and not colorMask
d[i] = res
break addToZCT
add(gch.zct, res)
when logGC: writeCell("new cell", res) when logGC: writeCell("new cell", res)
gcTrace(res, csAllocated) gcTrace(res, csAllocated)
release(gch) release(gch)

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.

View file

@ -1,11 +1,13 @@
* thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch
- implicit ref/ptr->var conversion - implicit ref/ptr->var conversion
- warning for implicit openArray -> varargs convention
- implement explicit varargs
High priority (version 0.9.0) High priority (version 0.9.0)
============================= =============================
- warning for implicit openArray -> varargs convention
- implement explicit varargs
- tests: run modules that contain "#RUN_ME", compile the other - tests: run modules that contain "#RUN_ME", compile the other
modules; run the GC tests modules; run the GC tests
- fix implicit generic routines - fix implicit generic routines
@ -32,11 +34,8 @@ To implement
* hash tables and sets; count tables; ordered dicts * hash tables and sets; count tables; ordered dicts
* distinct types for array/seq indexes * distinct types for array/seq indexes
* implement closures for the C code generator * implement closures for the C code generator
* GC: marker procs for native Nimrod GC and Boehm GC * GC: marker procs for native Nimrod GC and Boehm GC
* thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch
* built-in serialization * built-in serialization