new VM: improvements

This commit is contained in:
Araq 2013-12-12 01:34:01 +01:00
commit 6db20a4be8
7 changed files with 114 additions and 57 deletions

View file

@ -300,11 +300,11 @@ proc semOf(c: PContext, n: PNode): PNode =
result = n result = n
proc isOpImpl(c: PContext, n: PNode): PNode = proc isOpImpl(c: PContext, n: PNode): PNode =
InternalAssert n.sonsLen == 3 and internalAssert n.sonsLen == 3 and
n[1].kind == nkSym and n[1].sym.kind == skType and n[1].typ != nil and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType} n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].sym.typ.skipTypes({tyTypeDesc}) let t1 = n[1].typ.skipTypes({tyTypeDesc})
if n[2].kind in {nkStrLit..nkTripleStrLit}: if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize case n[2].strVal.normalize

View file

@ -33,10 +33,8 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result.add(line) result.add(line)
proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode = proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
InternalAssert operand.kind == nkSym let typ = operand.skipTypes({tyTypeDesc})
let typ = operand.sym.typ.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize case trait.sym.name.s.normalize
of "name": of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName)) result = newStrNode(nkStrLit, typ.typeToString(preferName))
@ -51,13 +49,10 @@ proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode =
proc semTypeTraits(c: PContext, n: PNode): PNode = proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
internalAssert n.sons[1].kind == nkSym let t = n.sons[1].typ
let typArg = n.sons[1].sym internalAssert t != nil
if typArg.kind == skType or if not containsGenericType(t):
(typArg.kind == skParam and typArg.typ.sonsLen > 0): result = evalTypeTrait(n[0], t, GetCurrOwner())
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n[0], n[1], GetCurrOwner())
else: else:
# a typedesc variable, pass unmodified to evals # a typedesc variable, pass unmodified to evals
result = n result = n

View file

