ARC: implemented a simple cycle detector

This commit is contained in:
Araq
2019-11-28 09:32:14 +01:00
committed by Andreas Rumpf
parent 7e747d11c6
commit 2dea920379
4 changed files with 44 additions and 6 deletions

View File

@@ -19,6 +19,8 @@ import
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
lineinfos, parampatterns, sighashes
from trees import exprStructuralEquivalent
type
Con = object
owner: PSym
@@ -461,6 +463,35 @@ proc isCursor(n: PNode): bool =
else:
result = false
proc cycleCheck(n: PNode; c: var Con) =
if c.graph.config.selectedGC != gcDestructors: return
var value = n[1]
if value.kind == nkClosure:
value = value[1]
if value.kind == nkNilLit: return
let destTyp = n[0].typ.skipTypes(abstractInst)
if destTyp.kind != tyRef and not (destTyp.kind == tyProc and destTyp.callConv == ccClosure):
return
var x = n[0]
var field: PNode = nil
while true:
if x.kind == nkDotExpr:
if field == nil: field = x[1]
x = x[0]
elif x.kind in {nkBracketExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref}:
x = x[0]
else:
break
if exprStructuralEquivalent(x, value, strictSymEquality = true):
let msg =
if field != nil:
"'$#' creates an uncollectable ref cycle; annotate '$#' with .cursor" % [$n, $field]
else:
"'$#' creates an uncollectable ref cycle" % [$n]
message(c.graph.config, n.info, warnCycleCreated, msg)
break
proc p(n: PNode; c: var Con; consumed = false): PNode =
case n.kind
of nkCallKinds:
@@ -544,6 +575,8 @@ proc p(n: PNode; c: var Con; consumed = false): PNode =
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
result = newNodeI(nkEmpty, n.info)
else:
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c)
result = moveOrCopy(n[0], n[1], c)
else:
result = copyNode(n)

View File

@@ -366,13 +366,15 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
if upField.typ.skipTypes({tyOwned, tyRef, tyPtr}) != fieldType.skipTypes({tyOwned, tyRef, tyPtr}):
localError(c.graph.config, dep.info, "internal error: up references do not agree")
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
when false:
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
else:
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
result.typ = fieldType
if c.graph.config.selectedGC == gcDestructors:
result.flags.incl sfCursor
when false:
if c.graph.config.selectedGC == gcDestructors:
result.flags.incl sfCursor
rawAddField(obj, result)
discard """

View File

@@ -37,7 +37,7 @@ type
warnEachIdentIsTuple,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnCaseTransition, warnUser,
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser,
hintSuccess, hintSuccessX, hintCC,
hintLineTooLong, hintXDeclaredButNotUsed,
hintConvToBaseNotNeeded,
@@ -94,6 +94,7 @@ const
warnResultShadowed: "Special variable 'result' is shadowed.",
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
warnCaseTransition: "Potential object case transition, instantiate new object instead",
warnCycleCreated: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
@@ -139,7 +140,7 @@ const
"UnsafeCode", "UnusedImport", "EachIdentIsTuple",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "CaseTransition", "User"]
"Spacing", "CaseTransition", "CycleCreated", "User"]
HintsToStr* = [
"Success", "SuccessX", "CC", "LineTooLong",

View File

@@ -341,6 +341,8 @@ when defined(windows) or defined(nimdoc):
addr lpNumberOfBytesTransferred, addr lpCompletionKey,
cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
result = true
when defined(gcDestructors):
GC_ref(customOverlapped)
# http://stackoverflow.com/a/12277264/492186
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html