Skip to content

Commit

Permalink
specialize genericReset (#14398)
Browse files Browse the repository at this point in the history
* progress
* make tests green
* maybe we also want to reset pointers, dunno
* progress
* cleanup; fixes #13879 [backport:1.2]

(cherry picked from commit b35d370)
  • Loading branch information
Araq authored and narimiran committed May 20, 2020
1 parent bcfbaea commit 7800fa3
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 26 deletions.
46 changes: 23 additions & 23 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1194,9 +1194,11 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
proc genReset(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a),
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
specializeReset(p, a)
when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a),
genTypeInfo(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)
Expand Down Expand Up @@ -2787,6 +2789,21 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
else:
globalError(p.config, info, "cannot create null element for: " & $t.kind)

proc caseObjDefaultBranch(obj: PNode; branch: Int128): int =
for i in 1 ..< obj.len:
for j in 0 .. obj[i].len - 2:
if obj[i][j].kind == nkRange:
let x = getOrdValue(obj[i][j][0])
let y = getOrdValue(obj[i][j][1])
if branch >= x and branch <= y:
return i
elif getOrdValue(obj[i][j]) == branch:
return i
if obj[i].len == 1:
# else branch
return i
assert(false, "unreachable")

proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
result: var Rope; count: var int;
isConst: bool, info: TLineInfo) =
Expand All @@ -2809,31 +2826,14 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
branch = getOrdValue(constOrNil[i])
break

var selectedBranch = -1
block branchSelection:
for i in 1 ..< obj.len:
for j in 0 .. obj[i].len - 2:
if obj[i][j].kind == nkRange:
let x = getOrdValue(obj[i][j][0])
let y = getOrdValue(obj[i][j][1])
if branch >= x and branch <= y:
selectedBranch = i
break branchSelection
elif getOrdValue(obj[i][j]) == branch:
selectedBranch = i
break branchSelection
if obj[i].len == 1:
# else branch
selectedBranch = i
assert(selectedBranch >= 1)

let selectedBranch = caseObjDefaultBranch(obj, branch)
result.add "{"
var countB = 0
let b = lastSon(obj[selectedBranch])
# designated initilization is the only way to init non first element of unions
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
if b.kind == nkRecList and b.len > 0:
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
if b.kind == nkRecList and b.len > 0:
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
result.add "}"
elif b.kind == nkSym:
Expand Down
94 changes: 94 additions & 0 deletions compiler/ccgreset.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#

# included from cgen.nim

## Code specialization instead of the old, incredibly slow 'genericReset'
## implementation.

proc specializeResetT(p: BProc, accessor: Rope, typ: PType)

proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
typ: PType) =
if n == nil: return
case n.kind
of nkRecList:
for i in 0..<n.len:
specializeResetN(p, accessor, n[i], typ)
of nkRecCase:
if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN")
let disc = n[0].sym
if disc.loc.r == nil: fillObjectFields(p.module, typ)
if disc.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
lineF(p, cpsStmts, "default:$n", [])
specializeResetN(p, accessor, lastSon(branch), typ)
lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n", [])
specializeResetT(p, "$1.$2" % [accessor, disc.loc.r], disc.loc.t)
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.r == nil: fillObjectFields(p.module, typ)
if field.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
specializeResetT(p, "$1.$2" % [accessor, field.loc.r], field.loc.t)
else: internalError(p.config, n.info, "specializeResetN()")

proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
if typ == nil: return

case typ.kind
of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
tySink, tyOwned:
specializeResetT(p, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(p.config, typ[0])
var i: TLoc
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
lineF(p, cpsStmts, "}$n", [])
of tyObject:
for i in 0..<typ.len:
var x = typ[i]
if x != nil: x = x.skipTypes(skipPtrs)
specializeResetT(p, accessor.parentObj(p.module), x)
if typ.n != nil: specializeResetN(p, accessor, typ.n, typ)
of tyTuple:
let typ = getUniqueType(typ)
for i in 0..<typ.len:
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), typ[i])

of tyString, tyRef, tySequence:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor])

of tyProc:
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1.ClE_0, NIM_NIL);$n", [accessor])
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
else:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCString, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
else:
discard

proc specializeReset(p: BProc, a: TLoc) =
specializeResetT(p, rdLoc(a), a.t)
8 changes: 6 additions & 2 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ proc isComplexValueType(t: PType): bool {.inline.} =
result = t.kind in {tyArray, tySet, tyTuple, tyObject} or
(t.kind == tyProc and t.callConv == ccClosure)

include ccgreset

proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t)
let typ = skipTypes(loc.t, abstractVarRange)
Expand All @@ -409,8 +411,10 @@ proc resetLoc(p: BProc, loc: var TLoc) =
if optNilCheck in p.options:
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", [addrLoc(p.config, loc)])
if loc.storage != OnStack and containsGcRef:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)])
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)])
# XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
Expand Down
2 changes: 1 addition & 1 deletion lib/system/gc_ms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
# used for code generation concerning debugging
result = usrToCell(c).typ

proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline.} =
proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline, compilerproc.} =
dest[] = src

proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
Expand Down

0 comments on commit 7800fa3

Please sign in to comment.