@ -52,9 +52,9 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
msg: TMsgKind, arg = "") = msg: TMsgKind, arg = "") =
MsgWriteln("stack trace: (most recent call last)") msgWriteln("stack trace: (most recent call last)")
stackTraceAux(c, tos, pc) stackTraceAux(c, tos, pc)
LocalError(c.debug[pc], msg, arg) localError(c.debug[pc], msg, arg)
proc bailOut(c: PCtx; tos: PStackFrame) = proc bailOut(c: PCtx; tos: PStackFrame) =
stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX, stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
@ -63,9 +63,6 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
when not defined(nimComputedGoto): when not defined(nimComputedGoto):
{.pragma: computedGoto.} {.pragma: computedGoto.}
template inc(pc: ptr TInstr, diff = 1) =
inc cast[TAddress](pc), TInstr.sizeof * diff
proc myreset(n: PNode) = proc myreset(n: PNode) =
when defined(system.reset): when defined(system.reset):
var oldInfo = n.info var oldInfo = n.info
@ -299,6 +296,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let instr = c.code[pc] let instr = c.code[pc]
let ra = instr.regA let ra = instr.regA
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
#message(c.debug[pc], warnUser, "gah")
case instr.opcode case instr.opcode
of opcEof: return regs[ra] of opcEof: return regs[ra]
of opcRet: of opcRet:
@ -338,25 +336,38 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
# a = b[c] # a = b[c]
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
let idx = regs[rc].intVal let idx = regs[rc].intVal.int
# XXX what if the array is not 0-based? -> codegen should insert a sub # XXX what if the array is not 0-based? -> codegen should insert a sub
assert regs[rb].kind != nkMetaNode assert regs[rb].kind != nkMetaNode
asgnComplex(regs[ra], regs[rb].sons[idx.int]) let src = regs[rb]
if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
asgnComplex(regs[ra], src.sons[idx])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcLdStrIdx: of opcLdStrIdx:
decodeBC(nkIntLit) decodeBC(nkIntLit)
let idx = regs[rc].intVal let idx = regs[rc].intVal.int
regs[ra].intVal = regs[rb].strVal[idx.int].ord if idx <=% regs[rb].strVal.len:
regs[ra].intVal = regs[rb].strVal[idx].ord
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcWrArr: of opcWrArr:
# a[b] = c # a[b] = c
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
let idx = regs[rb].intVal let idx = regs[rb].intVal.int
asgnComplex(regs[ra].sons[idx.int], regs[rc]) if idx <% regs[ra].len:
asgnComplex(regs[ra].sons[idx], regs[rc])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcWrArrRef: of opcWrArrRef:
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
let idx = regs[rb].intVal let idx = regs[rb].intVal.int
asgnRef(regs[ra].sons[idx.int], regs[rc]) if idx <% regs[ra].len:
asgnRef(regs[ra].sons[idx], regs[rc])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcLdObj: of opcLdObj:
# a = b.c # a = b.c
let rb = instr.regB let rb = instr.regB
@ -381,7 +392,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcWrStrIdx: of opcWrStrIdx:
decodeBC(nkStrLit) decodeBC(nkStrLit)
let idx = regs[rb].intVal.int let idx = regs[rb].intVal.int
regs[ra].strVal[idx] = chr(regs[rc].intVal) if idx <% regs[ra].strVal.len:
regs[ra].strVal[idx] = chr(regs[rc].intVal)
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcAddr: of opcAddr:
decodeB(nkRefTy) decodeB(nkRefTy)
if regs[ra].len == 0: regs[ra].add regs[rb] if regs[ra].len == 0: regs[ra].add regs[rb]
@ -631,7 +645,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
#echo "new pc ", newPc, " calling: ", prc.name.s #echo "new pc ", newPc, " calling: ", prc.name.s
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
newSeq(newFrame.slots, prc.offset) newSeq(newFrame.slots, prc.offset)
if not isEmptyType(prc.typ.sons[0]): if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info) newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info)
# pass every parameter by var (the language definition allows this): # pass every parameter by var (the language definition allows this):
for i in 1 .. rc-1: for i in 1 .. rc-1:
@ -769,7 +783,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
regs[ra].strVal.setLen(regs[rb].getOrdValue.int) regs[ra].strVal.setLen(regs[rb].getOrdValue.int)
of opcOf: of opcOf:
decodeBC(nkIntLit) decodeBC(nkIntLit)
regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, regs[rc].typ) >= 0) let typ = c.types[regs[rc].intVal.int]
regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, typ) >= 0)
of opcIs:
decodeBC(nkIntLit)
let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
let t2 = c.types[regs[rc].intVal.int]
let match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
else: sameType(t1, t2)
regs[ra].intVal = ord(match)
of opcSetLenSeq: of opcSetLenSeq:
decodeB(nkBracket) decodeB(nkBracket)
let newLen = regs[rb].getOrdValue.int let newLen = regs[rb].getOrdValue.int
@ -787,10 +809,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeBC(nkMetaNode) decodeBC(nkMetaNode)
if regs[rb].kind != nkMetaNode: if regs[rb].kind != nkMetaNode:
internalError(c.debug[pc], "no MetaNode") internalError(c.debug[pc], "no MetaNode")
setMeta(regs[ra], regs[rb].uast.sons[regs[rc].intVal.int]) let idx = regs[rc].intVal.int
let src = regs[rb].uast
if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
setMeta(regs[ra], src.sons[idx])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcNSetChild: of opcNSetChild:
decodeBC(nkMetaNode) decodeBC(nkMetaNode)
regs[ra].uast.sons[regs[rb].intVal.int] = regs[rc].uast let idx = regs[rb].intVal.int
var dest = regs[ra].uast
if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len:
dest.sons[idx] = regs[rc].uast
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcNAdd: of opcNAdd:
decodeBC(nkMetaNode) decodeBC(nkMetaNode)
var u = regs[rb].uast var u = regs[rb].uast
@ -986,6 +1018,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeB(nkStrLit) decodeB(nkStrLit)
let typ = regs[rb].sym.typ.skipTypes({tyTypeDesc}) let typ = regs[rb].sym.typ.skipTypes({tyTypeDesc})
regs[ra].strVal = typ.typeToString(preferExported) regs[ra].strVal = typ.typeToString(preferExported)
of opcGlobalOnce:
let rb = instr.regBx
if c.globals.sons[rb - wordExcess - 1].kind != nkEmpty:
# skip initialization instructions:
while true:
inc pc
if c.code[pc].opcode in {opcWrGlobal, opcWrGlobalRef} and
c.code[pc].regBx == rb:
break
inc pc inc pc
proc fixType(result, n: PNode) {.inline.} = proc fixType(result, n: PNode) {.inline.} =
@ -1073,6 +1114,7 @@ proc setupMacroParam(x: PNode): PNode =
y.flags.incl nfIsRef y.flags.incl nfIsRef
result = newNode(nkMetaNode) result = newNode(nkMetaNode)
result.add y result.add y
result.typ = x.typ
var evalMacroCounter: int var evalMacroCounter: int

View file

@ -60,7 +60,7 @@ type
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
opcSwap, opcIsNil, opcOf, opcSwap, opcIsNil, opcOf, opcIs,
opcSubStr, opcConv, opcCast, opcQuit, opcReset, opcSubStr, opcConv, opcCast, opcQuit, opcReset,
opcAddStrCh, opcAddStrCh,
@ -122,6 +122,7 @@ type
opcLdImmInt, # dest = immediate value opcLdImmInt, # dest = immediate value
opcWrGlobal, opcWrGlobal,
opcWrGlobalRef, opcWrGlobalRef,
opcGlobalOnce, # used to introduce an assignment to a global once
opcSetType, # dest.typ = types[Bx] opcSetType, # dest.typ = types[Bx]
opcTypeTrait opcTypeTrait

View file

@ -301,7 +301,8 @@ proc sameConstant*(a, b: PNode): bool =
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkEmpty, nkNilLit, nkType: result = true of nkType: result = a.typ == b.typ
of nkEmpty, nkNilLit: result = true
else: else:
if sonsLen(a) == sonsLen(b): if sonsLen(a) == sonsLen(b):
for i in countup(0, sonsLen(a) - 1): for i in countup(0, sonsLen(a) - 1):
@ -674,12 +675,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
unused(n, dest) unused(n, dest)
var d = c.genx(n.sons[1]) var d = c.genx(n.sons[1])
c.gABC(n, opcReset, d) c.gABC(n, opcReset, d)
of mOf: of mOf, mIs:
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
var tmp = c.genx(n.sons[1]) var tmp = c.genx(n.sons[1])
c.gABC(n, opcOf, dest, tmp) var idx = c.getTemp(getSysType(tyInt))
c.gABx(n, opcOf, 0, c.genType(n.sons[2].typ.skipTypes(abstractPtrs))) var typ = n.sons[2].typ
if m == mOf: typ = typ.skipTypes(abstractPtrs)
c.gABx(n, opcLdImmInt, idx, c.genType(typ))
c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
c.freeTemp(tmp) c.freeTemp(tmp)
c.freeTemp(idx)
of mSizeOf: of mSizeOf:
GlobalError(n.info, errCannotInterpretNodeX, renderTree(n)) GlobalError(n.info, errCannotInterpretNodeX, renderTree(n))
of mHigh: of mHigh:
@ -717,8 +722,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ)) c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
c.gABC(n, opcTypeTrait, dest, tmp) c.gABC(n, opcTypeTrait, dest, tmp)
c.freeTemp(tmp) c.freeTemp(tmp)
of mIs:
InternalError(n.info, "cannot generate code for: " & $m)
of mSlurp: genUnaryABC(c, n, dest, opcSlurp) of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
of mStaticExec: genBinaryABC(c, n, dest, opcGorge) of mStaticExec: genBinaryABC(c, n, dest, opcGorge)
of mNLen: genUnaryABI(c, n, dest, opcLenSeq) of mNLen: genUnaryABI(c, n, dest, opcLenSeq)
@ -905,6 +908,11 @@ proc genLit(c: PCtx; n: PNode; dest: var TDest) =
let lit = genLiteral(c, n) let lit = genLiteral(c, n)
c.gABx(n, opc, dest, lit) c.gABx(n, opc, dest, lit)
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
var n = newNode(nkType)
n.typ = t
genLit(c, n, dest)
proc importcSym(c: PCtx; info: TLineInfo; s: PSym) = proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
when hasFFI: when hasFFI:
if allowFFI in c.features: if allowFFI in c.features:
@ -920,6 +928,17 @@ proc cannotEval(n: PNode) {.noinline.} =
globalError(n.info, errGenerated, "cannot evaluate at compile time: " & globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
n.renderTree) n.renderTree)
proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
c.globals.add(emptyNode)
s.position = c.globals.len
# This is rather hard to support, due to the laziness of the VM code
# generator. See tests/compile/tmacro2 for why this is necesary:
# var decls{.compileTime.}: seq[PNimrodNode] = @[]
c.gABx(n, opcGlobalOnce, 0, s.position)
let tmp = c.genx(s.ast)
c.gABx(n, whichAsgnOpc(n, opcWrGlobal), tmp, s.position)
c.freeTemp(tmp)
proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
let s = n.sym let s = n.sym
if s.isGlobal: if s.isGlobal:
@ -930,10 +949,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0: dest = c.getTemp(s.typ) if dest < 0: dest = c.getTemp(s.typ)
if s.position == 0: if s.position == 0:
if sfImportc in s.flags: c.importcSym(n.info, s) if sfImportc in s.flags: c.importcSym(n.info, s)
else: else: genGlobalInit(c, n, s)
c.globals.add(s.ast)
s.position = c.globals.len
# XXX var g = codeHere() ?
c.gABx(n, opcLdGlobal, dest, s.position) c.gABx(n, opcLdGlobal, dest, s.position)
else: else:
if s.position > 0 or (s.position == 0 and s.kind in {skParam, skResult}): if s.position > 0 or (s.position == 0 and s.kind in {skParam, skResult}):
@ -1052,6 +1068,7 @@ proc genVarSection(c: PCtx; n: PNode) =
let sa = if s.ast.isNil: getNullValue(s.typ, a.info) else: s.ast let sa = if s.ast.isNil: getNullValue(s.typ, a.info) else: s.ast
c.globals.add(sa) c.globals.add(sa)
s.position = c.globals.len s.position = c.globals.len
# "Once support" is unnecessary here
if a.sons[2].kind == nkEmpty: if a.sons[2].kind == nkEmpty:
when false: when false:
withTemp(tmp, s.typ): withTemp(tmp, s.typ):
@ -1079,15 +1096,16 @@ proc genVarSection(c: PCtx; n: PNode) =
proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
c.gABx(n, opcLdNull, dest, c.genType(n.typ)) c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(tyInt) if n.len > 0:
var tmp = getTemp(c, intType) let intType = getSysType(tyInt)
c.gABx(n, opcLdNull, tmp, c.genType(intType)) var tmp = getTemp(c, intType)
for x in n: c.gABx(n, opcLdNull, tmp, c.genType(intType))
let a = c.genx(x) for x in n:
c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a) let a = c.genx(x)
c.gABI(n, opcAddImmInt, tmp, tmp, 1) c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
c.freeTemp(a) c.gABI(n, opcAddImmInt, tmp, tmp, 1)
c.freeTemp(tmp) c.freeTemp(a)
c.freeTemp(tmp)
proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) = proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
@ -1167,6 +1185,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
InternalError(n.info, InternalError(n.info,
"too large offset! cannot generate code for: " & s.name.s) "too large offset! cannot generate code for: " & s.name.s)
dest = s.position dest = s.position
of skType:
genTypeLit(c, s.typ, dest)
else: else:
InternalError(n.info, "cannot generate code for: " & s.name.s) InternalError(n.info, "cannot generate code for: " & s.name.s)
of nkCallKinds: of nkCallKinds:
@ -1371,7 +1391,7 @@ proc genProc(c: PCtx; s: PSym): int =
c.gABC(body, opcEof, eofInstr.regA) c.gABC(body, opcEof, eofInstr.regA)
c.optimizeJumps(result) c.optimizeJumps(result)
s.offset = c.prc.maxSlots s.offset = c.prc.maxSlots
#if s.name.s == "treeRepr" or s.name.s == "traverse": #if s.name.s == "importImpl_forward" or s.name.s == "importImpl":
# c.echoCode(result) # c.echoCode(result)
# echo renderTree(body) # echo renderTree(body)
c.prc = oldPrc c.prc = oldPrc

View file

@ -257,7 +257,7 @@ proc limitCommitMsg(m: string): string =
proc handleWebMessage(state: PState, line: string) = proc handleWebMessage(state: PState, line: string) =
echo("Got message from hub: " & line) echo("Got message from hub: " & line)
var json = parseJson(line) var json = parseJson(line)
if json.existsKey("payload"): if json.hasKey("payload"):
for i in 0..min(4, json["payload"]["commits"].len-1): for i in 0..min(4, json["payload"]["commits"].len-1):
var commit = json["payload"]["commits"][i] var commit = json["payload"]["commits"][i]
# Create the message # Create the message
@ -273,8 +273,8 @@ proc handleWebMessage(state: PState, line: string) =
# Send message to #nimrod. # Send message to #nimrod.
state.ircClient.privmsg(joinChans[0], message) state.ircClient.privmsg(joinChans[0], message)
elif json.existsKey("redisinfo"): elif json.hasKey("redisinfo"):
assert json["redisinfo"].existsKey("port") assert json["redisinfo"].hasKey("port")
#let redisPort = json["redisinfo"]["port"].num #let redisPort = json["redisinfo"]["port"].num
state.dbConnected = true state.dbConnected = true

View file

@ -20,7 +20,6 @@ Bugs
- bug: 'type T = ref T' not recognized as illegal recursion - bug: 'type T = ref T' not recognized as illegal recursion
- bug: type conversions concerning proc types are weird - bug: type conversions concerning proc types are weird
- compilation of niminst takes way too long. looks like a regression - compilation of niminst takes way too long. looks like a regression
- simple closure iterator doesn't work
- docgen: sometimes effects are listed twice - docgen: sometimes effects are listed twice
- 'result' is not properly cleaned for NRVO --> use uninit checking instead - 'result' is not properly cleaned for NRVO --> use uninit checking instead
- sneaking with qualifiedLookup() is really broken! - sneaking with qualifiedLookup() is really broken!