diff options
author | Araq <rumpf_a@web.de> | 2012-10-30 22:29:03 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-10-30 22:29:03 +0100 |
commit | 2133fbfccef934ae0f8ffafe0ecf4ef378e4cacf (patch) | |
tree | f134579954e688260d9417e86e48427129430181 | |
parent | 86ed9181570d16406e63754bd409c2b33c73b4a5 (diff) | |
download | Nim-2133fbfccef934ae0f8ffafe0ecf4ef378e4cacf.tar.gz |
bugfix: wrong assertions for C++ code generation; some solaris support; first steps to an effect system
-rwxr-xr-x | compiler/ast.nim | 7 | ||||
-rwxr-xr-x | compiler/cgen.nim | 6 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 13 | ||||
-rw-r--r-- | compiler/sempass2.nim | 158 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 5 | ||||
-rwxr-xr-x | compiler/tccgen.nim | 8 | ||||
-rwxr-xr-x | compiler/wordrecg.nim | 8 | ||||
-rwxr-xr-x | lib/nimbase.h | 2 | ||||
-rwxr-xr-x | lib/pure/sockets.nim | 3 | ||||
-rwxr-xr-x | tests/compile/thexrange.nim | 2 | ||||
-rwxr-xr-x | todo.txt | 3 |
11 files changed, 193 insertions, 22 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 870b2c016..88cf5fd61 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -277,6 +277,13 @@ const # getting ready for the future expr/stmt merge nkWhen* = nkWhenStmt nkWhenExpr* = nkWhenStmt + nkEffectList* = nkArgList + # hacks ahead: an nkEffectList is a node with 4 children: + exceptionEffects* = 0 # exceptions at position 0 + readEffects* = 1 # read effects at position 1 + writeEffects* = 2 # write effects at position 2 + tagEffects* = 3 # user defined tag ('gc', 'time' etc.) + effectListLen* = 4 # list of effects list type TTypeKind* = enum # order is important! diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0e0962936..bcb9f8ffc 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1131,11 +1131,6 @@ proc writeModule(m: BModule, pending: bool) = addFileToCompile(cfilenoext) addFileToLink(cfilenoext) -proc genPlatformAsserts(m: BModule) = - appf(m.s[cfsForwardTypes], - "typedef assert_numbits[sizeof(NI) == sizeof(void*) &&" & - "NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];$N") - proc myClose(b: PPassContext, n: PNode): PNode = result = n if b == nil or passes.skipCodegen(n): return @@ -1149,7 +1144,6 @@ proc myClose(b: PPassContext, n: PNode): PNode = if sfMainModule in m.module.flags: var disp = generateMethodDispatchers() for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) - genPlatformAsserts(m) genMainProc(m) # we need to process the transitive closure because recursive module # deps are allowed (and the system module is processed in the wrong diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 99c2996fa..e5854d93d 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -41,7 +41,7 @@ const wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, - wLinearScanEnd, wPatterns} + wLinearScanEnd, wPatterns, wEffects} lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame} @@ -292,14 +292,14 @@ proc processOption(c: PContext, n: PNode) = if n.sons[1].kind != nkIdent: invalidPragma(n) else: - case whichKeyword(n.sons[1].ident) - of wSpeed: + case n.sons[1].ident.s.normalize + of "speed": incl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) - of wSize: + of "size": excl(gOptions, optOptimizeSpeed) incl(gOptions, optOptimizeSize) - of wNone: + of "none": excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) else: LocalError(n.info, errNoneSpeedOrSizeExpected) @@ -656,6 +656,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = of wEmit: PragmaEmit(c, it) of wUnroll: PragmaUnroll(c, it) of wLinearScanEnd: PragmaLinearScanEnd(c, it) + of wEffects: + # is later processed in effect analysis: + noVal(it) of wIncompleteStruct: noVal(it) if sym.typ == nil: invalidPragma(it) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 9b00901bb..16a035839 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -14,7 +14,7 @@ import # way had some inherent problems. Performs: # # * procvar checks -# * effect tracking +# * effect+exception tracking # * closure analysis # * checks for invalid usages of compiletime magics (not implemented) # * checks for invalid usages of PNimNode (not implemented) @@ -29,6 +29,21 @@ import # --> a TR macro can annotate the proc with user defined annotations # --> the effect system can access these +# Load&Store analysis is performed on *paths*. A path is an access like +# obj.x.y[i].z; splitting paths up causes some problems: +# +# var x = obj.x +# var z = x.y[i].z +# +# Alias analysis is affected by this too! A good solution is *type splitting*: +# T becomes T1 and T2 if it's known that T1 and T2 can't alias. +# +# An aliasing problem and a race condition are effectively the same problem. +# Type based alias analysis is nice but not sufficient; especially splitting +# an array and filling it in parallel should be supported but is not easily +# done: It essentially requires a built-in 'indexSplit' operation and dependent +# typing. + proc sem2call(c: PContext, n: PNode): PNode = assert n.kind in nkCallKinds @@ -37,4 +52,145 @@ proc sem2call(c: PContext, n: PNode): PNode = proc sem2sym(c: PContext, n: PNode): PNode = assert n.kind == nkSym + +# ------------------------ exception tracking ------------------------------- + +discard """ + exception tracking: + + a() # raises 'x', 'e' + try: + b() # raises 'e' + except e: + # must not undo 'e' here; hrm + c() + + --> we need a stack of scopes for this analysis + + + Effect tracking: + + We track the effects per proc; forward declarations and indirect calls cause + problems: Forward declarations are computed lazily (we do this pass after + a whole module) and indirect calls are assumed the worst, unless they have + an effect annotation. +""" + +type + TEffects = object + exc: PNode # stack of exceptions + bottom: int + + PEffects = var TEffects + +proc throws(tracked: PEffects, n: PNode) = + # since a 'raise' statement occurs rarely and we need distinct reasons; + # we simply do not merge anything here, this would be problematic for the + # stack of exceptions anyway: + tracked.exc.add n + +proc excType(n: PNode): PType = + assert n.kind == nkRaiseStmt + # reraise is like raising E_Base: + let t = if n.sons[0].kind == nkEmpty: sysTypeFromName"E_Base" + else: n.sons[0].typ + result = skipTypes(t, skipPtrs) +proc mergeEffects(a: PEffects, b: PNode) = + var aa = a.exc + for effect in items(b): + block search + for i in a.bottom .. <aa.len: + if sameType(aa[i].excType, b.excType): break search + throws(a, effect) + +proc listEffects(a: PEffects) = + var aa = a.exc + for e in items(aa): + Message(e.info, hintUser, renderTree(e)) + +proc catches(tracked: PEffects, e: PType) = + let e = skipTypes(e, skipPtrs) + let L = tracked.exc.len + var i = tracked.bottom + while i < L: + # e supertype of r? + if inheritanceDiff(e, tracked.exc[i].excType) <= 0: + tracked.exc.sons[i] = tracked.exc.sons[L-1] + dec L + else: + inc i + +proc catchesAll(tracked: PEffects) = + setLen(tracked.exc.sons, tracked.bottom) + +proc track(tracked: PEffects, n: PNode) +proc trackTryStmt(tracked: PEffects, n: PNode) = + let oldBottom = tracked.bottom + tracked.bottom = tracked.exc.len + track(tracked, n.sons[0]) + for i in 1 .. < n.len: + let b = n.sons[i] + let blen = sonsLen(b) + if b.kind == nkExceptBranch: + if blen == 1: + catchesAll(tracked) + else: + for j in countup(0, blen - 2): + assert(b.sons[j].kind == nkType) + catches(tracked, b.sons[j].typ) + else: + assert b.kind == nkFinally + track(tracked, b.sons[blen-1]) + tracked.bottom = oldBottom + +proc isIndirectCall(n: PNode): bool = + result = n.kind != nkSym or n.sym.kind notin routineKinds + +proc isForwardedProc(n: PNode): bool = + result = n.kind == nkSym and sfForward in n.sym.flags + +proc trackPragmaStmt(tracked: PEffects, n: PNode) = + for i in countup(0, sonsLen(n) - 1): + var it = n.sons[i] + if whichPragma(it) == wEffects: + # list the computed effects up to here: + listEffects(tracked) + +proc track(tracked: PEffects, n: PNode) = + case n.kind + of nkRaiseStmt: throws(tracked, n) + of nkCallNode: + # p's effects are ours too: + let op = n.sons[0].typ + InternalAssert op.kind == tyProc and op.n.sons[0].kind == nkEffectList + var effectList = op.n.sons[0] + if effectList.len == 0: + if isIndirectCall(n.sons[0]) or isForwardedProc(n.sons[0]): + # assume the worst: raise of exception 'E_Base': + var rs = newNodeI(nkRaiseStmt, n.info) + var re = newNodeIT(nkType, n.info, sysTypeFromName"E_Base") + rs.add(re) + effectList.add(rs) + mergeEffects(tracked, effectList) + of nkTryStmt: + trackTryStmt(tracked, n) + return + of nkPragma: + trackPragmaStmt(tracked, n) + return + else: nil + for i in 0 .. <safeLen(n): + track(tracked, n.sons[i]) + +proc trackProc*(s: PSym, body: PNode) = + var effects = s.typ.n.sons[0] + InternalAssert effects.kind == nkEffectList + # effects already computed? + if effects.len == effectListLen: return + newSeq(effects.sons, effectListLen) + + var t: TEffects + t.exc = effects.sons[exceptionEffects] + track(t, body) + diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f3a76913d..00be65203 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -647,7 +647,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if genericParams != nil and sonsLen(genericParams) == 0: cl = initIntSet() rawAddSon(result, nil) # return type - res = newNodeI(nkType, n.info) + # result.n[0] used to be `nkType`, but now it's `nkEffectList` because + # the effects are now stored in there too ... this is a bit hacky, but as + # usual we desperately try to save memory: + res = newNodeI(nkEffectList, n.info) addSon(result.n, res) var check = initIntSet() var counter = 0 diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim index 0a7509afe..9ed6db8a1 100755 --- a/compiler/tccgen.nim +++ b/compiler/tccgen.nim @@ -59,6 +59,8 @@ proc setupEnvironment = #addFile(nimrodDir / r"tinyc\lib\libtcc1.c") else: addSysincludePath(gTinyC, "/usr/include") + when defined(amd64): + addSysincludePath(gTinyC, "/usr/include/x86_64-linux-gnu") proc compileCCode*(ccode: string) = if not libIncluded: @@ -66,11 +68,11 @@ proc compileCCode*(ccode: string) = setupEnvironment() discard compileString(gTinyC, ccode) -proc run*() = +proc run*() = var a: array[0..1, cstring] a[0] = "" a[1] = "" - var err = tinyc.run(gTinyC, 0'i32, addr(a)) != 0'i32 + var err = tinyc.run(gTinyC, 0'i32, cast[cstringArray](addr(a))) != 0'i32 closeCCState(gTinyC) - if err: rawMessage(errExecutionOfProgramFailed, "") + if err: rawMessage(errExecutionOfProgramFailed, "") diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 963b493db..e45b78c6d 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -18,7 +18,7 @@ import # Keywords must be kept sorted and within a range -type +type TSpecialWord* = enum wInvalid, @@ -52,7 +52,7 @@ type wBoundchecks, wOverflowchecks, wNilchecks, wFloatchecks, wNanChecks, wInfChecks, wAssertions, wPatterns, wWarnings, - wHints, wOptimization, wSpeed, wSize, wNone, + wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wDeadCodeElim, wSafecode, wPragma, wCompileTime, wNoInit, @@ -62,7 +62,7 @@ type wAcyclic, wShallow, wUnroll, wLinearScanEnd, wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, wNoStackFrame, - wImplicitStatic, wGlobal, wHoist + wImplicitStatic, wGlobal, wHoist, wAuto, wBool, wCatch, wChar, wClass, wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, @@ -133,7 +133,7 @@ const "floatchecks", "nanchecks", "infchecks", "assertions", "patterns", "warnings", "hints", - "optimization", "speed", "size", "none", + "optimization", "raises", "writes", "reads", "size", "effects", "deadcodeelim", "safecode", "pragma", "compiletime", "noinit", diff --git a/lib/nimbase.h b/lib/nimbase.h index 69aa904db..74dd931e6 100755 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -470,4 +470,6 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); } # define GC_GUARD #endif +typedef int assert_numbits[sizeof(NI) == sizeof(void*) && + NIM_INTBITS == sizeof(NI)*8 ? 1 : -1]; #endif diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 4782ddd2e..f0d4cb6b8 100755 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -24,6 +24,9 @@ when defined(Windows): import winlean else: import posix + + when defined(solaris): + {.passl: "-lsocket -lnsl".} # Note: The enumerations are mapped to Window's constants. diff --git a/tests/compile/thexrange.nim b/tests/compile/thexrange.nim index 875a5bab3..e5e4c10c6 100755 --- a/tests/compile/thexrange.nim +++ b/tests/compile/thexrange.nim @@ -4,5 +4,5 @@ type var a: TArray -echo a[0] #OUT 0 +echo a[0x0012] #OUT 0 diff --git a/todo.txt b/todo.txt index d61dddf25..ee2bd308c 100755 --- a/todo.txt +++ b/todo.txt @@ -37,7 +37,8 @@ version 0.9.XX echo a echo b) -- implement the "snoopResult" pragma +- implement the "snoopResult" pragma; no, make a strutils with string append + semantics instead ... - implement "closure tuple consists of a single 'ref'" optimization - JS gen: - fix exception handling |