Skip to content

Commit 8914baa

Browse files
ringaboutnarimiran
authored andcommitted
fixes #25007; implements setLenUninit for refc (#25022)
fixes #25007 ```nim proc setLengthSeqUninit(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {. compilerRtl.} = ``` In this added function, only the line `zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)` is removed from `proc setLengthSeqV2` when enlarging a sequence. JS and VM versions simply use `setLen`. (cherry picked from commit 611b8bb)
1 parent fcf4f10 commit 8914baa

File tree

11 files changed

+80
-10
lines changed

11 files changed

+80
-10
lines changed

compiler/ast.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ type
500500
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
501501
mInSet, mRepr, mExit,
502502
mSetLengthStr, mSetLengthSeq,
503+
mSetLengthSeqUninit,
503504
mIsPartOf, mAstToStr, mParallel,
504505
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
505506
mNewString, mNewStringOfCap, mParseBiggestFloat,

compiler/ccgexprs.nim

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,7 +1932,7 @@ proc isTrivialTypesToSnippet(t: PType): Rope =
19321932
else:
19331933
result = rope"NIM_TRUE"
19341934

1935-
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
1935+
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc, noinit = false) =
19361936
if optSeqDestructors in p.config.globalOptions:
19371937
e[1] = makeAddr(e[1], p.module.idgen)
19381938
genCall(p, e, d)
@@ -1945,18 +1945,22 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
19451945
let t = skipTypes(e[1].typ, {tyVar})
19461946

19471947
var call = initLoc(locCall, e, OnHeap)
1948+
let name = if noinit: "setLengthSeqUninit" else: "setLengthSeqV2"
19481949
if not p.module.compileToCpp:
1949-
const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)"
1950+
const setLenPattern = "($3) #$6(($1)?&($1)->Sup:NIM_NIL, $4, $2, $5)"
19501951
call.snippet = ropecg(p.module, setLenPattern, [
19511952
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
1952-
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
1953+
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info),
1954+
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0]),
1955+
name])
19531956

19541957
else:
1955-
const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2, $5)"
1958+
const setLenPattern = "($3) #$6($1, $4, $2, $5)"
19561959
call.snippet = ropecg(p.module, setLenPattern, [
19571960
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
19581961
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info),
1959-
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0])])
1962+
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0]),
1963+
name])
19601964

19611965
genAssignment(p, a, call, {})
19621966
gcUsage(p.config, e)
@@ -2579,6 +2583,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
25792583
unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n")
25802584
of mSetLengthStr: genSetLengthStr(p, e, d)
25812585
of mSetLengthSeq: genSetLengthSeq(p, e, d)
2586+
of mSetLengthSeqUninit: genSetLengthSeq(p, e, d, noinit = true)
25822587
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
25832588
mInSet, mXorSet:
25842589
genSetOp(p, e, d, op)

compiler/condsyms.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,4 @@ proc initDefines*(symbols: StringTableRef) =
173173
defineSymbol("nimHasXorSet")
174174

175175
defineSymbol("nimHasPreviewDuplicateModuleError")
176+
defineSymbol("nimHasSetLengthSeqUninitMagic")

