diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-08-05 11:42:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-05 11:42:38 +0200 |
commit | c57e320c9486248a82c19d13e03178745d8eb53f (patch) | |
tree | f77f6a1e246cb37041756f1c1bb1059f30a08a3a /lib/system/sysstr.nim | |
parent | cc1fd50b2785cdb6ec14f283bc7d7ef87f64dd9e (diff) | |
download | Nim-c57e320c9486248a82c19d13e03178745d8eb53f.tar.gz |
fixes 7833 (#8533)
* fixes #7833; still to-do: fix setLen * make tests green again * also fixes setLen and string concats; refs #7833 * change formating to avoid a compiler warning * emit the write barrier also for addChar * fixes yet another regression * make setLengthStr compile for the old version * make growobjcrash complete earlier
Diffstat (limited to 'lib/system/sysstr.nim')
-rw-r--r-- | lib/system/sysstr.nim | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 8e9e18b05..19c2c62ad 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -184,8 +184,13 @@ proc addChar(s: NimString, c: char): NimString = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[NimString](growObj(result, - sizeof(TGenericSeq) + r + 1)) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(r) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + else: + result = cast[NimString](growObj(result, + sizeof(TGenericSeq) + r + 1)) result.reserved = r result.data[result.len] = c result.data[result.len+1] = '\0' @@ -228,8 +233,13 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = elif dest.len + addlen <= dest.space: result = dest else: # slow path: - var sp = max(resize(dest.space), dest.len + addlen) - result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) + let sp = max(resize(dest.space), dest.len + addlen) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = dest.len + copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1) + else: + result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) result.reserved = sp #result = rawNewString(sp) #copyMem(result, dest, dest.len + sizeof(TGenericSeq)) @@ -246,13 +256,21 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} = inc(dest.len) proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = - var n = max(newLen, 0) + let n = max(newLen, 0) if s == nil: result = mnewString(newLen) elif n <= s.space: result = s else: - result = resizeString(s, n) + let sp = max(resize(s.space), newLen) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + zeroMem(addr result.data[s.len], newLen - s.len) + result.reserved = sp + else: + result = resizeString(s, n) result.len = n result.data[n] = '\0' @@ -282,6 +300,9 @@ proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = GenericSeqSize)) result.reserved = r +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = if s == nil: result = cast[PGenericSeq](newSeq(typ, 1)) @@ -290,9 +311,16 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, typ.base.size * r + + when defined(nimIncrSeqV3): + result = cast[PGenericSeq](newSeq(typ, r)) + result.len = s.len + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + else: + result = cast[PGenericSeq](growObj(result, typ.base.size * r + GenericSeqSize)) - result.reserved = r + result.reserved = r proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. compilerRtl, inl.} = @@ -336,10 +364,43 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. compilerRtl.} = + sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq" if s == nil: result = cast[PGenericSeq](newSeq(typ, newLen)) else: - result = setLengthSeq(s, typ.base.size, newLen) + when defined(nimIncrSeqV3): + let elemSize = typ.base.size + if s.space < newLen: + let r = max(resize(s.space), newLen) + result = cast[PGenericSeq](newSeq(typ, r)) + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, 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(cast[pointer](cast[ByteAddress](result) +% + GenericSeqSize +% (i*%elemSize)), + 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 destoy the cell in the + # finalizer of the sequence, but this makes destruction non-deterministic. + zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + (newLen*%elemSize)), (result.len-%newLen) *% elemSize) + else: + result = s + result.len = newLen + else: + result = setLengthSeq(s, typ.base.size, newLen) # --------------- other string routines ---------------------------------- proc add*(result: var string; x: int64) = |