Merge branch 'devel' of github.com:Araq/Nimrod into devel

This commit is contained in:
Dominik Picheta 2014-04-05 20:26:54 +01:00
commit 694fc87b1d
6 changed files with 109 additions and 61 deletions

View file

@ -138,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) =
if n.sons[0].kind == nkClosure: if n.sons[0].kind == nkClosure:
# XXX this produces quite inefficient code! # XXX this produces quite inefficient code!
initLocExpr(p, n.sons[0].sons[1], a) initLocExpr(p, n.sons[0].sons[1], a)
lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)]) lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
else: else:
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
# the environment is guaranteed to contain the 'state' field at offset 0: # the environment is guaranteed to contain the 'state' field at offset 0:

View file

@ -121,14 +121,14 @@ type
capturedVars: seq[PSym] # captured variables in this environment capturedVars: seq[PSym] # captured variables in this environment
deps: seq[TDep] # dependencies deps: seq[TDep] # dependencies
up: PEnv up: PEnv
tup: PType obj: PType
TInnerContext {.final.} = object TInnerContext = object
fn: PSym fn: PSym
closureParam: PSym closureParam: PSym
localsToAccess: TIdNodeTable localsToAccess: TIdNodeTable
TOuterContext {.final.} = object TOuterContext = object
fn: PSym # may also be a module! fn: PSym # may also be a module!
currentEnv: PEnv currentEnv: PEnv
isIter: bool # first class iterator? isIter: bool # first class iterator?
@ -139,8 +139,13 @@ type
up: POuterContext up: POuterContext
closureParam, state, resultSym: PSym # only if isIter closureParam, state, resultSym: PSym # only if isIter
tup: PType # only if isIter obj: PType # only if isIter
proc createObj(owner: PSym, info: TLineInfo): PType =
result = newType(tyObject, owner)
rawAddSon(result, nil)
incl result.flags, tfFinal
result.n = newNodeI(nkRecList, info)
proc getStateType(iter: PSym): PType = proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info) var n = newNodeI(nkRange, iter.info)
@ -185,13 +190,14 @@ proc getEnvParam(routine: PSym): PSym =
if hidden.kind == nkSym and hidden.sym.name.s == paramName: if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym result = hidden.sym
proc addField(tup: PType, s: PSym) = proc addField(obj: PType; s: PSym) =
var field = newSym(skField, s.name, s.owner, s.info) # because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
let t = skipIntLit(s.typ) let t = skipIntLit(s.typ)
field.typ = t field.typ = t
field.position = sonsLen(tup) field.position = sonsLen(obj.n)
addSon(tup.n, newSymNode(field)) addSon(obj.n, newSymNode(field))
rawAddSon(tup, t)
proc initIterContext(c: POuterContext, iter: PSym) = proc initIterContext(c: POuterContext, iter: PSym) =
c.fn = iter c.fn = iter
@ -199,25 +205,24 @@ proc initIterContext(c: POuterContext, iter: PSym) =
var cp = getEnvParam(iter) var cp = getEnvParam(iter)
if cp == nil: if cp == nil:
c.tup = newType(tyTuple, iter) c.obj = createObj(iter, iter.info)
c.tup.n = newNodeI(nkRecList, iter.info)
cp = newSym(skParam, getIdent(paramName), iter, iter.info) cp = newSym(skParam, getIdent(paramName), iter, iter.info)
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter) cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup) rawAddSon(cp.typ, c.obj)
addHiddenParam(iter, cp) addHiddenParam(iter, cp)
c.state = createStateField(iter) c.state = createStateField(iter)
addField(c.tup, c.state) addField(c.obj, c.state)
else: else:
c.tup = cp.typ.sons[0] c.obj = cp.typ.sons[0]
assert c.tup.kind == tyTuple assert c.obj.kind == tyObject
if c.tup.len > 0: if c.obj.n.len > 0:
c.state = c.tup.n[0].sym c.state = c.obj.n[0].sym
else: else:
c.state = createStateField(iter) c.state = createStateField(iter)
addField(c.tup, c.state) addField(c.obj, c.state)
c.closureParam = cp c.closureParam = cp
if iter.typ.sons[0] != nil: if iter.typ.sons[0] != nil:
@ -244,8 +249,7 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
new(result) new(result)
result.deps = @[] result.deps = @[]
result.capturedVars = @[] result.capturedVars = @[]
result.tup = newType(tyTuple, outerProc) result.obj = createObj(outerProc, outerProc.info)
result.tup.n = newNodeI(nkRecList, outerProc.info)
result.up = up result.up = up
result.attachedNode = n result.attachedNode = n
@ -254,28 +258,28 @@ proc addCapturedVar(e: PEnv, v: PSym) =
if x == v: return if x == v: return
# XXX meh, just add the state field for every closure for now, it's too # XXX meh, just add the state field for every closure for now, it's too
# hard to figure out if it comes from a closure iterator: # hard to figure out if it comes from a closure iterator:
if e.tup.len == 0: addField(e.tup, createStateField(v.owner)) if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner))
e.capturedVars.add(v) e.capturedVars.add(v)
addField(e.tup, v) addField(e.obj, v)
proc addDep(e, d: PEnv, owner: PSym): PSym = proc addDep(e, d: PEnv, owner: PSym): PSym =
for x, field in items(e.deps): for x, field in items(e.deps):
if x == d: return field if x == d: return field
var pos = sonsLen(e.tup) var pos = sonsLen(e.obj.n)
result = newSym(skField, getIdent(upName & $pos), owner, owner.info) result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
result.typ = newType(tyRef, owner) result.typ = newType(tyRef, owner)
result.position = pos result.position = pos
assert d.tup != nil assert d.obj != nil
rawAddSon(result.typ, d.tup) rawAddSon(result.typ, d.obj)
addField(e.tup, result) addField(e.obj, result)
e.deps.add((d, result)) e.deps.add((d, result))
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode = proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node # returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info) var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.sons[0] deref.typ = a.typ.sons[0]
assert deref.typ.kind == tyTuple assert deref.typ.kind == tyObject
let field = getSymFromList(deref.typ.n, b.name) let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
assert field != nil, b.name.s assert field != nil, b.name.s
addSon(deref, a) addSon(deref, a)
result = newNodeI(nkDotExpr, info) result = newNodeI(nkDotExpr, info)
@ -302,11 +306,11 @@ proc addClosureParam(i: PInnerContext, e: PEnv) =
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info) cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn) cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.tup) rawAddSon(cp.typ, e.obj)
addHiddenParam(i.fn, cp) addHiddenParam(i.fn, cp)
else: else:
e.tup = cp.typ.sons[0] e.obj = cp.typ.sons[0]
assert e.tup.kind == tyTuple assert e.obj.kind == tyObject
i.closureParam = cp i.closureParam = cp
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id #echo "closure param added for ", i.fn.name.s, " ", i.fn.id
@ -357,7 +361,7 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
access = indirectAccess(access, addDep(e, it, i.fn), info) access = indirectAccess(access, addDep(e, it, i.fn), info)
access = indirectAccess(access, local, info) access = indirectAccess(access, local, info)
if o.isIter: if o.isIter:
if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local) if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
else: else:
incl(o.capturedVars, local.id) incl(o.capturedVars, local.id)
idNodeTablePut(i.localsToAccess, local, access) idNodeTablePut(i.localsToAccess, local, access)
@ -543,7 +547,7 @@ proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info) result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
incl(result.flags, sfShadowed) incl(result.flags, sfShadowed)
result.typ = newType(tyRef, o.fn) result.typ = newType(tyRef, o.fn)
result.typ.rawAddSon(e.tup) result.typ.rawAddSon(e.obj)
proc getClosureVar(o: POuterContext; e: PEnv): PSym = proc getClosureVar(o: POuterContext; e: PEnv): PSym =
if e.createdVar == nil: if e.createdVar == nil:
@ -669,7 +673,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
var local = n.sym var local = n.sym
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id: if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local) if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
return indirectAccess(newSymNode(o.closureParam), local, n.info) return indirectAccess(newSymNode(o.closureParam), local, n.info)
var closure = PEnv(idTableGet(o.lambdasToEnv, local)) var closure = PEnv(idTableGet(o.lambdasToEnv, local))

