new VM: improvements

This commit is contained in:
Araq
2013-12-12 01:34:01 +01:00
parent 29357ab556
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
proc isOpImpl(c: PContext, n: PNode): PNode =
InternalAssert n.sonsLen == 3 and
n[1].kind == nkSym and n[1].sym.kind == skType and
internalAssert n.sonsLen == 3 and
n[1].typ != nil and
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}:
case n[2].strVal.normalize

View File

@@ -33,10 +33,8 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result.add(line)
proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode =
InternalAssert operand.kind == nkSym
let typ = operand.sym.typ.skipTypes({tyTypeDesc})
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
let typ = operand.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
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 =
checkMinSonsLen(n, 2)
internalAssert n.sons[1].kind == nkSym
let typArg = n.sons[1].sym
if typArg.kind == skType or
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
# 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())
let t = n.sons[1].typ
internalAssert t != nil
if not containsGenericType(t):
result = evalTypeTrait(n[0], t, GetCurrOwner())
else:
# a typedesc variable, pass unmodified to evals
result = n

View File

@@ -52,9 +52,9 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
msg: TMsgKind, arg = "") =
MsgWriteln("stack trace: (most recent call last)")
msgWriteln("stack trace: (most recent call last)")
stackTraceAux(c, tos, pc)
LocalError(c.debug[pc], msg, arg)
localError(c.debug[pc], msg, arg)
proc bailOut(c: PCtx; tos: PStackFrame) =
stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
@@ -63,9 +63,6 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
when not defined(nimComputedGoto):
{.pragma: computedGoto.}
template inc(pc: ptr TInstr, diff = 1) =
inc cast[TAddress](pc), TInstr.sizeof * diff
proc myreset(n: PNode) =
when defined(system.reset):
var oldInfo = n.info
@@ -299,6 +296,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let instr = c.code[pc]
let ra = instr.regA
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
#message(c.debug[pc], warnUser, "gah")
case instr.opcode
of opcEof: return regs[ra]
of opcRet:
@@ -338,25 +336,38 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
# a = b[c]
let rb = instr.regB
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
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:
decodeBC(nkIntLit)
let idx = regs[rc].intVal
regs[ra].intVal = regs[rb].strVal[idx.int].ord
let idx = regs[rc].intVal.int
if idx <=% regs[rb].strVal.len:
regs[ra].intVal = regs[rb].strVal[idx].ord
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcWrArr:
# a[b] = c
let rb = instr.regB
let rc = instr.regC
let idx = regs[rb].intVal
asgnComplex(regs[ra].sons[idx.int], regs[rc])
let idx = regs[rb].intVal.int
if idx <% regs[ra].len:
asgnComplex(regs[ra].sons[idx], regs[rc])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcWrArrRef:
let rb = instr.regB
let rc = instr.regC
let idx = regs[rb].intVal
asgnRef(regs[ra].sons[idx.int], regs[rc])
let idx = regs[rb].intVal.int
if idx <% regs[ra].len:
asgnRef(regs[ra].sons[idx], regs[rc])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcLdObj:
# a = b.c
let rb = instr.regB
@@ -381,7 +392,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcWrStrIdx:
decodeBC(nkStrLit)
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:
decodeB(nkRefTy)
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
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
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)
# pass every parameter by var (the language definition allows this):
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)
of opcOf:
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:
decodeB(nkBracket)
let newLen = regs[rb].getOrdValue.int
@@ -787,10 +809,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeBC(nkMetaNode)
if regs[rb].kind != nkMetaNode:
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:
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:
decodeBC(nkMetaNode)
var u = regs[rb].uast
@@ -986,6 +1018,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeB(nkStrLit)
let typ = regs[rb].sym.typ.skipTypes({tyTypeDesc})
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
proc fixType(result, n: PNode) {.inline.} =
@@ -1073,6 +1114,7 @@ proc setupMacroParam(x: PNode): PNode =
y.flags.incl nfIsRef
result = newNode(nkMetaNode)
result.add y
result.typ = x.typ
var evalMacroCounter: int

View File

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

View File

@@ -301,7 +301,8 @@ proc sameConstant*(a, b: PNode): bool =
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
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:
if sonsLen(a) == sonsLen(b):
for i in countup(0, sonsLen(a) - 1):
@@ -674,12 +675,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
unused(n, dest)
var d = c.genx(n.sons[1])
c.gABC(n, opcReset, d)
of mOf:
of mOf, mIs:
if dest < 0: dest = c.getTemp(n.typ)
var tmp = c.genx(n.sons[1])
c.gABC(n, opcOf, dest, tmp)
c.gABx(n, opcOf, 0, c.genType(n.sons[2].typ.skipTypes(abstractPtrs)))
var idx = c.getTemp(getSysType(tyInt))
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(idx)
of mSizeOf:
GlobalError(n.info, errCannotInterpretNodeX, renderTree(n))
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.gABC(n, opcTypeTrait, dest, tmp)
c.freeTemp(tmp)
of mIs:
InternalError(n.info, "cannot generate code for: " & $m)
of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
of mStaticExec: genBinaryABC(c, n, dest, opcGorge)
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)
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) =
when hasFFI:
if allowFFI in c.features:
@@ -920,6 +928,17 @@ proc cannotEval(n: PNode) {.noinline.} =
globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
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) =
let s = n.sym
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 s.position == 0:
if sfImportc in s.flags: c.importcSym(n.info, s)
else:
c.globals.add(s.ast)
s.position = c.globals.len
# XXX var g = codeHere() ?
else: genGlobalInit(c, n, s)
c.gABx(n, opcLdGlobal, dest, s.position)
else:
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
c.globals.add(sa)
s.position = c.globals.len
# "Once support" is unnecessary here
if a.sons[2].kind == nkEmpty:
when false:
withTemp(tmp, s.typ):
@@ -1079,15 +1096,16 @@ proc genVarSection(c: PCtx; n: PNode) =
proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(tyInt)
var tmp = getTemp(c, intType)
c.gABx(n, opcLdNull, tmp, c.genType(intType))
for x in n:
let a = c.genx(x)
c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
c.gABI(n, opcAddImmInt, tmp, tmp, 1)
c.freeTemp(a)
c.freeTemp(tmp)
if n.len > 0:
let intType = getSysType(tyInt)
var tmp = getTemp(c, intType)
c.gABx(n, opcLdNull, tmp, c.genType(intType))
for x in n:
let a = c.genx(x)
c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
c.gABI(n, opcAddImmInt, tmp, tmp, 1)
c.freeTemp(a)
c.freeTemp(tmp)
proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
@@ -1167,6 +1185,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
InternalError(n.info,
"too large offset! cannot generate code for: " & s.name.s)
dest = s.position
of skType:
genTypeLit(c, s.typ, dest)
else:
InternalError(n.info, "cannot generate code for: " & s.name.s)
of nkCallKinds:
@@ -1371,7 +1391,7 @@ proc genProc(c: PCtx; s: PSym): int =
c.gABC(body, opcEof, eofInstr.regA)
c.optimizeJumps(result)
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)
# echo renderTree(body)
c.prc = oldPrc

View File

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

View File

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