summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2022-11-08 20:08:01 +0800
committerGitHub <noreply@github.com>2022-11-08 13:08:01 +0100
commit7d15fdd375e115d57f5937b9d6d25b25d439ab99 (patch)
tree4292d17301fd4afe970e95aea1124602f140fa5c /compiler
parentca3b6cba5dca1b0f73d8dec7476d440af9780567 (diff)
downloadNim-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.nim38
-rw-r--r--compiler/ccgstmts.nim33
-rw-r--r--compiler/ccgtypes.nim45
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