Skip to content

Commit

Permalink
new VM: preparations for evalMacroCall
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Aug 11, 2013
1 parent a294d45 commit d18c82a
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 19 deletions.
92 changes: 81 additions & 11 deletions compiler/vm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,14 @@ proc execute(c: PCtx, start: int) =
let ra = instr.regA
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
case instr.opcode
of opcEof: break
of opcEof: return regs[ra]
of opcRet:
# XXX perform any cleanup actions
pc = tos.comesFrom
tos = tos.next
if tos.isNil: return

let retVal = regs[0]
if tos.isNil: return retVal

move(regs, tos.slots)
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
if c.code[pc].opcode == opcIndCallAsgn:
Expand Down Expand Up @@ -637,6 +637,16 @@ proc execute(c: PCtx, start: int) =
regs[ra] = copyTree(c.constants.sons[rb])
else:
asgnComplex(regs[ra], c.constants.sons[rb])
of opcLdGlobal:
let rb = instr.regBx - wordExcess
if regs[ra].isNil:
regs[ra] = copyTree(c.globals.sons[rb])
else:
asgnComplex(regs[ra], c.globals.sons[rb])
of opcRepr, opcSetLenStr, opcSetLenSeq,
opcSwap, opcIsNil, opcOf,
opcCast, opcQuit, opcReset:
internalError(c.debug[pc], "too implement")
of opcNBindSym:
# trivial implementation:
let rb = instr.regB
Expand Down Expand Up @@ -810,19 +820,33 @@ proc execute(c: PCtx, start: int) =
of opcNCopyNimTree:
let rb = instr.regB
regs[ra] = copyTree(regs[rb])
else:
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
of opcNDel:
let rb = instr.regB
let rc = instr.regC
for i in countup(0, regs[rc].intVal.int-1):
delSon(regs[ra], regs[rb].intVal.int)
of opcGenSym:
let k = regs[instr.regB].intVal
let b = regs[instr.regC]
let name = if b.strVal.len == 0: ":tmp" else: b.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)
inc pc

proc eval*(c: PCtx, n: PNode): PNode =
## eval never returns nil! This simplifies the code a lot and
## makes it faster too.
proc evalStmt*(c: PCtx, n: PNode) =
let start = genStmt(c, n)
# execute new instructions; this redundant opcEof check saves us lots
# of allocations in 'execute':
if c.code[start].opcode != opcEof:
execute(c, start)
result = emptyNode
discard execute(c, start)

proc evalExpr*(c: PCtx, n: PNode): PNode =
let start = genExpr(c, n)
assert c.code[start].opcode != opcEof
result = execute(c, start)

proc myOpen(module: PSym): PPassContext =
#var c = newEvalContext(module, emRepl)
Expand All @@ -835,10 +859,56 @@ var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode =
# don't eval errornous code:
if oldErrorCount == msgs.gErrorCounter:
result = eval(PCtx(c), n)
evalStmt(PCtx(c), n)
result = emptyNode
else:
result = n
oldErrorCount = msgs.gErrorCounter

const vmPass* = makePass(myOpen, nil, myProcess, myProcess)

proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
var p = newCtx(module)
var s = newStackFrame()
s.call = e
s.prc = prc
pushStackFrame(p, s)
result = tryEval(p, e)
if result != nil and result.kind == nkExceptBranch: result = nil
popStackFrame(p)

proc evalConstExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, nil, e, emConst)

proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, prc, e, emStatic)

proc setupMacroParam(x: PNode): PNode =
result = x
if result.kind == nkHiddenStdConv: result = result.sons[1]

proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
# XXX GlobalError() is ugly here, but I don't know a better solution for now
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)

c.callsite = nOrig
var s = newStackFrame()
s.call = n
s.prc = sym
var L = n.safeLen
if L == 0: L = 1
setlen(s.slots, L)
# return value:
s.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
# setup parameters:
for i in 1 .. < L: s.slots[i] = setupMacroParam(n.sons[i])
pushStackFrame(c, s)
discard eval(c, optBody(c, sym))
result = s.slots[0]
popStackFrame(c)
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
dec(evalTemplateCounter)
c.callsite = nil

2 changes: 1 addition & 1 deletion compiler/vmdef.nim
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type

opcNSetIntVal,
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree,
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,

opcSlurp,
opcGorge,
Expand Down
22 changes: 16 additions & 6 deletions compiler/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -674,26 +674,27 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
genUnaryABC(c, n, dest, opcParseStmtToAst)
of mExpandToAst:
InternalError(n.info, "cannot generate code for: " & $m)
of mTypeTrait: InternalError(n.info, "cannot generate code for: " & $m)
of mIs: InternalError(n.info, "cannot generate code for: " & $m)
of mTypeTrait:

InternalError(n.info, "cannot generate code for: " & $m)
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)
of mNChild: genBinaryABC(c, n, dest, opcNChild)
of mNSetChild:
of mNSetChild, mNDel:
unused(n, dest)
var
tmp1 = c.genx(n.sons[1])
tmp2 = c.genx(n.sons[2])
tmp3 = c.genx(n.sons[3])
c.gABC(n, opcNSetChild, tmp1, tmp2, tmp3)
c.gABC(n, if m == mNSetChild: opcNSetChild else: opcNDel, tmp1, tmp2, tmp3)
c.freeTemp(tmp1)
c.freeTemp(tmp2)
c.freeTemp(tmp3)
of mNAdd: genBinaryABC(c, n, dest, opcNAdd)
of mNAddMultiple: genBinaryABC(c, n, dest, opcNAddMultiple)
of mNDel:
InternalError(n.info, "cannot generate code for: " & $m)
of mNKind: genUnaryABC(c, n, dest, opcNKind)
of mNIntVal: genUnaryABC(c, n, dest, opcNIntVal)
of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
Expand Down Expand Up @@ -740,6 +741,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
of mNCallSite:
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcCallSite, dest)
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
c.genCall(n, dest)
else:
Expand Down Expand Up @@ -1166,6 +1168,14 @@ proc genStmt*(c: PCtx; n: PNode): int =
c.gABC(n, opcEof)
InternalAssert d < 0

proc genExpr*(c: PCtx; n: PNode): int =
c.removeLastEof
result = c.code.len
var d: TDest = -1
c.gen(n, d)
InternalAssert d >= 0
c.gABC(n, opcEof, d)

proc genParams(c: PCtx; params: PNode) =
# res.sym.position is already 0
c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
Expand Down
3 changes: 2 additions & 1 deletion todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ version 0.9.4
=============

- new VM:
- implement the glue to replace evals.nim
- implement missing magics
- implement overflow checking
- implement the glue to replace evals.nim
- implement the FFI
- implement on the fly CSE

- make 'bind' default for templates and introduce 'mixin'
Expand Down

0 comments on commit d18c82a

Please sign in to comment.