diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-03-05 17:29:48 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-03-05 19:58:54 +0100 |
commit | 4be36d77f6b5d9c32a5f35919dfbb825e9551b0e (patch) | |
tree | 1a3ae91b141cd23d9631de62e088239d2a993176 | |
parent | 20a21aa1848726a60493432b7337ecbfd491f7ac (diff) | |
download | Nim-4be36d77f6b5d9c32a5f35919dfbb825e9551b0e.tar.gz |
introduce tfHasOwned for fast must-move checkings; removed tfAcyclic as the GC has ignored this hint for quite some time now
-rw-r--r-- | compiler/ast.nim | 9 | ||||
-rw-r--r-- | compiler/cgen.nim | 5 | ||||
-rw-r--r-- | compiler/dfa.nim | 2 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/semtypes.nim | 4 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 6 | ||||
-rw-r--r-- | compiler/transf.nim | 3 | ||||
-rw-r--r-- | compiler/types.nim | 25 | ||||
-rw-r--r-- | doc/manual.rst | 37 |
9 files changed, 30 insertions, 63 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index b325e6d42..9ce102c2f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -479,7 +479,7 @@ type tfNoSideEffect, # procedure type does not allow side effects tfFinal, # is the object final? tfInheritable, # is the object inheritable? - tfAcyclic, # type is acyclic (for GC optimization) + tfHasOwned, # type contains an 'owned' type and must be moved tfEnumHasHoles, # enum cannot be mapped into a range tfShallow, # type can be shallow copied on assignment tfThread, # proc type is marked as ``thread``; alias for ``gcsafe`` @@ -1472,6 +1472,13 @@ proc propagateToOwner*(owner, elem: PType) = o2.flags.incl tfHasAsgn owner.flags.incl tfHasAsgn + if tfHasOwned in elem.flags: + let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) + if o2.kind in {tyTuple, tyObject, tyArray, + tySequence, tyOpt, tySet, tyDistinct}: + o2.flags.incl tfHasOwned + owner.flags.incl tfHasOwned + if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, tyGenericInvocation, tyPtr}: let elemB = elem.skipTypes({tyGenericInst, tyAlias, tySink}) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 45daa00d9..09076c520 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -42,8 +42,6 @@ when not declared(dynlib.libCandidates): when options.hasTinyCBackend: import tccgen -# implementation - proc hcrOn(m: BModule): bool = m.config.hcrOn proc hcrOn(p: BProc): bool = p.module.config.hcrOn @@ -295,6 +293,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, includeHeader(p.module, "<new>") linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t)) + if optNimV2 in p.config.globalOptions: return case analyseObjectWithTypeField(t) of frNone: discard @@ -303,7 +302,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, if not takeAddr: r = "(*$1)" % [r] var s = skipTypes(t, abstractInst) if not p.module.compileToCpp: - while (s.kind == tyObject) and (s.sons[0] != nil): + while s.kind == tyObject and s.sons[0] != nil: add(r, ".Sup") s = skipTypes(s.sons[0], skipPtrs) linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info)) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 968b16945..cecb8394c 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -596,7 +596,7 @@ proc genCall(c: var Con; n: PNode) = gen(c, n[i]) when false: if t != nil and i < t.len and t.sons[i].kind == tyVar: - # XXX This is wrong! Pass by var is a 'might def', not a 'must def' + # This is wrong! Pass by var is a 'might def', not a 'must def' # like the other defs we emit. This is not good enough for a move # optimizer. genDef(c, n[i]) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index addc9e9f3..364006dd1 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -933,7 +933,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wAcyclic: noVal(c, it) if sym.typ == nil: invalidPragma(c, it) - else: incl(sym.typ.flags, tfAcyclic) + # now: ignored of wShallow: noVal(c, it) if sym.typ == nil: invalidPragma(c, it) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e717c6e07..0fabd5531 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1854,7 +1854,9 @@ proc processMagicType(c: PContext, m: PSym) = case m.name.s of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize) of "sink": setMagicType(c.config, m, tySink, szUncomputedSize) - of "owned": setMagicType(c.config, m, tyOwned, c.config.target.ptrSize) + of "owned": + setMagicType(c.config, m, tyOwned, c.config.target.ptrSize) + incl m.typ.flags, tfHasOwned else: localError(c.config, m.info, errTypeExpected) else: localError(c.config, m.info, errTypeExpected) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 483588e6b..e3380c0e3 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -16,16 +16,12 @@ const tfInstClearedFlags = {tfHasMeta, tfUnresolved} proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = - if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: - localError(conf, info, "invalid pragma: acyclic") - elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: + if t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) if t.kind in tyTypeClasses: discard - elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: - localError(conf, info, "invalid pragma: acyclic") elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") elif computeSize(conf, t) == szIllegalRecursion: diff --git a/compiler/transf.nim b/compiler/transf.nim index ec390da9a..ed4a7018d 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -893,7 +893,8 @@ proc transform(c: PTransf, n: PNode): PTransNode = nkBlockStmt, nkBlockExpr}: oldDeferAnchor = c.deferAnchor c.deferAnchor = n - if n.typ != nil and tfHasAsgn in n.typ.flags: + if (n.typ != nil and tfHasAsgn in n.typ.flags) or + optNimV2 in c.graph.config.globalOptions: c.needsDestroyPass = true case n.kind of nkSym: diff --git a/compiler/types.nim b/compiler/types.nim index 86e5e756a..b71888906 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -68,17 +68,6 @@ const typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc, tyOwned} -type - TTypeFieldResult* = enum - frNone, # type has no object type field - frHeader, # type has an object type field only in the header - frEmbedded # type has an object type field somewhere embedded - -proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult - # this does a complex analysis whether a call to ``objectInit`` needs to be - # made or intializing of the type field suffices or if there is no type field - # at all in this type. - proc invalidGenericInst*(f: PType): bool = result = f.kind == tyGenericInst and lastSon(f) == nil @@ -242,11 +231,16 @@ proc containsObject*(t: PType): bool = result = searchTypeFor(t, isObjectPredicate) proc isObjectWithTypeFieldPredicate(t: PType): bool = - result = t.kind == tyObject and t.sons[0] == nil and not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and tfFinal notin t.flags +type + TTypeFieldResult* = enum + frNone, # type has no object type field + frHeader, # type has an object type field only in the header + frEmbedded # type has an object type field somewhere embedded + proc analyseObjectWithTypeFieldAux(t: PType, marker: var IntSet): TTypeFieldResult = var res: TTypeFieldResult @@ -276,7 +270,10 @@ proc analyseObjectWithTypeFieldAux(t: PType, else: discard -proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = +proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult = + # this does a complex analysis whether a call to ``objectInit`` needs to be + # made or intializing of the type field suffices or if there is no type field + # at all in this type. var marker = initIntSet() result = analyseObjectWithTypeFieldAux(t, marker) @@ -323,9 +320,7 @@ proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = false if typ == nil: return - if tfAcyclic in typ.flags: return var t = skipTypes(typ, abstractInst+{tyOwned}-{tyTypeDesc}) - if tfAcyclic in t.flags: return case t.kind of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs: if not containsOrIncl(marker, t.id): diff --git a/doc/manual.rst b/doc/manual.rst index a2d51cf08..09daf4a95 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6925,41 +6925,8 @@ The ``noreturn`` pragma is used to mark a proc that never returns. acyclic pragma -------------- -The ``acyclic`` pragma can be used for object types to mark them as acyclic -even though they seem to be cyclic. This is an **optimization** for the garbage -collector to not consider objects of this type as part of a cycle: - -.. code-block:: nim - type - Node = ref NodeObj - NodeObj {.acyclic.} = object - left, right: Node - data: string - -Or if we directly use a ref object: - -.. code-block:: nim - type - Node = ref object {.acyclic.} - left, right: Node - data: string - -In the example a tree structure is declared with the ``Node`` type. Note that -the type definition is recursive and the GC has to assume that objects of -this type may form a cyclic graph. The ``acyclic`` pragma passes the -information that this cannot happen to the GC. If the programmer uses the -``acyclic`` pragma for data types that are in reality cyclic, the GC may leak -memory, but nothing worse happens. - -**Future directions**: The ``acyclic`` pragma may become a property of a -``ref`` type: - -.. code-block:: nim - type - Node = acyclic ref NodeObj - NodeObj = object - left, right: Node - data: string +The ``acyclic`` pragma applies to type declarations. It is deprecated and +ignored. final pragma |