signature hashing: more progress

This commit is contained in:
Araq 2016-11-11 08:58:42 +01:00
commit 860cbd3107
7 changed files with 301 additions and 300 deletions

View file

@ -50,7 +50,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of tyUInt64: result = uint64Literal(uint64(n.intVal)) of tyUInt64: result = uint64Literal(uint64(n.intVal))
else: else:
result = "(($1) $2)" % [getTypeDesc(p.module, result = "(($1) $2)" % [getTypeDesc(p.module,
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)] ty), intLiteral(n.intVal)]
of nkNilLit: of nkNilLit:
let t = skipTypes(ty, abstractVarRange) let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure: if t.kind == tyProc and t.callConv == ccClosure:
@ -61,7 +61,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
inc(p.module.labels) inc(p.module.labels)
addf(p.module.s[cfsData], addf(p.module.s[cfsData],
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, t), result]) [getTypeDesc(p.module, ty), result])
else: else:
result = rope("NIM_NIL") result = rope("NIM_NIL")
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
@ -266,7 +266,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# little HACK to support the new 'var T' as return type: # little HACK to support the new 'var T' as return type:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
return return
var ty = skipTypes(dest.t, abstractRange) let ty = skipTypes(dest.t, abstractRange)
case ty.kind case ty.kind
of tyRef: of tyRef:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
@ -315,8 +315,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
genGenericAsgn(p, dest, src, flags) genGenericAsgn(p, dest, src, flags)
elif needsComplexAssignment(ty): elif needsComplexAssignment(ty):
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
discard getTypeDesc(p.module, ty) discard getTypeDesc(p.module, dest.t)
ty = getUniqueType(ty)
internalAssert ty.n != nil internalAssert ty.n != nil
genOptAsgnObject(p, dest, src, flags, ty.n) genOptAsgnObject(p, dest, src, flags, ty.n)
else: else:
@ -330,7 +329,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
rdLoc(dest), rdLoc(src), getTypeDesc(p.module, ty)) rdLoc(dest), rdLoc(src), getTypeDesc(p.module, dest.t))
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
# open arrays are always on the stack - really? What if a sequence is # open arrays are always on the stack - really? What if a sequence is
# passed to an open array? # passed to an open array?
@ -494,12 +493,12 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# later via 'chckRange' # later via 'chckRange'
let t = e.typ.skipTypes(abstractRange) let t = e.typ.skipTypes(abstractRange)
if optOverflowCheck notin p.options: if optOverflowCheck notin p.options:
let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)] let res = opr[m] % [getTypeDesc(p.module, e.typ), rdLoc(a), rdLoc(b)]
putIntoDest(p, d, e.typ, res) putIntoDest(p, d, e.typ, res)
else: else:
let res = binaryArithOverflowRaw(p, t, a, b, let res = binaryArithOverflowRaw(p, t, a, b,
if t.kind == tyInt64: prc64[m] else: prc[m]) if t.kind == tyInt64: prc64[m] else: prc[m])
putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res]) putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const const
@ -700,12 +699,11 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
template inheritLocation(d: var TLoc, a: TLoc) = template inheritLocation(d: var TLoc, a: TLoc) =
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType = proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux") if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
d.inheritLocation(a) d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = a.t.getUniqueType
proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var var
@ -714,13 +712,12 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
d.inheritLocation(a) d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
var ty = a.t.getUniqueType
var r = rdLoc(a) var r = rdLoc(a)
case e.sons[1].kind case e.sons[1].kind
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal) of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem") else: internalError(e.info, "genTupleElem")
addf(r, ".Field$1", [rope(i)]) addf(r, ".Field$1", [rope(i)])
putIntoDest(p, d, ty.sons[i], r, a.s) putIntoDest(p, d, a.t.sons[i], r, a.s)
proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym = proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym =
var ty = ty var ty = ty
@ -731,14 +728,15 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym =
result = lookupInRecord(ty.n, field.name) result = lookupInRecord(ty.n, field.name)
if result != nil: break if result != nil: break
if not p.module.compileToCpp: add(r, ".Sup") if not p.module.compileToCpp: add(r, ".Sup")
ty = getUniqueType(ty.sons[0]) ty = ty.sons[0]
if result == nil: internalError(field.info, "genCheckedRecordField") if result == nil: internalError(field.info, "genCheckedRecordField")
proc genRecordField(p: BProc, e: PNode, d: var TLoc) = proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
var ty = genRecordFieldAux(p, e, d, a) genRecordFieldAux(p, e, d, a)
var r = rdLoc(a) var r = rdLoc(a)
var f = e.sons[1].sym var f = e.sons[1].sym
let ty = skipTypes(a.t, abstractInst)
if ty.kind == tyTuple: if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information # we found a unique tuple type which lacks field information
# so we use Field$i # so we use Field$i
@ -746,7 +744,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, f.typ, r, a.s) putIntoDest(p, d, f.typ, r, a.s)
else: else:
let field = lookupFieldAgain(p, ty, f, r) let field = lookupFieldAgain(p, ty, f, r)
if field.loc.r == nil: internalError(e.info, "genRecordField 3") if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty))
addf(r, ".$1", [field.loc.r]) addf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r, a.s) putIntoDest(p, d, field.typ, r, a.s)
#d.s = a.s #d.s = a.s
@ -789,7 +787,8 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
if optFieldCheck in p.options: if optFieldCheck in p.options:
var a: TLoc var a: TLoc
let ty = genRecordFieldAux(p, e.sons[0], d, a) genRecordFieldAux(p, e.sons[0], d, a)
let ty = skipTypes(a.t, abstractInst)
var r = rdLoc(a) var r = rdLoc(a)
let f = e.sons[0].sons[1].sym let f = e.sons[0].sons[1].sym
let field = lookupFieldAgain(p, ty, f, r) let field = lookupFieldAgain(p, ty, f, r)
@ -1029,10 +1028,10 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
var a, b, dest: TLoc var a, b, dest: TLoc
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
let bt = skipTypes(e.sons[2].typ, abstractVar) let bt = skipTypes(e.sons[2].typ, {tyVar})
lineCg(p, cpsStmts, seqAppendPattern, [ lineCg(p, cpsStmts, seqAppendPattern, [
rdLoc(a), rdLoc(a),
getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)), getTypeDesc(p.module, e.sons[1].typ),
getTypeDesc(p.module, bt)]) getTypeDesc(p.module, bt)])
#if bt != b.t: #if bt != b.t:
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
@ -1046,16 +1045,17 @@ proc genReset(p: BProc, n: PNode) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[1], a) initLocExpr(p, n.sons[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))) addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, {tyVar})))
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
var sizeExpr = sizeExpr var sizeExpr = sizeExpr
let refType = skipTypes(a.t, abstractVarRange) let refType = a.t
var b: TLoc var b: TLoc
initLoc(b, locExpr, a.t, OnHeap) initLoc(b, locExpr, a.t, OnHeap)
let bt = refType.lastSon
if sizeExpr.isNil: if sizeExpr.isNil:
sizeExpr = "sizeof($1)" % sizeExpr = "sizeof($1)" %
[getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))] [getTypeDesc(p.module, bt)]
let args = [getTypeDesc(p.module, refType), let args = [getTypeDesc(p.module, refType),
genTypeInfo(p.module, refType), genTypeInfo(p.module, refType),
sizeExpr] sizeExpr]
@ -1070,7 +1070,6 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
else: else:
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args) b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
genAssignment(p, a, b, {}) # set the object type: genAssignment(p, a, b, {}) # set the object type:
let bt = skipTypes(refType.sons[0], abstractRange)
genObjectInit(p, cpsStmts, bt, a, false) genObjectInit(p, cpsStmts, bt, a, false)
proc genNew(p: BProc, e: PNode) = proc genNew(p: BProc, e: PNode) =
@ -1122,7 +1121,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
proc genConstExpr(p: BProc, n: PNode): Rope proc genConstExpr(p: BProc, n: PNode): Rope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr: if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
var t = getUniqueType(n.typ) let t = n.typ
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic) fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
@ -1322,7 +1321,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
gcUsage(e) gcUsage(e)
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
var t = skipTypes(e.sons[1].typ, abstractVarRange) let t = e.sons[1].typ
putIntoDest(p, d, e.typ, genTypeInfo(p.module, t)) putIntoDest(p, d, e.typ, genTypeInfo(p.module, t))
proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
@ -1336,7 +1335,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e.sons[1] var a = e.sons[1]
if a.kind == nkHiddenAddr: a = a.sons[0] if a.kind == nkHiddenAddr: a = a.sons[0]
var typ = skipTypes(a.typ, abstractVar) let typ = skipTypes(a.typ, abstractVar)
case typ.kind case typ.kind
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)") if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)")
@ -1363,7 +1362,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
assert(d.k == locNone) assert(d.k == locNone)
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar) let t = skipTypes(e.sons[1].typ, {tyVar})
let setLenPattern = if not p.module.compileToCpp: let setLenPattern = if not p.module.compileToCpp:
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n" "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
else: else:
@ -1371,7 +1370,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
lineCg(p, cpsStmts, setLenPattern, [ lineCg(p, cpsStmts, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
getTypeDesc(p.module, t.sons[0])]) getTypeDesc(p.module, t.skipTypes(abstractInst).sons[0])])
gcUsage(e) gcUsage(e)
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
@ -1562,7 +1561,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
var tmp: TLoc var tmp: TLoc
tmp.r = "LOC$1.source" % [lbl] tmp.r = "LOC$1.source" % [lbl]
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl) getTypeDesc(p.module, e.sons[1].typ), getTypeDesc(p.module, e.typ), lbl)
tmp.k = locExpr tmp.k = locExpr
tmp.t = srct tmp.t = srct
tmp.s = OnStack tmp.s = OnStack
@ -1796,7 +1795,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
var rec: TLoc var rec: TLoc
if not handleConstExpr(p, n, d): if not handleConstExpr(p, n, d):
var t = getUniqueType(n.typ) let t = n.typ
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
if d.k == locNone: getTemp(p, t, d) if d.k == locNone: getTemp(p, t, d)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -1805,11 +1804,6 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
initLoc(rec, locExpr, it.typ, d.s) initLoc(rec, locExpr, it.typ, d.s)
rec.r = "$1.Field$2" % [rdLoc(d), rope(i)] rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
expr(p, it, rec) expr(p, it, rec)
when false:
initLoc(rec, locExpr, it.typ, d.s)
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
rec.r = "$1.$2" % [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]
expr(p, it, rec)
proc isConstClosure(n: PNode): bool {.inline.} = proc isConstClosure(n: PNode): bool {.inline.} =
result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
@ -1863,7 +1857,7 @@ proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) =
proc upConv(p: BProc, n: PNode, d: var TLoc) = proc upConv(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
var dest = skipTypes(n.typ, abstractPtrs) let dest = skipTypes(n.typ, abstractPtrs)
if optObjCheck in p.options and not isObjLackingTypeField(dest): if optObjCheck in p.options and not isObjLackingTypeField(dest):
var r = rdLoc(a) var r = rdLoc(a)
var nilCheck: Rope = nil var nilCheck: Rope = nil
@ -1925,7 +1919,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
putIntoDest(p, d, n.typ, r, a.s) putIntoDest(p, d, n.typ, r, a.s)
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ) let t = n.typ
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
let tmp = p.module.tmpBase & rope(id) let tmp = p.module.tmpBase & rope(id)
@ -2161,13 +2155,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
data.add("}") data.add("}")
result = getTempName(p.module) result = getTempName(p.module)
let base = t.skipTypes(abstractInst).sons[0]
appcg(p.module, cfsData, appcg(p.module, cfsData,
"NIM_CONST struct {$n" & "NIM_CONST struct {$n" &
" #TGenericSeq Sup;$n" & " #TGenericSeq Sup;$n" &
" $1 data[$2];$n" & " $1 data[$2];$n" &
"} $3 = $4;$n", [ "} $3 = $4;$n", [
getTypeDesc(p.module, t.sons[0]), n.len.rope, result, data]) getTypeDesc(p.module, base), n.len.rope, result, data])
result = "(($1)&$2)" % [getTypeDesc(p.module, t), result] result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
@ -2182,7 +2177,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
of nkBracket, nkPar, nkClosure, nkObjConstr: of nkBracket, nkPar, nkClosure, nkObjConstr:
var t = skipTypes(n.typ, abstractInst) var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence: if t.kind == tySequence:
result = genConstSeq(p, n, t) result = genConstSeq(p, n, n.typ)
else: else:
result = genConstSimpleList(p, n) result = genConstSimpleList(p, n)
else: else:

