summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-10-30 22:29:03 +0100
committerAraq <rumpf_a@web.de>2012-10-30 22:29:03 +0100
commit2133fbfccef934ae0f8ffafe0ecf4ef378e4cacf (patch)
treef134579954e688260d9417e86e48427129430181
parent86ed9181570d16406e63754bd409c2b33c73b4a5 (diff)
downloadNim-2133fbfccef934ae0f8ffafe0ecf4ef378e4cacf.tar.gz
bugfix: wrong assertions for C++ code generation; some solaris support; first steps to an effect system
-rwxr-xr-xcompiler/ast.nim7
-rwxr-xr-xcompiler/cgen.nim6
-rwxr-xr-xcompiler/pragmas.nim13
-rw-r--r--compiler/sempass2.nim158
-rwxr-xr-xcompiler/semtypes.nim5
-rwxr-xr-xcompiler/tccgen.nim8
-rwxr-xr-xcompiler/wordrecg.nim8
-rwxr-xr-xlib/nimbase.h2
-rwxr-xr-xlib/pure/sockets.nim3
-rwxr-xr-xtests/compile/thexrange.nim2
-rwxr-xr-xtodo.txt3
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