123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- 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])
|