fixes for exception handling; added system.compileOption

This commit is contained in:
Araq 2010-09-13 00:52:44 +02:00
commit 866572e2e4
18 changed files with 329 additions and 165 deletions

View file

@ -177,10 +177,6 @@ __TINYC__
** **
** Fortunately the ISO C99 specifications define the functions lrint, lrintf, ** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
** llrint and llrintf which fix this problem as a side effect. ** llrint and llrintf which fix this problem as a side effect.
**
** On Unix-like systems, the configure process should have detected the
** presence of these functions. If they weren't found we have to replace them
** here with a standard C cast.
*/ */
/* /*
@ -444,4 +440,12 @@ __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
} }
#endif #endif
#ifdef __GNUC__
# define likely(x) __builtin_expect(x, 1)
# define unlikely(x) __builtin_expect(x, 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
#endif #endif

View file

@ -144,6 +144,7 @@ type
E_Base* {.compilerproc.} = object of TObject ## base exception class; E_Base* {.compilerproc.} = object of TObject ## base exception class;
## each exception has to ## each exception has to
## inherit from `E_Base`. ## inherit from `E_Base`.
parent: ref E_Base ## parent exception (can be used as a stack)
name: cstring ## The exception's name is its Nimrod identifier. name: cstring ## The exception's name is its Nimrod identifier.
## This field is filled automatically in the ## This field is filled automatically in the
## ``raise`` statement. ## ``raise`` statement.
@ -717,6 +718,22 @@ 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".
proc compileOption*(option: string): bool {.
magic: "CompileOption", noSideEffect.}
## can be used to determine a on|off compile-time option. Example:
##
## .. code-block:: nimrod
## when compileOption("floatchecks"):
## echo "compiled with floating point NaN and Inf checks"
proc compileOption*(option, arg: string): bool {.
magic: "CompileOptionArg", noSideEffect.}
## can be used to determine an enum compile-time option. Example:
##
## .. code-block:: nimrod
## when compileOption("opt", "size") and compileOption("gc", "boehm"):
## echo "compiled with optimization for size and uses Boehm's GC"
include "system/inclrtl" include "system/inclrtl"
include "system/cgprocs" include "system/cgprocs"
@ -961,14 +978,6 @@ proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
#proc writeStackTrace() {.export: "writeStackTrace".} #proc writeStackTrace() {.export: "writeStackTrace".}
when not defined(NimrodVM):
proc getCurrentExceptionMsg*(): string {.exportc.}
## retrieves the error message that was attached to the current
## exception; if there is none, "" is returned.
proc getCurrentException*(): ref E_Base
## retrieves the current exception; if there is none, nil is returned.
# new constants: # new constants:
const const
inf* {.magic: "Inf".} = 1.0 / 0.0 inf* {.magic: "Inf".} = 1.0 / 0.0
@ -1168,15 +1177,6 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
## `op` to every item in `data`. ## `op` to every item in `data`.
for i in 0..data.len-1: op(data[i]) for i in 0..data.len-1: op(data[i])
# ----------------- FPU ------------------------------------------------------
#proc disableFPUExceptions*()
# disables all floating point unit exceptions
#proc enableFPUExceptions*()
# enables all floating point unit exceptions
# ----------------- GC interface --------------------------------------------- # ----------------- GC interface ---------------------------------------------
proc GC_disable*() {.rtl.} proc GC_disable*() {.rtl.}
@ -1577,14 +1577,15 @@ when not defined(EcmaScript) and not defined(NimrodVM):
include "system/assign" include "system/assign"
include "system/repr" include "system/repr"
# we have to implement it here after gentostr for the cstrToNimStrDummy proc proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
proc getCurrentExceptionMsg(): string = ## retrieves the current exception; if there is none, nil is returned.
if excHandler == nil: return "" result = currException
return $excHandler.exc.msg
proc getCurrentException(): ref E_Base = proc getCurrentExceptionMsg*(): string {.inline.} =
if excHandler != nil: ## retrieves the error message that was attached to the current
result = excHandler.exc ## exception; if there is none, "" is returned.
var e = getCurrentException()
return if e == nil: "" else: e.msg
{.push stack_trace: off.} {.push stack_trace: off.}
when defined(endb): when defined(endb):
@ -1594,6 +1595,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
include "system/profiler" include "system/profiler"
{.pop.} # stacktrace {.pop.} # stacktrace
proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
## can be used to mark a condition to be likely. This is a hint for the
## optimizer.
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
## can be used to mark a condition to be unlikely. This is a hint for the
## optimizer.
elif defined(ecmaScript): elif defined(ecmaScript):
include "system/ecmasys" include "system/ecmasys"
elif defined(NimrodVM): elif defined(NimrodVM):

View file

@ -20,9 +20,6 @@ else:
proc writeToStdErr(msg: CString) = proc writeToStdErr(msg: CString) =
discard MessageBoxA(0, msg, nil, 0) discard MessageBoxA(0, msg, nil, 0)
proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.}
proc reraiseException() {.compilerproc.}
proc registerSignalHandler() {.compilerproc.} proc registerSignalHandler() {.compilerproc.}
proc chckIndx(i, a, b: int): int {.inline, compilerproc.} proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
@ -34,20 +31,29 @@ type
PSafePoint = ptr TSafePoint PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc, final.} = object TSafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point ON THE STACK prev: PSafePoint # points to next safe point ON THE STACK
exc: ref E_Base
status: int status: int
exc: ref E_Base # XXX only needed for bootstrapping
context: C_JmpBuf context: C_JmpBuf
var var
excHandler {.compilerproc.}: PSafePoint = nil excHandler {.compilerproc.}: PSafePoint = nil
# list of exception handlers # list of exception handlers
# a global variable for the root of all try blocks # a global variable for the root of all try blocks
currException: ref E_Base
proc reraiseException() = proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
if excHandler == nil: s.prev = excHandler
raise newException(ENoExceptionToReraise, "no exception to reraise") excHandler = s
else:
c_longjmp(excHandler.context, 1) proc popSafePoint {.compilerRtl, inl.} =
excHandler = excHandler.prev
proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} =
e.parent = currException
currException = e
proc popCurrentException {.compilerRtl, inl.} =
currException = currException.parent
type type
PFrame = ptr TFrame PFrame = ptr TFrame
@ -114,13 +120,17 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
add(s, stackTraceNewLine) add(s, stackTraceNewLine)
proc rawWriteStackTrace(s: var string) = proc rawWriteStackTrace(s: var string) =
if framePtr == nil: when compileOption("stacktrace") or compileOption("linetrace"):
if framePtr == nil:
add(s, "No stack traceback available")
add(s, stackTraceNewLine)
else:
add(s, "Traceback (most recent call last)")
add(s, stackTraceNewLine)
auxWriteStackTrace(framePtr, s)
else:
add(s, "No stack traceback available") add(s, "No stack traceback available")
add(s, stackTraceNewLine) add(s, stackTraceNewLine)
else:
add(s, "Traceback (most recent call last)")
add(s, stackTraceNewLine)
auxWriteStackTrace(framePtr, s)
proc quitOrDebug() {.inline.} = proc quitOrDebug() {.inline.} =
when not defined(endb): when not defined(endb):
@ -128,11 +138,11 @@ proc quitOrDebug() {.inline.} =
else: else:
endbStep() # call the debugger endbStep() # call the debugger
proc raiseException(e: ref E_Base, ename: CString) = proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
GC_disable() # a bad thing is an error in the GC while raising an exception GC_disable() # a bad thing is an error in the GC while raising an exception
e.name = ename e.name = ename
if excHandler != nil: if excHandler != nil:
excHandler.exc = e pushCurrentException(e)
c_longjmp(excHandler.context, 1) c_longjmp(excHandler.context, 1)
else: else:
if not isNil(buf): if not isNil(buf):
@ -152,6 +162,12 @@ proc raiseException(e: ref E_Base, ename: CString) =
quitOrDebug() quitOrDebug()
GC_enable() GC_enable()
proc reraiseException() {.compilerRtl.} =
if currException == nil:
raise newException(ENoExceptionToReraise, "no exception to reraise")
else:
raiseException(currException, currException.name)
var var
gAssertionFailed: ref EAssertionFailed gAssertionFailed: ref EAssertionFailed

View file

@ -61,6 +61,8 @@ type
decStack: TCellSeq # cells in the stack that are to decref again decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSet cycleRoots: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination tempStack: TCellSeq # temporary stack for recursion elimination
cycleRootsLock: TSysLock
zctLock: TSysLock
stat: TGcStat stat: TGcStat
var var
@ -68,12 +70,22 @@ var
gch: TGcHeap gch: TGcHeap
cycleThreshold: int = InitialCycleThreshold cycleThreshold: int = InitialCycleThreshold
recGcLock: int = 0 recGcLock: int = 0
# we use a lock to prevend the garbage collector to be triggered in a # we use a lock to prevent the garbage collector to be triggered in a
# finalizer; the collector should not call itself this way! Thus every # finalizer; the collector should not call itself this way! Thus every
# object allocated by a finalizer will not trigger a garbage collection. # object allocated by a finalizer will not trigger a garbage collection.
# This is wasteful but safe. This is a lock against recursive garbage # This is wasteful but safe. This is a lock against recursive garbage
# collection, not a lock for threads! # collection, not a lock for threads!
proc lock(gch: var TGcHeap) {.inline.} =
if isMultiThreaded:
Lock(gch.zctLock)
lock(gch.cycleRootsLock)
proc unlock(gch: var TGcHeap) {.inline.} =
if isMultiThreaded:
unlock(gch.zctLock)
unlock(gch.cycleRootsLock)
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} = proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
if (c.refcount and rcZct) == 0: if (c.refcount and rcZct) == 0:
c.refcount = c.refcount and not colorMask or rcZct c.refcount = c.refcount and not colorMask or rcZct
@ -159,7 +171,7 @@ when traceGC:
for c in elements(states[csAllocated]): for c in elements(states[csAllocated]):
inc(e) inc(e)
if c in states[csZctFreed]: inc(z) if c in states[csZctFreed]: inc(z)
elif c in states[csCycFreed]: inc(z) elif c in states[csCycFreed]: inc(y)
else: writeCell("leak", c) else: writeCell("leak", c)
cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n", cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
e, z, y) e, z, y)
@ -190,25 +202,28 @@ proc prepareDealloc(cell: PCell) =
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
# we MUST access gch as a global here, because this crosses DLL boundaries! # we MUST access gch as a global here, because this crosses DLL boundaries!
if isMultiThreaded: Lock(gch.cycleRootsLock)
incl(gch.cycleRoots, c) incl(gch.cycleRoots, c)
if isMultiThreaded: Unlock(gch.cycleRootsLock)
proc rtlAddZCT(c: PCell) {.rtl, inl.} = proc rtlAddZCT(c: PCell) {.rtl, inl.} =
# we MUST access gch as a global here, because this crosses DLL boundaries! # we MUST access gch as a global here, because this crosses DLL boundaries!
if isMultiThreaded: Lock(gch.zctLock)
addZCT(gch.zct, c) addZCT(gch.zct, c)
if isMultiThreaded: Unlock(gch.zctLock)
proc decRef(c: PCell) {.inline.} = proc decRef(c: PCell) {.inline.} =
when stressGC: when stressGC:
if c.refcount <% rcIncrement: if c.refcount <% rcIncrement:
writeCell("broken cell", c) writeCell("broken cell", c)
assert(c.refcount >=% rcIncrement) assert(c.refcount >=% rcIncrement)
c.refcount = c.refcount -% rcIncrement if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
if c.refcount <% rcIncrement:
rtlAddZCT(c) rtlAddZCT(c)
elif canBeCycleRoot(c): elif canBeCycleRoot(c):
rtlAddCycleRoot(c) rtlAddCycleRoot(c)
proc incRef(c: PCell) {.inline.} = proc incRef(c: PCell) {.inline.} =
c.refcount = c.refcount +% rcIncrement discard atomicInc(c.refcount, rcIncrement)
if canBeCycleRoot(c): if canBeCycleRoot(c):
rtlAddCycleRoot(c) rtlAddCycleRoot(c)
@ -228,11 +243,10 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
# cycle is possible. # cycle is possible.
if src != nil: if src != nil:
var c = usrToCell(src) var c = usrToCell(src)
c.refcount = c.refcount +% rcIncrement discard atomicInc(c.refcount, rcIncrement)
if dest^ != nil: if dest^ != nil:
var c = usrToCell(dest^) var c = usrToCell(dest^)
c.refcount = c.refcount -% rcIncrement if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
if c.refcount <% rcIncrement:
rtlAddZCT(c) rtlAddZCT(c)
dest^ = src dest^ = src
@ -260,6 +274,8 @@ proc initGC() =
init(gch.tempStack) init(gch.tempStack)
Init(gch.cycleRoots) Init(gch.cycleRoots)
Init(gch.decStack) Init(gch.decStack)
InitLock(gch.cycleRootsLock)
InitLock(gch.zctLock)
new(gOutOfMem) # reserve space for the EOutOfMemory exception here! new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
@ -310,6 +326,7 @@ proc checkCollection {.inline.} =
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
lock(gch)
assert(typ.kind in {tyRef, tyString, tySequence}) assert(typ.kind in {tyRef, tyString, tySequence})
checkCollection() checkCollection()
var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell))) var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell)))
@ -337,15 +354,18 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
break addToZCT break addToZCT
add(gch.zct, res) add(gch.zct, res)
when logGC: writeCell("new cell", res) when logGC: writeCell("new cell", res)
gcTrace(res, csAllocated) gcTrace(res, csAllocated)
unlock(gch)
result = cellToUsr(res) result = cellToUsr(res)
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
# `newObj` already uses locks, so no need for them here.
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
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 {.rtl.} = proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
lock(gch)
checkCollection() checkCollection()
var ol = usrToCell(old) var ol = usrToCell(old)
assert(ol.typ != nil) assert(ol.typ != nil)
@ -383,6 +403,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
else: else:
assert(ol.typ != nil) assert(ol.typ != nil)
zeroMem(ol, sizeof(TCell)) zeroMem(ol, sizeof(TCell))
unlock(gch)
result = cellToUsr(res) result = cellToUsr(res)
# ---------------- cycle collector ------------------------------------------- # ---------------- cycle collector -------------------------------------------
@ -632,9 +653,9 @@ proc collectCT(gch: var TGcHeap) =
unmarkStackAndRegisters(gch) unmarkStackAndRegisters(gch)
when not defined(useNimRtl): when not defined(useNimRtl):
proc GC_disable() = inc(recGcLock) proc GC_disable() = discard atomicInc(recGcLock, 1)
proc GC_enable() = proc GC_enable() =
if recGcLock > 0: dec(recGcLock) if recGcLock > 0: discard atomicDec(recGcLock, 1)
proc GC_setStrategy(strategy: TGC_Strategy) = proc GC_setStrategy(strategy: TGC_Strategy) =
case strategy case strategy
@ -651,10 +672,12 @@ when not defined(useNimRtl):
# set to the max value to suppress the cycle detector # set to the max value to suppress the cycle detector
proc GC_fullCollect() = proc GC_fullCollect() =
lock(gch)
var oldThreshold = cycleThreshold var oldThreshold = cycleThreshold
cycleThreshold = 0 # forces cycle collection cycleThreshold = 0 # forces cycle collection
collectCT(gch) collectCT(gch)
cycleThreshold = oldThreshold cycleThreshold = oldThreshold
unlock(gch)
proc GC_getStatistics(): string = proc GC_getStatistics(): string =
GC_disable() GC_disable()

View file

@ -15,6 +15,10 @@ when defined(gcc) or defined(llvm_gcc):
elif defined(vcc): elif defined(vcc):
proc sync_add_and_fetch(p: var int, val: int): int {. proc sync_add_and_fetch(p: var int, val: int): int {.
importc: "NimXadd", nodecl.} importc: "NimXadd", nodecl.}
else:
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
inc(p, val)
result = p
const const
isMultiThreaded* = true isMultiThreaded* = true
@ -37,12 +41,51 @@ proc atomicDec(memLoc: var int, x: int): int =
dec(memLoc, x) dec(memLoc, x)
result = memLoc result = memLoc
when defined(Windows):
type
THandle = int
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
DebugInfo: pointer
LockCount: int32
RecursionCount: int32
OwningThread: int
LockSemaphore: int
Reserved: int32
proc InitLock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
proc Lock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "EnterCriticalSection".}
proc Unlock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
lpStartAddress: pointer, lpParameter: Pointer,
dwCreationFlags: int32, lpThreadId: var int32): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
else:
type
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
proc InitLock(L: var TSysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>".}
proc Lock(L: var TSysLock) {.
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc Unlock(L: var TSysLock) {.
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
type type
TThread* {.final, pure.} = object TThread* {.final, pure.} = object
id: int
next: ptr TThread next: ptr TThread
TThreadFunc* = proc (closure: pointer) TThreadFunc* = proc (closure: pointer) {.cdecl.}
proc createThread*(t: var TThread, fn: TThreadFunc) = proc createThread*(t: var TThread, fn: TThreadFunc) =
nil nil
proc destroyThread*(t: var TThread) = proc destroyThread*(t: var TThread) =
@ -50,4 +93,3 @@ proc destroyThread*(t: var TThread) =

View file

@ -31,8 +31,8 @@ type
const const
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
"noconv"] "closure", "noconv"]
type type
TNodeKind* = enum # order is extremely important, because ranges are used TNodeKind* = enum # order is extremely important, because ranges are used
@ -329,8 +329,9 @@ type
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNaN, mInf, mNegInf,
mNegInf, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,

View file

@ -27,21 +27,15 @@ proc genLineDir(p: BProc, t: PNode) =
appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n", appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n",
[toRope(line), makeCString(toFilename(t.info).extractFilename)]) [toRope(line), makeCString(toFilename(t.info).extractFilename)])
proc finishTryStmt(p: BProc, howMany: int) = proc popSafePoints(p: BProc, howMany: int) =
for i in countup(1, howMany): for i in countup(1, howMany):
inc(p.labels, 3) appcg(p, cpsStmts, "#popSafePoint();$n", [])
appff(p.s[cpsStmts], "excHandler = excHandler->prev;$n",
"%LOC$1 = load %TSafePoint** @excHandler$n" &
"%LOC$2 = getelementptr %TSafePoint* %LOC$1, %NI 0$n" &
"%LOC$3 = load %TSafePoint** %LOC$2$n" &
"store %TSafePoint* %LOC$3, %TSafePoint** @excHandler$n",
[toRope(p.labels), toRope(p.labels - 1), toRope(p.labels - 2)])
proc genReturnStmt(p: BProc, t: PNode) = proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true p.beforeRetNeeded = true
genLineDir(p, t) genLineDir(p, t)
if (t.sons[0] != nil): genStmts(p, t.sons[0]) if (t.sons[0] != nil): genStmts(p, t.sons[0])
finishTryStmt(p, p.nestedTryStmts) popSafePoints(p, p.nestedTryStmts)
appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", []) appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", [])
proc genVarTuple(p: BProc, n: PNode) = proc genVarTuple(p: BProc, n: PNode) =
@ -202,7 +196,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
assert(sym.loc.k == locOther) assert(sym.loc.k == locOther)
idx = sym.loc.a idx = sym.loc.a
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
finishTryStmt(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts) popSafePoints(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)]) appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)])
proc genAsmStmt(p: BProc, t: PNode) = proc genAsmStmt(p: BProc, t: PNode) =
@ -477,7 +471,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
# { # {
# case DIVIDE_BY_ZERO: # case DIVIDE_BY_ZERO:
# tmpRethrow = false; # tmpRethrow = false;
# printf('Division by Zero\n'); # printf("Division by Zero\n");
# break; # break;
# default: // used for general except! # default: // used for general except!
# generalExceptPart(); # generalExceptPart();
@ -526,8 +520,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
inc(i) inc(i)
if t.sons[1].kind == nkExceptBranch: if t.sons[1].kind == nkExceptBranch:
app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement
popSafePoints(p, p.nestedTryStmts)
dec(p.nestedTryStmts) dec(p.nestedTryStmts)
app(p.s[cpsStmts], "excHandler = excHandler->prev;" & tnl)
if (i < length) and (t.sons[i].kind == nkFinally): if (i < length) and (t.sons[i].kind == nkFinally):
genStmts(p, t.sons[i].sons[0]) genStmts(p, t.sons[i].sons[0])
if rethrowFlag != nil: if rethrowFlag != nil:
@ -536,38 +530,39 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
proc genTryStmt(p: BProc, t: PNode) = proc genTryStmt(p: BProc, t: PNode) =
# code to generate: # code to generate:
# #
# sp.prev = excHandler; # TSafePoint sp;
# excHandler = &sp; # pushSafePoint(&sp);
# sp.status = setjmp(sp.context); # sp.status = setjmp(sp.context);
# if (sp.status == 0) { # if (sp.status == 0) {
# myDiv(4, 9); # myDiv(4, 9);
# popSafePoint();
# } else { # } else {
# popSafePoint();
# /* except DivisionByZero: */ # /* except DivisionByZero: */
# if (sp.status == DivisionByZero) { # if (sp.status == DivisionByZero) {
# printf('Division by Zero\n'); # printf('Division by Zero\n');
# # clearException();
# /* longjmp(excHandler->context, RangeError); /* raise rangeError */ # } else {
# sp.status = RangeError; /* if raise; else 0 */ # clearException();
# } # }
# } # }
# excHandler = excHandler->prev; /* deactivate this safe point */
# /* finally: */ # /* finally: */
# printf('fin!\n'); # printf('fin!\n');
# if (sp.status != 0) # if (exception not cleared)
# longjmp(excHandler->context, sp.status); # propagateCurrentException();
genLineDir(p, t) genLineDir(p, t)
var safePoint = getTempName() var safePoint = getTempName()
discard cgsym(p.module, "E_Base") discard cgsym(p.module, "E_Base")
appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
appcg(p, cpsStmts, "$1.prev = #excHandler;$n" & "excHandler = &$1;$n" & appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" &
"$1.status = setjmp($1.context);$n", [safePoint]) "$1.status = setjmp($1.context);$n", [safePoint])
if optStackTrace in p.Options: if optStackTrace in p.Options:
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl) app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint]) appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t) var length = sonsLen(t)
inc(p.nestedTryStmts) inc(p.nestedTryStmts)
genStmts(p, t.sons[0]) genStmts(p, t.sons[0])
app(p.s[cpsStmts], "} else {" & tnl) appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n")
var i = 1 var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
var blen = sonsLen(t.sons[i]) var blen = sonsLen(t.sons[i])
@ -575,27 +570,27 @@ proc genTryStmt(p: BProc, t: PNode) =
# general except section: # general except section:
if i > 1: app(p.s[cpsStmts], "else {" & tnl) if i > 1: app(p.s[cpsStmts], "else {" & tnl)
genStmts(p, t.sons[i].sons[0]) genStmts(p, t.sons[i].sons[0])
appf(p.s[cpsStmts], "$1.status = 0;$n", [safePoint]) appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();$n", [safePoint])
if i > 1: app(p.s[cpsStmts], '}' & tnl) if i > 1: app(p.s[cpsStmts], '}' & tnl)
else: else:
var orExpr: PRope = nil var orExpr: PRope = nil
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
if orExpr != nil: app(orExpr, "||") if orExpr != nil: app(orExpr, "||")
appf(orExpr, "($1.exc->Sup.m_type == $2)", appcg(p.module, orExpr, "#getCurrentException()->Sup.m_type == $1",
[safePoint, genTypeInfo(p.module, t.sons[i].sons[j].typ)]) [genTypeInfo(p.module, t.sons[i].sons[j].typ)])
if i > 1: app(p.s[cpsStmts], "else ") if i > 1: app(p.s[cpsStmts], "else ")
appf(p.s[cpsStmts], "if ($1) {$n", [orExpr]) appf(p.s[cpsStmts], "if ($1) {$n", [orExpr])
genStmts(p, t.sons[i].sons[blen - 1]) # code to clear the exception: genStmts(p, t.sons[i].sons[blen-1])
appf(p.s[cpsStmts], "$1.status = 0;}$n", [safePoint]) # code to clear the exception:
appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();}$n",
[safePoint])
inc(i) inc(i)
app(p.s[cpsStmts], '}' & tnl) # end of if statement app(p.s[cpsStmts], '}' & tnl) # end of if statement
finishTryStmt(p, p.nestedTryStmts)
dec(p.nestedTryStmts) dec(p.nestedTryStmts)
if (i < length) and (t.sons[i].kind == nkFinally): if i < length and t.sons[i].kind == nkFinally:
genStmts(p, t.sons[i].sons[0]) genStmts(p, t.sons[i].sons[0])
appcg(p, cpsStmts, "if ($1.status != 0) { " & appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
"#raiseException($1.exc, $1.exc->name); }$n", [safePoint])
var var
breakPointId: int = 0 breakPointId: int = 0

