diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/vm.nim | 69 | ||||
-rw-r--r-- | compiler/vmdef.nim | 30 | ||||
-rw-r--r-- | compiler/vmgen.nim | 30 |
3 files changed, 80 insertions, 49 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim index dd8b8d8f2..b2c848287 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -96,19 +96,24 @@ template decodeBx(k: expr) {.immediate, dirty.} = template move(a, b: expr) = system.shallowCopy(a, b) # XXX fix minor 'shallowCopy' overloading bug in compiler -proc asgnRef(x, y: PNode) = - 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) +when false: + proc asgnRef(x, y: PNode) = + 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 proc asgnComplex(x, y: PNode) = myreset(x) @@ -279,7 +284,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = of opcAsgnRef: asgnRef(regs[ra], regs[instr.regB]) of opcWrGlobalRef: - asgnRef(c.globals[instr.regBx-wordExcess-1], regs[ra]) + asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra]) of opcWrGlobal: asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra]) of opcLdArr: @@ -470,24 +475,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = regs[ra].intVal = not regs[rb].intVal of opcEqStr: decodeBC(nkIntLit) - regs[ra].intVal = Ord(regs[rb].strVal == regs[rc].strVal) + regs[ra].intVal = ord(regs[rb].strVal == regs[rc].strVal) of opcLeStr: decodeBC(nkIntLit) - regs[ra].intVal = Ord(regs[rb].strVal <= regs[rc].strVal) + regs[ra].intVal = ord(regs[rb].strVal <= regs[rc].strVal) of opcLtStr: decodeBC(nkIntLit) - regs[ra].intVal = Ord(regs[rb].strVal < regs[rc].strVal) + regs[ra].intVal = ord(regs[rb].strVal < regs[rc].strVal) of opcLeSet: decodeBC(nkIntLit) - regs[ra].intVal = Ord(containsSets(regs[rb], regs[rc])) + regs[ra].intVal = ord(containsSets(regs[rb], regs[rc])) of opcEqSet: decodeBC(nkIntLit) - regs[ra].intVal = Ord(equalSets(regs[rb], regs[rc])) + regs[ra].intVal = ord(equalSets(regs[rb], regs[rc])) of opcLtSet: decodeBC(nkIntLit) let a = regs[rb] let b = regs[rc] - regs[ra].intVal = Ord(containsSets(a, b) and not equalSets(a, b)) + regs[ra].intVal = ord(containsSets(a, b) and not equalSets(a, b)) of opcMulSet: decodeBC(nkCurly) move(regs[ra].sons, nimsets.intersectSets(regs[rb], regs[rc]).sons) @@ -652,9 +657,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = regs[ra] = copyTree(c.globals.sons[rb]) else: asgnComplex(regs[ra], c.globals.sons[rb]) - of opcRepr, opcSetLenStr, opcSetLenSeq, + of opcRepr: + decodeB(nkStrLit) + regs[ra].strVal = renderTree(regs[rb], {renderNoComments}) + of opcQuit: + if c.mode in {emRepl, emStatic}: + Message(c.debug[pc], hintQuitCalled) + quit(int(getOrdValue(regs[ra]))) + else: + return nil + of opcSetLenStr: + decodeB(nkStrLit) + regs[ra].strVal.setLen(regs[rb].getOrdValue.int) + of opcSetLenSeq, opcSwap, opcIsNil, opcOf, - opcCast, opcQuit, opcReset: + opcCast, opcReset: internalError(c.debug[pc], "too implement") of opcNBindSym: # trivial implementation: @@ -670,7 +687,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = regs[ra].sons[regs[rb].intVal.int] = regs[rc] of opcNAdd: declBC() - regs[rb].add(regs[rb]) + regs[rb].add(regs[rc]) regs[ra] = regs[rb] of opcNAddMultiple: declBC() @@ -904,6 +921,7 @@ const evalPass* = makePass(myOpen, nil, myProcess, myProcess) proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode = setupGlobalCtx(module) var c = globalCtx + c.mode = mode let start = genExpr(c, n) assert c.code[start].opcode != opcEof var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil) @@ -935,7 +953,8 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = let start = genProc(c, sym) var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil) - newSeq(tos.slots, c.prc.maxSlots) + let maxSlots = sym.position + newSeq(tos.slots, maxSlots) # setup arguments: var L = n.safeLen if L == 0: L = 1 @@ -945,7 +964,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = # setup parameters: for i in 1 .. < L: tos.slots[i] = setupMacroParam(n.sons[i]) # temporary storage: - for i in L .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) + for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty) result = rawExecute(c, start, tos) if cyclicTree(result): GlobalError(n.info, errCyclicTree) dec(evalMacroCounter) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index bc6824d3b..fabce58d7 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -129,6 +129,20 @@ type label*: PSym fixups*: seq[TPosition] + TEvalMode* = enum ## reason for evaluation + emRepl, ## evaluate because in REPL mode + emConst, ## evaluate for 'const' according to spec + emOptimize, ## evaluate for optimization purposes (same as + ## emConst?) + emStatic ## evaluate for enforced compile time eval + ## ('static' context) + + TSandboxFlag* = enum ## what the evaluation engine should allow + allowCast, ## allow unsafe language feature: 'cast' + allowFFI, ## allow the FFI + allowInfiniteLoops ## allow endless loops + TSandboxFlags* = set[TSandboxFlag] + TSlotKind* = enum # We try to re-use slots in a smart way to # minimize allocations; however the VM supports arbitrary # temporary slot usage. This is required for the parameter @@ -160,25 +174,11 @@ type prc*: PProc module*: PSym callsite*: PNode + mode*: TEvalMode TPosition* = distinct int PEvalContext* = PCtx - - TEvalMode* = enum ## reason for evaluation - emRepl, ## evaluate because in REPL mode - emConst, ## evaluate for 'const' according to spec - emOptimize, ## evaluate for optimization purposes (same as - ## emConst?) - emStatic ## evaluate for enforced compile time eval - ## ('static' context) - - TSandboxFlag* = enum ## what the evaluation engine should allow - allowCast, ## allow unsafe language feature: 'cast' - allowFFI, ## allow the FFI - allowInfiniteLoops ## allow endless loops - TSandboxFlags* = set[TSandboxFlag] - proc newCtx*(module: PSym): PCtx = PCtx(code: @[], debug: @[], diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 37807b2d0..4296609cb 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -112,8 +112,10 @@ const proc getTemp(c: PCtx; typ: PType): TRegister = let c = c.prc - # we prefer the same slot kind here for efficiency: - let k = typ.getSlotKind + # we prefer the same slot kind here for efficiency. Unfortunately for + # discardable return types we may not know the desired type. This can happen + # for e.g. mNAdd[Multiple]: + let k = if typ.isNil: slotTempComplex else: typ.getSlotKind for i in 0 .. c.maxSlots-1: if c.slots[i].kind == k and not c.slots[i].inUse: c.slots[i].inUse = true @@ -179,7 +181,7 @@ proc gen(c: PCtx; n: PNode; dest: TRegister) = proc gen(c: PCtx; n: PNode) = var tmp: TDest = -1 gen(c, n, tmp) - InternalAssert tmp < 0 + #if n.typ.isEmptyType: InternalAssert tmp < 0 proc genx(c: PCtx; n: PNode): TRegister = var tmp: TDest = -1 @@ -463,7 +465,7 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) = c.freeTemp(tmp) proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) = - let tmp = c.genx(n.sons[2]) + let tmp = c.genx(n.sons[1]) c.gABC(n, opc, tmp, 0, 0) c.freeTemp(tmp) @@ -852,11 +854,13 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = else: c.gABC(le, whichAsgnOpc(le, opcWrArr), dest, idx, tmp) c.freeTemp(tmp) - of nkDotExpr: - let dest = c.genx(le.sons[0]) - let idx = c.genx(le.sons[1]) + of nkDotExpr, nkCheckedFieldExpr: + # XXX field checks here + let left = if le.kind == nkDotExpr: le else: le.sons[0] + let dest = c.genx(left.sons[0]) + let idx = c.genx(left.sons[1]) let tmp = c.genx(ri) - c.gABC(le, whichAsgnOpc(le, opcWrObj), dest, idx, tmp) + c.gABC(left, whichAsgnOpc(left, opcWrObj), dest, idx, tmp) c.freeTemp(tmp) of nkSym: let s = le.sym @@ -910,6 +914,10 @@ proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc genObjAccess(c: PCtx; n: PNode; dest: var TDest) = genAccess(c, n, dest, opcLdObj) +proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest) = + # XXX implement field checks! + genAccess(c, n.sons[0], dest, opcLdObj) + proc genArrAccess(c: PCtx; n: PNode; dest: var TDest) = if n.sons[0].typ.skipTypes(abstractVarRange).kind in {tyString, tyCString}: genAccess(c, n, dest, opcLdStrIdx) @@ -1023,7 +1031,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = c.gABx(n, opcLdNull, tmp, c.genType(intType)) for x in n: let a = c.genx(x) - c.gABC(n, opcWrArr, dest, a, tmp) + c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a) c.gABI(n, opcAddImmInt, tmp, tmp, 1) c.freeTemp(a) c.freeTemp(tmp) @@ -1116,6 +1124,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) = unused(n, dest) genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn) of nkDotExpr: genObjAccess(c, n, dest) + of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest) of nkBracketExpr: genArrAccess(c, n, dest) of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcDeref) of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddr) @@ -1288,5 +1297,8 @@ proc genProc(c: PCtx; s: PSym): int = c.gABC(body, opcEof, eofInstr.regA) s.position = c.prc.maxSlots c.prc = oldPrc + #if s.name.s == "xmlConstructor": + # echoCode(c) else: + c.prc.maxSlots = s.position result = x.intVal.int |