before stack init change

This commit is contained in:
Andreas Rumpf 2010-08-01 14:49:54 +02:00
commit 03724c2952
13 changed files with 93 additions and 57 deletions

View file

@ -385,8 +385,6 @@ proc intToStr(x: int, minchars: int = 1): string =
if x < 0: if x < 0:
result = '-' & result result = '-' & result
proc toString[Ty](x: Ty): string = return $x
proc toOctal(c: char): string = proc toOctal(c: char): string =
result = newString(3) result = newString(3)
var val = ord(c) var val = ord(c)

View file

@ -666,7 +666,8 @@ proc `&` * (x: char, y: string): string {.
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
include "system/inclrtl"
include "system/cgprocs" include "system/cgprocs"
when not defined(ECMAScript): when not defined(ECMAScript):
@ -824,8 +825,6 @@ const
## a string that describes the application type. Possible values: ## a string that describes the application type. Possible values:
## "console", "gui", "lib". ## "console", "gui", "lib".
include "system/inclrtl"
proc toFloat*(i: int): float {. proc toFloat*(i: int): float {.
magic: "ToFloat", noSideEffect, importc: "toFloat".} magic: "ToFloat", noSideEffect, importc: "toFloat".}
## converts an integer `i` into a ``float``. If the conversion ## converts an integer `i` into a ``float``. If the conversion
@ -1305,12 +1304,17 @@ when not defined(EcmaScript) and not defined(NimrodVM):
proc initGC() proc initGC()
proc initStackBottom() {.inline.} =
var locals: array[0..7, int]
setStackBottom(addr(locals))
var var
strDesc: TNimType strDesc: TNimType
strDesc.size = sizeof(string) strDesc.size = sizeof(string)
strDesc.kind = tyString strDesc.kind = tyString
strDesc.flags = {ntfAcyclic} strDesc.flags = {ntfAcyclic}
initStackBottom()
initGC() # BUGFIX: need to be called here! initGC() # BUGFIX: need to be called here!
{.push stack_trace: off.} {.push stack_trace: off.}

View file

@ -11,4 +11,16 @@
proc addChar(s: NimString, c: char): NimString {.compilerProc.} proc addChar(s: NimString, c: char): NimString {.compilerProc.}
type
TLibHandle = pointer # private type
TProcAddr = pointer # libary loading and loading of procs:
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
proc setStackBottom(theStackBottom: pointer) {.compilerRtl.}

View file

@ -12,24 +12,28 @@
# However, the interface has been designed to take platform differences into # However, the interface has been designed to take platform differences into
# account and been ported to all major platforms. # account and been ported to all major platforms.
type
TLibHandle = pointer # private type
TProcAddr = pointer # libary loading and loading of procs:
const const
NilLibHandle: TLibHandle = nil NilLibHandle: TLibHandle = nil
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.} proc rawWrite(f: TFile, s: string) =
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.} # we cannot throw an exception here!
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.} discard writeBuffer(f, cstring(s), s.len)
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.} = proc nimLoadLibraryError(path: string) =
when true: # carefully written to avoid memory allocation:
# carefully written to avoid memory allocation: #stdout.write("could not load: ")
stdout.write("could not load: ") #quit(path)
quit(path) stdout.rawWrite("could not load: ")
else: stdout.rawWrite(path)
raise newException(EInvalidLibrary, "could not load: " & path) stdout.rawWrite("\n")
quit(1)
proc ProcAddrError(name: cstring) {.noinline.} =
# carefully written to avoid memory allocation:
stdout.rawWrite("could not import: ")
stdout.write(name)
stdout.rawWrite("\n")
quit(1)
# this code was inspired from Lua's source code: # this code was inspired from Lua's source code:
# Lua - An Extensible Extension Language # Lua - An Extensible Extension Language
@ -65,7 +69,7 @@ when defined(posix):
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr = proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
result = dlsym(lib, name) result = dlsym(lib, name)
if result == nil: nimLoadLibraryError($name) if result == nil: ProcAddrError(name)
elif defined(windows) or defined(dos): elif defined(windows) or defined(dos):
# #
@ -90,7 +94,7 @@ elif defined(windows) or defined(dos):
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr = proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
result = GetProcAddress(cast[THINSTANCE](lib), name) result = GetProcAddress(cast[THINSTANCE](lib), name)
if result == nil: nimLoadLibraryError($name) if result == nil: ProcAddrError(name)
elif defined(mac): elif defined(mac):
# #
@ -126,7 +130,7 @@ elif defined(mac):
nss: NSSymbol nss: NSSymbol
nss = NSLookupSymbolInModule(NSModule(lib), name) nss = NSLookupSymbolInModule(NSModule(lib), name)
result = TProcAddr(NSAddressOfSymbol(nss)) result = TProcAddr(NSAddressOfSymbol(nss))
if result == nil: nimLoadLibraryError($name) if result == nil: ProcAddrError(name)
else: else:
{.error: "no implementation for dyncalls".} {.error: "no implementation for dyncalls".}

