diff options
Diffstat (limited to 'compiler/vmdef.nim')
-rw-r--r-- | compiler/vmdef.nim | 168 |
1 files changed, 125 insertions, 43 deletions
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index cec61ade5..bdb0aeed1 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,20 +10,44 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets, options, modulegraphs, lineinfos, - tables, btrees +import std/[tables, strutils] + +import ast, idents, options, modulegraphs, lineinfos + +type TInstrType* = uint64 const + regOBits = 8 # Opcode + regABits = 16 + regBBits = 16 + regCBits = 16 + regBxBits = 24 + byteExcess* = 128 # we use excess-K for immediates - wordExcess* = 32768 - MaxLoopIterations* = 1_000_000_000 # max iterations of all loops +# Calculate register shifts, masks and ranges +const + regOShift* = 0.TInstrType + regAShift* = (regOShift + regOBits) + regBShift* = (regAShift + regABits) + regCShift* = (regBShift + regBBits) + regBxShift* = (regAShift + regABits) + + regOMask* = ((1.TInstrType shl regOBits) - 1) + regAMask* = ((1.TInstrType shl regABits) - 1) + regBMask* = ((1.TInstrType shl regBBits) - 1) + regCMask* = ((1.TInstrType shl regCBits) - 1) + regBxMask* = ((1.TInstrType shl regBxBits) - 1) + + wordExcess* = 1 shl (regBxBits-1) + regBxMin* = -wordExcess+1 + regBxMax* = wordExcess-1 type - TRegister* = range[0..255] - TDest* = range[-1 .. 255] - TInstr* = distinct uint32 + TRegister* = range[0..regAMask.int] + TDest* = range[-1..regAMask.int] + TInstr* = distinct TInstrType TOpcode* = enum opcEof, # end of code @@ -32,16 +56,23 @@ type opcYldVal, # yield with a value opcAsgnInt, - opcAsgnStr, opcAsgnFloat, opcAsgnRef, opcAsgnComplex, - opcRegToNode, + opcCastIntToFloat32, # int and float must be of the same byte size + opcCastIntToFloat64, # int and float must be of the same byte size + opcCastFloatToInt32, # int and float must be of the same byte size + opcCastFloatToInt64, # int and float must be of the same byte size + opcCastPtrToInt, + opcCastIntToPtr, + opcFastAsgnComplex, opcNodeToReg, opcLdArr, # a = b[c] + opcLdArrAddr, # a = addr(b[c]) opcWrArr, # a[b] = c opcLdObj, # a = b.c + opcLdObjAddr, # a = addr(b.c) opcWrObj, # a.b = c opcAddrReg, opcAddrNode, @@ -49,6 +80,8 @@ type opcWrDeref, opcWrStrIdx, opcLdStrIdx, # a = b[c] + opcLdStrIdxAddr, # a = addr(b[c]) + opcSlice, # toOpenArray(collection, left, right) opcAddInt, opcAddImmInt, @@ -56,21 +89,24 @@ type opcSubImmInt, opcLenSeq, opcLenStr, + opcLenCstring, opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt, - opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt, + opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, + opcShrInt, opcShlInt, opcAshrInt, opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat, opcLeFloat, opcLtFloat, opcLeu, opcLtu, - opcEqRef, opcEqNimrodNode, opcSameNodeType, + opcEqRef, opcEqNimNode, opcSameNodeType, opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, - opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, - opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, + opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, + opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcIsNil, opcOf, opcIs, - opcSubStr, opcParseFloat, opcConv, opcCast, - opcQuit, opcReset, + opcParseFloat, opcConv, opcCast, + opcQuit, opcInvalidField, opcNarrowS, opcNarrowU, + opcSignExtend, opcAddStrCh, opcAddStrStr, @@ -87,13 +123,15 @@ type opcNIdent, opcNGetType, opcNStrVal, + opcNSigHash, + opcNGetSize, opcNSetIntVal, - opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal, + opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetStrVal, opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym, opcNccValue, opcNccInc, opcNcsAdd, opcNcsIncl, opcNcsLen, opcNcsAt, - opcNctPut, opcNctLen, opcNctGet, opcNctHasNext, opcNctNext, + opcNctPut, opcNctLen, opcNctGet, opcNctHasNext, opcNctNext, opcNodeId, opcSlurp, opcGorge, @@ -103,10 +141,12 @@ type opcNError, opcNWarning, opcNHint, - opcNGetLine, opcNGetColumn, opcNGetFile, + opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine, + opcNSetLineInfoColumn, opcNSetLineInfoFile opcEqIdent, opcStrToIdent, opcGetImpl, + opcGetImplTransf opcEcho, opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ... @@ -135,13 +175,15 @@ type opcAsgnConst, # dest = copy(constants[Bx]) opcLdGlobal, # dest = globals[Bx] opcLdGlobalAddr, # dest = addr(globals[Bx]) + opcLdGlobalDerefFFI, # dest = globals[Bx][] + opcLdGlobalAddrDerefFFI, # globals[Bx][] = ... opcLdImmInt, # dest = immediate value - opcNBindSym, + opcNBindSym, opcNDynBindSym, opcSetType, # dest.typ = types[Bx] opcTypeTrait, - opcMarshalLoad, opcMarshalStore, - opcToNarrowInt + opcSymOwner, + opcSymIsInstantiationOf TBlock* = object label*: PSym @@ -158,7 +200,6 @@ type 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] @@ -176,21 +217,32 @@ type slotTempComplex, # some complex temporary (s.node field is used) slotTempPerm # slot is temporary but permanent (hack) + TRegisterKind* = enum + rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr + TFullReg* = object # with a custom mark proc, we could use the same + # data representation as LuaJit (tagged NaNs). + case kind*: TRegisterKind + of rkNone: nil + of rkInt: intVal*: BiggestInt + of rkFloat: floatVal*: BiggestFloat + of rkNode: node*: PNode + of rkRegisterAddr: regAddr*: ptr TFullReg + of rkNodeAddr: nodeAddr*: ptr PNode + PProc* = ref object blocks*: seq[TBlock] # blocks; temp data structure sym*: PSym - slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] - maxSlots*: int + regInfo*: seq[tuple[inUse: bool, kind: TSlotKind]] VmArgs* = object ra*, rb*, rc*: Natural - slots*: pointer + slots*: ptr UncheckedArray[TFullReg] currentException*: PNode currentLineInfo*: TLineInfo VmCallback* = proc (args: VmArgs) {.closure.} PCtx* = ref TCtx - TCtx* = object of passes.TPassContext # code gen context + TCtx* = object of TPassContext # code gen context code*: seq[TInstr] debug*: seq[TLineInfo] # line info for every instruction; kept separate # to not slow down interpretation @@ -207,47 +259,77 @@ type traceActive*: bool loopIterations*: int comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces - callbacks*: seq[tuple[key: string, value: VmCallback]] + callbacks*: seq[VmCallback] + callbackIndex*: Table[string, int] errorFlag*: string cache*: IdentCache config*: ConfigRef graph*: ModuleGraph oldErrorCount*: int + profiler*: Profiler + templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst + vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC) + procToCodePos*: Table[int, int] + + PStackFrame* = ref TStackFrame + TStackFrame* {.acyclic.} = object + prc*: PSym # current prc; proc that is evaluated + slots*: seq[TFullReg] # parameters passed to the proc + locals; + # parameters come first + next*: PStackFrame # for stacking + comesFrom*: int + safePoints*: seq[int] # used for exception handling + # XXX 'break' should perform cleanup actions + # What does the C backend do for it? + Profiler* = object + tEnter*: float + tos*: PStackFrame TPosition* = distinct int PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx = +proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], - prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, - comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", - cache: cache, config: g.config, graph: g) + prc: PProc(blocks: @[]), module: module, loopIterations: g.config.maxLoopIterationsVM, + comesFromHeuristic: unknownLineInfo, callbacks: @[], callbackIndex: initTable[string, int](), errorFlag: "", + cache: cache, config: g.config, graph: g, idgen: idgen) -proc refresh*(c: PCtx, module: PSym) = +proc refresh*(c: PCtx, module: PSym; idgen: IdGenerator) = c.module = module c.prc = PProc(blocks: @[]) - c.loopIterations = MaxLoopIterations - -proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = - c.callbacks.add((name, callback)) + c.loopIterations = c.config.maxLoopIterationsVM + c.idgen = idgen + +proc reverseName(s: string): string = + result = newStringOfCap(s.len) + let y = s.split('.') + for i in 1..y.len: + result.add y[^i] + if i != y.len: + result.add '.' + +proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} = + result = c.callbacks.len + c.callbacks.add(callback) + c.callbackIndex[reverseName(name)] = result const firstABxInstr* = opcTJmp largeInstrs* = { # instructions which use 2 int32s instead of 1: - opcSubStr, opcConv, opcCast, opcNewSeq, opcOf, - opcMarshalLoad, opcMarshalStore} + opcConv, opcCast, opcNewSeq, opcOf + } slotSomeTemp* = slotTempUnknown relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack} # flag is used to signal opcSeqLen if node is NimNode. const nimNodeFlag* = 16 -template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32) -template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32) -template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32) -template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32) -template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int +template opcode*(x: TInstr): TOpcode = TOpcode(x.TInstrType shr regOShift and regOMask) +template regA*(x: TInstr): TRegister = TRegister(x.TInstrType shr regAShift and regAMask) +template regB*(x: TInstr): TRegister = TRegister(x.TInstrType shr regBShift and regBMask) +template regC*(x: TInstr): TRegister = TRegister(x.TInstrType shr regCShift and regCMask) +template regBx*(x: TInstr): int = (x.TInstrType shr regBxShift and regBxMask).int template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess |