summary refs log tree commit diff stats
path: root/compiler/ic/replayer.nim
blob: 61aa0e697f6bc4e4ea2fa8c2ab516ee929a6a3b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#
#
#           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 tables

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 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.methodsPerType):
    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.methodsPerType.mgetOrPut(key, @[]).add (col, 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.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)