summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-09-16 14:57:01 +0200
committerGitHub <noreply@github.com>2020-09-16 14:57:01 +0200
commitfd31e8ff6f96527cc52125d01311d022ff82fead (patch)
treeda6f772f157a34fc80316a6ba4888f8cbd730971 /compiler
parent0aaf4e2dfa2d06a71202bd283e99bb017c781f2c (diff)
downloadNim-fd31e8ff6f96527cc52125d01311d022ff82fead.tar.gz
allow old styled RTTI for arc/orc (#15331)
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/ccgexprs.nim83
-rw-r--r--compiler/ccgstmts.nim8
-rw-r--r--compiler/ccgtrav.nim2
-rw-r--r--compiler/ccgtypes.nim164
-rw-r--r--compiler/cgen.nim9
-rw-r--r--compiler/cgendata.nim2
-rw-r--r--compiler/liftdestructors.nim4
-rw-r--r--compiler/options.nim5
9 files changed, 172 insertions, 107 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 8baf49265..4d37b284c 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -680,7 +680,7 @@ type
     mNBindSym, mNCallSite,
     mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
     mNHint, mNWarning, mNError,
-    mInstantiationInfo, mGetTypeInfo,
+    mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
     mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
     mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
     mSymIsInstantiationOf, mNodeId
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 8f45452bf..0d235f62e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -266,10 +266,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
            [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)])
     else:
       linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
-              [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)])
+              [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
   else:
     linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
-            [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)])
+            [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
 
 proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
   assert d.k != locNone
@@ -318,7 +318,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     else:
       linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
               [addrLoc(p.config, dest), rdLoc(src),
-              genTypeInfo(p.module, dest.t, dest.lode.info)])
+              genTypeInfoV1(p.module, dest.t, dest.lode.info)])
   of tyString:
     if optSeqDestructors in p.config.globalOptions:
       genGenericAsgn(p, dest, src, flags)
@@ -383,7 +383,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       linefmt(p, cpsStmts,     # XXX: is this correct for arrays?
            "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
            [addrLoc(p.config, dest), addrLoc(p.config, src),
-           genTypeInfo(p.module, dest.t, dest.lode.info)])
+           genTypeInfoV1(p.module, dest.t, dest.lode.info)])
     else:
       linefmt(p, cpsStmts,
            # bug #4799, keep the nimCopyMem for a while
@@ -425,16 +425,21 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
     # XXX optimize this
     linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
             [addrLoc(p.config, dest), addrLocOrTemp(src),
-            genTypeInfo(p.module, dest.t, dest.lode.info)])
+            genTypeInfoV1(p.module, dest.t, dest.lode.info)])
   of tySequence, tyString:
-    linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
-            [addrLoc(p.config, dest), rdLoc(src),
-            genTypeInfo(p.module, dest.t, dest.lode.info)])
+    if optTinyRtti in p.config.globalOptions:
+      linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
+              [addrLoc(p.config, dest), addrLocOrTemp(src),
+              genTypeInfoV1(p.module, dest.t, dest.lode.info)])
+    else:
+      linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
+              [addrLoc(p.config, dest), rdLoc(src),
+              genTypeInfoV1(p.module, dest.t, dest.lode.info)])
   of tyOpenArray, tyVarargs:
     linefmt(p, cpsStmts,
          "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
          [addrLoc(p.config, dest), addrLocOrTemp(src),
-         genTypeInfo(p.module, dest.t, dest.lode.info)])
+         genTypeInfoV1(p.module, dest.t, dest.lode.info)])
   of tySet:
     if mapSetType(p.config, ty) == ctArray:
       linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
@@ -1229,12 +1234,12 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
     const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)"
     call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
       getTypeDesc(p.module, e[1].typ),
-      genTypeInfo(p.module, seqType, e.info)])
+      genTypeInfoV1(p.module, seqType, e.info)])
   else:
     const seqAppendPattern = "($2) #incrSeqV3($1, $3)"
     call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
       getTypeDesc(p.module, e[1].typ),
-      genTypeInfo(p.module, seqType, e.info)])
+      genTypeInfoV1(p.module, seqType, e.info)])
   # emit the write barrier if required, but we can always move here, so
   # use 'genRefAssign' for the seq.
   genRefAssign(p, a, call)
