diff options
Diffstat (limited to 'compiler/liftdestructors.nim')
-rw-r--r-- | compiler/liftdestructors.nim | 253 |
1 files changed, 193 insertions, 60 deletions
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 6b36dd6fb..aea244a78 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -113,9 +113,13 @@ proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode = proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = result = newAsgnStmt(x, newOpCall(op, y)) +proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} = + result = optNimV2 in c.graph.config.globalOptions and + (tfHasGCedMem in t.flags or t.isGCedMem) + proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; field: PSym): bool = - if tfHasAsgn in t.flags: + if tfHasAsgn in t.flags or useNoGc(c, t): var op: PSym if sameType(t, c.asgnForType): # generate recursive call: @@ -136,15 +140,28 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; body.add newAsgnCall(c.graph, op, x, y) result = true -proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = - case c.kind - of attachedDestructor: - let op = t.destructor - if op != nil: +proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode): bool = + let op = t.destructor + if op != nil: + markUsed(c.graph.config, c.info, op, c.graph.usageSym) + onUse(c.info, op) + body.add destructorCall(c.graph, op, x) + result = true + elif useNoGc(c, t): + if sameType(t, c.asgnForType) and c.kind == attachedDestructor: + let op = c.fn markUsed(c.graph.config, c.info, op, c.graph.usageSym) onUse(c.info, op) body.add destructorCall(c.graph, op, x) result = true + else: + internalError(c.graph.config, c.info, + "type-bound operator could not be resolved") + +proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = + case c.kind + of attachedDestructor: + result = addDestructorCall(c, t, body, x) of attachedAsgn: result = considerAsgnOrSink(c, t, body, x, y, t.assignment) of attachedSink: @@ -185,12 +202,15 @@ proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = result = newNodeI(nkWhileStmt, c.info, 2) - let cmp = genBuiltin(c.graph, mLeI, "<=", i) - cmp.add genHigh(c.graph, dest) + let cmp = genBuiltin(c.graph, mLtI, "<", i) + cmp.add genLen(c.graph, dest) cmp.typ = getSysType(c.graph, c.info, tyBool) result.sons[0] = cmp result.sons[1] = newNodeI(nkStmtList, c.info) +proc genIf(c: var TLiftCtx; cond, action: PNode): PNode = + result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action)) + proc addIncStmt(c: var TLiftCtx; body, i: PNode) = let incCall = genBuiltin(c.graph, mInc, "inc", i) incCall.add lowerings.newIntLit(c.graph, c.info, 1) @@ -203,42 +223,166 @@ proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode = lenCall.typ = getSysType(g, x.info, tyInt) result.add lenCall +proc setLenCall(g: ModuleGraph; x, y: PNode): PNode = + let lenCall = genBuiltin(g, mLengthSeq, "len", y) + lenCall.typ = getSysType(g, x.info, tyInt) + result = genBuiltin(g, mSetLengthSeq, "setLen", genAddr(g, x)) + result.add lenCall + +proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = + let i = declareCounter(c, body, firstOrd(c.graph.config, t)) + let whileLoop = genWhileLoop(c, i, x) + let elemType = t.lastSon + liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), + y.at(i, elemType)) + addIncStmt(c, whileLoop.sons[1], i) + body.add whileLoop + +proc seqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + case c.kind + of attachedAsgn, attachedDeepCopy: + # we generate: + # setLen(dest, y.len) + # var i = 0 + # while i < y.len: dest[i] = y[i]; inc(i) + # This is usually more efficient than a destroy/create pair. + body.add setLenCall(c.graph, x, y) + forallElements(c, t, body, x, y) + of attachedSink: + let moveCall = genBuiltin(c.graph, mMove, "move", x) + moveCall.add y + doAssert t.destructor != nil + moveCall.add destructorCall(c.graph, t.destructor, x) + body.add moveCall + when false: + # we generate: + # if a.len != 0 and a.p != b.p: + # `=destroy`(x) + # a.len = b.len + # a.p = b.p + # Note: '@' is either '.' or '->'. + body.add genIf(c, genVerbatim("dest@len != 0 && dest@p != src.p", c.info), + destructorCall(c.graph, t.destructor, x)) + body.add genVerbatim("dest@len=src.len; dest@p=src.p;", c.info) + of attachedDestructor: + # destroy all elements: + forallElements(c, t, body, x, y) + body.add genBuiltin(c.graph, mDestroy, "destroy", x) + when false: + var deallocStmt = genVerbatim("dest@region->dealloc(dest@region, dest@p, " & + "(dest@p->cap * sizeof($)) + sizeof(NI) + sizeof(void*)); dest@len = 0;", c.info) + deallocStmt.typ = t.lastSon + body.add genIf(c, genVerbatim("dest@len != 0 && dest@region", c.info), deallocStmt) + +proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + seqOp(c, t, body, x, y) + +proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + case c.kind + of attachedSink: + # we 'nil' y out afterwards so we *need* to take over its reference + # count value: + body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x)) + body.add newAsgnStmt(x, y) + of attachedAsgn: + body.add callCodegenProc(c.graph, "nimIncWeakRef", c.info, y) + body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x)) + body.add newAsgnStmt(x, y) + of attachedDestructor: + body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x)) + of attachedDeepCopy: assert(false, "cannot happen") + +proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + var actions = newNodeI(nkStmtList, c.info) + + let elemType = t.lastSon + #liftBodyAux(c, elemType, actions, genDeref(x), genDeref(y)) + #var disposeCall = genBuiltin(c.graph, mDispose, "dispose", x) + + if isFinal(elemType): + discard addDestructorCall(c, elemType, actions, x) + actions.add callCodegenProc(c.graph, "nimRawDispose", c.info, x) + else: + discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), x) + actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, x) + + case c.kind + of attachedSink, attachedAsgn: + body.add genIf(c, x, actions) + body.add newAsgnStmt(x, y) + of attachedDestructor: + body.add genIf(c, x, actions) + of attachedDeepCopy: assert(false, "cannot happen") + +proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + if c.kind == attachedDeepCopy: + # a big problem is that we don't know the enviroment's type here, so we + # have to go through some indirection; we delegate this to the codegen: + let call = newNodeI(nkCall, c.info, 2) + call.typ = t + call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy)) + call.sons[1] = y + body.add newAsgnStmt(x, call) + elif optNimV2 in c.graph.config.globalOptions: + case c.kind + of attachedSink, attachedAsgn: discard + of attachedDestructor: discard + of attachedDeepCopy: assert(false, "cannot happen") + +proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + discard "to implement" + proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind of tyNone, tyEmpty, tyVoid: discard of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, - tyPtr, tyRef, tyOpt, tyUncheckedArray: + tyPtr, tyOpt, tyUncheckedArray: defaultOp(c, t, body, x, y) + of tyRef: + if optNimV2 in c.graph.config.globalOptions: + weakrefOp(c, t, body, x, y) + else: + defaultOp(c, t, body, x, y) + of tyProc: + if t.callConv == ccClosure: + closureOp(c, t, body, x, y) + else: + defaultOp(c, t, body, x, y) + of tyOwned: + let base = t.skipTypes(abstractInstOwned) + if optNimV2 in c.graph.config.globalOptions: + case base.kind + of tyRef: + ownedRefOp(c, base, body, x, y) + return + of tyProc: + if base.callConv == ccClosure: + ownedClosureOp(c, base, body, x, y) + return + else: discard + defaultOp(c, base, body, x, y) of tyArray: - if tfHasAsgn in t.flags: - let i = declareCounter(c, body, firstOrd(c.graph.config, t)) - let whileLoop = genWhileLoop(c, i, x) - let elemType = t.lastSon - liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), - y.at(i, elemType)) - addIncStmt(c, whileLoop.sons[1], i) - body.add whileLoop + if tfHasAsgn in t.flags or useNoGc(c, t): + forallElements(c, t, body, x, y) else: defaultOp(c, t, body, x, y) of tySequence: - # note that tfHasAsgn is propagated so we need the check on - # 'selectedGC' here to determine if we have the new runtime. - if c.graph.config.selectedGC == gcDestructors: + if useNoGc(c, t): + seqOp(c, t, body, x, y) + elif c.graph.config.selectedGC == gcDestructors: + # note that tfHasAsgn is propagated so we need the check on + # 'selectedGC' here to determine if we have the new runtime. discard considerOverloadedOp(c, t, body, x, y) elif tfHasAsgn in t.flags: if c.kind != attachedDestructor: body.add newSeqCall(c.graph, x, y) - let i = declareCounter(c, body, firstOrd(c.graph.config, t)) - let whileLoop = genWhileLoop(c, i, x) - let elemType = t.lastSon - liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), - y.at(i, elemType)) - addIncStmt(c, whileLoop.sons[1], i) - body.add whileLoop + forallElements(c, t, body, x, y) else: defaultOp(c, t, body, x, y) of tyString: - if tfHasAsgn in t.flags: + if useNoGc(c, t): + strOp(c, t, body, x, y) + elif tfHasAsgn in t.flags: discard considerOverloadedOp(c, t, body, x, y) else: defaultOp(c, t, body, x, y) @@ -250,17 +394,6 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = liftBodyAux(c, t.sons[0].skipTypes(skipPtrs), body, x, y) of tyTuple: liftBodyTup(c, t, body, x, y) - of tyProc: - if t.callConv != ccClosure or c.kind != attachedDeepCopy: - defaultOp(c, t, body, x, y) - else: - # a big problem is that we don't know the enviroment's type here, so we - # have to go through some indirection; we delegate this to the codegen: - let call = newNodeI(nkCall, c.info, 2) - call.typ = t - call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy)) - call.sons[1] = y - body.add newAsgnStmt(x, call) of tyVarargs, tyOpenArray: localError(c.graph.config, c.info, "cannot copy openArray") of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, @@ -269,7 +402,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyTypeDesc, tyGenericInvocation, tyForward: internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t)) of tyOrdinal, tyRange, tyInferred, - tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink, tyOwned: + tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink: liftBodyAux(c, lastSon(t), body, x, y) proc newProcType(info: TLineInfo; owner: PSym): PType = @@ -290,26 +423,26 @@ proc liftBodyDistinctType(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp; inf assert typ.kind == tyDistinct let baseType = typ[0] case kind - of attachedAsgn: - if baseType.assignment == nil: - discard liftBody(g, baseType, kind, info) - typ.assignment = baseType.assignment - result = typ.assignment - of attachedSink: - if baseType.sink == nil: - discard liftBody(g, baseType, kind, info) - typ.sink = baseType.sink - result = typ.sink - of attachedDeepCopy: - if baseType.deepCopy == nil: - discard liftBody(g, baseType, kind, info) - typ.deepCopy = baseType.deepCopy - result = typ.deepCopy - of attachedDestructor: - if baseType.destructor == nil: - discard liftBody(g, baseType, kind, info) - typ.destructor = baseType.destructor - result = typ.destructor + of attachedAsgn: + if baseType.assignment == nil: + discard liftBody(g, baseType, kind, info) + typ.assignment = baseType.assignment + result = typ.assignment + of attachedSink: + if baseType.sink == nil: + discard liftBody(g, baseType, kind, info) + typ.sink = baseType.sink + result = typ.sink + of attachedDeepCopy: + if baseType.deepCopy == nil: + discard liftBody(g, baseType, kind, info) + typ.deepCopy = baseType.deepCopy + result = typ.deepCopy + of attachedDestructor: + if baseType.destructor == nil: + discard liftBody(g, baseType, kind, info) + typ.destructor = baseType.destructor + result = typ.destructor proc liftBody(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = |