mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-10 23:15:02 +00:00
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 611b8bbf67)
This commit is contained in:
@@ -500,6 +500,7 @@ type
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInSet, mRepr, mExit,
|
||||
mSetLengthStr, mSetLengthSeq,
|
||||
mSetLengthSeqUninit,
|
||||
mIsPartOf, mAstToStr, mParallel,
|
||||
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
|
||||
@@ -1932,7 +1932,7 @@ proc isTrivialTypesToSnippet(t: PType): Rope =
|
||||
else:
|
||||
result = rope"NIM_TRUE"
|
||||
|
||||
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc, noinit = false) =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
e[1] = makeAddr(e[1], p.module.idgen)
|
||||
genCall(p, e, d)
|
||||
@@ -1952,11 +1952,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
|
||||
|
||||
else:
|
||||
const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2, $5)"
|
||||
const setLenPattern = "($3) #$6($1, $4, $2, $5)"
|
||||
let name = if noinit: "setLengthSeqUninit" else: "setLengthSeqV2"
|
||||
call.snippet = ropecg(p.module, setLenPattern, [
|
||||
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
||||
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info),
|
||||
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0])])
|
||||
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0]),
|
||||
name])
|
||||
|
||||
genAssignment(p, a, call, {})
|
||||
gcUsage(p.config, e)
|
||||
@@ -2579,6 +2581,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n")
|
||||
of mSetLengthStr: genSetLengthStr(p, e, d)
|
||||
of mSetLengthSeq: genSetLengthSeq(p, e, d)
|
||||
of mSetLengthSeqUninit: genSetLengthSeq(p, e, d, noinit = true)
|
||||
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
|
||||
mInSet, mXorSet:
|
||||
genSetOp(p, e, d, op)
|
||||
|
||||
@@ -173,3 +173,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasXorSet")
|
||||
|
||||
defineSymbol("nimHasPreviewDuplicateModuleError")
|
||||
defineSymbol("nimHasSetLengthSeqUninitMagic")
|
||||
|
||||
@@ -2439,7 +2439,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
binaryExpr(p, n, r, "mnewString",
|
||||
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
|
||||
else {$3.length = $4; }""")
|
||||
of mSetLengthSeq:
|
||||
of mSetLengthSeq, mSetLengthSeqUninit:
|
||||
var x, y: TCompRes = default(TCompRes)
|
||||
gen(p, n[1], x)
|
||||
gen(p, n[2], y)
|
||||
|
||||
@@ -708,7 +708,7 @@ proc analyseIfAddressTakenInCall*(c: PContext, n: PNode, isConverter = false) =
|
||||
return
|
||||
const
|
||||
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
|
||||
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
|
||||
mSetLengthStr, mSetLengthSeq, mSetLengthSeqUninit, mAppendStrCh, mAppendStrStr, mSwap,
|
||||
mAppendSeqElem, mNewSeq, mShallowCopy, mDeepCopy, mMove, mWasMoved}
|
||||
|
||||
template checkIfConverterCalled(c: PContext, n: PNode) =
|
||||
|
||||
@@ -667,7 +667,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result = semQuantifier(c, n)
|
||||
of mOld:
|
||||
result = semOld(c, n)
|
||||
of mSetLengthSeq:
|
||||
of mSetLengthSeq, mSetLengthSeqUninit:
|
||||
result = n
|
||||
let seqType = result[1].typ.skipTypes({tyPtr, tyRef, # in case we had auto-dereferencing
|
||||
tyVar, tyGenericInst, tyOwned, tySink,
|
||||
|
||||
@@ -1230,7 +1230,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMag
|
||||
var tmp = c.genx(n[1])
|
||||
c.gABC(n, opcQuit, tmp)
|
||||
c.freeTemp(tmp)
|
||||
of mSetLengthStr, mSetLengthSeq:
|
||||
of mSetLengthStr, mSetLengthSeq, mSetLengthSeqUninit:
|
||||
unused(c, n, dest)
|
||||
var d = c.genx(n[1])
|
||||
var tmp = c.genx(n[2])
|
||||
|
||||
@@ -955,6 +955,22 @@ proc setLen*[T](s: var seq[T], newlen: Natural) {.
|
||||
## assert x == @[10]
|
||||
## ```
|
||||
|
||||
when defined(nimHasSetLengthSeqUninitMagic):
|
||||
func setLenUninit*[T](s: var seq[T], newlen: Natural) {.magic: "SetLengthSeqUninit", nodestroy.} =
|
||||
## Sets the length of seq `s` to `newlen`. `T` may be any sequence type.
|
||||
## New slots will not be initialized.
|
||||
##
|
||||
## If the current length is greater than the new length,
|
||||
## `s` will be truncated.
|
||||
## ```nim
|
||||
## var x = @[10, 20]
|
||||
## x.setLenUninit(5)
|
||||
## x[4] = 50
|
||||
## assert x[4] == 50Add commentMore actions
|
||||
## x.setLenUninit(1)
|
||||
## assert x == @[10]
|
||||
## ```
|
||||
|
||||
proc setLen*(s: var string, newlen: Natural) {.
|
||||
magic: "SetLengthStr", noSideEffect.}
|
||||
## Sets the length of string `s` to `newlen`.
|
||||
|
||||
@@ -196,7 +196,7 @@ func capacity*[T](self: seq[T]): int {.inline.} =
|
||||
let sek = cast[ptr NimSeqV2[T]](unsafeAddr self)
|
||||
result = if sek.p != nil: sek.p.cap and not strlitFlag else: 0
|
||||
|
||||
func setLenUninit*[T](s: var seq[T], newlen: Natural) {.nodestroy.} =
|
||||
func setLenUninit[T](s: var seq[T], newlen: Natural) {.nodestroy.} =
|
||||
## Sets the length of seq `s` to `newlen`. `T` may be any sequence type.
|
||||
## New slots will not be initialized.
|
||||
##
|
||||
|
||||
@@ -300,6 +300,46 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
result.len = newLen
|
||||
|
||||
proc setLengthSeqUninit(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqUninit: type is not a seq"
|
||||
if s == nil:
|
||||
if newLen == 0:
|
||||
result = s
|
||||
else:
|
||||
result = cast[PGenericSeq](newSeq(typ, newLen))
|
||||
else:
|
||||
let elemSize = typ.base.size
|
||||
let elemAlign = typ.base.align
|
||||
if s.space < newLen:
|
||||
let r = max(resize(s.space), newLen)
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
copyMem(dataPointer(result, elemAlign), dataPointer(s, elemAlign), s.len * elemSize)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
elif newLen < s.len:
|
||||
result = s
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
when not defined(boehmGC) and not defined(nogc) and
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcRegions):
|
||||
if ntfNoRefs notin typ.base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||
# This is a tough problem, because even if we don't zeroMem here, in the
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
if not isTrivial: # optimization for trivial types
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
else:
|
||||
result = s
|
||||
result.len = newLen
|
||||
|
||||
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"
|
||||
|
||||
@@ -236,6 +236,13 @@ proc bar2() =
|
||||
doAssert cstring(nil) <= cstring(nil)
|
||||
doAssert cstring("") <= cstring("")
|
||||
|
||||
var x = @[10, 20]
|
||||
x.setLenUninit(5)
|
||||
x[4] = 50
|
||||
doAssert x[4] == 50
|
||||
x.setLenUninit(1)
|
||||
doAssert x == @[10]
|
||||
|
||||
static: bar2()
|
||||
bar2()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user