compiler/jsgen.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2439,7 +2439,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
24392439
binaryExpr(p, n, r, "mnewString",
24402440
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
24412441
else {$3.length = $4; }""")
2442-
of mSetLengthSeq:
2442+
of mSetLengthSeq, mSetLengthSeqUninit:
24432443
var x, y: TCompRes = default(TCompRes)
24442444
gen(p, n[1], x)
24452445
gen(p, n[2], y)

compiler/semdata.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ proc analyseIfAddressTakenInCall*(c: PContext, n: PNode, isConverter = false) =
708708
return
709709
const
710710
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
711-
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
711+
mSetLengthStr, mSetLengthSeq, mSetLengthSeqUninit, mAppendStrCh, mAppendStrStr, mSwap,
712712
mAppendSeqElem, mNewSeq, mShallowCopy, mDeepCopy, mMove, mWasMoved}
713713

714714
template checkIfConverterCalled(c: PContext, n: PNode) =

compiler/semmagic.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
667667
result = semQuantifier(c, n)
668668
of mOld:
669669
result = semOld(c, n)
670-
of mSetLengthSeq:
670+
of mSetLengthSeq, mSetLengthSeqUninit:
671671
result = n
672672
let seqType = result[1].typ.skipTypes({tyPtr, tyRef, # in case we had auto-dereferencing
673673
tyVar, tyGenericInst, tyOwned, tySink,

compiler/vmgen.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMag
12301230
var tmp = c.genx(n[1])
12311231
c.gABC(n, opcQuit, tmp)
12321232
c.freeTemp(tmp)
1233-
of mSetLengthStr, mSetLengthSeq:
1233+
of mSetLengthStr, mSetLengthSeq, mSetLengthSeqUninit:
12341234
unused(c, n, dest)
12351235
var d = c.genx(n[1])
12361236
var tmp = c.genx(n[2])

lib/system.nim

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,22 @@ proc setLen*[T](s: var seq[T], newlen: Natural) {.
955955
## assert x == @[10]
956956
## ```
957957

958+
when defined(nimHasSetLengthSeqUninitMagic):
959+
func setLenUninit*[T](s: var seq[T], newlen: Natural) {.magic: "SetLengthSeqUninit", nodestroy.} =
960+
## Sets the length of seq `s` to `newlen`. `T` may be any sequence type.
961+
## New slots will not be initialized.
962+
##
963+
## If the current length is greater than the new length,
964+
## `s` will be truncated.
965+
## ```nim
966+
## var x = @[10, 20]
967+
## x.setLenUninit(5)
968+
## x[4] = 50
969+
## assert x[4] == 50Add commentMore actions
970+
## x.setLenUninit(1)
971+
## assert x == @[10]
972+
## ```
973+
958974
proc setLen*(s: var string, newlen: Natural) {.
959975
magic: "SetLengthStr", noSideEffect.}
960976
## Sets the length of string `s` to `newlen`.

lib/system/seqs_v2.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func capacity*[T](self: seq[T]): int {.inline.} =
196196
let sek = cast[ptr NimSeqV2[T]](unsafeAddr self)
197197
result = if sek.p != nil: sek.p.cap and not strlitFlag else: 0
198198

199-
func setLenUninit*[T](s: var seq[T], newlen: Natural) {.nodestroy.} =
199+
func setLenUninit[T](s: var seq[T], newlen: Natural) {.nodestroy.} =
200200
## Sets the length of seq `s` to `newlen`. `T` may be any sequence type.
201201
## New slots will not be initialized.
202202
##

lib/system/sysstr.nim

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,46 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS
300300
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
301301
result.len = newLen
302302

303+
proc setLengthSeqUninit(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
304+
compilerRtl.} =
305+
sysAssert typ.kind == tySequence, "setLengthSeqUninit: type is not a seq"
306+
if s == nil:
307+
if newLen == 0:
308+
result = s
309+
else:
310+
result = cast[PGenericSeq](newSeq(typ, newLen))
311+
else:
312+
let elemSize = typ.base.size
313+
let elemAlign = typ.base.align
314+
if s.space < newLen:
315+
let r = max(resize(s.space), newLen)
316+
result = cast[PGenericSeq](newSeq(typ, r))
317+
copyMem(dataPointer(result, elemAlign), dataPointer(s, elemAlign), s.len * elemSize)
318+
# since we steal the content from 's', it's crucial to set s's len to 0.
319+
s.len = 0
320+
elif newLen < s.len:
321+
result = s
322+
# we need to decref here, otherwise the GC leaks!
323+
when not defined(boehmGC) and not defined(nogc) and
324+
not defined(gcMarkAndSweep) and not defined(gogc) and
325+
not defined(gcRegions):
326+
if ntfNoRefs notin typ.base.flags:
327+
for i in newLen..result.len-1:
328+
forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i),
329+
extGetCellType(result).base, waZctDecRef)
330+
331+
# XXX: zeroing out the memory can still result in crashes if a wiped-out
332+
# cell is aliased by another pointer (ie proc parameter or a let variable).
333+
# This is a tough problem, because even if we don't zeroMem here, in the
334+
# presence of user defined destructors, the user will expect the cell to be
335+
# "destroyed" thus creating the same problem. We can destroy the cell in the
336+
# finalizer of the sequence, but this makes destruction non-deterministic.
337+
if not isTrivial: # optimization for trivial types
338+
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
339+
else:
340+
result = s
341+
result.len = newLen
342+
303343
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
304344
compilerRtl.} =
305345
sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"

0 commit comments

Comments
 (0)