diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2022-11-08 20:08:01 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-08 13:08:01 +0100 |
commit | 7d15fdd375e115d57f5937b9d6d25b25d439ab99 (patch) | |
tree | 4292d17301fd4afe970e95aea1124602f140fa5c /compiler | |
parent | ca3b6cba5dca1b0f73d8dec7476d440af9780567 (diff) | |
download | Nim-7d15fdd375e115d57f5937b9d6d25b25d439ab99.tar.gz |
implements display based subtype checking (6.4x faster without threads; 2.8x faster with threads) (#20781)
* WIP: fast 'of' operator based on the literature * implement display based subtype checking Co-authored-by: Araq <rumpf_a@web.de>
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgexprs.nim | 38 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 33 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 45 |
3 files changed, 79 insertions, 37 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c481221a5..d3797b11d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1704,11 +1704,8 @@ proc genNewFinalize(p: BProc, e: PNode) = proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Rope) = if optTinyRtti in p.config.globalOptions: - let ti = genTypeInfo2Name(p.module, dest) - inc p.module.labels - let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope - p.module.s[cfsVars].addf("static TNimTypeV2* $#[2];$n", [cache]) - appcg(p.module, result, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) + let token = $genDisplayElem(MD5Digest(hashType(dest))) + appcg(p.module, result, "#isObjDisplayCheck($#.m_type, $#, $#)", [a, getObjDepth(dest), token]) else: # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we # have to call it here first: @@ -1722,10 +1719,6 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Ro let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope p.module.s[cfsVars].addf("static TNimType* $#[2];$n", [cache]) appcg(p.module, result, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) - when false: - # former version: - appcg(p.module, result, "#isObj($1.m_type, $2)", - [a, genTypeInfoV1(p.module, dest, info)]) proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var a: TLoc @@ -2775,16 +2768,23 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = var nilCheck = "" var r = newRopeAppender() rdMType(p, a, nilCheck, r) - let checkFor = if optTinyRtti in p.config.globalOptions: - genTypeInfo2Name(p.module, dest) - else: - genTypeInfoV1(p.module, dest, n.info) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor]) - else: - linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); ", - [r, checkFor]) + if optTinyRtti in p.config.globalOptions: + let checkFor = $getObjDepth(dest) + let token = $genDisplayElem(MD5Digest(hashType(dest))) + if nilCheck != "": + linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ", + [nilCheck, r, checkFor, token]) + else: + linefmt(p, cpsStmts, "if (!#isObjDisplayCheck($1, $2, $3)){ #raiseObjectConversionError(); ", + [r, checkFor, token]) + else: + let checkFor = genTypeInfoV1(p.module, dest, n.info) + if nilCheck != "": + linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); ", + [nilCheck, r, checkFor]) + else: + linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); ", + [r, checkFor]) raiseInstr(p, p.s(cpsStmts)) linefmt p, cpsStmts, "}$n", [] diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 7b5f4ff72..fbdb9a347 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1079,12 +1079,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = hasImportedCppExceptions = true else: if orExpr.len != 0: orExpr.add("||") - let checkFor = if optTinyRtti in p.config.globalOptions: - genTypeInfo2Name(p.module, typeNode.typ) - else: - genTypeInfoV1(p.module, typeNode.typ, typeNode.info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) + if optTinyRtti in p.config.globalOptions: + let checkFor = $getObjDepth(typeNode.typ) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ)))]) + else: + let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info) + appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) if orExpr.len != 0: if hasIf: @@ -1297,12 +1298,13 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = for j in 0..<t[i].len - 1: assert(t[i][j].kind == nkType) if orExpr.len != 0: orExpr.add("||") - let checkFor = if optTinyRtti in p.config.globalOptions: - genTypeInfo2Name(p.module, t[i][j].typ) - else: - genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) + if optTinyRtti in p.config.globalOptions: + let checkFor = $getObjDepth(t[i][j].typ) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))]) + else: + let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) + appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) @@ -1441,12 +1443,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = for j in 0..<t[i].len - 1: assert(t[i][j].kind == nkType) if orExpr.len != 0: orExpr.add("||") - let checkFor = if optTinyRtti in p.config.globalOptions: - genTypeInfo2Name(p.module, t[i][j].typ) - else: - genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) + if optTinyRtti in p.config.globalOptions: + let checkFor = $getObjDepth(t[i][j].typ) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))]) + else: + let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) + appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 72c8d4896..d56fdcba4 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -12,6 +12,7 @@ # ------------------------- Name Mangling -------------------------------- import sighashes, modulegraphs +import std/md5 proc isKeyword(w: PIdent): bool = # Nim and C++ share some keywords @@ -1321,7 +1322,37 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: internalError(m.config, info, "no attached trace proc found") result.add rope("NIM_NIL") -proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = +proc getObjDepth(t: PType): int16 = + var x = t + result = -1 + while x != nil: + x = skipTypes(x, skipPtrs) + x = x[0] + inc(result) + +proc genDisplayElem(d: MD5Digest): uint32 = + result = 0 + for i in 0..3: + result += uint32(d[i]) + result = result shl 8 + +proc genDisplay(t: PType, depth: int): Rope = + result = Rope"{" + var x = t + var seqs = newSeq[string](depth+1) + var i = 0 + while x != nil: + x = skipTypes(x, skipPtrs) + seqs[i] = $genDisplayElem(MD5Digest(hashType(x))) + x = x[0] + inc i + + for i in countdown(depth, 1): + result.add seqs[i] & ", " + result.add seqs[0] + result.add "}" + +proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) = var typeName: Rope if t.kind in {tyObject, tyDistinct}: if incompleteType(t): @@ -1344,8 +1375,16 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn addf(typeEntry, "; $1.traceImpl = (void*)", [name]) genHook(m, t, info, attachedTrace, typeEntry) - addf(typeEntry, "; $1.name = $2;$n; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.flags = $4;", - [name, typeName, getTypeDesc(m, t), rope(flags)]) + let objDepth = if t.kind == tyObject: getObjDepth(t) else: -1 + + addf(typeEntry, "; $1.name = $2;$n; $1.size = sizeof($3); $1.align = (NI16) NIM_ALIGNOF($3); $1.depth = $4; $1.flags = $5;", + [name, typeName, getTypeDesc(m, t), rope(objDepth), rope(flags)]) + + if objDepth >= 0: + let objDisplay = genDisplay(t, objDepth) + let objDisplayStore = getTempName(m) + m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) + addf(typeEntry, "; $1.display = $2;$n", [name, rope(objDisplayStore)]) m.s[cfsTypeInit3].add typeEntry |