diff options
Diffstat (limited to 'compiler/vtables.nim')
-rw-r--r-- | compiler/vtables.nim | 334 |
1 files changed, 167 insertions, 167 deletions
diff --git a/compiler/vtables.nim b/compiler/vtables.nim index f57b59eae..928c64dd5 100644 --- a/compiler/vtables.nim +++ b/compiler/vtables.nim @@ -1,167 +1,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]) +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.signatureLen + 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.returnType) + 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.returnType != 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.firstParamType.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.firstParamType.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.firstParamType.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.firstParamType.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.baseClass.skipTypes(skipPtrs).itemId + itemTable[idx][mIndex] = itemTable[parentIndex][mIndex] + g.setMethodsPerType(idx, itemTable[idx]) |