some bugfixes for 'deepCopy'

This commit is contained in:
Araq 2014-08-06 09:54:23 +02:00
commit a64d733029
2 changed files with 29 additions and 15 deletions

View file

@ -360,13 +360,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else: internalError("genAssignment: " & $ty.kind) else: internalError("genAssignment: " & $ty.kind)
proc genDeepCopy(p: BProc; dest, src: TLoc) = proc genDeepCopy(p: BProc; dest, src: TLoc) =
var ty = skipTypes(dest.t, abstractRange) var ty = skipTypes(dest.t, abstractVarRange)
case ty.kind case ty.kind
of tyPtr, tyRef, tyString, tyProc, tyTuple, tyObject, tyArray, tyArrayConstr: of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray, tyArrayConstr:
# XXX optimize this # XXX optimize this
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
of tySequence: of tySequence, tyString:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)) addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
@ -1687,7 +1687,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
expr(p, n, d) expr(p, n, d)
of mDeepCopy: of mDeepCopy:
var a, b: TLoc var a, b: TLoc
initLocExpr(p, e.sons[1], a) let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
initLocExpr(p, x, a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
genDeepCopy(p, a, b) genDeepCopy(p, a, b)
else: internalError(e.info, "genMagicExpr: " & $op) else: internalError(e.info, "genMagicExpr: " & $op)

View file

@ -32,6 +32,12 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.gcsafe.} =
genericDeepCopyAux(dest, src, m) genericDeepCopyAux(dest, src, m)
of nkNone: sysAssert(false, "genericDeepCopyAux") of nkNone: sysAssert(false, "genericDeepCopyAux")
proc copyDeepString(src: NimString): NimString {.inline.} =
if src != nil:
result = rawNewString(src.space)
result.len = src.len
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
var var
d = cast[TAddress](dest) d = cast[TAddress](dest)
@ -44,7 +50,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
if s2 == nil: if s2 == nil:
unsureAsgnRef(x, s2) unsureAsgnRef(x, s2)
else: else:
unsureAsgnRef(x, copyString(cast[NimString](s2))) unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
of tySequence: of tySequence:
var s2 = cast[PPointer](src)[] var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2) var seq = cast[PGenericSeq](s2)
@ -76,25 +82,31 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size), genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base) cast[pointer](s +% i*% mt.base.size), mt.base)
of tyRef: of tyRef:
var z: pointer
if mt.base.deepCopy != nil: if mt.base.deepCopy != nil:
z = mt.base.deepCopy(cast[PPointer](s)[]) let z = mt.base.deepCopy(cast[PPointer](src)[])
unsureAsgnRef(cast[PPointer](dest), z)
else: else:
# we modify the header of the cell temporarily; instead of the type # we modify the header of the cell temporarily; instead of the type
# field we store a forwarding pointer. XXX This is bad when the cloning # field we store a forwarding pointer. XXX This is bad when the cloning
# fails due to OOM etc. # fails due to OOM etc.
let x = usrToCell(cast[PPointer](s)[]) let s2 = cast[PPointer](src)[]
if s2 == nil:
unsureAsgnRef(cast[PPointer](dest), s2)
return
let x = usrToCell(s2)
let forw = cast[int](x.typ) let forw = cast[int](x.typ)
if (forw and 1) == 1: if (forw and 1) == 1:
# we stored a forwarding pointer, so let's use that: # we stored a forwarding pointer, so let's use that:
z = cast[pointer](forw and not 1) let z = cast[pointer](forw and not 1)
unsureAsgnRef(cast[PPointer](dest), z)
else: else:
let realType = x.typ let realType = x.typ
z = newObj(realType, realType.base.size) let z = newObj(realType, realType.base.size)
unsureAsgnRef(cast[PPointer](dest), z)
x.typ = cast[PNimType](cast[int](z) or 1) x.typ = cast[PNimType](cast[int](z) or 1)
genericDeepCopyAux(dest, addr(z), realType) genericDeepCopyAux(z, s2, realType.base)
x.typ = realType x.typ = realType
unsureAsgnRef(cast[PPointer](dest), z)
of tyPtr: of tyPtr:
# no cycle check here, but also not really required # no cycle check here, but also not really required
if mt.base.deepCopy != nil: if mt.base.deepCopy != nil:
@ -102,12 +114,13 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
else: else:
cast[PPointer](dest)[] = cast[PPointer](s)[] cast[PPointer](dest)[] = cast[PPointer](s)[]
else: else:
copyMem(dest, src, mt.size) # copy raw bits copyMem(dest, src, mt.size)
proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} = proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
genericDeepCopyAux(dest, src, mt) genericDeepCopyAux(dest, src, mt)
proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} = proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
# also invoked for 'string'
var src = src var src = src
genericDeepCopy(dest, addr(src), mt) genericDeepCopy(dest, addr(src), mt)