View file

@ -193,7 +193,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope =
while true: while true:
j = (j * 10) + Ord(frmt[i]) - ord('0') j = (j * 10) + Ord(frmt[i]) - ord('0')
inc(i) inc(i)
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break if i >= length or not (frmt[i] in {'0'..'9'}): break
num = j num = j
if j > high(args) + 1: if j > high(args) + 1:
internalError("ropes: invalid format string $" & $(j)) internalError("ropes: invalid format string $" & $(j))

View file

@ -222,6 +222,54 @@ proc processCompile(filename: string) =
extccomp.addExternalFileToCompile(found) extccomp.addExternalFileToCompile(found)
extccomp.addFileToLink(completeCFilePath(trunc, false)) extccomp.addFileToLink(completeCFilePath(trunc, false))
proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
case whichKeyword(switch)
of wGC:
case whichKeyword(arg)
of wBoehm: result = contains(gGlobalOptions, optBoehmGC)
of wRefc: result = contains(gGlobalOptions, optRefcGC)
of wNone: result = gGlobalOptions * {optBoehmGC, optRefcGC} == {}
else: liMessage(info, errNoneBoehmRefcExpectedButXFound, arg)
of wOpt:
case whichKeyword(arg)
of wSpeed: result = contains(gOptions, optOptimizeSpeed)
of wSize: result = contains(gOptions, optOptimizeSize)
of wNone: result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
else: liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: InvalidCmdLineOption(passCmd1, switch, info)
proc testCompileOption*(switch: string, info: TLineInfo): bool =
case whichKeyword(switch)
of wDebuginfo: result = contains(gGlobalOptions, optCDebug)
of wCompileOnly, wC: result = contains(gGlobalOptions, optCompileOnly)
of wNoLinking: result = contains(gGlobalOptions, optNoLinking)
of wNoMain: result = contains(gGlobalOptions, optNoMain)
of wForceBuild, wF: result = contains(gGlobalOptions, optForceFullMake)
of wWarnings, wW: result = contains(gOptions, optWarns)
of wHints: result = contains(gOptions, optHints)
of wCheckpoints: result = contains(gOptions, optCheckpoints)
of wStackTrace: result = contains(gOptions, optStackTrace)
of wLineTrace: result = contains(gOptions, optLineTrace)
of wDebugger: result = contains(gOptions, optEndb)
of wProfiler: result = contains(gOptions, optProfiler)
of wChecks, wX: result = gOptions * checksOptions == checksOptions
of wFloatChecks:
result = gOptions * {optNanCheck, optInfCheck} == {optNanCheck, optInfCheck}
of wInfChecks: result = contains(gOptions, optInfCheck)
of wNanChecks: result = contains(gOptions, optNanCheck)
of wObjChecks: result = contains(gOptions, optObjCheck)
of wFieldChecks: result = contains(gOptions, optFieldCheck)
of wRangeChecks: result = contains(gOptions, optRangeCheck)
of wBoundChecks: result = contains(gOptions, optBoundsCheck)
of wOverflowChecks: result = contains(gOptions, optOverflowCheck)
of wLineDir: result = contains(gOptions, optLineDir)
of wAssertions, wA: result = contains(gOptions, optAssert)
of wDeadCodeElim: result = contains(gGlobalOptions, optDeadCodeElim)
of wRun, wR: result = contains(gGlobalOptions, optRun)
of wSymbolFiles: result = contains(gGlobalOptions, optSymbolFiles)
of wGenScript: result = contains(gGlobalOptions, optGenScript)
else: InvalidCmdLineOption(passCmd1, switch, info)
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
var var
theOS: TSystemOS theOS: TSystemOS

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 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.
@ -10,10 +10,8 @@
# This module is responsible for loading of rod files. # This module is responsible for loading of rod files.
# #
# Reading and writing binary files are really hard to debug. Therefore we use # Reading and writing binary files are really hard to debug. Therefore we use
# a special text format. ROD-files only describe the interface of a module. # a special text format. ROD-files are more efficient to process because
# Thus they are smaller than the source files most of the time. Even if they # symbols are only loaded on demand.
# are bigger, they are more efficient to process because symbols are only
# loaded on demand.
# It consists of: # It consists of:
# #
# - a header: # - a header:
@ -149,10 +147,10 @@ proc decodeBInt(r: PRodReader): biggestInt
proc encode(s: string): PRope = proc encode(s: string): PRope =
var res = "" var res = ""
for i in countup(0, len(s) + 0 - 1): for i in countup(0, len(s) - 1):
case s[i] case s[i]
of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(res, s[i]) of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(res, s[i])
else: res = res & '\\' & toHex(ord(s[i]), 2) else: add(res, '\\' & toHex(ord(s[i]), 2))
result = toRope(res) result = toRope(res)
proc encodeIntAux(str: var string, x: BiggestInt) = proc encodeIntAux(str: var string, x: BiggestInt) =
@ -191,9 +189,6 @@ proc decodeLineInfo(r: PRodReader, info: var TLineInfo) =
info = newLineInfo(r.files[decodeInt(r)], info.line, info.col) info = newLineInfo(r.files[decodeInt(r)], info.line, info.col)
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
var
id: int
fl: string
result = nil result = nil
if r.s[r.pos] == '(': if r.s[r.pos] == '(':
inc(r.pos) inc(r.pos)
@ -207,7 +202,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
result.flags = cast[TNodeFlags](int32(decodeInt(r))) result.flags = cast[TNodeFlags](int32(decodeInt(r)))
if r.s[r.pos] == '^': if r.s[r.pos] == '^':
inc(r.pos) inc(r.pos)
id = decodeInt(r) var id = decodeInt(r)
result.typ = rrGetType(r, id, result.info) result.typ = rrGetType(r, id, result.info)
case result.kind case result.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkInt64Lit:
@ -217,7 +212,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
if r.s[r.pos] == '!': if r.s[r.pos] == '!':
inc(r.pos) inc(r.pos)
fl = decode(r) var fl = decode(r)
result.floatVal = parseFloat(fl) result.floatVal = parseFloat(fl)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if r.s[r.pos] == '!': if r.s[r.pos] == '!':
@ -228,14 +223,14 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
of nkIdent: of nkIdent:
if r.s[r.pos] == '!': if r.s[r.pos] == '!':
inc(r.pos) inc(r.pos)
fl = decode(r) var fl = decode(r)
result.ident = getIdent(fl) result.ident = getIdent(fl)
else: else:
internalError(result.info, "decodeNode: nkIdent") internalError(result.info, "decodeNode: nkIdent")
of nkSym: of nkSym:
if r.s[r.pos] == '!': if r.s[r.pos] == '!':
inc(r.pos) inc(r.pos)
id = decodeInt(r) var id = decodeInt(r)
result.sym = rrGetSym(r, id, result.info) result.sym = rrGetSym(r, id, result.info)
else: else:
internalError(result.info, "decodeNode: nkSym") internalError(result.info, "decodeNode: nkSym")
@ -282,7 +277,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
else: InternalError(info, "decodeLoc " & r.s[r.pos]) else: InternalError(info, "decodeLoc " & r.s[r.pos])
proc decodeType(r: PRodReader, info: TLineInfo): PType = proc decodeType(r: PRodReader, info: TLineInfo): PType =
var d: int
result = nil result = nil
if r.s[r.pos] == '[': if r.s[r.pos] == '[':
inc(r.pos) inc(r.pos)
@ -335,7 +329,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
else: InternalError(info, "decodeType ^(" & r.s[r.pos]) else: InternalError(info, "decodeType ^(" & r.s[r.pos])
addSon(result, nil) addSon(result, nil)
else: else:
d = decodeInt(r) var d = decodeInt(r)
addSon(result, rrGetType(r, d, info)) addSon(result, rrGetType(r, d, info))
proc decodeLib(r: PRodReader, info: TLineInfo): PLib = proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
@ -470,8 +464,8 @@ proc decode(r: PRodReader): string =
of '\\': of '\\':
inc(i, 3) inc(i, 3)
var xi = 0 var xi = 0
hexChar(r.s[i - 2], xi) hexChar(r.s[i-2], xi)
hexChar(r.s[i - 1], xi) hexChar(r.s[i-1], xi)
add(result, chr(xi)) add(result, chr(xi))
of 'a'..'z', 'A'..'Z', '0'..'9', '_': of 'a'..'z', 'A'..'Z', '0'..'9', '_':
add(result, r.s[i]) add(result, r.s[i])
@ -488,7 +482,7 @@ proc skipSection(r: PRodReader) =
while true: while true:
case r.s[r.pos] case r.s[r.pos]
of '\x0A': inc(r.line) of '\x0A': inc(r.line)
of '(': inc(c) of '(': inc(c)
of ')': of ')':
if c == 0: if c == 0:
inc(r.pos) inc(r.pos)
@ -499,7 +493,7 @@ proc skipSection(r: PRodReader) =
else: nil else: nil
inc(r.pos) inc(r.pos)
else: else:
InternalError("skipSection " & $(r.line)) InternalError("skipSection " & $r.line)
proc rdWord(r: PRodReader): string = proc rdWord(r: PRodReader): string =
result = "" result = ""
@ -530,18 +524,14 @@ proc processInterf(r: PRodReader, module: PSym) =
IdTablePut(r.syms, s, s) IdTablePut(r.syms, s, s)
proc processCompilerProcs(r: PRodReader, module: PSym) = proc processCompilerProcs(r: PRodReader, module: PSym) =
var
s: PSym
w: string
key: int
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs") if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
r.pos = r.compilerProcsIdx r.pos = r.compilerProcsIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
w = decode(r) var w = decode(r)
inc(r.pos) inc(r.pos)
key = decodeInt(r) var key = decodeInt(r)
inc(r.pos) # #10 inc(r.pos) # #10
s = PSym(IdTableGet(r.syms, key)) var s = PSym(IdTableGet(r.syms, key))
if s == nil: if s == nil:
s = newStub(r, w, key) s = newStub(r, w, key)
s.owner = module s.owner = module
@ -572,24 +562,25 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
proc processRodFile(r: PRodReader, crc: TCrc32) = proc processRodFile(r: PRodReader, crc: TCrc32) =
var var
section, w: string w: string
d, L, inclCrc: int d, L, inclCrc: int
while r.s[r.pos] != '\0': while r.s[r.pos] != '\0':
section = rdWord(r) var section = rdWord(r)
if r.reason != rrNone: if r.reason != rrNone:
break # no need to process this file further break # no need to process this file further
if section == "CRC": case section
of "CRC":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
if int(crc) != decodeInt(r): r.reason = rrCrcChange if int(crc) != decodeInt(r): r.reason = rrCrcChange
elif section == "ID": of "ID":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
r.moduleID = decodeInt(r) r.moduleID = decodeInt(r)
setID(r.moduleID) setID(r.moduleID)
elif section == "OPTIONS": of "OPTIONS":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
r.options = cast[TOptions](int32(decodeInt(r))) r.options = cast[TOptions](int32(decodeInt(r)))
if options.gOptions != r.options: r.reason = rrOptions if options.gOptions != r.options: r.reason = rrOptions
elif section == "DEFINES": of "DEFINES":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
d = 0 d = 0
while r.s[r.pos] > '\x0A': while r.s[r.pos] > '\x0A':
@ -599,7 +590,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
r.reason = rrDefines #MessageOut('not defined, but should: ' + w); r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
if r.s[r.pos] == ' ': inc(r.pos) if r.s[r.pos] == ' ': inc(r.pos)
if (d != countDefinedSymbols()): r.reason = rrDefines if (d != countDefinedSymbols()): r.reason = rrDefines
elif section == "FILES": of "FILES":
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
L = 0 L = 0
@ -610,7 +601,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.line) inc(r.line)
inc(L) inc(L)
if r.s[r.pos] == ')': inc(r.pos) if r.s[r.pos] == ')': inc(r.pos)
elif section == "INCLUDES": of "INCLUDES":
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
@ -624,7 +615,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.pos) inc(r.pos)
inc(r.line) inc(r.line)
if r.s[r.pos] == ')': inc(r.pos) if r.s[r.pos] == ')': inc(r.pos)
elif section == "DEPS": of "DEPS":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
L = 0 L = 0
while (r.s[r.pos] > '\x0A'): while (r.s[r.pos] > '\x0A'):
@ -632,32 +623,32 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
r.modDeps[L] = r.files[decodeInt(r)] r.modDeps[L] = r.files[decodeInt(r)]
inc(L) inc(L)
if r.s[r.pos] == ' ': inc(r.pos) if r.s[r.pos] == ' ': inc(r.pos)
elif section == "INTERF": of "INTERF":
r.interfIdx = r.pos + 2 r.interfIdx = r.pos + 2
skipSection(r) skipSection(r)
elif section == "COMPILERPROCS": of "COMPILERPROCS":
r.compilerProcsIdx = r.pos + 2 r.compilerProcsIdx = r.pos + 2
skipSection(r) skipSection(r)
elif section == "INDEX": of "INDEX":
processIndex(r, r.index) processIndex(r, r.index)
elif section == "IMPORTS": of "IMPORTS":
processIndex(r, r.imports) processIndex(r, r.imports)
elif section == "CONVERTERS": of "CONVERTERS":
r.convertersIdx = r.pos + 1 r.convertersIdx = r.pos + 1
skipSection(r) skipSection(r)
elif section == "DATA": of "DATA":
r.dataIdx = r.pos + 2 # "(\10" r.dataIdx = r.pos + 2 # "(\10"
# We do not read the DATA section here! We read the needed objects on # We do not read the DATA section here! We read the needed objects on
# demand. # demand.
skipSection(r) skipSection(r)
elif section == "INIT": of "INIT":
r.initIdx = r.pos + 2 # "(\10" r.initIdx = r.pos + 2 # "(\10"
skipSection(r) skipSection(r)
elif section == "CGEN": of "CGEN":
r.cgenIdx = r.pos + 2 r.cgenIdx = r.pos + 2
skipSection(r) skipSection(r)
else: else:
MessageOut("skipping section: " & $(r.pos)) MessageOut("skipping section: " & $r.pos)
skipSection(r) skipSection(r)
if r.s[r.pos] == '\x0A': if r.s[r.pos] == '\x0A':
inc(r.pos) inc(r.pos)
@ -686,7 +677,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
inc(r.pos) inc(r.pos)
if r.s[r.pos] == '\x0A': inc(r.pos) if r.s[r.pos] == '\x0A': inc(r.pos)
if version == FileVersion: if version == FileVersion:
# since ROD files are only for caching, no backwarts compability is # since ROD files are only for caching, no backwarts compatibility is
# needed # needed
processRodFile(r, crc) processRodFile(r, crc)
else: else:
@ -814,7 +805,8 @@ proc checkDep(filename: string): TReasonForRecompile =
for i in countup(0, high(r.modDeps)): for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i]) res = checkDep(r.modDeps[i])
if res != rrNone: if res != rrNone:
result = rrModDeps #break // BUGFIX: cannot break here! result = rrModDeps
# we cannot break here, because of side-effects of `checkDep`
else: else:
result = rrRodDoesNotExist result = rrRodDoesNotExist
if (result != rrNone) and (gVerbosity > 0): if (result != rrNone) and (gVerbosity > 0):

