diff --git a/compiler/ast.nim b/compiler/ast.nim index 870b2c016d..88cf5fd61a 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 0e0962936f..bcb9f8ffc0 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 99c2996faa..e5854d93de 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 9b00901bbd..16a0358398 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 ..