View file

@ -48,9 +48,17 @@ type
# XXX 'break' should perform cleanup actions # XXX 'break' should perform cleanup actions
# What does the C backend do for it? # What does the C backend do for it?
proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) = proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
if x != nil: if x != nil:
stackTraceAux(c, x.next, x.comesFrom) if recursionLimit == 0:
var calls = 0
var x = x
while x != nil:
inc calls
x = x.next
msgWriteln($calls & " calls omitted\n")
return
stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
var info = c.debug[pc] var info = c.debug[pc]
# we now use the same format as in system/except.nim # we now use the same format as in system/except.nim
var s = toFilename(info) var s = toFilename(info)
@ -222,13 +230,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop() proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int = proc cleanUpOnException(c: PCtx; tos: PStackFrame):
tuple[pc: int, f: PStackFrame] =
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs) let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
var f = tos var f = tos
while true: while true:
while f.safePoints.isNil or f.safePoints.len == 0: while f.safePoints.isNil or f.safePoints.len == 0:
f = f.next f = f.next
if f.isNil: return -1 if f.isNil: return (-1, nil)
var pc2 = f.safePoints[f.safePoints.high] var pc2 = f.safePoints[f.safePoints.high]
var nextExceptOrFinally = -1 var nextExceptOrFinally = -1
@ -244,13 +253,13 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int =
c.currentExceptionB = c.currentExceptionA c.currentExceptionB = c.currentExceptionA
c.currentExceptionA = nil c.currentExceptionA = nil
# execute the corresponding handler: # execute the corresponding handler:
return pc2 return (pc2, f)
inc pc2 inc pc2
if nextExceptOrFinally >= 0: if nextExceptOrFinally >= 0:
pc2 = nextExceptOrFinally pc2 = nextExceptOrFinally
if c.code[pc2].opcode == opcFinally: if c.code[pc2].opcode == opcFinally:
# execute the corresponding handler, but don't quit walking the stack: # execute the corresponding handler, but don't quit walking the stack:
return pc2 return (pc2, f)
# not the right one: # not the right one:
discard f.safePoints.pop discard f.safePoints.pop
@ -869,19 +878,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcFinallyEnd: of opcFinallyEnd:
if c.currentExceptionA != nil: if c.currentExceptionA != nil:
# we are in a cleanup run: # we are in a cleanup run:
pc = cleanUpOnException(c, tos, regs)-1 let (newPc, newTos) = cleanUpOnException(c, tos)
if pc < 0: if newPc-1 < 0:
bailOut(c, tos) bailOut(c, tos)
return return
pc = newPc-1
if tos != newTos:
tos = newTos
move(regs, tos.slots)
of opcRaise: of opcRaise:
let raised = regs[ra].node let raised = regs[ra].node
c.currentExceptionA = raised c.currentExceptionA = raised
c.exceptionInstr = pc c.exceptionInstr = pc
let (newPc, newTos) = cleanUpOnException(c, tos)
# -1 because of the following 'inc' # -1 because of the following 'inc'
pc = cleanUpOnException(c, tos, regs) - 1 if pc-1 < 0:
if pc < 0:
bailOut(c, tos) bailOut(c, tos)
return return
pc = newPc -1
if tos != newTos:
tos = newTos
move(regs, tos.slots)
of opcNew: of opcNew:
ensureKind(rkNode) ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess] let typ = c.types[instr.regBx - wordExcess]

