new minor language feature: .noSideEffect blocks like .gcsafe blocks
This commit is contained in:
parent
93cf0ef52e
commit
413580bc04
7 changed files with 30 additions and 12 deletions
|
|
@ -89,7 +89,8 @@ proc enumToString*(enums: openArray[enum]): string =
|
||||||
### Language additions
|
### Language additions
|
||||||
|
|
||||||
- Vm suport for float32<->int32 and float64<->int64 casts was added.
|
- Vm suport for float32<->int32 and float64<->int64 casts was added.
|
||||||
|
- There is a new pragma block `noSideEffect` that works like
|
||||||
|
the `gcsafe` pragma block.
|
||||||
|
|
||||||
### Language changes
|
### Language changes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||||
wTags, wLocks, wGcSafe, wExportNims, wUsed}
|
wTags, wLocks, wGcSafe, wExportNims, wUsed}
|
||||||
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
|
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNosideeffect}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions,
|
wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions,
|
||||||
wWarnings, wHints,
|
wWarnings, wHints,
|
||||||
|
|
@ -855,8 +855,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
sym.flags.incl sfOverriden
|
sym.flags.incl sfOverriden
|
||||||
of wNosideeffect:
|
of wNosideeffect:
|
||||||
noVal(c, it)
|
noVal(c, it)
|
||||||
incl(sym.flags, sfNoSideEffect)
|
if sym != nil:
|
||||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
incl(sym.flags, sfNoSideEffect)
|
||||||
|
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||||
of wSideeffect:
|
of wSideeffect:
|
||||||
noVal(c, it)
|
noVal(c, it)
|
||||||
incl(sym.flags, sfSideEffect)
|
incl(sym.flags, sfSideEffect)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ type
|
||||||
guards: TModel # nested guards
|
guards: TModel # nested guards
|
||||||
locked: seq[PNode] # locked locations
|
locked: seq[PNode] # locked locations
|
||||||
gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
|
gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
|
||||||
|
inEnforcedNoSideEffects: bool
|
||||||
maxLockLevel, currLockLevel: TLockLevel
|
maxLockLevel, currLockLevel: TLockLevel
|
||||||
config: ConfigRef
|
config: ConfigRef
|
||||||
graph: ModuleGraph
|
graph: ModuleGraph
|
||||||
|
|
@ -194,10 +195,10 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
|
||||||
|
|
||||||
when true:
|
when true:
|
||||||
template markSideEffect(a: PEffects; reason: typed) =
|
template markSideEffect(a: PEffects; reason: typed) =
|
||||||
a.hasSideEffect = true
|
if not a.inEnforcedNoSideEffects: a.hasSideEffect = true
|
||||||
else:
|
else:
|
||||||
template markSideEffect(a: PEffects; reason: typed) =
|
template markSideEffect(a: PEffects; reason: typed) =
|
||||||
a.hasSideEffect = true
|
if not a.inEnforcedNoSideEffects: a.hasSideEffect = true
|
||||||
markGcUnsafe(a, reason)
|
markGcUnsafe(a, reason)
|
||||||
|
|
||||||
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
|
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
|
||||||
|
|
@ -846,15 +847,20 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
let oldLocked = tracked.locked.len
|
let oldLocked = tracked.locked.len
|
||||||
let oldLockLevel = tracked.currLockLevel
|
let oldLockLevel = tracked.currLockLevel
|
||||||
var enforcedGcSafety = false
|
var enforcedGcSafety = false
|
||||||
|
var enforceNoSideEffects = false
|
||||||
for i in 0 ..< pragmaList.len:
|
for i in 0 ..< pragmaList.len:
|
||||||
let pragma = whichPragma(pragmaList.sons[i])
|
let pragma = whichPragma(pragmaList.sons[i])
|
||||||
if pragma == wLocks:
|
if pragma == wLocks:
|
||||||
lockLocations(tracked, pragmaList.sons[i])
|
lockLocations(tracked, pragmaList.sons[i])
|
||||||
elif pragma == wGcSafe:
|
elif pragma == wGcSafe:
|
||||||
enforcedGcSafety = true
|
enforcedGcSafety = true
|
||||||
|
elif pragma == wNosideeffect:
|
||||||
|
enforceNoSideEffects = true
|
||||||
if enforcedGcSafety: tracked.inEnforcedGcSafe = true
|
if enforcedGcSafety: tracked.inEnforcedGcSafe = true
|
||||||
|
if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true
|
||||||
track(tracked, n.lastSon)
|
track(tracked, n.lastSon)
|
||||||
if enforcedGcSafety: tracked.inEnforcedGcSafe = false
|
if enforcedGcSafety: tracked.inEnforcedGcSafe = false
|
||||||
|
if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false
|
||||||
setLen(tracked.locked, oldLocked)
|
setLen(tracked.locked, oldLocked)
|
||||||
tracked.currLockLevel = oldLockLevel
|
tracked.currLockLevel = oldLockLevel
|
||||||
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
||||||
|
|
|
||||||
|
|
@ -1860,7 +1860,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
for i in 0 ..< pragmaList.len:
|
for i in 0 ..< pragmaList.len:
|
||||||
case whichPragma(pragmaList.sons[i])
|
case whichPragma(pragmaList.sons[i])
|
||||||
of wLine: setLine(result, pragmaList.sons[i].info)
|
of wLine: setLine(result, pragmaList.sons[i].info)
|
||||||
of wLocks, wGcSafe:
|
of wLocks, wGcSafe, wNosideeffect:
|
||||||
result = n
|
result = n
|
||||||
result.typ = n.sons[1].typ
|
result.typ = n.sons[1].typ
|
||||||
of wNoRewrite:
|
of wNoRewrite:
|
||||||
|
|
|
||||||
|
|
@ -1239,8 +1239,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.gABC(n, opcCallSite, dest)
|
c.gABC(n, opcCallSite, dest)
|
||||||
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
|
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
|
||||||
of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
|
of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, mDotDot:
|
||||||
mDotDot:
|
|
||||||
c.genCall(n, dest)
|
c.genCall(n, dest)
|
||||||
of mExpandToAst:
|
of mExpandToAst:
|
||||||
if n.len != 2:
|
if n.len != 2:
|
||||||
|
|
|
||||||
|
|
@ -6755,6 +6755,16 @@ routines marked as ``noSideEffect``.
|
||||||
func `+` (x, y: int): int
|
func `+` (x, y: int): int
|
||||||
|
|
||||||
|
|
||||||
|
To override the compiler's side effect analysis a ``{.noSideEffect.}``
|
||||||
|
pragma block can be used:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
func f() =
|
||||||
|
{.noSideEffect.}:
|
||||||
|
echo "test"
|
||||||
|
|
||||||
|
|
||||||
compileTime pragma
|
compileTime pragma
|
||||||
------------------
|
------------------
|
||||||
The ``compileTime`` pragma is used to mark a proc or variable to be used at
|
The ``compileTime`` pragma is used to mark a proc or variable to be used at
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ type
|
||||||
cap: int
|
cap: int
|
||||||
region: Allocator
|
region: Allocator
|
||||||
|
|
||||||
proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} =
|
proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, noSideEffect.} =
|
||||||
# we have to use type erasure here as Nim does not support generic
|
# we have to use type erasure here as Nim does not support generic
|
||||||
# compilerProcs. Oh well, this will all be inlined anyway.
|
# compilerProcs. Oh well, this will all be inlined anyway.
|
||||||
if cap <= 0:
|
if cap <= 0:
|
||||||
|
|
@ -94,7 +94,8 @@ proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} =
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.compilerRtl.} =
|
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
|
||||||
|
compilerRtl, noSideEffect.} =
|
||||||
if len+addlen <= len:
|
if len+addlen <= len:
|
||||||
result = p
|
result = p
|
||||||
elif p == nil:
|
elif p == nil:
|
||||||
|
|
@ -128,7 +129,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
|
||||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T)))
|
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T)))
|
||||||
xu.len = newLen
|
xu.len = newLen
|
||||||
for i in oldLen .. newLen-1:
|
for i in oldLen .. newLen-1:
|
||||||
x.data[i] = value
|
xu.p.data[i] = value
|
||||||
|
|
||||||
proc setLen[T](s: var seq[T], newlen: Natural) =
|
proc setLen[T](s: var seq[T], newlen: Natural) =
|
||||||
if newlen < s.len:
|
if newlen < s.len:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue