summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-10-25 15:26:36 +0200
committerAraq <rumpf_a@web.de>2011-10-25 15:26:36 +0200
commit9fb36bd20c76ebffa98dfa859f49756972b9491b (patch)
tree60b63ee0026a0c3dde2dec5365070d852d0a3803 /compiler
parent9fb97e24bf05fa980bcc781dd4b32fd3efed48a0 (diff)
downloadNim-9fb36bd20c76ebffa98dfa859f49756972b9491b.tar.gz
compilation cache: mostly working; generics not yet
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/rodread.nim16
-rwxr-xr-xcompiler/rodwrite.nim25
-rwxr-xr-xcompiler/sem.nim8
-rwxr-xr-xcompiler/semdata.nim38
-rwxr-xr-xcompiler/semexprs.nim9
-rwxr-xr-xcompiler/seminst.nim27
-rwxr-xr-xcompiler/semtypes.nim3
-rwxr-xr-xcompiler/semtypinst.nim10
-rwxr-xr-xcompiler/sigmatch.nim4
10 files changed, 93 insertions, 49 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 9b2f210a3..c20e504d1 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -568,7 +568,7 @@ const
   ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, 
                                     tyTuple, tySequence}
   ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, 
-    skMacro, skTemplate, skConverter, skStub}
+    skMacro, skTemplate, skConverter, skEnumField, skStub}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
   namePos* = 0
   genericParamsPos* = 1
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 6da2c9532..cd6719f35 100755
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -142,7 +142,7 @@ type
   PRodReader* = ref TRodReader
 
 const 
-  FileVersion* = "1024"       # modify this if the rod-format changes!
+  FileVersion* = "1026"       # modify this if the rod-format changes!
 
 var rodCompilerprocs*: TStrTable
 
@@ -657,17 +657,26 @@ proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
   result = decodeSym(rd, info)
   rd.pos = oldPos
 
+proc findSomeWhere(id: int) =
+  for i in countup(0, high(gMods)): 
+    var rd = gMods[i].rd
+    if rd != nil: 
+      var d = IITableGet(rd.index.tab, id)
+      if d != invalidKey:
+        echo "found id ", id, " in ", gMods[i].filename
+
 proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = 
   result = PSym(IdTableGet(r.syms, id))
   if result == nil: 
     # load the symbol:
     var d = IITableGet(r.index.tab, id)
     if d == invalidKey: 
+      # import from other module:
       var moduleID = IiTableGet(r.imports.tab, id)
-      if moduleID < 0: 
+      if moduleID < 0:
         var x = ""
         encodeVInt(id, x)
-        InternalError(info, "missing from both indexes: +" & x) 
+        InternalError(info, "missing from both indexes: +" & x)
       # find the reader with the correct moduleID:
       for i in countup(0, high(gMods)): 
         var rd = gMods[i].rd
@@ -680,6 +689,7 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
             else:
               var x = ""
               encodeVInt(id, x)
+              when false: findSomeWhere(id)
               InternalError(info, "rrGetSym: no reader found: +" & x)
           else:
             #if IiTableGet(rd.index.tab, id) <> invalidKey then
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 626d0382c..5a08ee144 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -322,7 +322,10 @@ proc addToIndex(w: var TIndex, key, val: int) =
   w.lastIdxVal = val
   IiTablePut(w.tab, key, val)
 
-#var debugWritten = initIntSet()
+const debugWrittenIds = false
+
+when debugWrittenIds:
+  var debugWritten = initIntSet()
 
 proc symStack(w: PRodWriter) =
   var i = 0
@@ -335,10 +338,12 @@ proc symStack(w: PRodWriter) =
         # put definition in here
         var L = w.data.len
         addToIndex(w.index, s.id, L) 
-        #intSetIncl(debugWritten, s.id)
+        when debugWrittenIds: incl(debugWritten, s.id)
         encodeSym(w, s, w.data)
         add(w.data, rodNL)