View file

@ -1034,6 +1034,7 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
proc setSlot(c: PCtx; v: PSym) = proc setSlot(c: PCtx; v: PSym) =
# XXX generate type initialization here? # XXX generate type initialization here?
if v.position == 0: if v.position == 0:
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
v.position = c.prc.maxSlots v.position = c.prc.maxSlots
c.prc.slots[v.position] = (inUse: true, c.prc.slots[v.position] = (inUse: true,
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar) kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)

View file

@ -45,7 +45,7 @@ proc raiseInvalidReply(expected, got: char) =
[$expected, $got]) [$expected, $got])
proc raiseNoOK(status: string) = proc raiseNoOK(status: string) =
if status != "OK": if status != "QUEUED" and status != "OK":
raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status) raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status)
proc parseStatus(r: TRedis): TRedisStatus = proc parseStatus(r: TRedis): TRedisStatus =
@ -64,6 +64,10 @@ proc parseStatus(r: TRedis): TRedisStatus =
proc parseInteger(r: TRedis): TRedisInteger = proc parseInteger(r: TRedis): TRedisInteger =
var line = "" var line = ""
r.socket.readLine(line) r.socket.readLine(line)
if line == "+QUEUED": # inside of multi
return -1
if line == "": if line == "":
raise newException(ERedis, "Server closed connection prematurely") raise newException(ERedis, "Server closed connection prematurely")
@ -81,10 +85,7 @@ proc recv(sock: TSocket, size: int): TaintedString =
if sock.recv(cstring(result), size) != size: if sock.recv(cstring(result), size) != size:
raise newException(EInvalidReply, "recv failed") raise newException(EInvalidReply, "recv failed")
proc parseBulk(r: TRedis, allowMBNil = False): TRedisString = proc parseSingle(r: TRedis, line:string, allowMBNil = False): TRedisString =
var line = ""
r.socket.readLine(line.TaintedString)
# Error. # Error.
if line[0] == '-': if line[0] == '-':
raise newException(ERedis, strip(line)) raise newException(ERedis, strip(line))
@ -94,6 +95,9 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
if line == "*-1": if line == "*-1":
return RedisNil return RedisNil
if line == "+QUEUED" or line == "+OK" : # inside of a transaction (multi)
return nil
if line[0] != '$': if line[0] != '$':
raiseInvalidReply('$', line[0]) raiseInvalidReply('$', line[0])
@ -104,18 +108,41 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
var s = r.socket.recv(numBytes+2) var s = r.socket.recv(numBytes+2)
result = strip(s.string) result = strip(s.string)
proc parseMultiBulk(r: TRedis): TRedisList = proc parseMultiLines(r: TRedis, countLine:string): TRedisList =
var line = TaintedString"" if countLine.string[0] != '*':
r.socket.readLine(line) raiseInvalidReply('*', countLine.string[0])
if line.string[0] != '*': var numElems = parseInt(countLine.string.substr(1))
raiseInvalidReply('*', line.string[0])
var numElems = parseInt(line.string.substr(1))
if numElems == -1: return nil if numElems == -1: return nil
result = @[] result = @[]
for i in 1..numElems: for i in 1..numElems:
result.add(r.parseBulk()) var line = ""
r.socket.readLine(line.TaintedString)
if line[0] == '*': # after exec() may contain more multi-bulk replies
var parsed = r.parseMultiLines(line)
for item in parsed:
result.add(item)
else:
result.add(r.parseSingle(line))
proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
var line = ""
r.socket.readLine(line.TaintedString)
if line == "+QUEUED" or line == "+OK": # inside of a transaction (multi)
return nil
return r.parseSingle(line, allowMBNil)
proc parseMultiBulk(r: TRedis): TRedisList =
var line = TaintedString""
r.socket.readLine(line)
if line == "+QUEUED": # inside of a transaction (multi)
return nil
return r.parseMultiLines(line)
proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) = proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) =
var request = "*" & $(1 + args.len()) & "\c\L" var request = "*" & $(1 + args.len()) & "\c\L"
@ -722,6 +749,7 @@ proc discardMulti*(r: TRedis) =
proc exec*(r: TRedis): TRedisList = proc exec*(r: TRedis): TRedisList =
## Execute all commands issued after MULTI ## Execute all commands issued after MULTI
r.sendCommand("EXEC") r.sendCommand("EXEC")
return r.parseMultiBulk() return r.parseMultiBulk()
proc multi*(r: TRedis) = proc multi*(r: TRedis) =

View file

@ -1,8 +1,6 @@
version 0.9.4 version 0.9.4
============= =============
- fix GC issues
Bugs Bugs
==== ====