Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

closureiters: minor optimization #15454

Merged
merged 5 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3050,7 +3050,23 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
case n.kind
of nkHiddenStdConv, nkHiddenSubConv:
result = genBracedInit(p, n[1], isConst)
when false:
# XXX The frontend doesn't keep conversions to openArray for us. :-(
# We need to change 'transformConv' first, but that is hard.
if n.typ.kind == tyOpenArray:
assert n[1].kind == nkBracket
let data = genBracedInit(p, n[1], isConst)

let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, n.typ.skipTypes(abstractInst)[0])
let arrLen = n[1].len
appcg(p.module, cfsData,
"static $5 $1 $3[$2] = $4;$n", [
ctype, arrLen, payload, data,
if isConst: "const" else: ""])
result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen]
else:
result = genBracedInit(p, n[1], isConst)
else:
var ty = tyNone
if n.typ == nil:
Expand Down
105 changes: 102 additions & 3 deletions compiler/closureiters.nim
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@

import
ast, msgs, idents,
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
tables, options

type
Ctx = object
Expand Down Expand Up @@ -1103,7 +1104,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =

result = ctx.states[stateIdx][0].intVal.int

proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode =
proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
result = n
case n.kind
of nkSkip:
Expand Down Expand Up @@ -1283,6 +1284,101 @@ proc deleteEmptyStates(ctx: var Ctx) =
else:
inc i

type
PreprocessContext = object
finallys: seq[PNode]
config: ConfigRef
blocks: seq[(PNode, int)]
FreshVarsContext = object
tab: Table[int, PSym]
config: ConfigRef
info: TLineInfo

proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
case n.kind
of nkSym:
let x = c.tab.getOrDefault(n.sym.id)
if x == nil:
result = n
else:
result = newSymNode(x, n.info)
of nkSkip - {nkSym}:
result = n
of nkLetSection, nkVarSection:
result = copyNode(n)
for it in n:
if it.kind in {nkIdentDefs, nkVarTuple}:
let idefs = copyNode(it)
for v in 0..it.len-3:
if it[v].kind == nkSym:
let x = copySym(it[v].sym)
c.tab[it[v].sym.id] = x
idefs.add newSymNode(x)
else:
idefs.add it[v]

for rest in it.len-2 ..< it.len: idefs.add it[rest]
result.add idefs
else:
result.add it
of nkRaiseStmt:
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
else:
result = n
for i in 0..<n.safeLen:
result[i] = freshVars(n[i], c)

proc preprocess(c: var PreprocessContext; n: PNode): PNode =
# in order to fix bug #15243 without risking regressions, we preprocess
# the AST so that 'break' statements inside a 'try finally' also have the
# finally section. We need to duplicate local variables here and also
# detect: 'finally: raises X' which is currently not supported. We produce
# an error for this case for now. All this will be done properly with Yuriy's
# patch.
result = n
case n.kind
of nkTryStmt:
let f = n.lastSon
if f.kind == nkFinally:
c.finallys.add f.lastSon

for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])

if f.kind == nkFinally:
discard c.finallys.pop()

of nkWhileStmt, nkBlockStmt:
c.blocks.add((n, c.finallys.len))
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
discard c.blocks.pop()

of nkBreakStmt:
if c.blocks.len == 0:
discard
else:
var fin = -1
if n[0].kind == nkEmpty:
fin = c.blocks[^1][1]
elif n[0].kind == nkSym:
for i in countdown(c.blocks.high, 0):
if c.blocks[i][0].kind == nkBlockStmt and c.blocks[i][0][0].kind == nkSym and
c.blocks[i][0][0].sym == n[0].sym:
fin = c.blocks[i][1]
break

if fin >= 0:
result = newNodeI(nkStmtList, n.info)
for i in countdown(c.finallys.high, fin):
var vars = FreshVarsContext(tab: initTable[int, PSym](), config: c.config, info: n.info)
result.add freshVars(preprocess(c, c.finallys[i]), vars)
result.add n
of nkSkip: discard
else:
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])

proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
var ctx: Ctx
ctx.g = g
Expand All @@ -1295,7 +1391,10 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
var n = n.toStmtList
var pc = PreprocessContext(finallys: @[], config: g.config)
var n = preprocess(pc, n.toStmtList)
#echo "transformed into ", n
#var n = n.toStmtList

discard ctx.newState(n, nil)
let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
Expand Down
7 changes: 7 additions & 0 deletions compiler/nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ define:useStdoutAsStdmsg
styleCheck:error
@end

# die when the Nim compiler uses more than 4GB:
@if cpu32:
define:"nimMaxHeap=2000"
@else:
define:"nimMaxHeap=4000"
@end

#define:useNodeIds
#gc:markAndSweep

Expand Down
4 changes: 2 additions & 2 deletions lib/pure/xmltree.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type

XmlNodeKind* = enum ## Different kinds of XML nodes.
xnText, ## a text element
xnVerbatimText, ##
xnVerbatimText, ##
xnElement, ## an element with 0 or more children
xnCData, ## a CDATA node
xnEntity, ## an entity (like ``&thing;``)
Expand Down Expand Up @@ -103,7 +103,7 @@ proc newText*(text: string): XmlNode =
result = newXmlNode(xnText)
result.fText = text

proc newVerbatimText*(text: string): XmlNode {.since: (1, 3).} =
proc newVerbatimText*(text: string): XmlNode {.since: (1, 3).} =
## Creates a new ``XmlNode`` of kind ``xnVerbatimText`` with the text `text`.
## **Since**: Version 1.3.
result = newXmlNode(xnVerbatimText)
Expand Down
66 changes: 0 additions & 66 deletions tests/async/tasyncawait_cyclebreaker.nim

This file was deleted.

25 changes: 25 additions & 0 deletions tests/async/tbreak_must_exec_finally.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
discard """
output: '''
finally handler 8
do not duplicate this one
'''
"""

# bug #15243

import asyncdispatch

proc f() {.async.} =
try:
while true:
try:
await sleepAsync(400)
break
finally:
var localHere = 8
echo "finally handler ", localHere
finally:
echo "do not duplicate this one"

when isMainModule:
waitFor f()