View file

@ -12,7 +12,7 @@
import import
ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils, ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils,
intsets, platform, llstream intsets, platform, llstream, tables, sighashes
# Careful! Section marks need to contain a tabulator so that they cannot # Careful! Section marks need to contain a tabulator so that they cannot
# be part of C string literals. # be part of C string literals.
@ -69,7 +69,7 @@ proc genSectionEnd*(ps: TCProcSection): Rope =
if compilationCachePresent: if compilationCachePresent:
result = rope(NimMergeEndMark & tnl) result = rope(NimMergeEndMark & tnl)
proc writeTypeCache(a: TIdTable, s: var string) = proc writeTypeCache(a: TypeCache, s: var string) =
var i = 0 var i = 0
for id, value in pairs(a): for id, value in pairs(a):
if i == 10: if i == 10:
@ -77,9 +77,9 @@ proc writeTypeCache(a: TIdTable, s: var string) =
s.add(tnl) s.add(tnl)
else: else:
s.add(' ') s.add(' ')
encodeVInt(id, s) encodeStr($id, s)
s.add(':') s.add(':')
encodeStr($Rope(value), s) encodeStr($value, s)
inc i inc i
s.add('}') s.add('}')
@ -103,8 +103,9 @@ proc genMergeInfo*(m: BModule): Rope =
writeTypeCache(m.typeCache, s) writeTypeCache(m.typeCache, s)
s.add("declared:{") s.add("declared:{")
writeIntSet(m.declaredThings, s) writeIntSet(m.declaredThings, s)
s.add("typeInfo:{") when false:
writeIntSet(m.typeInfoMarker, s) s.add("typeInfo:{")
writeIntSet(m.typeInfoMarker, s)
s.add("labels:") s.add("labels:")
encodeVInt(m.labels, s) encodeVInt(m.labels, s)
s.add(" flags:") s.add(" flags:")
@ -185,19 +186,18 @@ proc newFakeType(id: int): PType =
new(result) new(result)
result.id = id result.id = id
proc readTypeCache(L: var TBaseLexer, result: var TIdTable) = proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
inc L.bufpos inc L.bufpos
while ^L.bufpos != '}': while ^L.bufpos != '}':
skipWhite(L) skipWhite(L)
var key = decodeVInt(L.buf, L.bufpos) var key = decodeStr(L.buf, L.bufpos)
if ^L.bufpos != ':': internalError("ccgmerge: ':' expected") if ^L.bufpos != ':': internalError("ccgmerge: ':' expected")
inc L.bufpos inc L.bufpos
var value = decodeStr(L.buf, L.bufpos) var value = decodeStr(L.buf, L.bufpos)
# XXX little hack: we create a "fake" type object with the correct Id # XXX implement me
# better would be to adapt the data structure to not even store the when false:
# object as key, but only the Id idTablePut(result, newFakeType(key), value.rope)
idTablePut(result, newFakeType(key), value.rope)
inc L.bufpos inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var IntSet) = proc readIntSet(L: var TBaseLexer, result: var IntSet) =
@ -220,7 +220,8 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
case k case k
of "typeCache": readTypeCache(L, m.typeCache) of "typeCache": readTypeCache(L, m.typeCache)
of "declared": readIntSet(L, m.declaredThings) of "declared": readIntSet(L, m.declaredThings)
of "typeInfo": readIntSet(L, m.typeInfoMarker) of "typeInfo":
when false: readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos) of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "flags": of "flags":
m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)

View file

@ -43,15 +43,9 @@ proc idOrSig(m: BModule; s: PSym): Rope =
# signatures for exported routines are reliable enough to # signatures for exported routines are reliable enough to
# produce a unique name and this means produced C++ is more stable wrt # produce a unique name and this means produced C++ is more stable wrt
# Nim changes: # Nim changes:
when false:
let h = hashType(s.typ, {considerParamNames})
if m.hashConflicts.containsOrIncl(cast[int](h)):
result = s.id
else:
result = BiggestInt(h)
result = rope($hashProc(s)) result = rope($hashProc(s))
else: else:
result = rope s.id result = "_" & rope s.id
proc mangleName(m: BModule; s: PSym): Rope = proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r result = s.loc.r
@ -102,7 +96,6 @@ proc mangleName(m: BModule; s: PSym): Rope =
if keepOrigName: if keepOrigName:
result.add "0" result.add "0"
else: else:
add(result, ~"_")
add(result, m.idOrSig(s)) add(result, m.idOrSig(s))
#add(result, ~"_") #add(result, ~"_")
#add(result, rope(hashOwner(s).BiggestInt)) #add(result, rope(hashOwner(s).BiggestInt))
@ -112,24 +105,12 @@ proc typeName(typ: PType): Rope =
result = if typ.sym != nil: typ.sym.name.s.mangle.rope result = if typ.sym != nil: typ.sym.name.s.mangle.rope
else: ~"TY" else: ~"TY"
proc getTypeName(m: BModule; typ: PType): Rope = proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}: if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
result = typ.sym.loc.r result = typ.sym.loc.r
else: else:
if typ.loc.r == nil: if typ.loc.r == nil:
when false: typ.loc.r = typ.typeName & $sig
# doesn't work yet and would require bigger rewritings
let h = hashType(typ, {considerParamNames})# and 0x0fff_ffffu32
let sig =
if m.hashConflicts.containsOrIncl(cast[int](h)) and false:
BiggestInt typ.id
else:
BiggestInt h
else:
let sig = BiggestInt typ.id
typ.loc.r = typ.typeName & sig.rope #& ("_" & m.module.name.s)
#if typ.kind != tySet:
# typ.loc.r.add "_" & m.module.name.s
result = typ.loc.r result = typ.loc.r
if result == nil: internalError("getTypeName: " & $typ.kind) if result == nil: internalError("getTypeName: " & $typ.kind)
@ -196,7 +177,7 @@ proc isImportedType(t: PType): bool =
proc isImportedCppType(t: PType): bool = proc isImportedCppType(t: PType): bool =
result = t.sym != nil and sfInfixCall in t.sym.flags result = t.sym != nil and sfInfixCall in t.sym.flags
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope
proc needsComplexAssignment(typ: PType): bool = proc needsComplexAssignment(typ: PType): bool =
result = containsGarbageCollectedRef(typ) result = containsGarbageCollectedRef(typ)
@ -229,11 +210,11 @@ const
# but one can #define it to what one wants # but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
proc cacheGetType(tab: TIdTable, key: PType): Rope = proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
# returns nil if we need to declare this type # returns nil if we need to declare this type
# since types are now unique via the ``getUniqueType`` mechanism, this slow # since types are now unique via the ``getUniqueType`` mechanism, this slow
# linear search is not necessary anymore: # linear search is not necessary anymore:
result = Rope(idTableGet(tab, key)) result = tab.getOrDefault(sig)
proc getTempName(m: BModule): Rope = proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels) result = m.tmpBase & rope(m.labels)
@ -266,7 +247,7 @@ proc fillResult(param: PSym) =
proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope = proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone: if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
result = getTypeName(m, t) result = t.sym.loc.r
else: else:
result = rope(literal) result = rope(literal)
@ -299,11 +280,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
proc pushType(m: BModule, typ: PType) = proc pushType(m: BModule, typ: PType) =
add(m.typeStack, typ) add(m.typeStack, typ)
proc getTypePre(m: BModule, typ: PType): Rope = proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
if typ == nil: result = rope("void") if typ == nil: result = rope("void")
else: else:
result = getSimpleTypeDesc(m, typ) result = getSimpleTypeDesc(m, typ)
if result == nil: result = cacheGetType(m.typeCache, typ) if result == nil: result = cacheGetType(m.typeCache, sig)
proc structOrUnion(t: PType): Rope = proc structOrUnion(t: PType): Rope =
(if tfUnion in t.flags: rope("union") else: rope("struct")) (if tfUnion in t.flags: rope("union") else: rope("struct"))
@ -312,42 +293,44 @@ proc getForwardStructFormat(m: BModule): string =
if m.compileToCpp: result = "$1 $2;$n" if m.compileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n" else: result = "typedef $1 $2 $2;$n"
proc getTypeForward(m: BModule, typ: PType): Rope = proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
result = cacheGetType(m.forwTypeCache, typ) result = cacheGetType(m.forwTypeCache, sig)
if result != nil: return if result != nil: return
result = getTypePre(m, typ) result = getTypePre(m, typ, sig)
if result != nil: return if result != nil: return
case typ.kind case typ.skipTypes(abstractInst).kind
of tySequence, tyTuple, tyObject: of tySequence, tyTuple, tyObject:
result = getTypeName(m, typ) result = getTypeName(m, typ, sig)
m.forwTypeCache[sig] = result
if not isImportedType(typ): if not isImportedType(typ):
addf(m.s[cfsForwardTypes], "/* getTypeForward: $1 $2 $3 */", [rope typeToString typ,
rope typ.id, rope m.module.id])
addf(m.s[cfsForwardTypes], getForwardStructFormat(m), addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(typ), result]) [structOrUnion(typ), result])
idTablePut(m.forwTypeCache, typ, result) doAssert m.forwTypeCache[sig] == result
else: internalError("getTypeForward(" & $typ.kind & ')') else: internalError("getTypeForward(" & $typ.kind & ')')
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
## like getTypeDescAux but creates only a *weak* dependency. In other words ## like getTypeDescAux but creates only a *weak* dependency. In other words
## we know we only need a pointer to it so we only generate a struct forward ## we know we only need a pointer to it so we only generate a struct forward
## declaration: ## declaration:
var etB = t.skipTypes(abstractInst) let etB = t.skipTypes(abstractInst)
case etB.kind case etB.kind
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(etB) and t.kind == tyGenericInst: if isImportedCppType(etB) and t.kind == tyGenericInst:
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
else: else:
let x = getUniqueType(etB) result = getTypeForward(m, t, hashType(t))
result = getTypeForward(m, x) pushType(m, t)
pushType(m, x)
of tySequence: of tySequence:
let x = getUniqueType(etB) result = getTypeForward(m, t, hashType(t)) & "*"
result = getTypeForward(m, x) & "*" pushType(m, t)
pushType(m, x)
else: else:
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
proc paramStorageLoc(param: PSym): TStorageLoc = proc paramStorageLoc(param: PSym): TStorageLoc =
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray, tyVarargs, tyArrayConstr}: if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {
tyArray, tyOpenArray, tyVarargs, tyArrayConstr}:
result = OnStack result = OnStack
else: else:
result = OnUnknown result = OnUnknown
@ -419,10 +402,6 @@ proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
proc genRecordFieldsAux(m: BModule, n: PNode, proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: Rope, rectype: PType, accessExpr: Rope, rectype: PType,
check: var IntSet): Rope = check: var IntSet): Rope =
var
ae, uname, sname, a: Rope
k: PNode
field: PSym
result = nil result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
@ -431,18 +410,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
of nkRecCase: of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux") if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check)) add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
uname = rope(mangle(n.sons[0].sym.name.s) & 'U') let uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
if accessExpr != nil: ae = "$1.$2" % [accessExpr, uname] let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname]
else: ae = uname else: uname
var unionBody: Rope = nil var unionBody: Rope = nil
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind case n.sons[i].kind
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
k = lastSon(n.sons[i]) let k = lastSon(n.sons[i])
if k.kind != nkSym: if k.kind != nkSym:
sname = "S" & rope(i) let sname = "S" & rope(i)
a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype, let a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
check) check)
if a != nil: if a != nil:
add(unionBody, "struct {") add(unionBody, "struct {")
add(unionBody, a) add(unionBody, a)
@ -453,12 +432,12 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if unionBody != nil: if unionBody != nil:
addf(result, "union{$n$1} $2;$n", [unionBody, uname]) addf(result, "union{$n$1} $2;$n", [unionBody, uname])
of nkSym: of nkSym:
field = n.sym let field = n.sym
if field.typ.kind == tyVoid: return if field.typ.kind == tyVoid: return
#assert(field.ast == nil) #assert(field.ast == nil)
sname = mangleRecFieldName(field, rectype) let sname = mangleRecFieldName(field, rectype)
if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname] let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
else: ae = sname else: sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown) fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't # for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
@ -558,24 +537,29 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
result = if result.kind == tyGenericInst: result.sons[1] result = if result.kind == tyGenericInst: result.sons[1]
else: result.elemType else: result.elemType
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = const
irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
tyDistinct, tyRange, tyStatic}
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
# returns only the type's name # returns only the type's name
var t = getUniqueType(typ) var t = origTyp.skipTypes(irrelevantForBackend)
if t == nil: internalError("getTypeDescAux: t == nil")
if t.sym != nil: useHeader(m, t.sym) if t.sym != nil: useHeader(m, t.sym)
result = getTypePre(m, t) if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp)
result = getTypePre(m, t, sig)
if result != nil: return if result != nil: return
if containsOrIncl(check, t.id): if containsOrIncl(check, t.id):
if not (isImportedCppType(typ) or isImportedCppType(t)): if not (isImportedCppType(origTyp) or isImportedCppType(t)):
internalError("cannot generate C type for: " & typeToString(typ)) internalError("cannot generate C type for: " & typeToString(origTyp))
# XXX: this BUG is hard to fix -> we need to introduce helper structs, # XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split # but determining when this needs to be done is hard. We should split
# C type generation into an analysis and a code generation phase somehow. # C type generation into an analysis and a code generation phase somehow.
case t.kind case t.kind
of tyRef, tyPtr, tyVar: of tyRef, tyPtr, tyVar:
var star = if t.kind == tyVar and tfVarIsPtr notin typ.flags and var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
compileToCpp(m): "&" else: "*" compileToCpp(m): "&" else: "*"
var et = typ.skipTypes(abstractInst).lastSon var et = origTyp.skipTypes(abstractInst).lastSon
var etB = et.skipTypes(abstractInst) var etB = et.skipTypes(abstractInst)
if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
# this is correct! sets have no proper base type, so we treat # this is correct! sets have no proper base type, so we treat
@ -589,33 +573,30 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
result = getTypeDescAux(m, et, check) & star result = getTypeDescAux(m, et, check) & star
else: else:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let x = getUniqueType(etB) let name = getTypeForward(m, et, hashType et)
let name = getTypeForward(m, x)
result = name & star result = name & star
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
pushType(m, x) pushType(m, et)
of tySequence: of tySequence:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let x = getUniqueType(etB) let name = getTypeForward(m, et, hashType et)
let name = getTypeForward(m, x)
result = name & "*" & star result = name & "*" & star
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
pushType(m, x) pushType(m, et)
else: else:
# else we have a strong dependency :-( # else we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star result = getTypeDescAux(m, et, check) & star
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = getTypeDescWeak(m, t.sons[0], check) & "*" result = getTypeDescWeak(m, t.sons[0], check) & "*"
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
of tyRange, tyEnum: of tyEnum:
let t = if t.kind == tyRange: t.lastSon else: t result = cacheGetType(m.typeCache, sig)
result = cacheGetType(m.typeCache, t)
if result == nil: if result == nil:
result = getTypeName(m, t) result = getTypeName(m, t, sig)
if not (isImportedCppType(t) or if not (isImportedCppType(t) or
(sfImportc in t.sym.flags and t.sym.magic == mNone)): (sfImportc in t.sym.flags and t.sym.magic == mNone)):
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
var size: int var size: int
if firstOrd(t) < 0: if firstOrd(t) < 0:
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result]) addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
@ -639,8 +620,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id, gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
name: t.sym.name.s, values: vals)) name: t.sym.name.s, values: vals))
of tyProc: of tyProc:
result = getTypeName(m, t) result = getTypeName(m, origTyp, sig)
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
var rettype, desc: Rope var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, true, true) genProcParams(m, t, rettype, desc, check, true, true)
if not isImportedType(t): if not isImportedType(t):
@ -655,15 +636,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
of tySequence: of tySequence:
# we cannot use getTypeForward here because then t would be associated # we cannot use getTypeForward here because then t would be associated
# with the name of the struct, not with the pointer to the struct: # with the name of the struct, not with the pointer to the struct:
result = cacheGetType(m.forwTypeCache, t) result = cacheGetType(m.forwTypeCache, sig)
if result == nil: if result == nil:
result = getTypeName(m, t) result = getTypeName(m, origTyp, sig)
if not isImportedType(t): if not isImportedType(t):
addf(m.s[cfsForwardTypes], getForwardStructFormat(m), addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result]) [structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result) m.forwTypeCache[sig] = result
assert(cacheGetType(m.typeCache, t) == nil) assert(cacheGetType(m.typeCache, sig) == nil)
idTablePut(m.typeCache, t, result & "*") m.typeCache[sig] = result & "*"
if not isImportedType(t): if not isImportedType(t):
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty: if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const const
@ -677,20 +658,20 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
else: else:
result = rope("TGenericSeq") result = rope("TGenericSeq")
add(result, "*") add(result, "*")
of tyArrayConstr, tyArray: of tyArray:
var n: BiggestInt = lengthOrd(t) var n: BiggestInt = lengthOrd(t)
if n <= 0: n = 1 # make an array of at least one element if n <= 0: n = 1 # make an array of at least one element
result = getTypeName(m, t) result = getTypeName(m, origTyp, sig)
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
if not isImportedType(t): if not isImportedType(t):
let foo = getTypeDescAux(m, t.sons[1], check) let foo = getTypeDescAux(m, t.sons[1], check)
addf(m.s[cfsTypes], "typedef $1 $2[$3];$n", addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
[foo, result, rope(n)]) [foo, result, rope(n)])
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(t) and typ.kind == tyGenericInst: if isImportedCppType(t) and origTyp.kind == tyGenericInst:
# for instantiated templates we do not go through the type cache as the # for instantiated templates we do not go through the type cache as the
# the type cache is not aware of 'tyGenericInst'. # the type cache is not aware of 'tyGenericInst'.
let cppName = getTypeName(m, t) let cppName = getTypeName(m, t, sig)
var i = 0 var i = 0
var chunkStart = 0 var chunkStart = 0
while i < cppName.data.len: while i < cppName.data.len:
@ -701,7 +682,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
result.add cppName.data.substr(chunkStart, chunkEnd) result.add cppName.data.substr(chunkStart, chunkEnd)
chunkStart = i chunkStart = i
let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars) let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars)
if typeInSlot == nil or typeInSlot.kind == tyVoid: if typeInSlot == nil or typeInSlot.kind == tyVoid:
result.add(~"void") result.add(~"void")
else: else:
@ -713,28 +694,44 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
result.add cppName.data.substr(chunkStart) result.add cppName.data.substr(chunkStart)
else: else:
result = cppName & "<" result = cppName & "<"
for i in 1 .. typ.len-2: for i in 1 .. origTyp.len-2:
if i > 1: result.add(" COMMA ") if i > 1: result.add(" COMMA ")
result.add(getTypeDescAux(m, typ.sons[i], check)) result.add(getTypeDescAux(m, origTyp.sons[i], check))
result.add("> ") result.add("> ")
# always call for sideeffects: # always call for sideeffects:
assert t.kind != tyTuple assert t.kind != tyTuple
discard getRecordDesc(m, t, result, check) discard getRecordDesc(m, t, result, check)
else: else:
result = cacheGetType(m.forwTypeCache, t) when false:
if t.sym != nil and t.sym.name.s == "KeyValuePair":
if t == origTyp:
echo "wtf: came here"
writeStackTrace()
quit 1
result = cacheGetType(m.forwTypeCache, sig)
if result == nil: if result == nil:
result = getTypeName(m, t) when false:
if t.sym != nil and t.sym.name.s == "KeyValuePair":
# or {sfImportc, sfExportc} * t.sym.flags == {}:
if t.loc.r != nil:
echo t.kind, " ", hashType t
echo origTyp.kind, " ", sig
assert t.loc.r == nil
result = getTypeName(m, origTyp, sig)
m.forwTypeCache[sig] = result
if not isImportedType(t): if not isImportedType(t):
addf(m.s[cfsForwardTypes], "/* tyObject: $1 $2 $3 */", [rope typeToString t,
rope t.id, rope m.module.id])
addf(m.s[cfsForwardTypes], getForwardStructFormat(m), addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result]) [structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result) doAssert m.forwTypeCache[sig] == result
idTablePut(m.typeCache, t, result) # always call for sideeffects: m.typeCache[sig] = result # always call for sideeffects:
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check) let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
else: getTupleDesc(m, t, result, check) else: getTupleDesc(m, t, result, check)
if not isImportedType(t): add(m.s[cfsTypes], recdesc) if not isImportedType(t): add(m.s[cfsTypes], recdesc)
of tySet: of tySet:
result = getTypeName(m, t.lastSon) & "Set" result = getTypeName(m, t.lastSon, hashType t.lastSon) & "Set"
idTablePut(m.typeCache, t, result) m.typeCache[sig] = result
if not isImportedType(t): if not isImportedType(t):
let s = int(getSize(t)) let s = int(getSize(t))
case s case s
@ -822,8 +819,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
var size: Rope var size: Rope
if tfIncompleteStruct in typ.flags: size = rope"void*" if tfIncompleteStruct in typ.flags: size = rope"void*"
elif m.compileToCpp: size = getTypeDesc(m, origType) else: size = getTypeDesc(m, origType)
else: size = getTypeDesc(m, typ)
addf(m.s[cfsTypeInit3], addf(m.s[cfsTypeInit3],
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
[name, size, rope(nimtypeKind), base]) [name, size, rope(nimtypeKind), base])
@ -855,26 +851,26 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
objtype = objtype.sons[0] objtype = objtype.sons[0]
if objtype.sym == nil: if objtype.sym == nil:
internalError(d.info, "anonymous obj with discriminator") internalError(d.info, "anonymous obj with discriminator")
result = "NimDT_$1_$2" % [rope(objtype.id), rope(d.name.s.mangle)] result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope = proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d) var tmp = discriminatorTableName(m, objtype, d)
result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)] result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) = proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope) =
case n.kind case n.kind
of nkRecList: of nkRecList:
var L = sonsLen(n) var L = sonsLen(n)
if L == 1: if L == 1:
genObjectFields(m, typ, n.sons[0], expr) genObjectFields(m, typ, origType, n.sons[0], expr)
elif L > 0: elif L > 0:
var tmp = getTempName(m) var tmp = getTempName(m)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)]) addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
for i in countup(0, L-1): for i in countup(0, L-1):
var tmp2 = getNimNode(m) var tmp2 = getNimNode(m)
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2]) addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
genObjectFields(m, typ, n.sons[i], tmp2) genObjectFields(m, typ, origType, n.sons[i], tmp2)
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(L), tmp]) [expr, rope(L), tmp])
else: else:
@ -888,7 +884,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" & addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r, "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
genTypeInfo(m, field.typ), genTypeInfo(m, field.typ),
makeCString(field.name.s), makeCString(field.name.s),
tmp, rope(L)]) tmp, rope(L)])
@ -896,7 +892,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
for i in countup(1, sonsLen(n)-1): for i in countup(1, sonsLen(n)-1):
var b = n.sons[i] # branch var b = n.sons[i] # branch
var tmp2 = getNimNode(m) var tmp2 = getNimNode(m)
genObjectFields(m, typ, lastSon(b), tmp2) genObjectFields(m, typ, origType, lastSon(b), tmp2)
case b.kind case b.kind
of nkOfBranch: of nkOfBranch:
if sonsLen(b) < 2: if sonsLen(b) < 2:
@ -920,7 +916,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
if field.bitsize == 0: if field.bitsize == 0:
addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" & addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, typ), "$1.name = $5;$n", [expr, getTypeDesc(m, origType),
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)]) field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields") else: internalError(n.info, "genObjectFields")
@ -929,7 +925,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
else: genTypeInfoAuxBase(m, typ, origType, name, rope("0")) else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
var tmp = getNimNode(m) var tmp = getNimNode(m)
if not isImportedCppType(typ): if not isImportedCppType(typ):
genObjectFields(m, typ, typ.n, tmp) genObjectFields(m, typ, origType, typ.n, tmp)
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0] var t = typ.sons[0]
while t != nil: while t != nil:
@ -937,7 +933,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
t.flags.incl tfObjHasKids t.flags.incl tfObjHasKids
t = t.sons[0] t = t.sons[0]
proc genTupleInfo(m: BModule, typ: PType, name: Rope) = proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope) =
genTypeInfoAuxBase(m, typ, typ, name, rope("0")) genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
var expr = getNimNode(m) var expr = getNimNode(m)
var length = sonsLen(typ) var length = sonsLen(typ)
@ -952,7 +948,7 @@ proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
"$1.offset = offsetof($2, Field$3);$n" & "$1.offset = offsetof($2, Field$3);$n" &
"$1.typ = $4;$n" & "$1.typ = $4;$n" &
"$1.name = \"Field$3\";$n", "$1.name = \"Field$3\";$n",
[tmp2, getTypeDesc(m, typ), rope(i), genTypeInfo(m, a)]) [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a)])
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(length), tmp]) [expr, rope(length), tmp])
else: else:
@ -1034,27 +1030,20 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
proc genTypeInfo(m: BModule, t: PType): Rope = proc genTypeInfo(m: BModule, t: PType): Rope =
let origType = t let origType = t
var t = getUniqueType(t) var t = skipTypes(origType, irrelevantForBackend)
when false: let sig = hashType(origType)
let h = hashType(t, {considerParamNames}) result = m.typeInfoMarker.getOrDefault(sig)
let tid = if m.hashConflicts.containsOrIncl(cast[int](h)): if result != nil:
BiggestInt t.id
else:
BiggestInt h
else:
let tid = t.id
result = "NTI$1" % [rope(tid)]
if containsOrIncl(m.typeInfoMarker, t.id):
return "(&".rope & result & ")".rope return "(&".rope & result & ")".rope
# getUniqueType doesn't skip tyDistinct when that has an overriden operation: result = "NTI$1" % [rope($sig)]
while t.kind == tyDistinct: t = t.lastSon m.typeInfoMarker[sig] = result
let owner = t.skipTypes(typedescPtrs).owner.getModule let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module: if owner != m.module:
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfo(owner.bmod, t) discard genTypeInfo(owner.bmod, origType)
# reference the type info as extern here # reference the type info as extern here
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
@ -1072,7 +1061,8 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
if t.callConv != ccClosure: if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0") genTypeInfoAuxBase(m, t, t, result, rope"0")
else: else:
genTupleInfo(m, fakeClosureType(t.owner), result) let x = fakeClosureType(t.owner)
genTupleInfo(m, x, x, result)
of tySequence, tyRef: of tySequence, tyRef:
genTypeInfoAux(m, t, t, result) genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep: if gSelectedGC >= gcMarkAndSweep:
@ -1088,7 +1078,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
# else: # else:
# BUGFIX: use consistently RTTI without proper field names; otherwise # BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic! # results are not deterministic!
genTupleInfo(m, t, result) genTupleInfo(m, t, origType, result)
else: internalError("genTypeInfo(" & $t.kind & ')') else: internalError("genTypeInfo(" & $t.kind & ')')
if t.deepCopy != nil: if t.deepCopy != nil:
genDeepCopyProc(m, t.deepCopy, result) genDeepCopyProc(m, t.deepCopy, result)

