new VM is getting stable

This commit is contained in:
Araq 2013-10-29 01:07:59 +01:00
commit b4e25a6372
8 changed files with 206 additions and 124 deletions

View file

@ -68,6 +68,19 @@ proc myreset(n: PNode) =
reset(n[])
n.info = oldInfo
proc skipMeta(n: PNode): PNode = (if n.kind != nkMetaNode: n else: n.sons[0])
proc setMeta(n, child: PNode) =
assert n.kind == nkMetaNode
let child = child.skipMeta
if n.sons.isNil: n.sons = @[child]
else: n.sons[0] = child
proc uast(n: PNode): PNode {.inline.} =
# "underlying ast"
assert n.kind == nkMetaNode
n.sons[0]
template ensureKind(k: expr) {.immediate, dirty.} =
if regs[ra].kind != k:
myreset(regs[ra])
@ -98,28 +111,32 @@ template decodeBx(k: expr) {.immediate, dirty.} =
template move(a, b: expr) = system.shallowCopy(a, b)
# XXX fix minor 'shallowCopy' overloading bug in compiler
when false:
proc asgnRef(x, y: PNode) =
proc moveConst(x, y: PNode) =
if x.kind != y.kind:
myreset(x)
x.kind = y.kind
x.typ = y.typ
case x.kind
of nkCharLit..nkInt64Lit: x.intVal = y.intVal
of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal
of nkStrLit..nkTripleStrLit: x.strVal = y.strVal
of nkIdent: x.ident = y.ident
of nkSym: x.sym = y.sym
else:
if x.kind notin {nkEmpty..nkNilLit}:
move(x.sons, y.sons)
else:
# this seems to be the best way to model the reference semantics
# of PNimrodNode:
template asgnRef(x, y: expr) = x = y
x.typ = y.typ
case x.kind
of nkCharLit..nkInt64Lit: x.intVal = y.intVal
of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal
of nkStrLit..nkTripleStrLit: move(x.strVal, y.strVal)
of nkIdent: x.ident = y.ident
of nkSym: x.sym = y.sym
of nkMetaNode:
if x.sons.isNil: x.sons = @[y.sons[0]]
else: x.sons[0] = y.sons[0]
else:
if x.kind notin {nkEmpty..nkNilLit}:
move(x.sons, y.sons)
# this seems to be the best way to model the reference semantics
# of PNimrodNode:
template asgnRef(x, y: expr) = moveConst(x, y)
proc asgnComplex(x, y: PNode) =
myreset(x)
x.kind = y.kind
if x.kind != y.kind:
myreset(x)
x.kind = y.kind
x.typ = y.typ
case x.kind
of nkCharLit..nkInt64Lit: x.intVal = y.intVal
@ -127,6 +144,9 @@ proc asgnComplex(x, y: PNode) =
of nkStrLit..nkTripleStrLit: x.strVal = y.strVal
of nkIdent: x.ident = y.ident
of nkSym: x.sym = y.sym
of nkMetaNode:
if x.sons.isNil: x.sons = @[y.sons[0]]
else: x.sons[0] = y.sons[0]
else:
if x.kind notin {nkEmpty..nkNilLit}:
let y = y.copyTree
@ -286,16 +306,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcAsgnRef:
asgnRef(regs[ra], regs[instr.regB])
of opcWrGlobalRef:
asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra].skipMeta)
of opcWrGlobal:
asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra].skipMeta)
of opcLdArr:
# a = b[c]
let rb = instr.regB
let rc = instr.regC
let idx = regs[rc].intVal
# XXX what if the array is not 0-based? -> codegen should insert a sub
regs[ra] = regs[rb].sons[idx.int]
assert regs[rb].kind != nkMetaNode
asgnComplex(regs[ra], regs[rb].sons[idx.int])
of opcLdStrIdx:
decodeBC(nkIntLit)
let idx = regs[rc].intVal
@ -305,12 +326,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let rb = instr.regB
let rc = instr.regC
let idx = regs[rb].intVal
asgnComplex(regs[ra].sons[idx.int], regs[rc])
asgnComplex(regs[ra].sons[idx.int], regs[rc].skipMeta)
of opcWrArrRef:
let rb = instr.regB
let rc = instr.regC
let idx = regs[rb].intVal
asgnRef(regs[ra].sons[idx.int], regs[rc])
asgnRef(regs[ra].sons[idx.int], regs[rc].skipMeta)
of opcLdObj:
# a = b.c
let rb = instr.regB
@ -322,11 +343,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
# a.b = c
let rb = instr.regB
let rc = instr.regC
asgnComplex(regs[ra].sons[rb], regs[rc])
asgnComplex(regs[ra].sons[rb], regs[rc].skipMeta)
of opcWrObjRef:
let rb = instr.regB
let rc = instr.regC
asgnRef(regs[ra].sons[rb], regs[rc])
asgnRef(regs[ra].sons[rb], regs[rc].skipMeta)
of opcWrStrIdx:
decodeBC(nkStrLit)
let idx = regs[rb].intVal.int
@ -341,6 +362,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
if regs[rb].kind == nkNilLit:
stackTrace(c, tos, pc, errNilAccess)
assert regs[rb].kind == nkRefTy
# XXX this is not correct
regs[ra] = regs[rb].sons[0]
of opcAddInt:
decodeBC(nkIntLit)
@ -357,8 +379,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcLenSeq:
decodeBImm(nkIntLit)
#assert regs[rb].kind == nkBracket
# also used by mNLen
regs[ra].intVal = regs[rb].len - imm
# also used by mNLen:
regs[ra].intVal = regs[rb].skipMeta.len - imm
of opcLenStr:
decodeBImm(nkIntLit)
assert regs[rb].kind == nkStrLit
@ -366,6 +388,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcIncl:
decodeB(nkCurly)
if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb]))
of opcInclRange:
decodeBC(nkCurly)
var r = newNode(nkRange)
r.add regs[rb]
r.add regs[rc]
addSon(regs[ra], r.copyTree)
of opcExcl:
decodeB(nkCurly)
var b = newNodeIT(nkCurly, regs[rb].info, regs[rb].typ)
@ -456,6 +484,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
regs[ra].intVal = ord((regs[rb].kind == nkNilLit and
regs[rc].kind == nkNilLit) or
regs[rb].sons == regs[rc].sons)
of opcEqNimrodNode:
decodeBC(nkIntLit)
regs[ra].intVal = ord(regs[rb].uast == regs[rc].uast)
of opcXor:
decodeBC(nkIntLit)
regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
@ -529,7 +560,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
writeln(stdout, "")
of opcContainsSet:
decodeBC(nkIntLit)
regs[ra].intVal = Ord(inSet(regs[rb], regs[rc]))
regs[ra].intVal = ord(inSet(regs[rb], regs[rc]))
of opcSubStr:
decodeBC(nkStrLit)
inc pc
@ -581,18 +612,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
inc pc, rbx
of opcBranch:
# we know the next instruction is a 'jmp':
# we know the next instruction is a 'fjmp':
let branch = c.constants[instr.regBx-wordExcess]
var cond = false
for j in countup(0, sonsLen(branch) - 2):
if overlap(regs[ra], branch.sons[j]):
cond = true
break
assert c.code[pc+1].opcode == opcJmp
assert c.code[pc+1].opcode == opcFJmp
inc pc
# we skip this instruction so that the final 'inc(pc)' skips
# the following jump
if cond:
if not cond:
let instr2 = c.code[pc]
let rbx = instr2.regBx - wordExcess - 1 # -1 for the following 'inc pc'
inc pc, rbx
@ -646,7 +677,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let typ = c.types[instr.regBx - wordExcess]
regs[ra] = getNullValue(typ, c.debug[pc])
of opcLdConst:
regs[ra] = c.constants.sons[instr.regBx - wordExcess]
let rb = instr.regBx - wordExcess
if regs[ra].isNil:
regs[ra] = copyTree(c.constants.sons[rb])
else:
moveConst(regs[ra], c.constants.sons[rb])
of opcAsgnConst:
let rb = instr.regBx - wordExcess
if regs[ra].isNil:
@ -661,7 +696,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
asgnComplex(regs[ra], c.globals.sons[rb])
of opcRepr:
decodeB(nkStrLit)
regs[ra].strVal = renderTree(regs[rb], {renderNoComments})
regs[ra].strVal = renderTree(regs[rb].skipMeta, {renderNoComments})
of opcQuit:
if c.mode in {emRepl, emStatic}:
Message(c.debug[pc], hintQuitCalled)
@ -674,62 +709,71 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcOf:
decodeBC(nkIntLit)
regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, regs[rc].typ) >= 0)
of opcSetLenSeq,
opcSwap, opcIsNil,
opcCast, opcReset:
of opcSetLenSeq:
decodeB(nkBracket)
let newLen = regs[rb].getOrdValue.int
setLen(regs[ra].sons, newLen)
of opcSwap, opcCast, opcReset:
internalError(c.debug[pc], "too implement")
of opcIsNil:
decodeB(nkIntLit)
regs[ra].intVal = ord(regs[rb].skipMeta.kind == nkNilLit)
of opcNBindSym:
# trivial implementation:
let rb = instr.regB
regs[ra] = regs[rb].sons[1]
decodeB(nkMetaNode)
setMeta(regs[ra], regs[rb].skipMeta.sons[1])
of opcNChild:
let rb = instr.regB
let rc = instr.regC
regs[ra] = regs[rb].sons[regs[rc].intVal.int]
decodeBC(nkMetaNode)
setMeta(regs[ra], regs[rb].uast.sons[regs[rc].intVal.int])
of opcNSetChild:
let rb = instr.regB
let rc = instr.regC
regs[ra].sons[regs[rb].intVal.int] = regs[rc]
decodeBC(nkMetaNode)
regs[ra].uast.sons[regs[rb].intVal.int] = regs[rc].uast
of opcNAdd:
declBC()
regs[rb].add(regs[rc])
regs[ra] = regs[rb]
decodeBC(nkMetaNode)
var u = regs[rb].uast
u.add(regs[rc].uast)
setMeta(regs[ra], u)
of opcNAddMultiple:
declBC()
decodeBC(nkMetaNode)
let x = regs[rc]
var u = regs[rb].uast
# XXX can be optimized:
for i in 0.. <x.len: regs[rb].add(x.sons[i])
regs[ra] = regs[rb]
for i in 0.. <x.len: u.add(x.sons[i].skipMeta)
setMeta(regs[ra], u)
of opcNKind:
decodeB(nkIntLit)
regs[ra].intVal = ord(regs[rb].kind)
regs[ra].intVal = ord(regs[rb].uast.kind)
of opcNIntVal:
decodeB(nkIntLit)
let a = regs[rb]
let a = regs[rb].uast
case a.kind
of nkCharLit..nkInt64Lit: regs[ra].intVal = a.intVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
of opcNFloatVal:
decodeB(nkFloatLit)
let a = regs[rb]
let a = regs[rb].uast
case a.kind
of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
of opcNSymbol:
let rb = instr.regB
if regs[rb].kind != nkSym:
decodeB(nkSym)
let a = regs[rb].uast
if a.kind == nkSym:
regs[ra].sym = a.sym
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
regs[ra] = regs[rb]
of opcNIdent:
let rb = instr.regB
if regs[rb].kind != nkIdent:
decodeB(nkIdent)
let a = regs[rb].uast
if a.kind == nkIdent:
regs[ra].ident = a.ident
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
regs[ra] = regs[rb]
of opcNGetType:
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
of opcNStrVal:
decodeB(nkStrLit)
let a = regs[rb]
let a = regs[rb].uast
case a.kind
of nkStrLit..nkTripleStrLit: regs[ra].strVal = a.strVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
@ -746,25 +790,26 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
of opcNHint:
Message(c.debug[pc], hintUser, regs[ra].strVal)
of opcParseExprToAst:
let rb = instr.regB
decodeB(nkMetaNode)
# c.debug[pc].line.int - countLines(regs[rb].strVal) ?
let ast = parseString(regs[rb].strVal, c.debug[pc].toFilename,
c.debug[pc].line.int)
if sonsLen(ast) != 1:
GlobalError(c.debug[pc], errExprExpected, "multiple statements")
regs[ra] = ast.sons[0]
setMeta(regs[ra], ast.sons[0])
of opcParseStmtToAst:
let rb = instr.regB
decodeB(nkMetaNode)
let ast = parseString(regs[rb].strVal, c.debug[pc].toFilename,
c.debug[pc].line.int)
regs[ra] = ast
setMeta(regs[ra], ast)
of opcCallSite:
if c.callsite != nil: regs[ra] = c.callsite
ensureKind(nkMetaNode)
if c.callsite != nil: setMeta(regs[ra], c.callsite)
else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
of opcNLineInfo:
let rb = instr.regB
decodeB(nkStrLit)
let n = regs[rb]
regs[ra] = newStrNode(nkStrLit, n.info.toFileLineCol)
regs[ra].strVal = n.info.toFileLineCol
regs[ra].info = c.debug[pc]
of opcEqIdent:
decodeBC(nkIntLit)
@ -773,16 +818,16 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
else:
regs[ra].intVal = 0
of opcStrToIdent:
let rb = instr.regB
decodeB(nkIdent)
if regs[rb].kind notin {nkStrLit..nkTripleStrLit}:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
else:
regs[ra] = newNodeI(nkIdent, c.debug[pc])
regs[ra].info = c.debug[pc]
regs[ra].ident = getIdent(regs[rb].strVal)
of opcIdentToStr:
let rb = instr.regB
decodeB(nkStrLit)
let a = regs[rb]
regs[ra] = newNodeI(nkStrLit, c.debug[pc])
regs[ra].info = c.debug[pc]
if a.kind == nkSym:
regs[ra].strVal = a.sym.name.s
elif a.kind == nkIdent:
@ -800,71 +845,80 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
msgKindToString(errIllegalConvFromXtoY) % [
"unknown type" , "unknown type"])
of opcNSetIntVal:
let rb = instr.regB
if regs[ra].kind in {nkCharLit..nkInt64Lit} and
decodeB(nkMetaNode)
var dest = regs[ra].uast
if dest.kind in {nkCharLit..nkInt64Lit} and
regs[rb].kind in {nkCharLit..nkInt64Lit}:
regs[ra].intVal = regs[rb].intVal
else:
dest.intVal = regs[rb].intVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
of opcNSetFloatVal:
let rb = instr.regB
if regs[ra].kind in {nkFloatLit..nkFloat64Lit} and
decodeB(nkMetaNode)
var dest = regs[ra].uast
if dest.kind in {nkFloatLit..nkFloat64Lit} and
regs[rb].kind in {nkFloatLit..nkFloat64Lit}:
regs[ra].floatVal = regs[rb].floatVal
dest.floatVal = regs[rb].floatVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
of opcNSetSymbol:
let rb = instr.regB
if regs[ra].kind == nkSym and regs[rb].kind == nkSym:
regs[ra].sym = regs[rb].sym
decodeB(nkMetaNode)
var dest = regs[ra].uast
if dest.kind == nkSym and regs[rb].kind == nkSym:
dest.sym = regs[rb].sym
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
of opcNSetIdent:
let rb = instr.regB
if regs[ra].kind == nkIdent and regs[rb].kind == nkIdent:
regs[ra].ident = regs[rb].ident
decodeB(nkMetaNode)
var dest = regs[ra].uast
if dest.kind == nkIdent and regs[rb].kind == nkIdent:
dest.ident = regs[rb].ident
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
of opcNSetType:
let b = regs[instr.regB]
decodeB(nkMetaNode)
let b = regs[rb].skipMeta
InternalAssert b.kind == nkSym and b.sym.kind == skType
regs[ra].typ = b.sym.typ
regs[ra].uast.typ = b.sym.typ
of opcNSetStrVal:
let rb = instr.regB
if regs[ra].kind in {nkStrLit..nkTripleStrLit} and
decodeB(nkMetaNode)
var dest = regs[ra].uast
if dest.kind in {nkStrLit..nkTripleStrLit} and
regs[rb].kind in {nkStrLit..nkTripleStrLit}:
regs[ra].strVal = regs[rb].strVal
dest.strVal = regs[rb].strVal
else:
#c.echoCode
#debug regs[ra]
#debug regs[rb]
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
of opcNNewNimNode:
let rb = instr.regB
let rc = instr.regC
decodeBC(nkMetaNode)
var k = regs[rb].intVal
if k < 0 or k > ord(high(TNodeKind)):
internalError(c.debug[pc],
"request to create a NimNode with invalid kind")
regs[ra] = newNodeI(TNodeKind(int(k)),
if regs[rc].kind == nkNilLit: c.debug[pc] else: regs[rc].info)
"request to create a NimNode of invalid kind")
let cc = regs[rc].skipMeta
setMeta(regs[ra], newNodeI(TNodeKind(int(k)),
if cc.kind == nkNilLit: c.debug[pc] else: cc.info))
of opcNCopyNimNode:
let rb = instr.regB
regs[ra] = copyNode(regs[rb])
decodeB(nkMetaNode)
setMeta(regs[ra], copyNode(regs[rb]))
of opcNCopyNimTree:
let rb = instr.regB
regs[ra] = copyTree(regs[rb])
decodeB(nkMetaNode)
setMeta(regs[ra], copyTree(regs[rb]))
of opcNDel:
let rb = instr.regB
let rc = instr.regC
decodeBC(nkMetaNode)
let bb = regs[rb].intVal.int
for i in countup(0, regs[rc].intVal.int-1):
delSon(regs[ra], regs[rb].intVal.int)
delSon(regs[ra].uast, bb)
of opcGenSym:
let k = regs[instr.regB].intVal
let b = regs[instr.regC]
let name = if b.strVal.len == 0: ":tmp" else: b.strVal
decodeBC(nkMetaNode)
let k = regs[rb].intVal
let name = if regs[rc].strVal.len == 0: ":tmp" else: regs[rc].strVal
if k < 0 or k > ord(high(TSymKind)):
internalError(c.debug[pc], "request to create symbol of invalid kind")
regs[ra] = newSymNode(newSym(k.TSymKind, name.getIdent, c.module,
c.debug[pc]))
incl(regs[ra].sym.flags, sfGenSym)
var sym = newSym(k.TSymKind, name.getIdent, c.module, c.debug[pc])
incl(sym.flags, sfGenSym)
setMeta(regs[ra], newSymNode(sym))
of opcTypeTrait:
# XXX only supports 'name' for now; we can use regC to encode the
# type trait operation
@ -894,7 +948,9 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
let start = genExpr(c, n)
assert c.code[start].opcode != opcEof
result = execute(c, start)
fixType(result, n)
if not result.isNil:
result = result.skipMeta
fixType(result, n)
# for now we share the 'globals' environment. XXX Coming soon: An API for
# storing&loading the 'globals' environment to get what a component system
@ -949,6 +1005,9 @@ proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
proc setupMacroParam(x: PNode): PNode =
result = x
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
let y = result
result = newNode(nkMetaNode)
result.add y
var evalMacroCounter: int
@ -979,4 +1038,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
result = rawExecute(c, start, tos)
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
dec(evalMacroCounter)
if result != nil:
internalAssert result.kind == nkMetaNode
result = result.sons[0]
c.callsite = nil