View file

@ -70,8 +70,8 @@ proc fileIdx(w: PRodWriter, filename: string): int =
proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter = proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
new(result) new(result)
result.sstack = @ [] result.sstack = @[]
result.tstack = @ [] result.tstack = @[]
InitIITable(result.index.tab) InitIITable(result.index.tab)
InitIITable(result.imports.tab) InitIITable(result.imports.tab)
result.filename = modfilename result.filename = modfilename
@ -79,7 +79,7 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
result.module = module result.module = module
result.defines = getDefines() result.defines = getDefines()
result.options = options.gOptions result.options = options.gOptions
result.files = @ [] result.files = @[]
proc addModDep(w: PRodWriter, dep: string) = proc addModDep(w: PRodWriter, dep: string) =
if w.modDeps != nil: app(w.modDeps, " ") if w.modDeps != nil: app(w.modDeps, " ")
@ -284,11 +284,10 @@ proc symStack(w: PRodWriter) =
setlen(w.sstack, 0) setlen(w.sstack, 0)
proc typeStack(w: PRodWriter) = proc typeStack(w: PRodWriter) =
var i, L: int var i = 0
i = 0
while i < len(w.tstack): while i < len(w.tstack):
if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey: if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey:
L = ropeLen(w.data) var L = ropeLen(w.data)
addToIndex(w.index, w.tstack[i].id, L) addToIndex(w.index, w.tstack[i].id, L)
app(w.data, encodeType(w, w.tstack[i])) app(w.data, encodeType(w, w.tstack[i]))
app(w.data, rodNL) app(w.data, rodNL)
@ -317,9 +316,8 @@ proc addStmt(w: PRodWriter, n: PNode) =
processStacks(w) processStacks(w)
proc writeRod(w: PRodWriter) = proc writeRod(w: PRodWriter) =
var content: PRope
processStacks(w) # write header: processStacks(w) # write header:
content = toRope("NIM:") var content = toRope("NIM:")
app(content, toRope(FileVersion)) app(content, toRope(FileVersion))
app(content, rodNL) app(content, rodNL)
app(content, toRope("ID:")) app(content, toRope("ID:"))
@ -373,43 +371,39 @@ proc writeRod(w: PRodWriter) =
writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod"))) writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod")))
proc process(c: PPassContext, n: PNode): PNode = proc process(c: PPassContext, n: PNode): PNode =
var
w: PRodWriter
a: PNode
s: PSym
result = n result = n
if c == nil: return if c == nil: return
w = PRodWriter(c) var w = PRodWriter(c)
case n.kind case n.kind
of nkStmtList: of nkStmtList:
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i]) for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
of nkTemplateDef, nkMacroDef: of nkTemplateDef, nkMacroDef:
s = n.sons[namePos].sym var s = n.sons[namePos].sym
addInterfaceSym(w, s) addInterfaceSym(w, s)
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef: of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef:
s = n.sons[namePos].sym var s = n.sons[namePos].sym
if s == nil: InternalError(n.info, "rodwrite.process") if s == nil: InternalError(n.info, "rodwrite.process")
if (n.sons[codePos] != nil) or (s.magic != mNone) or if (n.sons[codePos] != nil) or (s.magic != mNone) or
not (sfForward in s.flags): not (sfForward in s.flags):
addInterfaceSym(w, s) addInterfaceSym(w, s)
of nkVarSection: of nkVarSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if a.kind != nkIdentDefs: InternalError(a.info, "rodwrite.process") if a.kind != nkIdentDefs: InternalError(a.info, "rodwrite.process")
addInterfaceSym(w, a.sons[0].sym) addInterfaceSym(w, a.sons[0].sym)
of nkConstSection: of nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if a.kind != nkConstDef: InternalError(a.info, "rodwrite.process") if a.kind != nkConstDef: InternalError(a.info, "rodwrite.process")
addInterfaceSym(w, a.sons[0].sym) addInterfaceSym(w, a.sons[0].sym)
of nkTypeSection: of nkTypeSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process") if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process")
s = a.sons[0].sym var s = a.sons[0].sym
addInterfaceSym(w, s) addInterfaceSym(w, s)
# this takes care of enum fields too # this takes care of enum fields too
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum # Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum

View file

@ -12,7 +12,8 @@
import import
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, rnimsyn, types nversion, platform, math, msgs, os, condsyms, idents, rnimsyn, types,
commands
proc getConstExpr*(m: PSym, n: PNode): PNode proc getConstExpr*(m: PSym, n: PNode): PNode
# evaluates the constant expression or returns nil if it is no constant # evaluates the constant expression or returns nil if it is no constant
@ -194,6 +195,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mArrToSeq: of mArrToSeq:
result = copyTree(a) result = copyTree(a)
result.typ = n.typ result.typ = n.typ
of mCompileOption:
result = newIntNodeT(Ord(commands.testCompileOption(getStr(a), n.info)), n)
of mCompileOptionArg:
result = newIntNodeT(Ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
of mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh, of mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mNLen..mNError, mEqRef: mNLen..mNError, mEqRef:

View file

@ -0,0 +1,21 @@
type
ESomething = object of E_Base
ESomeOtherErr = object of E_Base
proc genErrors(s: string) =
if s == "error!":
raise newException(ESomething, "Test")
else:
raise newException(EsomeotherErr, "bla")
try:
for i in 0..3:
try:
genErrors("error!")
except ESomething:
echo("Error happened")
echo "came here"
raise newException(EsomeotherErr, "bla")
finally:
echo "caught"

5
tests/accept/run/toverflw2.nim Executable file
View file

@ -0,0 +1,5 @@
var a : int32 = 2147483647
var b : int32 = 2147483647
var c = a + b

View file

@ -6,6 +6,11 @@
# define TCC_TARGET_PE 1 # define TCC_TARGET_PE 1
# define TCC_TARGET_I386 # define TCC_TARGET_I386
# define CONFIG_TCCDIR "." # define CONFIG_TCCDIR "."
#elif defined(__i386__)
# define TCC_TARGET_I386
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
# define GCC_MAJOR 4
# define HOST_I386 1
#else #else
# define TCC_TARGET_X86_64 # define TCC_TARGET_X86_64
# define CONFIG_TCCDIR "/usr/local/lib/tcc" # define CONFIG_TCCDIR "/usr/local/lib/tcc"

View file

@ -1,10 +1,8 @@
For version 0.8.10 For version 0.8.10
================== ==================
- exception propagation across DLLs
- fix exception handling
- fix implicit generic routines - fix implicit generic routines
- fix the streams implementation so that they use methods - fix the streams implementation so that it uses methods
High priority (version 0.9.0) High priority (version 0.9.0)

View file

@ -33,6 +33,9 @@ case $uos in
*darwin* ) *darwin* )
myos="macosx" myos="macosx"
LINK_FLAGS="$LINK_FLAGS -ldl -lm" LINK_FLAGS="$LINK_FLAGS -ldl -lm"
if [ `sysctl hw |grep 64bit` = "hw.cpu64bit_capable: 1" ] ; then
ucpu="amd64"
fi
;; ;;
*aix* ) *aix* )
myos="aix" myos="aix"