@@ -1254,7 +1259,7 @@ proc genReset(p: BProc, n: PNode) =
   when false:
     linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
             [addrLoc(p.config, a),
-            genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
+            genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)])
 
 proc genDefault(p: BProc; n: PNode; d: var TLoc) =
   if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
@@ -1280,7 +1285,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
           [getTypeDesc(p.module, typ), sizeExpr])
     genAssignment(p, a, b, {})
   else:
-    let ti = genTypeInfo(p.module, typ, a.lode.info)
+    let ti = genTypeInfoV1(p.module, typ, a.lode.info)
     if bt.destructor != nil and not isTrivialProc(bt.destructor):
       # the prototype of a destructor is ``=destroy(x: var T)`` and that of a
       # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
@@ -1339,18 +1344,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
       if p.config.selectedGC == gcGo:
         # we need the write barrier
         call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
-              genTypeInfo(p.module, seqtype, dest.lode.info), length])
+              genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
         linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc])
       else:
         call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype),
-              genTypeInfo(p.module, seqtype, dest.lode.info), length])
+              genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
         linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc])
   else:
     if lenIsZero:
       call.r = rope"NIM_NIL"
     else:
       call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
-              genTypeInfo(p.module, seqtype, dest.lode.info), length])
+              genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
     genAssignment(p, dest, call, {})
 
 proc genNewSeq(p: BProc, e: PNode) =
@@ -1383,7 +1388,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
     putIntoDest(p, d, e, ropecg(p.module,
                 "($1)#nimNewSeqOfCap($2, $3)", [
                 getTypeDesc(p.module, seqtype),
-                genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
+                genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc]))
     gcUsage(p.config, e)
 
 proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
@@ -1553,7 +1558,10 @@ proc genNewFinalize(p: BProc, e: PNode) =
   initLocExpr(p, e[1], a)
   initLocExpr(p, e[2], f)
   initLoc(b, locExpr, a.lode, OnHeap)
-  ti = genTypeInfo(p.module, refType, e.info)
+  if optTinyRtti in p.config.globalOptions:
+    ti = genTypeInfoV2(p.module, refType, e.info)
+  else:
+    ti = genTypeInfoV1(p.module, refType, e.info)
   p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
   b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
       getTypeDesc(p.module, refType),
@@ -1568,9 +1576,9 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
     result = ropecg(p.module, "#isObj($1.m_type, $2)",
       [a, genTypeInfo2Name(p.module, dest)])
   else:
-    # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
+    # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
     # have to call it here first:
-    let ti = genTypeInfo(p.module, dest, info)
+    let ti = genTypeInfoV1(p.module, dest, info)
     if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
                                 tfObjHasKids notin dest.flags):
       result = "$1.m_type == $2" % [a, ti]
@@ -1583,7 +1591,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
     when false:
       # former version:
       result = ropecg(p.module, "#isObj($1.m_type, $2)",
-                    [a, genTypeInfo(p.module, dest, info)])
+                    [a, genTypeInfoV1(p.module, dest, info)])
 
 proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
   var a: TLoc
@@ -1633,12 +1641,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
   of tyEnum, tyOrdinal:
     putIntoDest(p, d, e,
                 ropecg(p.module, "#reprEnum((NI)$1, $2)", [
-                rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
+                rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
   of tyString:
     putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage)
   of tySet:
     putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [
-                addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage)
+                addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
   of tyOpenArray, tyVarargs:
     var b: TLoc
     case skipTypes(a.t, abstractVarRange).kind
@@ -1653,20 +1661,20 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
     else: internalError(p.config, e[0].info, "genRepr()")
     putIntoDest(p, d, e,
         ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
-        genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
+        genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage)
   of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence:
     putIntoDest(p, d, e,
                 ropecg(p.module, "#reprAny($1, $2)", [
-                rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
+                rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
   of tyEmpty, tyVoid:
     localError(p.config, e.info, "'repr' doesn't support 'void' type")
   else:
     putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
-                              [addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]),
+                              [addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]),
                                a.storage)
   gcUsage(p.config, e)
 
-proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
+proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; enforceV1 = false): Rope =
   result = rdLoc(a)
   var t = skipTypes(a.t, abstractInst)
   while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
@@ -1680,13 +1688,20 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
       result.add(".Sup")
       t = skipTypes(t[0], skipPtrs)
   result.add ".m_type"
+  if optTinyRtti in p.config.globalOptions and enforceV1:
+    result.add "->typeInfoV1"
 
 proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
   discard cgsym(p.module, "TNimType")
   let t = e[1].typ
+  # ordinary static type information
+  putIntoDest(p, d, e, genTypeInfoV1(p.module, t, e.info))
+
+proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
+  let t = e[1].typ
   if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo":
     # ordinary static type information
-    putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info))
+    putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info))
   else:
     var a: TLoc
     initLocExpr(p, e[1], a)