-        if sfExported in s.flags and s.kind in ExportableSymKinds: 
+        # put into interface section if appropriate:
+        if {sfExported, sfFromGeneric} * s.flags == {sfExported} and 
+            s.kind in ExportableSymKinds: 
           encodeStr(s.name.s, w.interf)
           add(w.interf, ' ')
           encodeVInt(s.id, w.interf)
@@ -355,12 +360,14 @@ proc symStack(w: PRodWriter) =
           if w.methods.len != 0: add(w.methods, ' ')
           encodeVInt(s.id, w.methods)
       elif IiTableGet(w.imports.tab, s.id) == invalidKey: 
-        addToIndex(w.imports, s.id, m.id) #if not Contains(debugWritten, s.id):
-                                          #  MessageOut(w.filename);
-                                          #  debug(s.owner);
-                                          #  debug(s);
-                                          #  InternalError('BUG!!!!');
-                                          #end
+        addToIndex(w.imports, s.id, m.id)
+        when debugWrittenIds:
+          if not Contains(debugWritten, s.id):
+            echo(w.filename)
+            debug(s)
+            debug(s.owner)
+            debug(m)
+            InternalError("BUG!!!!")
     inc(i)
   setlen(w.sstack, 0)
 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index c59ac96a9..e530d6140 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -126,13 +126,13 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
 include semtypes, semexprs, semgnrc, semstmts
 
 proc addCodeForGenerics(c: PContext, n: PNode) = 
-  for i in countup(lastGenericIdx, Len(generics) - 1):
-    var prc = generics[i].instSym
+  for i in countup(c.generics.lastGenericIdx, Len(c.generics.generics) - 1):
+    var prc = c.generics.generics[i].instSym
     if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone: 
       if prc.ast == nil or prc.ast.sons[codePos] == nil: 
         InternalError(prc.info, "no code for " & prc.name.s)
       addSon(n, prc.ast)
-  lastGenericIdx = Len(generics)
+  c.generics.lastGenericIdx = Len(c.generics.generics)
 
 proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} = 
   result = semExpr(c, n, {})
