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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
import ast, modulegraphs, magicsys, lineinfos, options, cgmeth, types
import std/[algorithm, tables, intsets, assertions]
proc genVTableDispatcher(g: ModuleGraph; methods: seq[PSym]; index: int): PSym =
#[
proc dispatch(x: Base, params: ...) =
cast[proc bar(x: Base, params: ...)](x.vTable[index])(x, params)
]#
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
var body = newNodeI(nkStmtList, base.info)
var disp = newNodeI(nkIfStmt, base.info)
var vTableAccess = newNodeIT(nkBracketExpr, base.info, base.typ)
let nimGetVTableSym = getCompilerProc(g, "nimGetVTable")
let ptrPNimType = nimGetVTableSym.typ.n[1].sym.typ
var nTyp = base.typ.n[1].sym.typ
var dispatchObject = newSymNode(base.typ.n[1].sym)
if nTyp.kind == tyObject:
dispatchObject = newTree(nkAddr, dispatchObject)
else:
if g.config.backend != backendCpp: # TODO: maybe handle ptr?
if nTyp.kind == tyVar and nTyp.skipTypes({tyVar}).kind != tyObject:
dispatchObject = newTree(nkDerefExpr, dispatchObject)
var getVTableCall = newTree(nkCall,
newSymNode(nimGetVTableSym),
dispatchObject,
newIntNode(nkIntLit, index)
)
getVTableCall.typ = base.typ
var vTableCall = newNodeIT(nkCall, base.info, base.typ[0])
var castNode = newTree(nkCast,
newNodeIT(nkType, base.info, base.typ),
getVTableCall)
castNode.typ = base.typ
vTableCall.add castNode
for col in 1..<paramLen:
let param = base.typ.n[col].sym
vTableCall.add newSymNode(param)
var ret: PNode
if base.typ[0] != nil:
var a = newNodeI(nkFastAsgn, base.info)
a.add newSymNode(base.ast[resultPos].sym)
a.add vTableCall
ret = newNodeI(nkReturnStmt, base.info)
ret.add a
else:
ret = vTableCall
if base.typ.n[1].sym.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
let ifBranch = newNodeI(nkElifBranch, base.info)
let boolType = getSysType(g, unknownLineInfo, tyBool)
var isNil = getSysMagic(g, unknownLineInfo, "isNil", mIsNil)
let checkSelf = newNodeIT(nkCall, base.info, boolType)
checkSelf.add newSymNode(isNil)
checkSelf.add newSymNode(base.typ.n[1].sym)
ifBranch.add checkSelf
ifBranch.add newTree(nkCall,
newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(base.typ.n[1].sym))
let elseBranch = newTree(nkElifBranch, ret)
disp.add ifBranch
disp.add elseBranch
else:
disp = ret
body.add disp
body.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = body
proc containGenerics(base: PType, s: seq[tuple[depth: int, value: PType]]): bool =
result = tfHasMeta in base.flags
for i in s:
if tfHasMeta in i.value.flags:
result = true
break
proc collectVTableDispatchers*(g: ModuleGraph) =
var itemTable = initTable[ItemId, seq[LazySym]]()
var rootTypeSeq = newSeq[PType]()
var rootItemIdCount = initCountTable[ItemId]()
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
if relevantCol(g.methods[bucket].methods, 1): incl(relevantCols, 1)
sortBucket(g.methods[bucket].methods, relevantCols)
let base = g.methods[bucket].methods[^1]
let baseType = base.typ[1].skipTypes(skipPtrs-{tyTypeDesc})
if baseType.itemId in g.objectTree and not containGenerics(baseType, g.objectTree[baseType.itemId]):
let methodIndexLen = g.bucketTable[baseType.itemId]
if baseType.itemId notin itemTable: # once is enough
rootTypeSeq.add baseType
itemTable[baseType.itemId] = newSeq[LazySym](methodIndexLen)
sort(g.objectTree[baseType.itemId], cmp = proc (x, y: tuple[depth: int, value: PType]): int =
if x.depth >= y.depth: 1
else: -1
)
for item in g.objectTree[baseType.itemId]:
if item.value.itemId notin itemTable:
itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen)
var mIndex = 0 # here is the correpsonding index
if baseType.itemId notin rootItemIdCount:
rootItemIdCount[baseType.itemId] = 1
else:
mIndex = rootItemIdCount[baseType.itemId]
rootItemIdCount.inc(baseType.itemId)
for idx in 0..<g.methods[bucket].methods.len:
let obj = g.methods[bucket].methods[idx].typ[1].skipTypes(skipPtrs)
itemTable[obj.itemId][mIndex] = LazySym(sym: g.methods[bucket].methods[idx])
g.addDispatchers genVTableDispatcher(g, g.methods[bucket].methods, mIndex)
else: # if the base object doesn't have this method
g.addDispatchers genIfDispatcher(g, g.methods[bucket].methods, relevantCols, g.idgen)
proc sortVTableDispatchers*(g: ModuleGraph) =
var itemTable = initTable[ItemId, seq[LazySym]]()
var rootTypeSeq = newSeq[ItemId]()
var rootItemIdCount = initCountTable[ItemId]()
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
if relevantCol(g.methods[bucket].methods, 1): incl(relevantCols, 1)
sortBucket(g.methods[bucket].methods, relevantCols)
let base = g.methods[bucket].methods[^1]
let baseType = base.typ[1].skipTypes(skipPtrs-{tyTypeDesc})
if baseType.itemId in g.objectTree and not containGenerics(baseType, g.objectTree[baseType.itemId]):
let methodIndexLen = g.bucketTable[baseType.itemId]
if baseType.itemId notin itemTable: # once is enough
rootTypeSeq.add baseType.itemId
itemTable[baseType.itemId] = newSeq[LazySym](methodIndexLen)
sort(g.objectTree[baseType.itemId], cmp = proc (x, y: tuple[depth: int, value: PType]): int =
if x.depth >= y.depth: 1
else: -1
)
for item in g.objectTree[baseType.itemId]:
if item.value.itemId notin itemTable:
itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen)
var mIndex = 0 # here is the correpsonding index
if baseType.itemId notin rootItemIdCount:
rootItemIdCount[baseType.itemId] = 1
else:
mIndex = rootItemIdCount[baseType.itemId]
rootItemIdCount.inc(baseType.itemId)
for idx in 0..<g.methods[bucket].methods.len:
let obj = g.methods[bucket].methods[idx].typ[1].skipTypes(skipPtrs)
itemTable[obj.itemId][mIndex] = LazySym(sym: g.methods[bucket].methods[idx])
for baseType in rootTypeSeq:
g.setMethodsPerType(baseType, itemTable[baseType])
for item in g.objectTree[baseType]:
let typ = item.value.skipTypes(skipPtrs)
let idx = typ.itemId
for mIndex in 0..<itemTable[idx].len:
if itemTable[idx][mIndex].sym == nil:
let parentIndex = typ[0].skipTypes(skipPtrs).itemId
itemTable[idx][mIndex] = itemTable[parentIndex][mIndex]
g.setMethodsPerType(idx, itemTable[idx])
|