@@ -1779,13 +1794,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
     const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)"
     call.r = ropecg(p.module, setLenPattern, [
       rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
-      genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
+      genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
 
   else:
     const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)"
     call.r = ropecg(p.module, setLenPattern, [
       rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
-      genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
+      genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
 
   genAssignment(p, a, call, {})
   gcUsage(p.config, e)
@@ -2226,6 +2241,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mAddI..mPred: binaryArithOverflow(p, e, d, op)
   of mRepr: genRepr(p, e, d)
   of mGetTypeInfo: genGetTypeInfo(p, e, d)
+  of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d)
   of mSwap: genSwap(p, e, d)
   of mInc, mDec:
     const opr: array[mInc..mDec, string] = ["+=", "-="]
@@ -2534,7 +2550,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
     let checkFor = if optTinyRtti in p.config.globalOptions:
                      genTypeInfo2Name(p.module, dest)
                    else:
-                     genTypeInfo(p.module, dest, n.info)
+                     genTypeInfoV1(p.module, dest, n.info)
     if nilCheck != nil:
       linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n",
               [nilCheck, r, checkFor, raiseInstr(p)])
@@ -2951,7 +2967,10 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode,
     getNullValueAuxT(p, orig, base, base.n, constOrNil, result, count, isConst, info)
     result.add "}"
   elif not isObjLackingTypeField(t):
-    result.add genTypeInfo(p.module, orig, obj.info)
+    if optTinyRtti in p.config.globalOptions:
+      result.add genTypeInfoV2(p.module, orig, obj.info)
+    else:
+      result.add genTypeInfoV1(p.module, orig, obj.info)
     inc count
   getNullValueAux(p, t, obj, constOrNil, result, count, isConst, info)
   # do not emit '{}' as that is not valid C:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 48c024b1f..5bed7cf32 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -1040,7 +1040,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
           let checkFor = if optTinyRtti in p.config.globalOptions:
             genTypeInfo2Name(p.module, typeNode.typ)
           else:
-            genTypeInfo(p.module, typeNode.typ, typeNode.info)
+            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])
 
@@ -1255,7 +1255,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
         let checkFor = if optTinyRtti in p.config.globalOptions:
           genTypeInfo2Name(p.module, t[i][j].typ)
         else:
-          genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
+          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])
 
@@ -1383,7 +1383,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
         let checkFor = if optTinyRtti in p.config.globalOptions:
           genTypeInfo2Name(p.module, t[i][j].typ)
         else:
-          genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
+          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])
 
@@ -1508,7 +1508,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
                           field: PSym) =
   var t = skipTypes(objtype, abstractVar)
   assert t.kind == tyObject
-  discard genTypeInfo(p.module, t, a.lode.info)
+  discard genTypeInfoV1(p.module, t, a.lode.info)
   if not containsOrIncl(p.module.declaredThings, field.id):
     appcg(p.module, cfsVars, "extern $1",
           [discriminatorTableDecl(p.module, t, field)])
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 63b1cb88a..29b93e530 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -173,7 +173,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
          [result, markerName, getModuleDllPath(m)])
 
 proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
-  discard genTypeInfo(m, s.loc.t, info)
+  discard genTypeInfoV1(m, s.loc.t, info)
 
   var c: TTraversalClosure
   var p = newProc(nil, m)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index aa92b8534..771e1ede9 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -609,7 +609,10 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
       if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
         appcg(m, result, " {$n", [])
       else:
-        appcg(m, result, " {$n#TNimType* m_type;$n", [])
+        if optTinyRtti in m.config.globalOptions:
+          appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
+        else:
+          appcg(m, result, " {$n#TNimType* m_type;$n", [])
         hasField = true
     elif m.compileToCpp:
       appcg(m, result, " : public $1 {$n",
@@ -1004,7 +1007,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
 
 # ------------------ type info generation -------------------------------------
 
-proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope
+proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope
 proc getNimNode(m: BModule): Rope =
   result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
   inc(m.typeNodes)
@@ -1067,7 +1070,7 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
     if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
       base = rope("0")
     else:
-      base = genTypeInfo(m, x, info)
+      base = genTypeInfoV1(m, x, info)
   else:
     base = rope("0")
   genTypeInfoAuxBase(m, typ, origType, name, base, info)
@@ -1126,7 +1129,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
         "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
         "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
         "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
-                           genTypeInfo(m, field.typ, info),
+                           genTypeInfoV1(m, field.typ, info),
                            makeCString(field.name.s),
                            tmp, rope(L)])
     m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)])
@@ -1163,7 +1166,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
       m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
           "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
           "$1.name = $5;$n", [expr, getTypeDesc(m, origType),
-          field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
+          field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)])
   else: internalError(m.config, n.info, "genObjectFields")
 
 proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
@@ -1198,7 +1201,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo)
           "$1.offset = offsetof($2, Field$3);$n" &
           "$1.typ = $4;$n" &
           "$1.name = \"Field$3\";$n",
-           [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)])
+           [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfoV1(m, a, info)])
     m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
          [expr, rope(typ.len), tmp])
   else:
@@ -1255,7 +1258,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
        [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
 
 proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
-  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ[1], info), info)
+  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info)
 
 proc fakeClosureType(m: BModule; owner: PSym): PType =
   # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -1273,13 +1276,14 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
   m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
      [result, s.loc.r])
 
-proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) =
+proc declareNimType(m: BModule, name: string; str: Rope, ownerModule: PSym) =
+  let nr = rope(name)
   if m.hcrOn:
-    m.s[cfsData].addf("static TNimType* $1;$n", [str])
-    m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
-          [str, getModuleDllPath(m, ownerModule)])
+    m.s[cfsData].addf("static $2* $1;$n", [str, nr])
+    m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n",
+          [str, getModuleDllPath(m, ownerModule), nr])
   else:
-    m.s[cfsData].addf("extern TNimType $1;$n", [str])
+    m.s[cfsData].addf("extern $2 $1;$n", [str, nr])
 
 proc genTypeInfo2Name(m: BModule; t: PType): Rope =
   var res = "|"
@@ -1327,7 +1331,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
         internalError(m.config, info, "no attached trace proc found")
     result = rope("NIM_NIL")
 
-proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
+proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
   var typeName: Rope
   if t.kind == tyObject:
     if incompleteType(t):
@@ -1337,8 +1341,8 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
   else:
     typeName = rope("NIM_NIL")
 
-  discard cgsym(m, "TNimType")
-  m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name])
+  discard cgsym(m, "TNimTypeV2")
+  m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
   let destroyImpl = genHook(m, t, info, attachedDestructor)
   let traceImpl = genHook(m, t, info, attachedTrace)
   let disposeImpl = genHook(m, t, info, attachedDispose)
@@ -1347,7 +1351,43 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
     name, destroyImpl, getTypeDesc(m, t), typeName,
     traceImpl, disposeImpl])
 
-proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
+proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
+  let origType = t
+  var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
+
+  let prefixTI = if m.hcrOn: "(" else: "(&"
+
+  let sig = hashType(origType)
+  result = m.typeInfoMarkerV2.getOrDefault(sig)
+  if result != nil:
+    return prefixTI.rope & result & ")".rope
+
+  let marker = m.g.typeInfoMarkerV2.getOrDefault(sig)
+  if marker.str != nil:
+    discard cgsym(m, "TNimTypeV2")
+    declareNimType(m, "TNimTypeV2", marker.str, marker.owner)
+    # also store in local type section:
+    m.typeInfoMarkerV2[sig] = marker.str
+    return prefixTI.rope & marker.str & ")".rope
+
+  result = "NTIv2$1_" % [rope($sig)]
+  m.typeInfoMarkerV2[sig] = result
+
+  let owner = t.skipTypes(typedescPtrs).owner.getModule
+  if owner != m.module:
+    # make sure the type info is created in the owner module
+    assert m.g.modules[owner.position] != nil
+    discard genTypeInfoV2(m.g.modules[owner.position], origType, info)
+    # reference the type info as extern here
+    discard cgsym(m, "TNimTypeV2")
+    declareNimType(m, "TNimTypeV2", result, owner)
+    return prefixTI.rope & result & ")".rope
+
+  m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner)
+  genTypeInfoV2Impl(m, t, origType, result, info)
+  result = prefixTI.rope & result & ")".rope
+
+proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
   let origType = t
   var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
 