View file

@ -214,11 +214,6 @@ proc prepareDealloc(cell: PCell) =
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell)) (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(recGcLock) dec(recGcLock)
proc setStackBottom(theStackBottom: pointer) {.compilerRtl.} =
# the first init must be the one that defines the stack bottom:
if stackBottom == nil:
stackBottom = theStackBottom
proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} = proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
if canbeCycleRoot(c): incl(gch.cycleRoots, c) if canbeCycleRoot(c): incl(gch.cycleRoots, c)
@ -367,7 +362,7 @@ proc newSeq(typ: PNimType, len: int): pointer =
cast[PGenericSeq](result).len = len cast[PGenericSeq](result).len = len
cast[PGenericSeq](result).space = len cast[PGenericSeq](result).space = len
proc growObj(old: pointer, newsize: int): pointer = proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
checkCollection() checkCollection()
var ol = usrToCell(old) var ol = usrToCell(old)
assert(ol.typ != nil) assert(ol.typ != nil)
@ -487,6 +482,25 @@ proc markThreadStacks(gch: var TGcHeap) =
# ----------------- stack management -------------------------------------- # ----------------- stack management --------------------------------------
# inspired from Smart Eiffel # inspired from Smart Eiffel
when defined(sparc):
const stackIncreases = false
elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
const stackIncreases = true
else:
const stackIncreases = false
proc setStackBottom(theStackBottom: pointer) =
# the first init must be the one that defines the stack bottom:
if stackBottom == nil: stackBottom = theStackBottom
else:
var a = cast[TAddress](theStackBottom)
var b = cast[TAddress](stackBottom)
when stackIncreases:
stackBottom = cast[pointer](min(a, b))
else:
stackBottom = cast[pointer](max(a, b))
proc stackSize(): int {.noinline.} = proc stackSize(): int {.noinline.} =
var stackTop: array[0..1, pointer] var stackTop: array[0..1, pointer]
result = abs(cast[int](addr(stackTop[0])) - cast[int](stackBottom)) result = abs(cast[int](addr(stackTop[0])) - cast[int](stackBottom))
@ -518,8 +532,7 @@ when defined(sparc): # For SPARC architecture.
elif defined(ELATE): elif defined(ELATE):
{.error: "stack marking code is to be written for this architecture".} {.error: "stack marking code is to be written for this architecture".}
elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or elif stackIncreases:
defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Generic code for architectures where addresses increase as the stack grows. # Generic code for architectures where addresses increase as the stack grows.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View file

@ -21,7 +21,7 @@ when defined(createNimRtl):
when defined(useNimRtl): when defined(useNimRtl):
{.error: "Cannot create and use nimrtl at the same time!".} {.error: "Cannot create and use nimrtl at the same time!".}
elif appType != "lib": elif appType != "lib":
{.error: "nimrtl must be build as a library!".} {.error: "nimrtl must be built as a library!".}
when defined(createNimRtl): when defined(createNimRtl):
# NOTE: compilerproc cannot make use of name mangling! # NOTE: compilerproc cannot make use of name mangling!

View file

@ -117,7 +117,7 @@ when defined(boehmgc):
proc growObj(old: pointer, newsize: int): pointer = proc growObj(old: pointer, newsize: int): pointer =
result = realloc(old, newsize) result = realloc(old, newsize)
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil proc setStackBottom(theStackBottom: pointer) = nil
proc nimGCref(p: pointer) {.compilerproc, inline.} = nil proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
@ -175,7 +175,7 @@ elif defined(nogc):
proc growObj(old: pointer, newsize: int): pointer = proc growObj(old: pointer, newsize: int): pointer =
result = realloc(old, newsize) result = realloc(old, newsize)
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil proc setStackBottom(theStackBottom: pointer) = nil
proc nimGCref(p: pointer) {.compilerproc, inline.} = nil proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
@ -194,12 +194,6 @@ elif defined(useNimRtl):
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
proc growObj(old: pointer, newsize: int): pointer {.rtl.} proc growObj(old: pointer, newsize: int): pointer {.rtl.}
proc setStackBottom(theStackBottom: pointer) {.compilerProc, inline.} =
# This happens before setStackBottom has been loaded by dlsym(), so
# we simply provide a dummy implemenation here for the code gen. No
# harm is done by this.
nil
proc nimGCref(p: pointer) {.compilerRtl.} proc nimGCref(p: pointer) {.compilerRtl.}
proc nimGCunref(p: pointer) {.compilerRtl.} proc nimGCunref(p: pointer) {.compilerRtl.}

