diff options
Diffstat (limited to 'lib/nimhcr.nim')
-rw-r--r-- | lib/nimhcr.nim | 125 |
1 files changed, 68 insertions, 57 deletions
diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 1bafa98cb..e87bb2413 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -1,3 +1,7 @@ +discard """ +batchable: false +""" + # # # Nim's Runtime Library @@ -16,7 +20,7 @@ # by storing them on the heap. For procs, we produce on the fly simple # trampolines that can be dynamically overwritten to jump to a different # target. In the host program, all globals and procs are first registered -# here with ``hcrRegisterGlobal`` and ``hcrRegisterProc`` and then the +# here with `hcrRegisterGlobal` and `hcrRegisterProc` and then the # returned permanent locations are used in every reference to these symbols # onwards. # @@ -196,6 +200,9 @@ # block. Perhaps something can be done about this - some way of re-allocating # the state and transferring the old... +when defined(nimPreviewSlimSystem): + import std/assertions + when not defined(js) and (defined(hotcodereloading) or defined(createNimHcr) or defined(testNimHcr)): @@ -205,14 +212,14 @@ when not defined(js) and (defined(hotcodereloading) or else: "so" type HcrProcGetter* = proc (libHandle: pointer, procName: cstring): pointer {.nimcall.} - HcrGcMarkerProc = proc () {.nimcall.} + HcrGcMarkerProc = proc () {.nimcall, raises: [].} HcrModuleInitializer* = proc () {.nimcall.} when defined(createNimHcr): when system.appType != "lib": {.error: "This file has to be compiled as a library!".} - import os, tables, sets, times, strutils, reservedmem, dynlib + import std/[os, tables, sets, times, strutils, reservedmem, dynlib] template trace(args: varargs[untyped]) = when defined(testNimHcr) or defined(traceHcr): @@ -226,41 +233,41 @@ when defined(createNimHcr): when defined(testNimHcr): return ($arg).splitFile.name.splitFile.name else: return $arg - {.pragma: nimhcr, compilerProc, exportc, dynlib.} - - when hostCPU in ["i386", "amd64"]: - type - ShortJumpInstruction {.packed.} = object - opcode: byte - offset: int32 - - LongJumpInstruction {.packed.} = object - opcode1: byte - opcode2: byte - offset: int32 - absoluteAddr: pointer - - proc writeJump(jumpTableEntry: ptr LongJumpInstruction, targetFn: pointer) = - let - jumpFrom = jumpTableEntry.shift(sizeof(ShortJumpInstruction)) - jumpDistance = distance(jumpFrom, targetFn) - - if abs(jumpDistance) < 0x7fff0000: - let shortJump = cast[ptr ShortJumpInstruction](jumpTableEntry) - shortJump.opcode = 0xE9 # relative jump - shortJump.offset = int32(jumpDistance) + {.pragma: nimhcr, compilerproc, exportc, dynlib.} + + # XXX these types are CPU specific and need ARM etc support + type + ShortJumpInstruction {.packed.} = object + opcode: byte + offset: int32 + + LongJumpInstruction {.packed.} = object + opcode1: byte + opcode2: byte + offset: int32 + absoluteAddr: pointer + + proc writeJump(jumpTableEntry: ptr LongJumpInstruction, targetFn: pointer) = + let + jumpFrom = jumpTableEntry.shift(sizeof(ShortJumpInstruction)) + jumpDistance = distance(jumpFrom, targetFn) + + if abs(jumpDistance) < 0x7fff0000: + let shortJump = cast[ptr ShortJumpInstruction](jumpTableEntry) + shortJump.opcode = 0xE9 # relative jump + shortJump.offset = int32(jumpDistance) + else: + jumpTableEntry.opcode1 = 0xff # indirect absolute jump + jumpTableEntry.opcode2 = 0x25 + when hostCPU == "i386": + # on x86 we write the absolute address of the following pointer + jumpTableEntry.offset = cast[int32](addr jumpTableEntry.absoluteAddr) else: - jumpTableEntry.opcode1 = 0xff # indirect absolute jump - jumpTableEntry.opcode2 = 0x25 - when hostCPU == "i386": - # on x86 we write the absolute address of the following pointer - jumpTableEntry.offset = cast[int32](addr jumpTableEntry.absoluteAddr) - else: - # on x64, we use a relative address for the same location - jumpTableEntry.offset = 0 - jumpTableEntry.absoluteAddr = targetFn - - elif hostCPU == "arm": + # on x64, we use a relative address for the same location + jumpTableEntry.offset = 0 + jumpTableEntry.absoluteAddr = targetFn + + if hostCPU == "arm": const jumpSize = 8 elif hostCPU == "arm64": const jumpSize = 16 @@ -298,7 +305,7 @@ when defined(createNimHcr): hash: string gen: int lastModification: Time - handlers: seq[tuple[isBefore: bool, cb: proc ()]] + handlers: seq[tuple[isBefore: bool, cb: proc () {.nimcall.}]] proc newModuleDesc(): ModuleDesc = result.procs = initTable[string, ProcSym]() @@ -419,7 +426,7 @@ when defined(createNimHcr): if modules.contains(name): unloadDll(name) else: - modules.add(name, newModuleDesc()) + modules[name] = newModuleDesc() let copiedName = name & ".copy." & dllExt copyFileWithPermissions(name, copiedName) @@ -483,7 +490,7 @@ when defined(createNimHcr): recursiveDiscovery(modules[curr].imports) allModulesOrderedByDFS.add(curr) continue - loadDll(curr) + loadDll(curr.cstring) # first load all dependencies of the current module and init it after that recursiveDiscovery(modules[curr].imports) @@ -493,20 +500,20 @@ when defined(createNimHcr): proc initModules() = # first init the pointers to hcr functions and also do the registering of typeinfo globals for curr in modulesToInit: - initHcrData(curr) - initTypeInfoGlobals(curr) + initHcrData(curr.cstring) + initTypeInfoGlobals(curr.cstring) # for now system always gets fully inited before any other module (including when reloading) - initPointerData(system) - initGlobalScope(system) + initPointerData(system.cstring) + initGlobalScope(system.cstring) # proceed with the DatInit calls - for all modules - including the main one! for curr in allModulesOrderedByDFS: if curr != system: - initPointerData(curr) + initPointerData(curr.cstring) mainDatInit() # execute top-level code (in global scope) for curr in modulesToInit: if curr != system: - initGlobalScope(curr) + initGlobalScope(curr.cstring) # cleanup old symbols which are gone now for curr in modulesToInit: cleanupSymbols(curr) @@ -550,13 +557,17 @@ when defined(createNimHcr): # Future versions of NIMHCR won't use the GC, because all globals and the # metadata needed to access them will be placed in shared memory, so they # can be manipulated from external programs without reloading. - GC_disable() - defer: GC_enable() + when declared(GC_disable): + GC_disable() + defer: GC_enable() + elif declared(GC_disableOrc): + GC_disableOrc() + defer: GC_enableOrc() inc(generation) trace "HCR RELOADING: ", generation - var traversedHandlerModules = initSet[string]() + var traversedHandlerModules = initHashSet[string]() proc recursiveExecuteHandlers(isBefore: bool, module: string) = # do not process an already traversed module @@ -591,18 +602,18 @@ when defined(createNimHcr): hashToModuleMap.del(modules[name].hash) modules.del(name) - proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) {.nimhcr.} = + proc hcrAddEventHandler*(isBefore: bool, cb: proc () {.nimcall.}) {.nimhcr.} = modules[currentModule].handlers.add( (isBefore: isBefore, cb: cb)) proc hcrAddModule*(module: cstring) {.nimhcr.} = if not modules.contains($module): - modules.add($module, newModuleDesc()) + modules[$module] = newModuleDesc() proc hcrGeneration*(): int {.nimhcr.} = generation - proc hcrMarkGlobals*() {.nimhcr, nimcall, gcsafe.} = + proc hcrMarkGlobals*() {.compilerproc, exportc, dynlib, nimcall, gcsafe.} = # This is gcsafe, because it will be registered # only in the GC of the main thread. {.gcsafe.}: @@ -618,7 +629,7 @@ elif defined(hotcodereloading) or defined(testNimHcr): elif defined(macosx): "libnimhcr." & dllExt else: "libnimhcr." & dllExt - {.pragma: nimhcr, compilerProc, importc, dynlib: nimhcrLibname.} + {.pragma: nimhcr, compilerproc, importc, dynlib: nimhcrLibname.} proc hcrRegisterProc*(module: cstring, name: cstring, fn: pointer): pointer {.nimhcr.} @@ -642,19 +653,19 @@ elif defined(hotcodereloading) or defined(testNimHcr): proc hcrPerformCodeReload*() {.nimhcr.} - proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) {.nimhcr.} + proc hcrAddEventHandler*(isBefore: bool, cb: proc () {.nimcall.}) {.nimhcr.} - proc hcrMarkGlobals*() {.nimhcr, nimcall, gcsafe.} + proc hcrMarkGlobals*() {.raises: [], nimhcr, nimcall, gcsafe.} when declared(nimRegisterGlobalMarker): - nimRegisterGlobalMarker(hcrMarkGlobals) + nimRegisterGlobalMarker(cast[GlobalMarkerProc](hcrMarkGlobals)) else: proc hcrHasModuleChanged*(moduleHash: string): bool = # TODO false - proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) = + proc hcrAddEventHandler*(isBefore: bool, cb: proc () {.nimcall.}) = # TODO discard |