fixes for exception handling; added system.compileOption

This commit is contained in:
Araq
2010-09-13 00:52:44 +02:00
parent 030d46f218
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,
** 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

View File

@@ -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):

View File

@@ -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:
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, stackTraceNewLine)
else:
add(s, "Traceback (most recent call last)")
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

View File

@@ -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()

View File

@@ -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) =

View File

@@ -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,

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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):

View File

@@ -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

View File

@@ -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:

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_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"

View File

@@ -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)

View File

@@ -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"

View File

@@ -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.