handling of compiler procs improved for DLL generation

This commit is contained in:
Andreas Rumpf
2010-07-29 21:30:04 +02:00
parent 804e2ac89d
commit ff02ce2d50
33 changed files with 694 additions and 664 deletions

14
lib/system/cgprocs.nim Normal file
View File

@@ -0,0 +1,14 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# Headers for procs that the code generator depends on ("compilerprocs")
proc addChar(s: NimString, c: char): NimString {.compilerProc.}

View File

@@ -24,7 +24,12 @@ proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.} =
raise newException(EInvalidLibrary, "could not load: " & path)
when true:
# carefully written to avoid memory allocation:
stdout.write("could not load: ")
quit(path)
else:
raise newException(EInvalidLibrary, "could not load: " & path)
# this code was inspired from Lua's source code:
# Lua - An Extensible Extension Language

View File

@@ -74,13 +74,13 @@ var
# This is wasteful but safe. This is a lock against recursive garbage
# collection, not a lock for threads!
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc.}
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerRtl.}
# unsureAsgnRef updates the reference counters only if dest is not on the
# stack. It is used by the code generator if it cannot decide wether a
# reference is in the stack or not (this can happen for var parameters).
#proc growObj(old: pointer, newsize: int): pointer {.compilerproc.}
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.}
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
if (c.refcount and rcZct) == 0:
@@ -214,8 +214,10 @@ proc prepareDealloc(cell: PCell) =
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(recGcLock)
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
stackBottom = theStackBottom
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.} =
if canbeCycleRoot(c): incl(gch.cycleRoots, c)
@@ -236,10 +238,10 @@ proc incRef(c: PCell) {.inline.} =
if canBeCycleRoot(c):
incl(gch.cycleRoots, c)
proc nimGCref(p: pointer) {.compilerproc, inline.} = incRef(usrToCell(p))
proc nimGCunref(p: pointer) {.compilerproc, inline.} = decRef(usrToCell(p))
proc nimGCref(p: pointer) {.compilerRtl, inl.} = incRef(usrToCell(p))
proc nimGCunref(p: pointer) {.compilerRtl, inl.} = decRef(usrToCell(p))
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
proc asgnRef(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
# the code generator calls this proc!
assert(not isOnStack(dest))
# BUGFIX: first incRef then decRef!
@@ -247,7 +249,7 @@ proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
if dest^ != nil: decRef(usrToCell(dest^))
dest^ = src
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
# the code generator calls this proc if it is known at compile time that no
# cycle is possible.
if src != nil:

45
lib/system/inclrtl.nim Executable file
View File

@@ -0,0 +1,45 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Pragmas for RTL generation. Has to be an include, because user-defined
## pragmas cannot be exported.
# There are 3 different usages:
# 1) Ordinary imported code.
# 2) Imported from nimrtl.
# -> defined(useNimRtl) or appType == "lib" and not defined(createNimRtl)
# 3) Exported into nimrtl.
# -> appType == "lib" and defined(createNimRtl)
when defined(createNimRtl):
when defined(useNimRtl):
{.error: "Cannot create and use nimrtl at the same time!".}
elif appType != "lib":
{.error: "nimrtl must be build as a library!".}
when defined(createNimRtl):
# NOTE: compilerproc cannot make use of name mangling!
{.pragma: rtl, exportc: "nimrtl_$1", dynlib.}
{.pragma: inl.}
{.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
elif defined(useNimRtl):
when hostOS == "windows":
const nimrtl* = "nimrtl.dll"
elif hostOS == "macosx":
const nimrtl* = "nimrtl.dynlib"
else:
const nimrtl* = "libnimrtl.so"
{.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl.}
{.pragma: inl.}
{.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.}
else:
{.pragma: rtl.}
{.pragma: inl, inline.}
{.pragma: compilerRtl, compilerproc.}

View File

@@ -187,60 +187,35 @@ elif defined(nogc):
dest^ = src
include "system/cellsets"
elif appType == "lib":
{.warning: "gc in a library context may not work".}
when hostOS == "windows":
const nimrtl = "nimrtl.dll"
elif hostOS == "macosx":
const nimrtl = "nimrtl.dynlib"
else:
const nimrtl = "libnimrtl.so"
when not defined(includeGC):
# ordinary client; use the GC from nimrtl.dll:
proc initGC() {.cdecl, importc, dynlib: nimrtl.}
proc GC_disable() {.cdecl, importc, dynlib: nimrtl.}
proc GC_enable() {.cdecl, importc, dynlib: nimrtl.}
proc GC_fullCollect() {.cdecl, importc, dynlib: nimrtl.}
proc GC_setStrategy(strategy: TGC_Strategy) {.
cdecl, importc, dynlib: nimrtl.}
proc GC_enableMarkAndSweep() {.cdecl, importc, dynlib: nimrtl.}
proc GC_disableMarkAndSweep() {.cdecl, importc, dynlib: nimrtl.}
proc GC_getStatistics(): string {.cdecl, importc, dynlib: nimrtl.}
elif defined(useNimRtl):
proc initGC() = nil
proc newObj(typ: PNimType, size: int): pointer {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc newSeq(typ: PNimType, len: int): pointer {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc growObj(old: pointer, newsize: int): pointer {.
cdecl, importc, dynlib: nimrtl.}
proc setStackBottom(theStackBottom: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc nimGCref(p: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc nimGCunref(p: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
proc growObj(old: pointer, newsize: int): pointer {.rtl.}
# The write barrier is performance critical!
# XXX We should ensure that they are inlined here.
# Later implementations will do this.
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 unsureAsgnRef(dest: ppointer, src: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc asgnRef(dest: ppointer, src: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
else:
# include the GC and export it!
include "system/alloc"
include "system/cellsets"
assert(sizeof(TCell) == sizeof(TFreeCell))
include "system/gc"
proc nimGCref(p: pointer) {.compilerRtl.}
proc nimGCunref(p: pointer) {.compilerRtl.}
# The write barrier is performance critical!
# XXX We should ensure that they are inlined here.
# Later implementations will do this.
proc unsureAsgnRef(dest: ppointer, src: pointer) {.
compilerRtl.}
proc asgnRef(dest: ppointer, src: pointer) {.
compilerRtl.}
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.
compilerRtl.}
include "system/cellsets"
else:
include "system/alloc"
include "system/cellsets"

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -35,15 +35,15 @@ proc reprStrAux(result: var string, s: string) =
else: result.add(c)
add result, "\""
proc reprStr(s: string): string {.compilerproc.} =
proc reprStr(s: string): string {.compilerRtl.} =
result = ""
reprStrAux(result, s)
proc reprBool(x: bool): string {.compilerproc.} =
proc reprBool(x: bool): string {.compilerRtl.} =
if x: result = "true"
else: result = "false"
proc reprChar(x: char): string {.compilerproc.} =
proc reprChar(x: char): string {.compilerRtl.} =
result = "\'"
case x
of '"': add result, "\\\""
@@ -52,7 +52,7 @@ proc reprChar(x: char): string {.compilerproc.} =
else: add result, x
add result, "\'"
proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} =
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
if e <% typ.node.len: # BUGFIX
result = $typ.node.sons[e].name
else:
@@ -97,7 +97,7 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
inc(elemCounter)
add result, "}"
proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
result = ""
reprSetAux(result, p, typ)
@@ -108,122 +108,123 @@ type
recdepth: int # do not recurse endless
indent: int # indentation
proc initReprClosure(cl: var TReprClosure) =
Init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
when not defined(useNimRtl):
proc initReprClosure(cl: var TReprClosure) =
Init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
proc deinitReprClosure(cl: var TReprClosure) =
Deinit(cl.marked)
proc deinitReprClosure(cl: var TReprClosure) =
Deinit(cl.marked)
proc reprBreak(result: var string, cl: TReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprBreak(result: var string, cl: TReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure)
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
add result, "]"
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
add result, "]"
proc reprSequence(result: var string, p: pointer, typ: PNimType,
proc reprSequence(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if p == nil:
add result, "nil"
return
result.add(reprPointer(p) & "[")
var bs = typ.base.size
for i in 0..cast[PGenericSeq](p).len-1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
typ.Base, cl)
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) =
case n.kind
of nkNone: assert(false)
of nkSlot:
add result, $n.name
add result, " = "
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
of nkList:
for i in 0..n.len-1:
if i > 0: add result, ",\n"
reprRecordAux(result, p, n.sons[i], cl)
of nkCase:
var m = selectBranch(p, n)
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if p == nil:
add result, "nil"
return
result.add(reprPointer(p) & "[")
var bs = typ.base.size
for i in 0..cast[PGenericSeq](p).len-1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
typ.Base, cl)
add result, "]"
add result, "["
reprRecordAux(result, p, typ.node, cl)
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) =
case n.kind
of nkNone: assert(false)
of nkSlot:
add result, $n.name
add result, " = "
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
of nkList:
for i in 0..n.len-1:
if i > 0: add result, ",\n"
reprRecordAux(result, p, n.sons[i], cl)
of nkCase:
var m = selectBranch(p, n)
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
# we know that p is not nil here:
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
var cell = usrToCell(p)
add result, "ref " & reprPointer(p)
if cell notin cl.marked:
# only the address is shown:
incl(cl.marked, cell)
add result, " --> "
reprAux(result, p, typ.base, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
reprRecordAux(result, p, typ.node, cl)
add result, "]"
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
# we know that p is not nil here:
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
var cell = usrToCell(p)
add result, "ref " & reprPointer(p)
if cell notin cl.marked:
# only the address is shown:
incl(cl.marked, cell)
add result, " --> "
reprAux(result, p, typ.base, cl)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
dec(cl.recdepth)
case typ.kind
of tySet: reprSetAux(result, p, typ)
of tyArray: reprArray(result, p, typ, cl)
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
of tyObject:
var t = cast[ptr PNimType](p)^
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
assert(p != nil)
if cast[ppointer](p)^ == nil: add result, "nil"
else: reprRef(result, cast[ppointer](p)^, typ, cl)
of tySequence:
reprSequence(result, cast[ppointer](p)^, typ, cl)
of tyInt: add result, $(cast[ptr int](p)^)
of tyInt8: add result, $int(cast[ptr Int8](p)^)
of tyInt16: add result, $int(cast[ptr Int16](p)^)
of tyInt32: add result, $int(cast[ptr Int32](p)^)
of tyInt64: add result, $(cast[ptr Int64](p)^)
of tyFloat: add result, $(cast[ptr float](p)^)
of tyFloat32: add result, $(cast[ptr float32](p)^)
of tyFloat64: add result, $(cast[ptr float64](p)^)
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
of tyBool: add result, reprBool(cast[ptr bool](p)^)
of tyChar: add result, reprChar(cast[ptr char](p)^)
of tyString: reprStrAux(result, cast[ptr string](p)^)
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
of tyRange: reprAux(result, p, typ.base, cl)
of tyProc, tyPointer:
if cast[ppointer](p)^ == nil: add result, "nil"
else: add result, reprPointer(cast[ppointer](p)^)
else:
add result, "(invalid data!)"
inc(cl.recdepth)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
dec(cl.recdepth)
case typ.kind
of tySet: reprSetAux(result, p, typ)
of tyArray: reprArray(result, p, typ, cl)
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
of tyObject:
var t = cast[ptr PNimType](p)^
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
assert(p != nil)
if cast[ppointer](p)^ == nil: add result, "nil"
else: reprRef(result, cast[ppointer](p)^, typ, cl)
of tySequence:
reprSequence(result, cast[ppointer](p)^, typ, cl)
of tyInt: add result, $(cast[ptr int](p)^)
of tyInt8: add result, $int(cast[ptr Int8](p)^)
of tyInt16: add result, $int(cast[ptr Int16](p)^)
of tyInt32: add result, $int(cast[ptr Int32](p)^)
of tyInt64: add result, $(cast[ptr Int64](p)^)
of tyFloat: add result, $(cast[ptr float](p)^)
of tyFloat32: add result, $(cast[ptr float32](p)^)
of tyFloat64: add result, $(cast[ptr float64](p)^)
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
of tyBool: add result, reprBool(cast[ptr bool](p)^)
of tyChar: add result, reprChar(cast[ptr char](p)^)
of tyString: reprStrAux(result, cast[ptr string](p)^)
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
of tyRange: reprAux(result, p, typ.base, cl)
of tyProc, tyPointer:
if cast[ppointer](p)^ == nil: add result, "nil"
else: add result, reprPointer(cast[ppointer](p)^)
else:
add result, "(invalid data!)"
inc(cl.recdepth)
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
compilerproc.} =
compilerRtl.} =
var
cl: TReprClosure
initReprClosure(cl)
@@ -235,15 +236,17 @@ proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
add result, "]"
deinitReprClosure(cl)
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
reprAux(result, p, typ, cl)
else:
var p = p
reprAux(result, addr(p), typ, cl)
add result, "\n"
deinitReprClosure(cl)
when not defined(useNimRtl):
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
reprAux(result, p, typ, cl)
else:
var p = p
reprAux(result, addr(p), typ, cl)
add result, "\n"
deinitReprClosure(cl)

View File

@@ -135,14 +135,6 @@ proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
f = fdopen(filehandle, FormatOpen[mode])
result = f != nil
proc OpenFile(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool =
result = open(f, filename, mode, bufSize)
proc openFile(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
result = open(f, filehandle, mode)
# C routine that is used here:
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
importc: "fread", noDecl.}

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -88,7 +88,8 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.exportc.} =
proc copyStr(s: NimString, start: int): NimString {.exportc.} =
return copyStrLast(s, start, s.len-1)
proc addChar(s: NimString, c: char): NimString {.compilerProc.} =
proc addChar(s: NimString, c: char): NimString =
# is compilerproc!
result = s
if result.len >= result.space:
result.space = resize(result.space)
@@ -196,7 +197,7 @@ proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
inc(result.len)
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
compilerProc.} =
compilerRtl.} =
when false:
# broken version:
result = seq
@@ -223,7 +224,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
result.len = newLen
# --------------- other string routines ----------------------------------
proc nimIntToStr(x: int): string {.compilerproc.} =
proc nimIntToStr(x: int): string {.compilerRtl.} =
result = newString(sizeof(x)*4)
var i = 0
var y = x
@@ -246,7 +247,7 @@ proc nimFloatToStr(x: float): string {.compilerproc.} =
c_sprintf(buf, "%#g", x)
return $buf
proc nimInt64ToStr(x: int64): string {.compilerproc.} =
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
# we don't rely on C's runtime here as some C compiler's
# int64 support is weak
result = newString(sizeof(x)*4)