@@ -1362,7 +1402,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
   if marker.str != nil:
     discard cgsym(m, "TNimType")
     discard cgsym(m, "TNimNode")
-    declareNimType(m, marker.str, marker.owner)
+    declareNimType(m, "TNimType", marker.str, marker.owner)
     # also store in local type section:
     m.typeInfoMarker[sig] = marker.str
     return prefixTI.rope & marker.str & ")".rope
@@ -1374,63 +1414,65 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
   if owner != m.module:
     # make sure the type info is created in the owner module
     assert m.g.modules[owner.position] != nil
-    discard genTypeInfo(m.g.modules[owner.position], origType, info)
+    discard genTypeInfoV1(m.g.modules[owner.position], origType, info)
     # reference the type info as extern here
     discard cgsym(m, "TNimType")
     discard cgsym(m, "TNimNode")
-    declareNimType(m, result, owner)
+    declareNimType(m, "TNimType", result, owner)
     return prefixTI.rope & result & ")".rope
 
   m.g.typeInfoMarker[sig] = (str: result, owner: owner)
 
-  if optTinyRtti in m.config.globalOptions:
-    genTypeInfoV2(m, t, origType, result, info)
-  else:
-    case t.kind
-    of tyEmpty, tyVoid: result = rope"0"
-    of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent:
+  case t.kind
+  of tyEmpty, tyVoid: result = rope"0"
+  of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent:
+    genTypeInfoAuxBase(m, t, t, result, rope"0", info)
+  of tyStatic:
+    if t.n != nil: result = genTypeInfoV1(m, lastSon t, info)
+    else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
+  of tyUserTypeClasses:
+    internalAssert m.config, t.isResolvedUserTypeClass
+    return genTypeInfoV1(m, t.lastSon, info)
+  of tyProc:
+    if t.callConv != ccClosure:
       genTypeInfoAuxBase(m, t, t, result, rope"0", info)
-    of tyStatic:
-      if t.n != nil: result = genTypeInfo(m, lastSon t, info)
-      else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
-    of tyUserTypeClasses:
-      internalAssert m.config, t.isResolvedUserTypeClass
-      return genTypeInfo(m, t.lastSon, info)
-    of tyProc:
-      if t.callConv != ccClosure:
-        genTypeInfoAuxBase(m, t, t, result, rope"0", info)
-      else:
-        let x = fakeClosureType(m, t.owner)
-        genTupleInfo(m, x, x, result, info)
-    of tySequence:
-      genTypeInfoAux(m, t, t, result, info)
-      if optSeqDestructors notin m.config.globalOptions:
-        if m.config.selectedGC >= gcMarkAndSweep:
-          let markerProc = genTraverseProc(m, origType, sig)
-          m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
-    of tyRef:
-      genTypeInfoAux(m, t, t, result, info)
-      if m.config.selectedGC >= gcMarkAndSweep:
-        let markerProc = genTraverseProc(m, origType, sig)
-        m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
-    of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
-    of tyArray: genArrayInfo(m, t, result, info)
-    of tySet: genSetInfo(m, t, result, info)
-    of tyEnum: genEnumInfo(m, t, result, info)
-    of tyObject:
-      genObjectInfo(m, t, origType, result, info)
-    of tyTuple:
-      # if t.n != nil: genObjectInfo(m, t, result)
-      # else:
-      # BUGFIX: use consistently RTTI without proper field names; otherwise
-      # results are not deterministic!
-      genTupleInfo(m, t, origType, result, info)
-    else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
+    else:
+      let x = fakeClosureType(m, t.owner)
+      genTupleInfo(m, x, x, result, info)
+  of tySequence:
+    genTypeInfoAux(m, t, t, result, info)
+    if m.config.selectedGC >= gcMarkAndSweep:
+      let markerProc = genTraverseProc(m, origType, sig)
+      m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
+  of tyRef:
+    genTypeInfoAux(m, t, t, result, info)
+    if m.config.selectedGC >= gcMarkAndSweep:
+      let markerProc = genTraverseProc(m, origType, sig)
+      m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
+  of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
+  of tyArray: genArrayInfo(m, t, result, info)
+  of tySet: genSetInfo(m, t, result, info)
+  of tyEnum: genEnumInfo(m, t, result, info)
+  of tyObject:
+    genObjectInfo(m, t, origType, result, info)
+  of tyTuple:
+    # if t.n != nil: genObjectInfo(m, t, result)
+    # else:
+    # BUGFIX: use consistently RTTI without proper field names; otherwise
+    # results are not deterministic!
+    genTupleInfo(m, t, origType, result, info)
+  else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
 
   if t.attachedOps[attachedDeepCopy] != nil:
     genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result)
   elif origType.attachedOps[attachedDeepCopy] != nil:
     genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result)