View file

@ -85,87 +85,77 @@ proc slowSearch(key: PType; k: TTypeKind): PType =
proc getUniqueType*(key: PType): PType = proc getUniqueType*(key: PType): PType =
# this is a hotspot in the compiler! # this is a hotspot in the compiler!
if key == nil: return result = key
var k = key.kind when false:
case k if key == nil: return
of tyBool, tyChar, tyInt..tyUInt64: var k = key.kind
# no canonicalization for integral types, so that e.g. ``pid_t`` is case k
# produced instead of ``NI``. of tyBool, tyChar, tyInt..tyUInt64:
result = key # no canonicalization for integral types, so that e.g. ``pid_t`` is
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString, # produced instead of ``NI``.
tyCString, tyNone, tyVoid:
result = gCanonicalTypes[k]
if result == nil:
gCanonicalTypes[k] = key
result = key result = key
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor: of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
if key.sym != nil: tyCString, tyNone, tyVoid:
internalError(key.sym.info, "metatype not eliminated") result = gCanonicalTypes[k]
else: if result == nil:
internalError("metatype not eliminated") gCanonicalTypes[k] = key
of tyDistinct: result = key
if key.deepCopy != nil: result = key of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
else: result = getUniqueType(lastSon(key)) if key.sym != nil:
of tyGenericInst, tyOrdinal, tyStatic: internalError(key.sym.info, "metatype not eliminated")
result = getUniqueType(lastSon(key)) else:
#let obj = lastSon(key) internalError("metatype not eliminated")
#if obj.sym != nil and obj.sym.name.s == "TOption": of tyDistinct:
# echo "for ", typeToString(key), " I returned " if key.deepCopy != nil: result = key
# debug result else: result = getUniqueType(lastSon(key))
of tyPtr, tyRef, tyVar: of tyGenericInst, tyOrdinal, tyStatic:
let elemType = lastSon(key) result = getUniqueType(lastSon(key))
if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}: #let obj = lastSon(key)
# no canonicalization for integral types, so that e.g. ``ptr pid_t`` is #if obj.sym != nil and obj.sym.name.s == "TOption":
# produced instead of ``ptr NI``. # echo "for ", typeToString(key), " I returned "
result = key # debug result
else: of tyPtr, tyRef, tyVar:
let elemType = lastSon(key)
if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
# no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
# produced instead of ``ptr NI``.
result = key
else:
result = slowSearch(key, k)
of tyArrayConstr, tyGenericInvocation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tySequence, tyForward, tyVarargs, tyProxy:
# we have to do a slow linear search because types may need
# to be compared by their structure:
result = slowSearch(key, k) result = slowSearch(key, k)
of tyArrayConstr, tyGenericInvocation, tyGenericBody, of tyObject:
tyOpenArray, tyArray, tySet, tyRange, tyTuple, if tfFromGeneric notin key.flags:
tySequence, tyForward, tyVarargs, tyProxy: # fast case; lookup per id suffices:
# we have to do a slow linear search because types may need result = PType(idTableGet(gTypeTable[k], key))
# to be compared by their structure: if result == nil:
result = slowSearch(key, k) idTablePut(gTypeTable[k], key, key)
of tyObject: result = key
if tfFromGeneric notin key.flags: else:
# fast case; lookup per id suffices: # ugly slow case: need to compare by structure
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
idTablePut(gTypeTable[k], key, key)
result = key
of tyEnum:
result = PType(idTableGet(gTypeTable[k], key)) result = PType(idTableGet(gTypeTable[k], key))
if result == nil: if result == nil:
idTablePut(gTypeTable[k], key, key) idTablePut(gTypeTable[k], key, key)
result = key result = key
else: of tyProc:
# ugly slow case: need to compare by structure if key.callConv != ccClosure:
if idTableHasObjectAsKey(gTypeTable[k], key): return key result = key
for h in countup(0, high(gTypeTable[k].data)): else:
var t = PType(gTypeTable[k].data[h].key) # ugh, we need the canon here:
if t != nil and sameBackendType(t, key): result = slowSearch(key, k)
return t of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("getUniqueType")
idTablePut(gTypeTable[k], key, key)
result = key
of tyEnum:
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
idTablePut(gTypeTable[k], key, key)
result = key
of tyProc:
if key.callConv != ccClosure:
result = key
else:
# ugh, we need the canon here:
result = slowSearch(key, k)
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("getUniqueType")
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
# returns nil if we need to declare this type
result = idTableGet(tab, key)
if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need
# to be compared by their structure:
for h in countup(0, high(tab.data)):
var t = PType(tab.data[h].key)
if t != nil:
if sameType(t, key):
return tab.data[h].val
proc makeSingleLineCString*(s: string): string = proc makeSingleLineCString*(s: string): string =
result = "\"" result = "\""