View file

@ -15,9 +15,10 @@ Bugfixes
- Bugfix: ``system.splitChunk`` still contained code for debug output. - Bugfix: ``system.splitChunk`` still contained code for debug output.
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of - Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
``STOCK_OPEN`` for the GTK backend. ``STOCK_OPEN`` for the GTK backend.
- Bugfix: ``raise`` within an exception handler did not work. - Bugfix: Various bugs concerning exception handling fixed.
- Bugfix: ``low(somestring)`` crashed the compiler. - Bugfix: ``low(somestring)`` crashed the compiler.
- Bugfix: ``strutils.endsWith`` lacked range checking. - Bugfix: ``strutils.endsWith`` lacked range checking.
- Bugfix: Better detection for AMD64 on Mac OS X.
Changes affecting backwards compatibility Changes affecting backwards compatibility
@ -48,6 +49,7 @@ Additions
- Added ``system.reopen``. - Added ``system.reopen``.
- Added ``system.getCurrentException``. - Added ``system.getCurrentException``.
- Added ``system.appType``. - Added ``system.appType``.
- Added ``system.compileOption``.
- Added ``times.epochTime`` and ``times.cpuTime``. - Added ``times.epochTime`` and ``times.cpuTime``.
- Implemented explicit type arguments for generics. - Implemented explicit type arguments for generics.
- Implemented implicit type arguments for generics. - Implemented implicit type arguments for generics.