+
+  if optTinyRtti in m.config.globalOptions and t.kind == tyObject:
+    let v2info = genTypeInfoV2(m, origType, info)
+    addf(m.s[cfsTypeInit3], "$1->typeInfoV1 = (void*)&$2; $2.typeInfoV2 = (void*)$1;$n", [
+      v2info, result])
+
   result = prefixTI.rope & result & ")".rope
 
 proc genTypeSection(m: BModule, n: PNode) =
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index d5e1e020c..242d1f89b 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -360,7 +360,10 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
       while s.kind == tyObject and s[0] != nil:
         r.add(".Sup")
         s = skipTypes(s[0], skipPtrs)
-    linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
+    if optTinyRtti in p.config.globalOptions:
+      linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV2(p.module, t, a.lode.info)])
+    else:
+      linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
   of frEmbedded:
     if optTinyRtti in p.config.globalOptions:
       var tmp: TLoc
@@ -376,7 +379,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
     else:
       # worst case for performance:
       var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a)
-      linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)])
+      linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
 
   if isException(t):
     var r = rdLoc(a)
@@ -417,7 +420,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
       specializeReset(p, loc)
       when false:
         linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
-                [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)])
+                [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)])
       # XXX: generated reset procs should not touch the m_type
       # field, so disabling this should be safe:
       genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 3384558f8..8e5094336 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -122,6 +122,7 @@ type
     forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
     generatedHeader*: BModule
     typeInfoMarker*: TypeCacheWithOwner
+    typeInfoMarkerV2*: TypeCacheWithOwner
     config*: ConfigRef
     graph*: ModuleGraph
     strVersion*, seqVersion*: int # version of the string/seq implementation to use
@@ -155,6 +156,7 @@ type
     declaredProtos*: IntSet   # prototypes we have declared in this .c file
     headerFiles*: seq[string] # needed headers to include
     typeInfoMarker*: TypeCache # needed for generating type information
+    typeInfoMarkerV2*: TypeCache
     initProc*: BProc          # code for init procedure
     preInitProc*: BProc       # code executed before the init proc
     hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 3d0635761..dd5332b38 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -523,7 +523,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   var cond: PNode
   if isCyclic:
     if isFinal(elemType):
-      let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType))
+      let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
       typInfo.typ = getSysType(c.g, c.info, tyPointer)
       cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo)
     else:
@@ -546,7 +546,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   of attachedDeepCopy: assert(false, "cannot happen")
   of attachedTrace:
     if isFinal(elemType):
-      let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType))
+      let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
       typInfo.typ = getSysType(c.g, c.info, tyPointer)
       body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
     else:
diff --git a/compiler/options.nim b/compiler/options.nim
index 5b23ac9af..03418d953 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -136,9 +136,8 @@ type
     cmdCompileToBackend,      # compile to backend in TBackend
   TStringSeq* = seq[string]
   TGCMode* = enum             # the selected GC
-    gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcArc, gcOrc,
-    gcHooks,
-    gcRefc, gcV2, gcGo
+    gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc,
+    gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo
     # gcRefc and the GCs that follow it use a write barrier,
     # as far as usesWriteBarrier() is concerned