View file

@ -14,7 +14,7 @@ import
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel lowerings, semparallel, tables
from modulegraphs import ModuleGraph from modulegraphs import ModuleGraph
@ -263,6 +263,7 @@ type
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc isComplexValueType(t: PType): bool {.inline.} = proc isComplexValueType(t: PType): bool {.inline.} =
let t = t.skipTypes(abstractInst)
result = t.kind in {tyArray, tyArrayConstr, tySet, tyTuple, tyObject} or result = t.kind in {tyArray, tyArrayConstr, tySet, tyTuple, tyObject} or
(t.kind == tyProc and t.callConv == ccClosure) (t.kind == tyProc and t.callConv == ccClosure)
@ -296,7 +297,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
genObjectInit(p, cpsStmts, loc.t, loc, true) genObjectInit(p, cpsStmts, loc.t, loc, true)
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) = proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
let typ = skipTypes(loc.t, abstractRange) let typ = loc.t
if not isComplexValueType(typ): if not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc), linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
getTypeDesc(p.module, typ)) getTypeDesc(p.module, typ))
@ -325,13 +326,9 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels) inc(p.labels)
result.r = "LOC" & rope(p.labels) result.r = "LOC" & rope(p.labels)
#addf(p.blocks[0].sections[cpsLocals],
# "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp result.k = locTemp
#result.a = - 1
result.t = t result.t = t
#result.t = getUniqueType(t)
result.s = OnStack result.s = OnStack
result.flags = {} result.flags = {}
constructLoc(p, result, not needsInit) constructLoc(p, result, not needsInit)
@ -1094,10 +1091,10 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.declaredProtos = initIntSet() result.declaredProtos = initIntSet()
result.cfilename = filename result.cfilename = filename
result.filename = filename result.filename = filename
initIdTable(result.typeCache) result.typeCache = initTable[SigHash, Rope]()
initIdTable(result.forwTypeCache) result.forwTypeCache = initTable[SigHash, Rope]()
result.module = module result.module = module
result.typeInfoMarker = initIntSet() result.typeInfoMarker = initTable[SigHash, Rope]()
result.initProc = newProc(nil, result) result.initProc = newProc(nil, result)
result.initProc.options = initProcOptions(result) result.initProc.options = initProcOptions(result)
result.preInitProc = newPreInitProc(result) result.preInitProc = newPreInitProc(result)
@ -1107,7 +1104,6 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.forwardedProcs = @[] result.forwardedProcs = @[]
result.typeNodesName = getTempName(result) result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result) result.nimTypesName = getTempName(result)
result.hashConflicts = initIntSet()
# no line tracing for the init sections of the system module so that we # no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization: # don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags: if sfSystemModule in module.flags:
@ -1124,7 +1120,7 @@ proc resetModule*(m: BModule) =
# away all the data that was written to disk # away all the data that was written to disk
initLinkedList(m.headerFiles) initLinkedList(m.headerFiles)
m.declaredProtos = initIntSet() m.declaredProtos = initIntSet()
initIdTable(m.forwTypeCache) m.forwTypeCache = initTable[SigHash, Rope]()
m.initProc = newProc(nil, m) m.initProc = newProc(nil, m)
m.initProc.options = initProcOptions(m) m.initProc.options = initProcOptions(m)
m.preInitProc = newPreInitProc(m) m.preInitProc = newPreInitProc(m)
@ -1141,7 +1137,6 @@ proc resetModule*(m: BModule) =
nullify m.s nullify m.s
m.typeNodes = 0 m.typeNodes = 0
m.nimTypes = 0 m.nimTypes = 0
m.hashConflicts = initIntSet()
nullify m.extensionLoaders nullify m.extensionLoaders
# indicate that this is now cached module # indicate that this is now cached module