View file

@ -284,7 +284,8 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
flagsToStr(n.options), toRope("position"), flagsToStr(n.options), toRope("position"),
toRope(n.position)]) toRope(n.position)])
proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, maxRecDepth: int): PRope = proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif intSetContainsOrIncl(marker, n.id): elif intSetContainsOrIncl(marker, n.id):
@ -417,7 +418,10 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
appf(result, "$n$1}", [spaces(indent)]) appf(result, "$n$1}", [spaces(indent)])
proc debug(n: PSym) = proc debug(n: PSym) =
writeln(stdout, ropeToStr(ropef("$1_$2", [toRope(n.name.s), toRope(n.id)]))) #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
flagsToStr(n.loc.flags)])))
proc debug(n: PType) = proc debug(n: PType) =
writeln(stdout, ropeToStr(debugType(n))) writeln(stdout, ropeToStr(debugType(n)))

View file

@ -715,10 +715,12 @@ proc genStmts(p: BProc, t: PNode) =
of nkProcDef, nkMethodDef, nkConverterDef: of nkProcDef, nkMethodDef, nkConverterDef:
if (t.sons[genericParamsPos] == nil): if (t.sons[genericParamsPos] == nil):
prc = t.sons[namePos].sym prc = t.sons[namePos].sym
if not (optDeadCodeElim in gGlobalOptions) and if (optDeadCodeElim notin gGlobalOptions and
not (sfDeadCodeElim in getModule(prc).flags) or sfDeadCodeElim notin getModule(prc).flags) or
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
(prc.kind == skMethod): (prc.kind == skMethod):
# we have not only the header:
if (t.sons[codePos] != nil) or (lfDynamicLib in prc.loc.flags): if (t.sons[codePos] != nil) or (lfDynamicLib in prc.loc.flags):
genProc(p.module, prc) genProc(p.module, prc)
else: internalError(t.info, "genStmts(" & $t.kind & ')') else: internalError(t.info, "genStmts(" & $t.kind & ')')

View file