@@ -162,7 +162,7 @@ proc myOpenCached(module: PSym, filename: string,
 proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = 
   result = semStmt(c, n)
   # BUGFIX: process newly generated generics here, not at the end!
-  if lastGenericIdx < Len(generics):
+  if c.generics.lastGenericIdx < Len(c.generics.generics):
     var a = newNodeI(nkStmtList, n.info)
     addCodeForGenerics(c, a)
     if sonsLen(a) > 0: 
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 50100160b..65ff11963 100755
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-# This module contains the data structures for the semantic checking phase.
+## This module contains the data structures for the semantic checking phase.
 
 import 
   strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
@@ -37,10 +37,24 @@ type
     genericSym*, instSym*: PSym
     concreteTypes*: seq[PType]
   
+  # If we generate an instance of a generic, we'd like to re-use that
+  # instance if possible across module boundaries. However, this is not
+  # possible if the compilation cache is enabled. So we give up then and use
+  # the caching of generics only per module, not per project.
+  TGenericsCache* {.final.} = object
+    InstTypes*: TIdTable # map PType to PType
+    generics*: seq[TInstantiatedSymbol] # a list of the things to compile
+    lastGenericIdx*: int      # used for the generics stack
+  
+  PGenericsCache* = ref TGenericsCache
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
     module*: PSym             # the module sym belonging to the context
     p*: PProcCon              # procedure context
+    generics*: PGenericsCache # may point to a global or module-local structure 
+    friendModule*: PSym       # current friend module; may access private data;
+                              # this is used so that generic instantiations can
+                              # access private object fields
     InstCounter*: int         # to prevent endless instantiations
    
     threadEntries*: TSymSeq   # list of thread entries to check
@@ -56,10 +70,13 @@ type
     filename*: string         # the module's filename
     userPragmas*: TStrTable
   
+var
+  gGenericsCache: PGenericsCache # save for modularity
 
-var gInstTypes*: TIdTable # map PType to PType
-var generics*: seq[TInstantiatedSymbol] = @[] # a list of the things to compile
-var lastGenericIdx*: int      # used for the generics stack
+proc newGenericsCache: PGenericsCache =
+  new(result)
+  initIdTable(result.InstTypes)
+  result.generics = @[]
 
 proc newContext*(module: PSym, nimfile: string): PContext
 
@@ -126,11 +143,21 @@ proc newContext(module: PSym, nimfile: string): PContext =
   initLinkedList(result.libs)
   append(result.optionStack, newOptionEntry())
   result.module = module
+  result.friendModule = module
   result.threadEntries = @[]
   result.converters = @[]
   result.filename = nimfile
   result.includedFiles = initIntSet()
   initStrTable(result.userPragmas)
+  if optSymbolFiles notin gGlobalOptions:
+    # re-usage of generic instantiations across module boundaries is
+    # very nice for code size:
+    if gGenericsCache == nil: gGenericsCache = newGenericsCache()
+    result.generics = gGenericsCache
+  else:
+    # we have to give up and use a per-module cache for generic instantiations:
+    result.generics = newGenericsCache()
+    assert gGenericsCache == nil
 
 proc addConverter(c: PContext, conv: PSym) = 
   var L = len(c.converters)
@@ -189,5 +216,4 @@ proc checkSonsLen*(n: PNode, length: int) =
   
 proc checkMinSonsLen*(n: PNode, length: int) = 
   if sonsLen(n) < length: illFormedAst(n)
-  
-initIdTable(gInstTypes)
+
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 708e3055d..e93644457 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -53,8 +53,9 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
 proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
   case s.kind
   of skProc, skMethod, skIterator, skConverter: 
+    var smoduleId = getModule(s).id
     if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
-        getModule(s).id != c.module.id: 
+        smoduleId != c.module.id and smoduleId != c.friendModule.id: 
       LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
     result = symChoice(c, n, s)
   of skConst:
@@ -673,8 +674,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       if ty.sons[0] == nil: break 
       ty = skipTypes(ty.sons[0], {tyGenericInst})
     if f != nil: 
-      if sfExported in f.flags or getModule(f).id == c.module.id: 
-        # is the access to a public field or in the same module?
+      var fmoduleId = getModule(f).id
+      if sfExported in f.flags or fmoduleId == c.module.id or
+          fmoduleId == c.friendModule.id: 
+        # is the access to a public field or in the same module or in a friend?
         n.sons[0] = makeDeref(n.sons[0])
         n.sons[1] = newSymNode(f) # we now have the correct field
         n.typ = f.typ
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index d53d33898..f66a90ecf 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -22,9 +22,9 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
     if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue 
     var s = newSym(skType, q.name, getCurrOwner())
     s.info = q.info
-    incl(s.flags, sfUsed)
+    s.flags = s.flags + {sfUsed, sfFromGeneric}
     var t = PType(IdTableGet(pt, q.typ))
-    if t == nil: 
+    if t == nil:
       LocalError(a.info, errCannotInstantiateX, s.name.s)
       break
     if t.kind == tyGenericParam: 
@@ -45,9 +45,9 @@ proc sameInstantiation(a, b: TInstantiatedSymbol): bool =
     result = true
 
 proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym = 
-  for i in countup(0, Len(generics) - 1):
-    if sameInstantiation(entry, generics[i]):
-      result = generics[i].instSym
+  for i in countup(0, Len(c.generics.generics) - 1):
+    if sameInstantiation(entry, c.generics.generics[i]):
+      result = c.generics.generics[i].instSym
       # checking for the concrete parameter list is wrong and unnecessary!
       #if equalParams(b.typ.n, instSym.typ.n) == paramsEqual:
       #echo "found in cache: ", getProcHeader(result)
@@ -86,9 +86,9 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
     popProcCon(c)
 
 proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
-  for i in countup(0, Len(generics) - 1):
-    if generics[i].genericSym.id == s.id:
-      var oldPrc = generics[i].instSym
+  for i in countup(0, Len(c.generics.generics) - 1):
+    if c.generics.generics[i].genericSym.id == s.id:
+      var oldPrc = c.generics.generics[i].instSym
       pushInfoContext(oldPrc.info)
       openScope(c.tab)
       var n = oldPrc.ast
@@ -112,10 +112,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
   inc(c.InstCounter)
   # NOTE: for access of private fields within generics from a different module
-  # and other identifiers we fake the current module temporarily!
-  # XXX bad hack!
-  var oldMod = c.module
-  c.module = getModule(fn)
+  # we set the friend module:
+  var oldFriend = c.friendModule
+  c.friendModule = getModule(fn)
   result = copySym(fn, false)
   incl(result.flags, sfFromGeneric)
   result.owner = getCurrOwner().owner
@@ -144,7 +143,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   ParamsTypeCheck(c, result.typ)
   var oldPrc = GenericCacheGet(c, entry)
   if oldPrc == nil:
-    generics.add(entry)
+    c.generics.generics.add(entry)
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
     instantiateBody(c, n, result)
@@ -154,7 +153,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   popInfoContext()
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.module = oldMod
+  c.friendModule = oldFriend
   dec(c.InstCounter)
   
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index d7ca0d8ef..3536a2a34 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -527,8 +527,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       typ = paramType(c, a.sons[length-2], genericParams, cl)
       #if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
       #  debug a.sons[length-2][0][1]
-        
-    else: 
+    else:
       typ = nil
     if a.sons[length-1].kind != nkEmpty:
       def = semExprWithType(c, a.sons[length-1]) 
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 88697dc85..5ce9d4688 100755
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -105,7 +105,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
   var header: PType = nil
   when true:
     # search for some instantiation here:
-    result = searchInstTypes(gInstTypes, t)
+    result = searchInstTypes(cl.c.generics.InstTypes, t)
     if result != nil: return
     for i in countup(1, sonsLen(t) - 1):
       var x = t.sons[i]
@@ -116,7 +116,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
         #idTablePut(cl.typeMap, body.sons[i-1], x)
     if header != nil:
       # search again after first pass:
-      result = searchInstTypes(gInstTypes, header)
+      result = searchInstTypes(cl.c.generics.InstTypes, header)
       if result != nil: return
     else:
       header = copyType(t, t.owner, false)
@@ -124,7 +124,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
     # we need to add the candidate here, before it's fully instantiated for
     # recursive instantions:
     result = newType(tyGenericInst, t.sons[0].owner)
-    idTablePut(gInstTypes, header, result)
+    idTablePut(cl.c.generics.InstTypes, header, result)
 
     for i in countup(1, sonsLen(t) - 1):
       var x = replaceTypeVarsT(cl, t.sons[i])
@@ -154,14 +154,14 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
       assert x.kind != tyGenericInvokation
       idTablePut(cl.typeMap, body.sons[i-1], x)
     if header == nil: header = t
-    result = searchInstTypes(gInstTypes, header)
+    result = searchInstTypes(cl.c.generics.InstTypes, header)
     if result != nil: return 
     result = newType(tyGenericInst, t.sons[0].owner)
     for i in countup(0, sonsLen(t) - 1): 
       # if one of the params is not concrete, we cannot do anything
       # but we already raised an error!
       addSon(result, header.sons[i])
-    idTablePut(gInstTypes, header, result)
+    idTablePut(cl.c.generics.InstTypes, header, result)
     var newbody = ReplaceTypeVarsT(cl, lastSon(body))
     newbody.flags = newbody.flags + t.flags + body.flags
     newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 543027b41..f91d4798a 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -7,8 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-# This module implements the signature matching for resolving
-# the call to overloaded procs, generic procs and operators.
+## This module implements the signature matching for resolving
+## the call to overloaded procs, generic procs and operators.
 
 import 
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,