View file

@ -10,7 +10,8 @@
## This module contains the data structures for the C code generation phase. ## This module contains the data structures for the C code generation phase.
import import
ast, astalgo, ropes, passes, options, intsets, lists, platform ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes,
tables
from msgs import TLineInfo from msgs import TLineInfo
@ -92,6 +93,7 @@ type
gcFrameType*: Rope # the struct {} we put the GC markers into gcFrameType*: Rope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType] TTypeSeq* = seq[PType]
TypeCache* = Table[SigHash, Rope]
Codegenflag* = enum Codegenflag* = enum
preventStackTrace, # true if stack traces need to be prevented preventStackTrace, # true if stack traces need to be prevented
@ -109,12 +111,12 @@ type
cfilename*: string # filename of the module (including path, cfilename*: string # filename of the module (including path,
# without extension) # without extension)
tmpBase*: Rope # base for temp identifier generation tmpBase*: Rope # base for temp identifier generation
typeCache*: TIdTable # cache the generated types typeCache*: TypeCache # cache the generated types
forwTypeCache*: TIdTable # cache for forward declarations of types forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file
headerFiles*: TLinkedList # needed headers to include headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: IntSet # needed for generating type information typeInfoMarker*: TypeCache # needed for generating type information
initProc*: BProc # code for init procedure initProc*: BProc # code for init procedure
postInitProc*: BProc # code to be executed after the init proc postInitProc*: BProc # code to be executed after the init proc
preInitProc*: BProc # code executed before the init proc preInitProc*: BProc # code executed before the init proc
@ -127,7 +129,6 @@ type
extensionLoaders*: array['0'..'9', Rope] # special procs for the extensionLoaders*: array['0'..'9', Rope] # special procs for the
# OpenGL wrapper # OpenGL wrapper
injectStmt*: Rope injectStmt*: Rope
hashConflicts*: IntSet
var var
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope

View file

@ -10,7 +10,10 @@
## Computes hash values for routine (proc, method etc) signatures. ## Computes hash values for routine (proc, method etc) signatures.
import ast, md5 import ast, md5
export md5.`==` from hashes import Hash
from astalgo import debug
from types import typeToString
from strutils import startsWith
when false: when false:
type type
@ -25,7 +28,7 @@ when false:
else: else:
type type
SigHash* = Md5Digest SigHash* = distinct Md5Digest
const const
cb64 = [ cb64 = [
@ -39,6 +42,7 @@ else:
proc toBase64a(s: cstring, len: int): string = proc toBase64a(s: cstring, len: int): string =
## encodes `s` into base64 representation. ## encodes `s` into base64 representation.
result = newStringOfCap(((len + 2) div 3) * 4) result = newStringOfCap(((len + 2) div 3) * 4)
result.add '_'
var i = 0 var i = 0
while i < len - 2: while i < len - 2:
let a = ord(s[i]) let a = ord(s[i])
@ -65,6 +69,15 @@ else:
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1) proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1)
proc `==`*(a, b: SigHash): bool =
# {.borrow.}
result = equalMem(unsafeAddr a, unsafeAddr b, sizeof(a))
proc hash*(u: SigHash): Hash =
result = 0
for x in 0..3:
result = (result shl 8) or u.MD5Digest[x].int
proc hashSym(c: var MD5Context, s: PSym) = proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam: if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon" c &= ":anon"
@ -105,28 +118,46 @@ proc hashTree(c: var MD5Context, n: PNode) =
type type
ConsiderFlag* = enum ConsiderFlag* = enum
considerParamNames CoProc
CoType
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# modelled after 'typeToString'
if t == nil: if t == nil:
c &= "\254" c &= "\254"
return return
c &= char(t.kind) c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this case t.kind
# is actually safe without an infinite recursion check: of tyGenericInst:
if t.sym != nil and sfAnon notin t.sym.flags: var x = t.lastSon
# t.n for literals, but not for e.g. objects! if x.kind == tyGenericBody: x = x.lastSon
if t.kind in {tyFloat, tyInt}: c.hashTree(t.n) if x.kind == tyTuple:
c.hashSym(t.sym) c.hashType x, flags
return
for i in countup(0, sonsLen(t) - 2):
c.hashType t.sons[i], flags
return return
of tyGenericInvocation:
for i in countup(0, sonsLen(t) - 1):
c.hashType t.sons[i], flags
return
of tyDistinct:
if CoType in flags:
c.hashType t.lastSon, flags
else:
c.hashSym(t.sym)
return
else:
discard
case t.kind case t.kind
of tyGenericBody, tyGenericInst, tyGenericInvocation: of tyObject, tyEnum:
for i in countup(0, sonsLen(t) - 1 - ord(t.kind != tyGenericInvocation)): # Every cyclic type in Nim need to be constructed via some 't.sym', so this
c.hashType t.sons[i], flags # is actually safe without an infinite recursion check:
c.hashSym(t.sym)
of tyRef, tyPtr, tyGenericBody:
c.hashType t.lastSon, flags
of tyUserTypeClass: of tyUserTypeClass:
if t.sym != nil and t.sym.owner != nil: if t.sym != nil and t.sym.owner != nil:
c &= t.sym.owner.name.s c &= t.sym.owner.name.s
@ -139,11 +170,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
c.hashType t.sons[i], flags c.hashType t.sons[i], flags
of tyFromExpr, tyFieldAccessor: of tyFromExpr, tyFieldAccessor:
c.hashTree(t.n) c.hashTree(t.n)
of tyArrayConstr:
c.hashTree(t.sons[0].n)
c.hashType(t.sons[1], flags)
of tyTuple: of tyTuple:
if t.n != nil: if t.n != nil and CoType notin flags:
assert(sonsLen(t.n) == sonsLen(t)) assert(sonsLen(t.n) == sonsLen(t))
for i in countup(0, sonsLen(t.n) - 1): for i in countup(0, sonsLen(t.n) - 1):
assert(t.n.sons[i].kind == nkSym) assert(t.n.sons[i].kind == nkSym)
@ -154,11 +182,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else: else:
for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i], flags for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i], flags
of tyRange: of tyRange:
c.hashTree(t.n) if CoType notin flags: c.hashTree(t.n)
c.hashType(t.sons[0], flags) c.hashType(t.sons[0], flags)
of tyProc: of tyProc:
c &= (if tfIterator in t.flags: "iterator " else: "proc ") c &= (if tfIterator in t.flags: "iterator " else: "proc ")
if considerParamNames in flags and t.n != nil: if CoProc in flags and t.n != nil:
let params = t.n let params = t.n
for i in 1..<params.len: for i in 1..<params.len:
let param = params[i].sym let param = params[i].sym
@ -170,22 +198,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else: else:
for i in 0.. <t.len: c.hashType(t.sons[i], flags) for i in 0.. <t.len: c.hashType(t.sons[i], flags)
c &= char(t.callConv) c &= char(t.callConv)
if tfNoSideEffect in t.flags: c &= ".noSideEffect" if CoType notin flags:
if tfThread in t.flags: c &= ".thread" if tfNoSideEffect in t.flags: c &= ".noSideEffect"
if tfThread in t.flags: c &= ".thread"
else: else:
for i in 0.. <t.len: c.hashType(t.sons[i], flags) for i in 0.. <t.len: c.hashType(t.sons[i], flags)
if tfNotNil in t.flags: c &= "not nil" if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
proc hashType*(t: PType; flags: set[ConsiderFlag]): SigHash = proc hashType*(t: PType; flags: set[ConsiderFlag] = {CoType}): SigHash =
var c: MD5Context var c: MD5Context
md5Init c md5Init c
hashType c, t, flags hashType c, t, flags
md5Final c, result md5Final c, result.Md5Digest
proc hashProc*(s: PSym): SigHash = proc hashProc*(s: PSym): SigHash =
var c: MD5Context var c: MD5Context
md5Init c md5Init c
hashType c, s.typ, {considerParamNames} hashType c, s.typ, {CoProc}
var m = s var m = s
while m.kind != skModule: m = m.owner while m.kind != skModule: m = m.owner
@ -195,7 +224,7 @@ proc hashProc*(s: PSym): SigHash =
c &= "." c &= "."
c &= m.name.s c &= m.name.s
md5Final c, result md5Final c, result.Md5Digest
proc hashOwner*(s: PSym): SigHash = proc hashOwner*(s: PSym): SigHash =
var c: MD5Context var c: MD5Context
@ -208,4 +237,4 @@ proc hashOwner*(s: PSym): SigHash =
c &= "." c &= "."
c &= m.name.s c &= m.name.s
md5Final c, result md5Final c, result.Md5Digest