@ -399,7 +399,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
lib.generated = true lib.generated = true
var tmp = getGlobalTempName() var tmp = getGlobalTempName()
assert(lib.name == nil) assert(lib.name == nil)
lib.name = tmp # BUGFIX: useMagic has awful side-effects lib.name = tmp # BUGFIX: cgsym has awful side-effects
appf(m.s[cfsVars], "static void* $1;$n", [tmp]) appf(m.s[cfsVars], "static void* $1;$n", [tmp])
if lib.path.kind in {nkStrLit..nkTripleStrLit}: if lib.path.kind in {nkStrLit..nkTripleStrLit}:
var s: TStringSeq = @[] var s: TStringSeq = @[]
@ -437,14 +437,14 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex var lib = sym.annex
var extname = sym.loc.r var extname = sym.loc.r
loadDynamicLib(m, lib) loadDynamicLib(m, lib)
discard cgsym(m, "nimGetProcAddr") #discard cgsym(m, "nimGetProcAddr")
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
var tmp = mangleDynLibProc(sym) var tmp = mangleDynLibProc(sym)
sym.loc.r = tmp # from now on we only need the internal name sym.loc.r = tmp # from now on we only need the internal name
sym.typ.sym = nil # generate a new name sym.typ.sym = nil # generate a new name
inc(m.labels, 2) inc(m.labels, 2)
appf(m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"$1 = ($2) nimGetProcAddr($3, $4);$n", "$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ), [tmp, getTypeDesc(m, sym.typ),
lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
appff(m.s[cfsVars], "$2 $1;$n", appff(m.s[cfsVars], "$2 $1;$n",
@ -458,7 +458,7 @@ proc cgsym(m: BModule, name: string): PRope =
of skProc, skMethod, skConverter: genProc(m, sym) of skProc, skMethod, skConverter: genProc(m, sym)
of skVar: genVarPrototype(m, sym) of skVar: genVarPrototype(m, sym)
of skType: discard getTypeDesc(m, sym.typ) of skType: discard getTypeDesc(m, sym.typ)
else: InternalError("useMagic: " & name) else: InternalError("cgsym: " & name)
else: else:
# we used to exclude the system module from this check, but for DLL # we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so # generation support this sloppyness leads to hard to detect bugs, so
@ -700,10 +700,10 @@ proc getFileHeader(cfilenoext: string): PRope =
proc genMainProc(m: BModule) = proc genMainProc(m: BModule) =
const const
CommonMainBody = " setStackBottom(dummy);$n" & " nim__datInit();$n" & CommonMainBody = " #setStackBottom(dummy);$n" & " nim__datInit();$n" &
" systemInit();$n" & "$1" & "$2" " systemInit();$n" & "$1" & "$2"
CommonMainBodyLLVM = " %MOC$3 = bitcast [8 x %NI]* %dummy to i8*$n" & CommonMainBodyLLVM = " %MOC$3 = bitcast [8 x %NI]* %dummy to i8*$n" &
" call void @setStackBottom(i8* %MOC$3)$n" & " call void @#setStackBottom(i8* %MOC$3)$n" &
" call void @nim__datInit()$n" & " call void systemInit()$n" & "$1" & " call void @nim__datInit()$n" & " call void systemInit()$n" & "$1" &
"$2" "$2"
PosixNimMain = "int cmdCount;$n" & "char** cmdLine;$n" & "char** gEnv;$n" & PosixNimMain = "int cmdCount;$n" & "char** cmdLine;$n" & "char** gEnv;$n" &
@ -744,7 +744,6 @@ proc genMainProc(m: BModule) =
" i8* %lpvReserved) {$n" & " i8* %lpvReserved) {$n" &
" call void @NimMain()$n" & " ret i32 1$n" & "}$n" " call void @NimMain()$n" & " ret i32 1$n" & "}$n"
var nimMain, otherMain: TFormatStr var nimMain, otherMain: TFormatStr
discard cgsym(m, "setStackBottom")
if (platform.targetOS == osWindows) and if (platform.targetOS == osWindows) and
(gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}): (gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}):
if optGenGuiApp in gGlobalOptions: if optGenGuiApp in gGlobalOptions:
@ -771,8 +770,10 @@ proc genMainProc(m: BModule) =
otherMain = PosixCMain otherMain = PosixCMain
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint") if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
inc(m.labels) inc(m.labels)
appf(m.s[cfsProcs], nimMain, [gBreakpoints, mainModInit, toRope(m.labels)]) appcg(m, m.s[cfsProcs], nimMain, [
if not (optNoMain in gGlobalOptions): appf(m.s[cfsProcs], otherMain, []) gBreakpoints, mainModInit, toRope(m.labels)])
if not (optNoMain in gGlobalOptions):
appcg(m, m.s[cfsProcs], otherMain, [])
proc getInitName(m: PSym): PRope = proc getInitName(m: PSym): PRope =
result = ropeff("$1Init", "@$1Init", [toRope(m.name.s)]) result = ropeff("$1Init", "@$1Init", [toRope(m.name.s)])

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2008 Andreas Rumpf # (c) Copyright 2010 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.
@ -33,8 +33,9 @@ proc verbosePass(): TPass =
proc cleanUp(c: PPassContext, n: PNode): PNode = proc cleanUp(c: PPassContext, n: PNode): PNode =
var s: PSym var s: PSym
result = n # we cannot clean up if dead code elimination is activated result = n
if (optDeadCodeElim in gGlobalOptions): return # we cannot clean up if dead code elimination is activated
if optDeadCodeElim in gGlobalOptions: return
case n.kind case n.kind
of nkStmtList: of nkStmtList:
for i in countup(0, sonsLen(n) - 1): discard cleanup(c, n.sons[i]) for i in countup(0, sonsLen(n) - 1): discard cleanup(c, n.sons[i])

View file

@ -1,7 +1,6 @@
For version 0.8.10 For version 0.8.10
================== ==================
- more robust boot strap process!
- support for generation of dynamic libraries - support for generation of dynamic libraries
- fix exception handling - fix exception handling
- fix implicit generic routines - fix implicit generic routines

View file

@ -34,6 +34,10 @@ Changes affecting backwards compatibility
- Removed ``strutils.splitLinesSeq``. - Removed ``strutils.splitLinesSeq``.
- Removed ``strutils.splitSeq``. - Removed ``strutils.splitSeq``.
- Removed ``strutils.toString``. - Removed ``strutils.toString``.
- If a DLL cannot be loaded (via the ``dynlib`` pragma) ``EInvalidLibrary``
is not raised anymore. Instead ``system.quit()`` is called. This is because
raising an exception requires heap allocations. However the memory manager
might be contained in the DLL that failed to load.
Additions Additions