diff options
-rwxr-xr-x | lib/nimbase.h | 12 | ||||
-rwxr-xr-x | lib/system.nim | 57 | ||||
-rwxr-xr-x | lib/system/excpt.nim | 48 | ||||
-rwxr-xr-x | lib/system/gc.nim | 45 | ||||
-rwxr-xr-x | lib/system/systhread.nim | 46 | ||||
-rwxr-xr-x | rod/ast.nim | 9 | ||||
-rwxr-xr-x | rod/ccgstmts.nim | 59 | ||||
-rwxr-xr-x | rod/cgen.nim | 2 | ||||
-rwxr-xr-x | rod/commands.nim | 48 | ||||
-rwxr-xr-x | rod/rodread.nim | 86 | ||||
-rwxr-xr-x | rod/rodwrite.nim | 32 | ||||
-rwxr-xr-x | rod/semfold.nim | 8 | ||||
-rw-r--r-- | tests/accept/run/tcontinuexc.nim | 21 | ||||
-rwxr-xr-x | tests/accept/run/toverflw2.nim | 5 | ||||
-rwxr-xr-x | tinyc/config_edited.h | 5 | ||||
-rwxr-xr-x | todo.txt | 4 | ||||
-rwxr-xr-x | tools/buildsh.tmpl | 3 | ||||
-rwxr-xr-x | web/news.txt | 4 |
18 files changed, 329 insertions, 165 deletions
diff --git a/lib/nimbase.h b/lib/nimbase.h index 01c3ece20..983bb112d 100755 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -177,10 +177,6 @@ __TINYC__ ** ** Fortunately the ISO C99 specifications define the functions lrint, lrintf, ** 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 +#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 diff --git a/lib/system.nim b/lib/system.nim index 0152ebf23..0b2959266 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -144,6 +144,7 @@ type E_Base* {.compilerproc.} = object of TObject ## base exception class; ## each exception has to ## 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. ## This field is filled automatically in the ## ``raise`` statement. @@ -717,6 +718,22 @@ const ## a string that describes the application type. Possible values: ## "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/cgprocs" @@ -961,14 +978,6 @@ proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.} #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: const 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`. 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 --------------------------------------------- proc GC_disable*() {.rtl.} @@ -1577,14 +1577,15 @@ when not defined(EcmaScript) and not defined(NimrodVM): include "system/assign" include "system/repr" - # we have to implement it here after gentostr for the cstrToNimStrDummy proc - proc getCurrentExceptionMsg(): string = - if excHandler == nil: return "" - return $excHandler.exc.msg + proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} = + ## retrieves the current exception; if there is none, nil is returned. + result = currException - proc getCurrentException(): ref E_Base = - if excHandler != nil: - result = excHandler.exc + proc getCurrentExceptionMsg*(): string {.inline.} = + ## retrieves the error message that was attached to the current + ## exception; if there is none, "" is returned. + var e = getCurrentException() + return if e == nil: "" else: e.msg {.push stack_trace: off.} when defined(endb): @@ -1594,6 +1595,14 @@ when not defined(EcmaScript) and not defined(NimrodVM): include "system/profiler" {.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): include "system/ecmasys" elif defined(NimrodVM): diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index d8bdf2a9f..c473c42f0 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -20,9 +20,6 @@ else: proc writeToStdErr(msg: CString) = discard MessageBoxA(0, msg, nil, 0) -proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.} -proc reraiseException() {.compilerproc.} - proc registerSignalHandler() {.compilerproc.} proc chckIndx(i, a, b: int): int {.inline, compilerproc.} @@ -34,20 +31,29 @@ type PSafePoint = ptr TSafePoint TSafePoint {.compilerproc, final.} = object prev: PSafePoint # points to next safe point ON THE STACK - exc: ref E_Base status: int + exc: ref E_Base # XXX only needed for bootstrapping context: C_JmpBuf var excHandler {.compilerproc.}: PSafePoint = nil # list of exception handlers # a global variable for the root of all try blocks + currException: ref E_Base -proc reraiseException() = - if excHandler == nil: - raise newException(ENoExceptionToReraise, "no exception to reraise") - else: - c_longjmp(excHandler.context, 1) +proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = + s.prev = excHandler + excHandler = s + +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 PFrame = ptr TFrame @@ -114,13 +120,17 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = add(s, stackTraceNewLine) proc rawWriteStackTrace(s: var string) = - if framePtr == nil: - add(s, "No stack traceback available") - add(s, stackTraceNewLine) + 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, "Traceback (most recent call last)") + add(s, "No stack traceback available") add(s, stackTraceNewLine) - auxWriteStackTrace(framePtr, s) proc quitOrDebug() {.inline.} = when not defined(endb): @@ -128,11 +138,11 @@ proc quitOrDebug() {.inline.} = else: 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 e.name = ename if excHandler != nil: - excHandler.exc = e + pushCurrentException(e) c_longjmp(excHandler.context, 1) else: if not isNil(buf): @@ -152,6 +162,12 @@ proc raiseException(e: ref E_Base, ename: CString) = quitOrDebug() GC_enable() +proc reraiseException() {.compilerRtl.} = + if currException == nil: + raise newException(ENoExceptionToReraise, "no exception to reraise") + else: + raiseException(currException, currException.name) + var gAssertionFailed: ref EAssertionFailed diff --git a/lib/system/gc.nim b/lib/system/gc.nim index cd803d70a..0c403b4bc 100755 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -61,6 +61,8 @@ type decStack: TCellSeq # cells in the stack that are to decref again cycleRoots: TCellSet tempStack: TCellSeq # temporary stack for recursion elimination + cycleRootsLock: TSysLock + zctLock: TSysLock stat: TGcStat var @@ -68,12 +70,22 @@ var gch: TGcHeap cycleThreshold: int = InitialCycleThreshold 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 # object allocated by a finalizer will not trigger a garbage collection. # This is wasteful but safe. This is a lock against recursive garbage # 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.} = if (c.refcount and rcZct) == 0: c.refcount = c.refcount and not colorMask or rcZct @@ -159,7 +171,7 @@ when traceGC: for c in elements(states[csAllocated]): inc(e) 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) cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n", e, z, y) @@ -190,25 +202,28 @@ proc prepareDealloc(cell: PCell) = proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! + if isMultiThreaded: Lock(gch.cycleRootsLock) incl(gch.cycleRoots, c) + if isMultiThreaded: Unlock(gch.cycleRootsLock) proc rtlAddZCT(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! + if isMultiThreaded: Lock(gch.zctLock) addZCT(gch.zct, c) + if isMultiThreaded: Unlock(gch.zctLock) proc decRef(c: PCell) {.inline.} = when stressGC: if c.refcount <% rcIncrement: writeCell("broken cell", c) assert(c.refcount >=% rcIncrement) - c.refcount = c.refcount -% rcIncrement - if c.refcount <% rcIncrement: + if atomicDec(c.refcount, rcIncrement) <% rcIncrement: rtlAddZCT(c) elif canBeCycleRoot(c): rtlAddCycleRoot(c) proc incRef(c: PCell) {.inline.} = - c.refcount = c.refcount +% rcIncrement + discard atomicInc(c.refcount, rcIncrement) if canBeCycleRoot(c): rtlAddCycleRoot(c) @@ -228,11 +243,10 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} = # cycle is possible. if src != nil: var c = usrToCell(src) - c.refcount = c.refcount +% rcIncrement + discard atomicInc(c.refcount, rcIncrement) if dest^ != nil: var c = usrToCell(dest^) - c.refcount = c.refcount -% rcIncrement - if c.refcount <% rcIncrement: + if atomicDec(c.refcount, rcIncrement) <% rcIncrement: rtlAddZCT(c) dest^ = src @@ -260,6 +274,8 @@ proc initGC() = init(gch.tempStack) Init(gch.cycleRoots) Init(gch.decStack) + InitLock(gch.cycleRootsLock) + InitLock(gch.zctLock) new(gOutOfMem) # reserve space for the EOutOfMemory exception here! proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = @@ -310,6 +326,7 @@ proc checkCollection {.inline.} = proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = # generates a new object and sets its reference counter to 0 + lock(gch) assert(typ.kind in {tyRef, tyString, tySequence}) checkCollection() var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell))) @@ -337,15 +354,18 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = break addToZCT add(gch.zct, res) when logGC: writeCell("new cell", res) - gcTrace(res, csAllocated) + gcTrace(res, csAllocated) + unlock(gch) result = cellToUsr(res) 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)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).space = len proc growObj(old: pointer, newsize: int): pointer {.rtl.} = + lock(gch) checkCollection() var ol = usrToCell(old) assert(ol.typ != nil) @@ -383,6 +403,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} = else: assert(ol.typ != nil) zeroMem(ol, sizeof(TCell)) + unlock(gch) result = cellToUsr(res) # ---------------- cycle collector ------------------------------------------- @@ -632,9 +653,9 @@ proc collectCT(gch: var TGcHeap) = unmarkStackAndRegisters(gch) when not defined(useNimRtl): - proc GC_disable() = inc(recGcLock) + proc GC_disable() = discard atomicInc(recGcLock, 1) proc GC_enable() = - if recGcLock > 0: dec(recGcLock) + if recGcLock > 0: discard atomicDec(recGcLock, 1) proc GC_setStrategy(strategy: TGC_Strategy) = case strategy @@ -651,10 +672,12 @@ when not defined(useNimRtl): # set to the max value to suppress the cycle detector proc GC_fullCollect() = + lock(gch) var oldThreshold = cycleThreshold cycleThreshold = 0 # forces cycle collection collectCT(gch) cycleThreshold = oldThreshold + unlock(gch) proc GC_getStatistics(): string = GC_disable() diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim index 58482ac65..583cd2a43 100755 --- a/lib/system/systhread.nim +++ b/lib/system/systhread.nim @@ -15,6 +15,10 @@ when defined(gcc) or defined(llvm_gcc): elif defined(vcc): proc sync_add_and_fetch(p: var int, val: int): int {. importc: "NimXadd", nodecl.} +else: + proc sync_add_and_fetch(p: var int, val: int): int {.inline.} = + inc(p, val) + result = p const isMultiThreaded* = true @@ -37,12 +41,51 @@ proc atomicDec(memLoc: var int, x: int): int = dec(memLoc, x) 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 TThread* {.final, pure.} = object + id: int next: ptr TThread - TThreadFunc* = proc (closure: pointer) + TThreadFunc* = proc (closure: pointer) {.cdecl.} proc createThread*(t: var TThread, fn: TThreadFunc) = + nil proc destroyThread*(t: var TThread) = @@ -50,4 +93,3 @@ proc destroyThread*(t: var TThread) = - diff --git a/rod/ast.nim b/rod/ast.nim index 5b5676495..a2d35044e 100755 --- a/rod/ast.nim +++ b/rod/ast.nim @@ -31,8 +31,8 @@ type const CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", - "noconv"] + "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", + "closure", "noconv"] type TNodeKind* = enum # order is extremely important, because ranges are used @@ -329,8 +329,9 @@ type mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType, - mNaN, mInf, - mNegInf, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, + mNaN, mInf, mNegInf, + mCompileOption, mCompileOptionArg, + mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, diff --git a/rod/ccgstmts.nim b/rod/ccgstmts.nim index 88deb7f12..e60648184 100755 --- a/rod/ccgstmts.nim +++ b/rod/ccgstmts.nim @@ -27,21 +27,15 @@ proc genLineDir(p: BProc, t: PNode) = appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n", [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): - inc(p.labels, 3) - 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)]) + appcg(p, cpsStmts, "#popSafePoint();$n", []) proc genReturnStmt(p: BProc, t: PNode) = p.beforeRetNeeded = true genLineDir(p, t) 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", []) proc genVarTuple(p: BProc, n: PNode) = @@ -202,7 +196,7 @@ proc genBreakStmt(p: BProc, t: PNode) = assert(sym.loc.k == locOther) idx = sym.loc.a 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)]) proc genAsmStmt(p: BProc, t: PNode) = @@ -477,7 +471,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) = # { # case DIVIDE_BY_ZERO: # tmpRethrow = false; - # printf('Division by Zero\n'); + # printf("Division by Zero\n"); # break; # default: // used for general except! # generalExceptPart(); @@ -526,8 +520,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) = inc(i) if t.sons[1].kind == nkExceptBranch: app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement + popSafePoints(p, p.nestedTryStmts) dec(p.nestedTryStmts) - app(p.s[cpsStmts], "excHandler = excHandler->prev;" & tnl) if (i < length) and (t.sons[i].kind == nkFinally): genStmts(p, t.sons[i].sons[0]) if rethrowFlag != nil: @@ -536,38 +530,39 @@ proc genTryStmtCpp(p: BProc, t: PNode) = proc genTryStmt(p: BProc, t: PNode) = # code to generate: # - # sp.prev = excHandler; - # excHandler = &sp; + # TSafePoint sp; + # pushSafePoint(&sp); # sp.status = setjmp(sp.context); # if (sp.status == 0) { # myDiv(4, 9); + # popSafePoint(); # } else { + # popSafePoint(); # /* except DivisionByZero: */ # if (sp.status == DivisionByZero) { # printf('Division by Zero\n'); - # - # /* longjmp(excHandler->context, RangeError); /* raise rangeError */ - # sp.status = RangeError; /* if raise; else 0 */ + # clearException(); + # } else { + # clearException(); # } # } - # excHandler = excHandler->prev; /* deactivate this safe point */ # /* finally: */ # printf('fin!\n'); - # if (sp.status != 0) - # longjmp(excHandler->context, sp.status); + # if (exception not cleared) + # propagateCurrentException(); genLineDir(p, t) var safePoint = getTempName() discard cgsym(p.module, "E_Base") appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) - appcg(p, cpsStmts, "$1.prev = #excHandler;$n" & "excHandler = &$1;$n" & - "$1.status = setjmp($1.context);$n", [safePoint]) + appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" & + "$1.status = setjmp($1.context);$n", [safePoint]) if optStackTrace in p.Options: app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl) appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint]) var length = sonsLen(t) inc(p.nestedTryStmts) genStmts(p, t.sons[0]) - app(p.s[cpsStmts], "} else {" & tnl) + appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n") var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): var blen = sonsLen(t.sons[i]) @@ -575,27 +570,27 @@ proc genTryStmt(p: BProc, t: PNode) = # general except section: if i > 1: app(p.s[cpsStmts], "else {" & tnl) 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) else: var orExpr: PRope = nil for j in countup(0, blen - 2): assert(t.sons[i].sons[j].kind == nkType) if orExpr != nil: app(orExpr, "||") - appf(orExpr, "($1.exc->Sup.m_type == $2)", - [safePoint, genTypeInfo(p.module, t.sons[i].sons[j].typ)]) + appcg(p.module, orExpr, "#getCurrentException()->Sup.m_type == $1", + [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) if i > 1: app(p.s[cpsStmts], "else ") appf(p.s[cpsStmts], "if ($1) {$n", [orExpr]) - genStmts(p, t.sons[i].sons[blen - 1]) # code to clear the exception: - appf(p.s[cpsStmts], "$1.status = 0;}$n", [safePoint]) + genStmts(p, t.sons[i].sons[blen-1]) + # code to clear the exception: + appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();}$n", + [safePoint]) inc(i) app(p.s[cpsStmts], '}' & tnl) # end of if statement - finishTryStmt(p, 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]) - appcg(p, cpsStmts, "if ($1.status != 0) { " & - "#raiseException($1.exc, $1.exc->name); }$n", [safePoint]) + appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) var breakPointId: int = 0 diff --git a/rod/cgen.nim b/rod/cgen.nim index 415eb1a9c..6d39623bb 100755 --- a/rod/cgen.nim +++ b/rod/cgen.nim @@ -193,7 +193,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope = while true: j = (j * 10) + Ord(frmt[i]) - ord('0') 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 if j > high(args) + 1: internalError("ropes: invalid format string $" & $(j)) diff --git a/rod/commands.nim b/rod/commands.nim index 706332447..b47bbf1bb 100755 --- a/rod/commands.nim +++ b/rod/commands.nim @@ -222,6 +222,54 @@ proc processCompile(filename: string) = extccomp.addExternalFileToCompile(found) 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) = var theOS: TSystemOS diff --git a/rod/rodread.nim b/rod/rodread.nim index ee295d122..3159ec961 100755 --- a/rod/rodread.nim +++ b/rod/rodread.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -10,10 +10,8 @@ # This module is responsible for loading of rod files. # # 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. -# Thus they are smaller than the source files most of the time. Even if they -# are bigger, they are more efficient to process because symbols are only -# loaded on demand. +# a special text format. ROD-files are more efficient to process because +# symbols are only loaded on demand. # It consists of: # # - a header: @@ -149,10 +147,10 @@ proc decodeBInt(r: PRodReader): biggestInt proc encode(s: string): PRope = var res = "" - for i in countup(0, len(s) + 0 - 1): + for i in countup(0, len(s) - 1): case 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) 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) proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = - var - id: int - fl: string result = nil if r.s[r.pos] == '(': inc(r.pos) @@ -207,7 +202,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = result.flags = cast[TNodeFlags](int32(decodeInt(r))) if r.s[r.pos] == '^': inc(r.pos) - id = decodeInt(r) + var id = decodeInt(r) result.typ = rrGetType(r, id, result.info) case result.kind of nkCharLit..nkInt64Lit: @@ -217,7 +212,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = of nkFloatLit..nkFloat64Lit: if r.s[r.pos] == '!': inc(r.pos) - fl = decode(r) + var fl = decode(r) result.floatVal = parseFloat(fl) of nkStrLit..nkTripleStrLit: if r.s[r.pos] == '!': @@ -228,14 +223,14 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = of nkIdent: if r.s[r.pos] == '!': inc(r.pos) - fl = decode(r) + var fl = decode(r) result.ident = getIdent(fl) else: internalError(result.info, "decodeNode: nkIdent") of nkSym: if r.s[r.pos] == '!': inc(r.pos) - id = decodeInt(r) + var id = decodeInt(r) result.sym = rrGetSym(r, id, result.info) else: 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]) proc decodeType(r: PRodReader, info: TLineInfo): PType = - var d: int result = nil if r.s[r.pos] == '[': inc(r.pos) @@ -335,7 +329,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = else: InternalError(info, "decodeType ^(" & r.s[r.pos]) addSon(result, nil) else: - d = decodeInt(r) + var d = decodeInt(r) addSon(result, rrGetType(r, d, info)) proc decodeLib(r: PRodReader, info: TLineInfo): PLib = @@ -470,8 +464,8 @@ proc decode(r: PRodReader): string = of '\\': inc(i, 3) var xi = 0 - hexChar(r.s[i - 2], xi) - hexChar(r.s[i - 1], xi) + hexChar(r.s[i-2], xi) + hexChar(r.s[i-1], xi) add(result, chr(xi)) of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, r.s[i]) @@ -488,7 +482,7 @@ proc skipSection(r: PRodReader) = while true: case r.s[r.pos] of '\x0A': inc(r.line) - of '(': inc(c) + of '(': inc(c) of ')': if c == 0: inc(r.pos) @@ -499,7 +493,7 @@ proc skipSection(r: PRodReader) = else: nil inc(r.pos) else: - InternalError("skipSection " & $(r.line)) + InternalError("skipSection " & $r.line) proc rdWord(r: PRodReader): string = result = "" @@ -530,18 +524,14 @@ proc processInterf(r: PRodReader, module: PSym) = IdTablePut(r.syms, s, s) proc processCompilerProcs(r: PRodReader, module: PSym) = - var - s: PSym - w: string - key: int if r.compilerProcsIdx == 0: InternalError("processCompilerProcs") r.pos = r.compilerProcsIdx while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): - w = decode(r) + var w = decode(r) inc(r.pos) - key = decodeInt(r) + var key = decodeInt(r) inc(r.pos) # #10 - s = PSym(IdTableGet(r.syms, key)) + var s = PSym(IdTableGet(r.syms, key)) if s == nil: s = newStub(r, w, key) s.owner = module @@ -572,24 +562,25 @@ proc processIndex(r: PRodReader, idx: var TIndex) = proc processRodFile(r: PRodReader, crc: TCrc32) = var - section, w: string + w: string d, L, inclCrc: int while r.s[r.pos] != '\0': - section = rdWord(r) + var section = rdWord(r) if r.reason != rrNone: break # no need to process this file further - if section == "CRC": + case section + of "CRC": inc(r.pos) # skip ':' if int(crc) != decodeInt(r): r.reason = rrCrcChange - elif section == "ID": + of "ID": inc(r.pos) # skip ':' r.moduleID = decodeInt(r) setID(r.moduleID) - elif section == "OPTIONS": + of "OPTIONS": inc(r.pos) # skip ':' r.options = cast[TOptions](int32(decodeInt(r))) if options.gOptions != r.options: r.reason = rrOptions - elif section == "DEFINES": + of "DEFINES": inc(r.pos) # skip ':' d = 0 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); if r.s[r.pos] == ' ': inc(r.pos) if (d != countDefinedSymbols()): r.reason = rrDefines - elif section == "FILES": + of "FILES": inc(r.pos, 2) # skip "(\10" inc(r.line) L = 0 @@ -610,7 +601,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) = inc(r.line) inc(L) if r.s[r.pos] == ')': inc(r.pos) - elif section == "INCLUDES": + of "INCLUDES": inc(r.pos, 2) # skip "(\10" inc(r.line) 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.line) if r.s[r.pos] == ')': inc(r.pos) - elif section == "DEPS": + of "DEPS": inc(r.pos) # skip ':' L = 0 while (r.s[r.pos] > '\x0A'): @@ -632,32 +623,32 @@ proc processRodFile(r: PRodReader, crc: TCrc32) = r.modDeps[L] = r.files[decodeInt(r)] inc(L) if r.s[r.pos] == ' ': inc(r.pos) - elif section == "INTERF": + of "INTERF": r.interfIdx = r.pos + 2 skipSection(r) - elif section == "COMPILERPROCS": + of "COMPILERPROCS": r.compilerProcsIdx = r.pos + 2 skipSection(r) - elif section == "INDEX": + of "INDEX": processIndex(r, r.index) - elif section == "IMPORTS": + of "IMPORTS": processIndex(r, r.imports) - elif section == "CONVERTERS": + of "CONVERTERS": r.convertersIdx = r.pos + 1 skipSection(r) - elif section == "DATA": + of "DATA": r.dataIdx = r.pos + 2 # "(\10" # We do not read the DATA section here! We read the needed objects on # demand. skipSection(r) - elif section == "INIT": + of "INIT": r.initIdx = r.pos + 2 # "(\10" skipSection(r) - elif section == "CGEN": + of "CGEN": r.cgenIdx = r.pos + 2 skipSection(r) else: - MessageOut("skipping section: " & $(r.pos)) + MessageOut("skipping section: " & $r.pos) skipSection(r) if r.s[r.pos] == '\x0A': inc(r.pos) @@ -686,7 +677,7 @@ proc newRodReader(modfilename: string, crc: TCrc32, inc(r.pos) if r.s[r.pos] == '\x0A': inc(r.pos) 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 processRodFile(r, crc) else: @@ -814,7 +805,8 @@ proc checkDep(filename: string): TReasonForRecompile = for i in countup(0, high(r.modDeps)): res = checkDep(r.modDeps[i]) if res != rrNone: - result = rrModDeps #break // BUGFIX: cannot break here! + result = rrModDeps + # we cannot break here, because of side-effects of `checkDep` else: result = rrRodDoesNotExist if (result != rrNone) and (gVerbosity > 0): diff --git a/rod/rodwrite.nim b/rod/rodwrite.nim index 370ebc314..ea427dce9 100755 --- a/rod/rodwrite.nim +++ b/rod/rodwrite.nim @@ -70,8 +70,8 @@ proc fileIdx(w: PRodWriter, filename: string): int = proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter = new(result) - result.sstack = @ [] - result.tstack = @ [] + result.sstack = @[] + result.tstack = @[] InitIITable(result.index.tab) InitIITable(result.imports.tab) result.filename = modfilename @@ -79,7 +79,7 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter = result.module = module result.defines = getDefines() result.options = options.gOptions - result.files = @ [] + result.files = @[] proc addModDep(w: PRodWriter, dep: string) = if w.modDeps != nil: app(w.modDeps, " ") @@ -284,11 +284,10 @@ proc symStack(w: PRodWriter) = setlen(w.sstack, 0) proc typeStack(w: PRodWriter) = - var i, L: int - i = 0 + var i = 0 while i < len(w.tstack): 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) app(w.data, encodeType(w, w.tstack[i])) app(w.data, rodNL) @@ -317,9 +316,8 @@ proc addStmt(w: PRodWriter, n: PNode) = processStacks(w) proc writeRod(w: PRodWriter) = - var content: PRope processStacks(w) # write header: - content = toRope("NIM:") + var content = toRope("NIM:") app(content, toRope(FileVersion)) app(content, rodNL) app(content, toRope("ID:")) @@ -373,43 +371,39 @@ proc writeRod(w: PRodWriter) = writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod"))) proc process(c: PPassContext, n: PNode): PNode = - var - w: PRodWriter - a: PNode - s: PSym result = n if c == nil: return - w = PRodWriter(c) + var w = PRodWriter(c) case n.kind of nkStmtList: for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i]) of nkTemplateDef, nkMacroDef: - s = n.sons[namePos].sym + var s = n.sons[namePos].sym addInterfaceSym(w, s) 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 (n.sons[codePos] != nil) or (s.magic != mNone) or not (sfForward in s.flags): addInterfaceSym(w, s) of nkVarSection: 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 != nkIdentDefs: InternalError(a.info, "rodwrite.process") addInterfaceSym(w, a.sons[0].sym) of nkConstSection: 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 != nkConstDef: InternalError(a.info, "rodwrite.process") addInterfaceSym(w, a.sons[0].sym) of nkTypeSection: for i in countup(0, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if a.kind == nkCommentStmt: continue 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) # this takes care of enum fields too # Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum diff --git a/rod/semfold.nim b/rod/semfold.nim index a4de04e4f..a447ac66f 100755 --- a/rod/semfold.nim +++ b/rod/semfold.nim @@ -12,7 +12,8 @@ import 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 # 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: result = copyTree(a) 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, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mNLen..mNError, mEqRef: diff --git a/tests/accept/run/tcontinuexc.nim b/tests/accept/run/tcontinuexc.nim new file mode 100644 index 000000000..97b190e3c --- /dev/null +++ b/tests/accept/run/tcontinuexc.nim @@ -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" + diff --git a/tests/accept/run/toverflw2.nim b/tests/accept/run/toverflw2.nim new file mode 100755 index 000000000..b54bda9fa --- /dev/null +++ b/tests/accept/run/toverflw2.nim @@ -0,0 +1,5 @@ +var a : int32 = 2147483647 +var b : int32 = 2147483647 +var c = a + b + + diff --git a/tinyc/config_edited.h b/tinyc/config_edited.h index ceb34f784..edaf335bb 100755 --- a/tinyc/config_edited.h +++ b/tinyc/config_edited.h @@ -6,6 +6,11 @@ # define TCC_TARGET_PE 1 # define TCC_TARGET_I386 # 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 # define TCC_TARGET_X86_64 # define CONFIG_TCCDIR "/usr/local/lib/tcc" diff --git a/todo.txt b/todo.txt index e752e5862..22529feb6 100755 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,8 @@ For version 0.8.10 ================== -- exception propagation across DLLs -- fix exception handling - 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) diff --git a/tools/buildsh.tmpl b/tools/buildsh.tmpl index f67330514..cdfdbf2c1 100755 --- a/tools/buildsh.tmpl +++ b/tools/buildsh.tmpl @@ -33,6 +33,9 @@ case $uos in *darwin* ) myos="macosx" LINK_FLAGS="$LINK_FLAGS -ldl -lm" + if [ `sysctl hw |grep 64bit` = "hw.cpu64bit_capable: 1" ] ; then + ucpu="amd64" + fi ;; *aix* ) myos="aix" diff --git a/web/news.txt b/web/news.txt index ec136b66f..e806c23f7 100755 --- a/web/news.txt +++ b/web/news.txt @@ -15,9 +15,10 @@ Bugfixes - Bugfix: ``system.splitChunk`` still contained code for debug output. - Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of ``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: ``strutils.endsWith`` lacked range checking. +- Bugfix: Better detection for AMD64 on Mac OS X. Changes affecting backwards compatibility @@ -48,6 +49,7 @@ Additions - Added ``system.reopen``. - Added ``system.getCurrentException``. - Added ``system.appType``. +- Added ``system.compileOption``. - Added ``times.epochTime`` and ``times.cpuTime``. - Implemented explicit type arguments for generics. - Implemented implicit type arguments for generics. |