summary refs log tree commit diff stats
path: root/compiler/ic/replayer.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ic/replayer.nim')
-rw-r--r--compiler/ic/replayer.nim171
1 files changed, 171 insertions, 0 deletions
diff --git a/compiler/ic/replayer.nim b/compiler/ic/replayer.nim
new file mode 100644
index 000000000..b244ec885
--- /dev/null
+++ b/compiler/ic/replayer.nim
@@ -0,0 +1,171 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2020 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Module that contains code to replay global VM state changes and pragma
+## state like ``{.compile: "foo.c".}``. For IC (= Incremental compilation)
+## support.
+
+import ".." / [ast, modulegraphs, trees, extccomp, btrees,
+  msgs, lineinfos, pathutils, options, cgmeth]
+
+import std/tables
+
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+
+import packed_ast, ic, bitabs
+
+proc replayStateChanges*(module: PSym; g: ModuleGraph) =
+  let list = module.ast
+  assert list != nil
+  assert list.kind == nkStmtList
+  for n in list:
+    assert n.kind == nkReplayAction
+    # Fortunately only a tiny subset of the available pragmas need to
+    # be replayed here. This is always a subset of ``pragmas.stmtPragmas``.
+    if n.len >= 2:
+      internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit
+      case n[0].strVal
+      of "hint": message(g.config, n.info, hintUser, n[1].strVal)
+      of "warning": message(g.config, n.info, warnUser, n[1].strVal)
+      of "error": localError(g.config, n.info, errUser, n[1].strVal)
+      of "compile":
+        internalAssert g.config, n.len == 4 and n[2].kind == nkStrLit
+        let cname = AbsoluteFile n[1].strVal
+        var cf = Cfile(nimname: splitFile(cname).name, cname: cname,
+                       obj: AbsoluteFile n[2].strVal,
+                       flags: {CfileFlag.External},
+                       customArgs: n[3].strVal)
+        extccomp.addExternalFileToCompile(g.config, cf)
+      of "link":
+        extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal)
+      of "passl":
+        extccomp.addLinkOption(g.config, n[1].strVal)
+      of "passc":
+        extccomp.addCompileOption(g.config, n[1].strVal)
+      of "localpassc":
+        extccomp.addLocalCompileOption(g.config, n[1].strVal, toFullPathConsiderDirty(g.config, module.info.fileIndex))
+      of "cppdefine":
+        options.cppDefine(g.config, n[1].strVal)
+      of "inc":
+        let destKey = n[1].strVal
+        let by = n[2].intVal
+        let v = getOrDefault(g.cacheCounters, destKey)
+        g.cacheCounters[destKey] = v+by
+      of "put":
+        let destKey = n[1].strVal
+        let key = n[2].strVal
+        let val = n[3]
+        if not contains(g.cacheTables, destKey):
+          g.cacheTables[destKey] = initBTree[string, PNode]()
+        if not contains(g.cacheTables[destKey], key):
+          g.cacheTables[destKey].add(key, val)
+        else:
+          internalError(g.config, n.info, "key already exists: " & key)
+      of "incl":
+        let destKey = n[1].strVal
+        let val = n[2]
+        if not contains(g.cacheSeqs, destKey):
+          g.cacheSeqs[destKey] = newTree(nkStmtList, val)
+        else:
+          block search:
+            for existing in g.cacheSeqs[destKey]:
+              if exprStructuralEquivalent(existing, val, strictSymEquality=true):
+                break search
+            g.cacheSeqs[destKey].add val
+      of "add":
+        let destKey = n[1].strVal
+        let val = n[2]
+        if not contains(g.cacheSeqs, destKey):
+          g.cacheSeqs[destKey] = newTree(nkStmtList, val)
+        else:
+          g.cacheSeqs[destKey].add val
+      else:
+        internalAssert g.config, false
+
+proc replayBackendProcs*(g: ModuleGraph; module: int) =
+  for it in mitems(g.packed[module].fromDisk.attachedOps):
+    let key = translateId(it[0], g.packed, module, g.config)
+    let op = it[1]
+    let tmp = translateId(it[2], g.packed, module, g.config)
+    let symId = FullId(module: tmp.module, packed: it[2])
+    g.attachedOps[op][key] = LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.enumToStringProcs):
+    let key = translateId(it[0], g.packed, module, g.config)
+    let tmp = translateId(it[1], g.packed, module, g.config)
+    let symId = FullId(module: tmp.module, packed: it[1])
+    g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.methodsPerType):
+    let key = translateId(it[0], g.packed, module, g.config)
+    let tmp = translateId(it[1], g.packed, module, g.config)
+    let symId = FullId(module: tmp.module, packed: it[1])
+    g.methodsPerType.mgetOrPut(key, @[]).add LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.dispatchers):
+    let tmp = translateId(it, g.packed, module, g.config)
+    let symId = FullId(module: tmp.module, packed: it)
+    g.dispatchers.add LazySym(id: symId, sym: nil)
+
+proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
+  ## We remember the generic instantiations a module performed
+  ## in order to to avoid the code bloat that generic code tends
+  ## to imply. This is cheaper than deduplication of identical
+  ## generic instantiations. However, deduplication is more
+  ## powerful and general and I hope to implement it soon too
+  ## (famous last words).
+  assert g.packed[module].status == loaded
+  for it in g.packed[module].fromDisk.typeInstCache:
+    let key = translateId(it[0], g.packed, module, g.config)
+    g.typeInstCache.mgetOrPut(key, @[]).add LazyType(id: FullId(module: module, packed: it[1]), typ: nil)
+
+  for it in mitems(g.packed[module].fromDisk.procInstCache):
+    let key = translateId(it.key, g.packed, module, g.config)
+    let sym = translateId(it.sym, g.packed, module, g.config)
+    var concreteTypes = newSeq[FullId](it.concreteTypes.len)
+    for i in 0..high(it.concreteTypes):
+      let tmp = translateId(it.concreteTypes[i], g.packed, module, g.config)
+      concreteTypes[i] = FullId(module: tmp.module, packed: it.concreteTypes[i])
+
+    g.procInstCache.mgetOrPut(key, @[]).add LazyInstantiation(
+      module: module, sym: FullId(module: sym.module, packed: it.sym),
+      concreteTypes: concreteTypes, inst: nil)
+
+  for it in mitems(g.packed[module].fromDisk.methodsPerGenericType):
+    let key = translateId(it[0], g.packed, module, g.config)
+    let col = it[1]
+    let tmp = translateId(it[2], g.packed, module, g.config)
+    let symId = FullId(module: tmp.module, packed: it[2])
+    g.methodsPerGenericType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
+
+  replayBackendProcs(g, module)
+
+  for it in mitems(g.packed[module].fromDisk.methods):
+    let sym = loadSymFromId(g.config, g.cache, g.packed, module,
+                            PackedItemId(module: LitId(0), item: it))
+    methodDef(g, g.idgen, sym)
+
+  when false:
+    # not used anymore:
+    for it in mitems(g.packed[module].fromDisk.compilerProcs):
+      let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it[1]))
+      g.lazyCompilerprocs[g.packed[module].fromDisk.sh.strings[it[0]]] = symId
+
+  for it in mitems(g.packed[module].fromDisk.converters):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
+    g.ifaces[module].converters.add LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.trmacros):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
+    g.ifaces[module].patterns.add LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.pureEnums):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
+    g.ifaces[module].pureEnums.add LazySym(id: symId, sym: nil)