1# 2# 3# The Nim Compiler 4# (c) Copyright 2015 Andreas Rumpf 5# 6# See the file "copying.txt", included in this 7# distribution, for details about the copyright. 8# 9 10## This file implements the new evaluation engine for Nim code. 11## An instruction is 1-3 int32s in memory, it is a register based VM. 12 13 14import 15 std/[strutils, tables, parseutils], 16 msgs, vmdef, vmgen, nimsets, types, passes, 17 parser, vmdeps, idents, trees, renderer, options, transf, 18 vmmarshal, gorgeimpl, lineinfos, btrees, macrocacheimpl, 19 modulegraphs, sighashes, int128, vmprofiler 20 21import ast except getstr 22from semfold import leValueConv, ordinalValToString 23from evaltempl import evalTemplate 24from magicsys import getSysType 25 26const 27 traceCode = defined(nimVMDebug) 28 29when hasFFI: 30 import evalffi 31 32 33proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = 34 if x != nil: 35 if recursionLimit == 0: 36 var calls = 0 37 var x = x 38 while x != nil: 39 inc calls 40 x = x.next 41 msgWriteln(c.config, $calls & " calls omitted\n", {msgNoUnitSep}) 42 return 43 stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1) 44 var info = c.debug[pc] 45 # we now use a format similar to the one in lib/system/excpt.nim 46 var s = "" 47 # todo: factor with quotedFilename 48 if optExcessiveStackTrace in c.config.globalOptions: 49 s = toFullPath(c.config, info) 50 else: 51 s = toFilename(c.config, info) 52 var line = toLinenumber(info) 53 var col = toColumn(info) 54 if line > 0: 55 s.add('(') 56 s.add($line) 57 s.add(", ") 58 s.add($(col + ColOffset)) 59 s.add(')') 60 if x.prc != nil: 61 for k in 1..max(1, 25-s.len): s.add(' ') 62 s.add(x.prc.name.s) 63 msgWriteln(c.config, s, {msgNoUnitSep}) 64 65proc stackTraceImpl(c: PCtx, tos: PStackFrame, pc: int, 66 msg: string, lineInfo: TLineInfo, infoOrigin: InstantiationInfo) {.noinline.} = 67 # noinline to avoid code bloat 68 msgWriteln(c.config, "stack trace: (most recent call last)", {msgNoUnitSep}) 69 stackTraceAux(c, tos, pc) 70 let action = if c.mode == emRepl: doRaise else: doNothing 71 # XXX test if we want 'globalError' for every mode 72 let lineInfo = if lineInfo == TLineInfo.default: c.debug[pc] else: lineInfo 73 liMessage(c.config, lineInfo, errGenerated, msg, action, infoOrigin) 74 75template stackTrace(c: PCtx, tos: PStackFrame, pc: int, 76 msg: string, lineInfo: TLineInfo = TLineInfo.default) = 77 stackTraceImpl(c, tos, pc, msg, lineInfo, instantiationInfo(-2, fullPaths = true)) 78 return 79 80proc bailOut(c: PCtx; tos: PStackFrame) = 81 stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " & 82 c.currentExceptionA[3].skipColon.strVal & 83 " [" & c.currentExceptionA[2].skipColon.strVal & "]") 84 85when not defined(nimComputedGoto): 86 {.pragma: computedGoto.} 87 88proc ensureKind(n: var TFullReg, kind: TRegisterKind) = 89 if n.kind != kind: 90 n = TFullReg(kind: kind) 91 92template ensureKind(k: untyped) {.dirty.} = 93 ensureKind(regs[ra], k) 94 95template decodeB(k: untyped) {.dirty.} = 96 let rb = instr.regB 97 ensureKind(k) 98 99template decodeBC(k: untyped) {.dirty.} = 100 let rb = instr.regB 101 let rc = instr.regC 102 ensureKind(k) 103 104template declBC() {.dirty.} = 105 let rb = instr.regB 106 let rc = instr.regC 107 108template decodeBImm(k: untyped) {.dirty.} = 109 let rb = instr.regB 110 let imm = instr.regC - byteExcess 111 ensureKind(k) 112 113template decodeBx(k: untyped) {.dirty.} = 114 let rbx = instr.regBx - wordExcess 115 ensureKind(k) 116 117template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b) 118# XXX fix minor 'shallowCopy' overloading bug in compiler 119 120proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: bool): bool = 121 # nim bug: `isAssign: static bool` doesn't work, giving odd compiler error 122 template fun(field, T, rkind) = 123 if isAssign: 124 cast[ptr T](address)[] = T(r.field) 125 else: 126 r.ensureKind(rkind) 127 let val = cast[ptr T](address)[] 128 when T is SomeInteger | char: 129 r.field = BiggestInt(val) 130 else: 131 r.field = val 132 return true 133 134 ## see also typeinfo.getBiggestInt 135 case typ.kind 136 of tyChar: fun(intVal, char, rkInt) 137 of tyInt: fun(intVal, int, rkInt) 138 of tyInt8: fun(intVal, int8, rkInt) 139 of tyInt16: fun(intVal, int16, rkInt) 140 of tyInt32: fun(intVal, int32, rkInt) 141 of tyInt64: fun(intVal, int64, rkInt) 142 of tyUInt: fun(intVal, uint, rkInt) 143 of tyUInt8: fun(intVal, uint8, rkInt) 144 of tyUInt16: fun(intVal, uint16, rkInt) 145 of tyUInt32: fun(intVal, uint32, rkInt) 146 of tyUInt64: fun(intVal, uint64, rkInt) # note: differs from typeinfo.getBiggestInt 147 of tyFloat: fun(floatVal, float, rkFloat) 148 of tyFloat32: fun(floatVal, float32, rkFloat) 149 of tyFloat64: fun(floatVal, float64, rkFloat) 150 else: return false 151 152proc createStrKeepNode(x: var TFullReg; keepNode=true) = 153 if x.node.isNil or not keepNode: 154 x.node = newNode(nkStrLit) 155 elif x.node.kind == nkNilLit and keepNode: 156 when defined(useNodeIds): 157 let id = x.node.id 158 x.node[] = TNode(kind: nkStrLit) 159 when defined(useNodeIds): 160 x.node.id = id 161 elif x.node.kind notin {nkStrLit..nkTripleStrLit} or 162 nfAllConst in x.node.flags: 163 # XXX this is hacky; tests/txmlgen triggers it: 164 x.node = newNode(nkStrLit) 165 # It not only hackey, it is also wrong for tgentemplate. The primary 166 # cause of bugs like these is that the VM does not properly distinguish 167 # between variable definitions (var foo = e) and variable updates (foo = e). 168 169include vmhooks 170 171template createStr(x) = 172 x.node = newNode(nkStrLit) 173 174template createSet(x) = 175 x.node = newNode(nkCurly) 176 177proc moveConst(x: var TFullReg, y: TFullReg) = 178 x.ensureKind(y.kind) 179 case x.kind 180 of rkNone: discard 181 of rkInt: x.intVal = y.intVal 182 of rkFloat: x.floatVal = y.floatVal 183 of rkNode: x.node = y.node 184 of rkRegisterAddr: x.regAddr = y.regAddr 185 of rkNodeAddr: x.nodeAddr = y.nodeAddr 186 187# this seems to be the best way to model the reference semantics 188# of system.NimNode: 189template asgnRef(x, y: untyped) = moveConst(x, y) 190 191proc copyValue(src: PNode): PNode = 192 if src == nil or nfIsRef in src.flags: 193 return src 194 result = newNode(src.kind) 195 result.info = src.info 196 result.typ = src.typ 197 result.flags = src.flags * PersistentNodeFlags 198 result.comment = src.comment 199 when defined(useNodeIds): 200 if result.id == nodeIdToDebug: 201 echo "COMES FROM ", src.id 202 case src.kind 203 of nkCharLit..nkUInt64Lit: result.intVal = src.intVal 204 of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal 205 of nkSym: result.sym = src.sym 206 of nkIdent: result.ident = src.ident 207 of nkStrLit..nkTripleStrLit: result.strVal = src.strVal 208 else: 209 newSeq(result.sons, src.len) 210 for i in 0..<src.len: 211 result[i] = copyValue(src[i]) 212 213proc asgnComplex(x: var TFullReg, y: TFullReg) = 214 x.ensureKind(y.kind) 215 case x.kind 216 of rkNone: discard 217 of rkInt: x.intVal = y.intVal 218 of rkFloat: x.floatVal = y.floatVal 219 of rkNode: x.node = copyValue(y.node) 220 of rkRegisterAddr: x.regAddr = y.regAddr 221 of rkNodeAddr: x.nodeAddr = y.nodeAddr 222 223proc fastAsgnComplex(x: var TFullReg, y: TFullReg) = 224 x.ensureKind(y.kind) 225 case x.kind 226 of rkNone: discard 227 of rkInt: x.intVal = y.intVal 228 of rkFloat: x.floatVal = y.floatVal 229 of rkNode: x.node = y.node 230 of rkRegisterAddr: x.regAddr = y.regAddr 231 of rkNodeAddr: x.nodeAddr = y.nodeAddr 232 233proc writeField(n: var PNode, x: TFullReg) = 234 case x.kind 235 of rkNone: discard 236 of rkInt: 237 if n.kind == nkNilLit: 238 n[] = TNode(kind: nkIntLit) # ideally, `nkPtrLit` 239 n.intVal = x.intVal 240 of rkFloat: n.floatVal = x.floatVal 241 of rkNode: n = copyValue(x.node) 242 of rkRegisterAddr: writeField(n, x.regAddr[]) 243 of rkNodeAddr: n = x.nodeAddr[] 244 245proc putIntoReg(dest: var TFullReg; n: PNode) = 246 case n.kind 247 of nkStrLit..nkTripleStrLit: 248 dest = TFullReg(kind: rkNode, node: newStrNode(nkStrLit, n.strVal)) 249 of nkIntLit: # use `nkPtrLit` once this is added 250 if dest.kind == rkNode: dest.node = n 251 elif n.typ != nil and n.typ.kind in PtrLikeKinds: 252 dest = TFullReg(kind: rkNode, node: n) 253 else: 254 dest = TFullReg(kind: rkInt, intVal: n.intVal) 255 of {nkCharLit..nkUInt64Lit} - {nkIntLit}: 256 dest = TFullReg(kind: rkInt, intVal: n.intVal) 257 of nkFloatLit..nkFloat128Lit: 258 dest = TFullReg(kind: rkFloat, floatVal: n.floatVal) 259 else: 260 dest = TFullReg(kind: rkNode, node: n) 261 262proc regToNode(x: TFullReg): PNode = 263 case x.kind 264 of rkNone: result = newNode(nkEmpty) 265 of rkInt: result = newNode(nkIntLit); result.intVal = x.intVal 266 of rkFloat: result = newNode(nkFloatLit); result.floatVal = x.floatVal 267 of rkNode: result = x.node 268 of rkRegisterAddr: result = regToNode(x.regAddr[]) 269 of rkNodeAddr: result = x.nodeAddr[] 270 271template getstr(a: untyped): untyped = 272 (if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal))) 273 274proc pushSafePoint(f: PStackFrame; pc: int) = 275 f.safePoints.add(pc) 276 277proc popSafePoint(f: PStackFrame) = 278 discard f.safePoints.pop() 279 280type 281 ExceptionGoto = enum 282 ExceptionGotoHandler, 283 ExceptionGotoFinally, 284 ExceptionGotoUnhandled 285 286proc findExceptionHandler(c: PCtx, f: PStackFrame, exc: PNode): 287 tuple[why: ExceptionGoto, where: int] = 288 let raisedType = exc.typ.skipTypes(abstractPtrs) 289 290 while f.safePoints.len > 0: 291 var pc = f.safePoints.pop() 292 293 var matched = false 294 var pcEndExcept = pc 295 296 # Scan the chain of exceptions starting at pc. 297 # The structure is the following: 298 # pc - opcExcept, <end of this block> 299 # - opcExcept, <pattern1> 300 # - opcExcept, <pattern2> 301 # ... 302 # - opcExcept, <patternN> 303 # - Exception handler body 304 # - ... more opcExcept blocks may follow 305 # - ... an optional opcFinally block may follow 306 # 307 # Note that the exception handler body already contains a jump to the 308 # finally block or, if that's not present, to the point where the execution 309 # should continue. 310 # Also note that opcFinally blocks are the last in the chain. 311 while c.code[pc].opcode == opcExcept: 312 # Where this Except block ends 313 pcEndExcept = pc + c.code[pc].regBx - wordExcess 314 inc pc 315 316 # A series of opcExcept follows for each exception type matched 317 while c.code[pc].opcode == opcExcept: 318 let excIndex = c.code[pc].regBx - wordExcess 319 let exceptType = 320 if excIndex > 0: c.types[excIndex].skipTypes(abstractPtrs) 321 else: nil 322 323 # echo typeToString(exceptType), " ", typeToString(raisedType) 324 325 # Determine if the exception type matches the pattern 326 if exceptType.isNil or inheritanceDiff(raisedType, exceptType) <= 0: 327 matched = true 328 break 329 330 inc pc 331 332 # Skip any further ``except`` pattern and find the first instruction of 333 # the handler body 334 while c.code[pc].opcode == opcExcept: 335 inc pc 336 337 if matched: 338 break 339 340 # If no handler in this chain is able to catch this exception we check if 341 # the "parent" chains are able to. If this chain ends with a `finally` 342 # block we must execute it before continuing. 343 pc = pcEndExcept 344 345 # Where the handler body starts 346 let pcBody = pc 347 348 if matched: 349 return (ExceptionGotoHandler, pcBody) 350 elif c.code[pc].opcode == opcFinally: 351 # The +1 here is here because we don't want to execute it since we've 352 # already pop'd this statepoint from the stack. 353 return (ExceptionGotoFinally, pc + 1) 354 355 return (ExceptionGotoUnhandled, 0) 356 357proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = 358 # Walk up the chain of safepoints and return the PC of the first `finally` 359 # block we find or -1 if no such block is found. 360 # Note that the safepoint is removed once the function returns! 361 result = -1 362 363 # Traverse the stack starting from the end in order to execute the blocks in 364 # the intended order 365 for i in 1..f.safePoints.len: 366 var pc = f.safePoints[^i] 367 # Skip the `except` blocks 368 while c.code[pc].opcode == opcExcept: 369 pc += c.code[pc].regBx - wordExcess 370 if c.code[pc].opcode == opcFinally: 371 discard f.safePoints.pop 372 return pc + 1 373 374proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = 375 if desttyp.kind == tyString: 376 dest.ensureKind(rkNode) 377 dest.node = newNode(nkStrLit) 378 let styp = srctyp.skipTypes(abstractRange) 379 case styp.kind 380 of tyEnum: 381 let n = styp.n 382 let x = src.intVal.int 383 if x <% n.len and (let f = n[x].sym; f.position == x): 384 dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal 385 else: 386 for i in 0..<n.len: 387 if n[i].kind != nkSym: internalError(c.config, "opConv for enum") 388 let f = n[i].sym 389 if f.position == x: 390 dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal 391 return 392 dest.node.strVal = styp.sym.name.s & " " & $x 393 of tyInt..tyInt64: 394 dest.node.strVal = $src.intVal 395 of tyUInt..tyUInt64: 396 dest.node.strVal = $uint64(src.intVal) 397 of tyBool: 398 dest.node.strVal = if src.intVal == 0: "false" else: "true" 399 of tyFloat..tyFloat128: 400 dest.node.strVal = $src.floatVal 401 of tyString: 402 dest.node.strVal = src.node.strVal 403 of tyCstring: 404 if src.node.kind == nkBracket: 405 # Array of chars 406 var strVal = "" 407 for son in src.node.sons: 408 let c = char(son.intVal) 409 if c == '\0': break 410 strVal.add(c) 411 dest.node.strVal = strVal 412 else: 413 dest.node.strVal = src.node.strVal 414 of tyChar: 415 dest.node.strVal = $chr(src.intVal) 416 else: 417 internalError(c.config, "cannot convert to string " & desttyp.typeToString) 418 else: 419 let desttyp = skipTypes(desttyp, abstractVarRange) 420 case desttyp.kind 421 of tyInt..tyInt64: 422 dest.ensureKind(rkInt) 423 case skipTypes(srctyp, abstractRange).kind 424 of tyFloat..tyFloat64: 425 dest.intVal = int(src.floatVal) 426 else: 427 dest.intVal = src.intVal 428 if toInt128(dest.intVal) < firstOrd(c.config, desttyp) or toInt128(dest.intVal) > lastOrd(c.config, desttyp): 429 return true 430 of tyUInt..tyUInt64: 431 dest.ensureKind(rkInt) 432 let styp = srctyp.skipTypes(abstractRange) # skip distinct types(dest type could do this too if needed) 433 case styp.kind 434 of tyFloat..tyFloat64: 435 dest.intVal = int(src.floatVal) 436 else: 437 let srcSize = getSize(c.config, styp) 438 let destSize = getSize(c.config, desttyp) 439 let srcDist = (sizeof(src.intVal) - srcSize) * 8 440 let destDist = (sizeof(dest.intVal) - destSize) * 8 441 var value = cast[BiggestUInt](src.intVal) 442 value = (value shl srcDist) shr srcDist 443 value = (value shl destDist) shr destDist 444 dest.intVal = cast[BiggestInt](value) 445 of tyBool: 446 dest.ensureKind(rkInt) 447 dest.intVal = 448 case skipTypes(srctyp, abstractRange).kind 449 of tyFloat..tyFloat64: int(src.floatVal != 0.0) 450 else: int(src.intVal != 0) 451 of tyFloat..tyFloat64: 452 dest.ensureKind(rkFloat) 453 case skipTypes(srctyp, abstractRange).kind 454 of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar: 455 dest.floatVal = toBiggestFloat(src.intVal) 456 else: 457 dest.floatVal = src.floatVal 458 of tyObject: 459 if srctyp.skipTypes(abstractVarRange).kind != tyObject: 460 internalError(c.config, "invalid object-to-object conversion") 461 # A object-to-object conversion is essentially a no-op 462 moveConst(dest, src) 463 else: 464 asgnComplex(dest, src) 465 466proc compile(c: PCtx, s: PSym): int = 467 result = vmgen.genProc(c, s) 468 when debugEchoCode: c.echoCode result 469 #c.echoCode 470 471template handleJmpBack() {.dirty.} = 472 if c.loopIterations <= 0: 473 if allowInfiniteLoops in c.features: 474 c.loopIterations = c.config.maxLoopIterationsVM 475 else: 476 msgWriteln(c.config, "stack trace: (most recent call last)", {msgNoUnitSep}) 477 stackTraceAux(c, tos, pc) 478 globalError(c.config, c.debug[pc], errTooManyIterations % $c.config.maxLoopIterationsVM) 479 dec(c.loopIterations) 480 481proc recSetFlagIsRef(arg: PNode) = 482 if arg.kind notin {nkStrLit..nkTripleStrLit}: 483 arg.flags.incl(nfIsRef) 484 for i in 0..<arg.safeLen: 485 arg[i].recSetFlagIsRef 486 487proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) = 488 let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}) 489 let oldLen = node.len 490 setLen(node.sons, newLen) 491 if oldLen < newLen: 492 for i in oldLen..<newLen: 493 node[i] = getNullValue(typ[0], info, c.config) 494 495const 496 errNilAccess = "attempt to access a nil address" 497 errOverOrUnderflow = "over- or underflow" 498 errConstantDivisionByZero = "division by zero" 499 errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'" 500 errTooManyIterations = "interpretation requires too many iterations; " & 501 "if you are sure this is not a bug in your code, compile with `--maxLoopIterationsVM:number` (current value: $1)" 502 errFieldXNotFound = "node lacks field: " 503 504 505template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool = 506 let node = node2 # prevent double evaluation 507 if node.kind == nkNilLit: 508 stackTrace(c, tos, pc, errNilAccess) 509 let typ = node.typ 510 if nfIsPtr in node.flags or (typ != nil and typ.kind == tyPtr): 511 assert node.kind == nkIntLit, $(node.kind) 512 assert typ != nil 513 let typ2 = if typ.kind == tyPtr: typ[0] else: typ 514 if not derefPtrToReg(node.intVal, typ2, reg, isAssign = isAssign2): 515 # tyObject not supported in this context 516 stackTrace(c, tos, pc, "deref unsupported ptr type: " & $(typeToString(typ), typ.kind)) 517 true 518 else: 519 false 520 521when not defined(nimHasSinkInference): 522 {.pragma: nosinks.} 523 524proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = 525 var pc = start 526 var tos = tos 527 # Used to keep track of where the execution is resumed. 528 var savedPC = -1 529 var savedFrame: PStackFrame 530 when defined(gcArc) or defined(gcOrc): 531 template updateRegsAlias = discard 532 template regs: untyped = tos.slots 533 else: 534 template updateRegsAlias = 535 move(regs, tos.slots) 536 var regs: seq[TFullReg] # alias to tos.slots for performance 537 updateRegsAlias 538 #echo "NEW RUN ------------------------" 539 while true: 540 #{.computedGoto.} 541 let instr = c.code[pc] 542 let ra = instr.regA 543 544 when traceCode: 545 template regDescr(name, r): string = 546 let kind = if r < regs.len: $regs[r].kind else: "" 547 let ret = name & ": " & $r & " " & $kind 548 alignLeft(ret, 15) 549 echo "PC:$pc $opcode $ra $rb $rc" % [ 550 "pc", $pc, "opcode", alignLeft($c.code[pc].opcode, 15), 551 "ra", regDescr("ra", ra), "rb", regDescr("rb", instr.regB), 552 "rc", regDescr("rc", instr.regC)] 553 if c.config.isVmTrace: 554 # unlike nimVMDebug, this doesn't require re-compiling nim and is controlled by user code 555 let info = c.debug[pc] 556 # other useful variables: c.loopIterations 557 echo "$# [$#] $#" % [c.config$info, $instr.opcode, c.config.sourceLine(info)] 558 c.profiler.enter(c, tos) 559 case instr.opcode 560 of opcEof: return regs[ra] 561 of opcRet: 562 let newPc = c.cleanUpOnReturn(tos) 563 # Perform any cleanup action before returning 564 if newPc < 0: 565 pc = tos.comesFrom 566 let retVal = regs[0] 567 tos = tos.next 568 if tos.isNil: 569 return retVal 570 571 updateRegsAlias 572 assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn} 573 if c.code[pc].opcode == opcIndCallAsgn: 574 regs[c.code[pc].regA] = retVal 575 else: 576 savedPC = pc 577 savedFrame = tos 578 # The -1 is needed because at the end of the loop we increment `pc` 579 pc = newPc - 1 580 of opcYldYoid: assert false 581 of opcYldVal: assert false 582 of opcAsgnInt: 583 decodeB(rkInt) 584 regs[ra].intVal = regs[rb].intVal 585 of opcAsgnFloat: 586 decodeB(rkFloat) 587 regs[ra].floatVal = regs[rb].floatVal 588 of opcCastFloatToInt32: 589 let rb = instr.regB 590 ensureKind(rkInt) 591 regs[ra].intVal = cast[int32](float32(regs[rb].floatVal)) 592 of opcCastFloatToInt64: 593 let rb = instr.regB 594 ensureKind(rkInt) 595 regs[ra].intVal = cast[int64](regs[rb].floatVal) 596 of opcCastIntToFloat32: 597 let rb = instr.regB 598 ensureKind(rkFloat) 599 regs[ra].floatVal = cast[float32](regs[rb].intVal) 600 of opcCastIntToFloat64: 601 let rb = instr.regB 602 ensureKind(rkFloat) 603 regs[ra].floatVal = cast[float64](regs[rb].intVal) 604 605 of opcCastPtrToInt: # RENAME opcCastPtrOrRefToInt 606 decodeBImm(rkInt) 607 case imm 608 of 1: # PtrLikeKinds 609 case regs[rb].kind 610 of rkNode: 611 regs[ra].intVal = cast[int](regs[rb].node.intVal) 612 of rkNodeAddr: 613 regs[ra].intVal = cast[int](regs[rb].nodeAddr) 614 else: 615 stackTrace(c, tos, pc, "opcCastPtrToInt: got " & $regs[rb].kind) 616 of 2: # tyRef 617 regs[ra].intVal = cast[int](regs[rb].node) 618 else: assert false, $imm 619 of opcCastIntToPtr: 620 let rb = instr.regB 621 let typ = regs[ra].node.typ 622 let node2 = newNodeIT(nkIntLit, c.debug[pc], typ) 623 case regs[rb].kind 624 of rkInt: node2.intVal = regs[rb].intVal 625 of rkNode: 626 if regs[rb].node.typ.kind notin PtrLikeKinds: 627 stackTrace(c, tos, pc, "opcCastIntToPtr: regs[rb].node.typ: " & $regs[rb].node.typ.kind) 628 node2.intVal = regs[rb].node.intVal 629 else: stackTrace(c, tos, pc, "opcCastIntToPtr: regs[rb].kind: " & $regs[rb].kind) 630 regs[ra].node = node2 631 of opcAsgnComplex: 632 asgnComplex(regs[ra], regs[instr.regB]) 633 of opcFastAsgnComplex: 634 fastAsgnComplex(regs[ra], regs[instr.regB]) 635 of opcAsgnRef: 636 asgnRef(regs[ra], regs[instr.regB]) 637 of opcNodeToReg: 638 let ra = instr.regA 639 let rb = instr.regB 640 # opcDeref might already have loaded it into a register. XXX Let's hope 641 # this is still correct this way: 642 if regs[rb].kind != rkNode: 643 regs[ra] = regs[rb] 644 else: 645 assert regs[rb].kind == rkNode 646 let nb = regs[rb].node 647 case nb.kind 648 of nkCharLit..nkUInt64Lit: 649 ensureKind(rkInt) 650 regs[ra].intVal = nb.intVal 651 of nkFloatLit..nkFloat64Lit: 652 ensureKind(rkFloat) 653 regs[ra].floatVal = nb.floatVal 654 else: 655 ensureKind(rkNode) 656 regs[ra].node = nb 657 of opcLdArr: 658 # a = b[c] 659 decodeBC(rkNode) 660 if regs[rc].intVal > high(int): 661 stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int))) 662 let idx = regs[rc].intVal.int 663 let src = regs[rb].node 664 if src.kind in {nkStrLit..nkTripleStrLit}: 665 if idx <% src.strVal.len: 666 regs[ra].node = newNodeI(nkCharLit, c.debug[pc]) 667 regs[ra].node.intVal = src.strVal[idx].ord 668 else: 669 stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.strVal.len-1)) 670 elif src.kind notin {nkEmpty..nkFloat128Lit} and idx <% src.len: 671 regs[ra].node = src[idx] 672 else: 673 stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1)) 674 of opcLdArrAddr: 675 # a = addr(b[c]) 676 decodeBC(rkNodeAddr) 677 if regs[rc].intVal > high(int): 678 stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int))) 679 let idx = regs[rc].intVal.int 680 let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[] 681 if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len: 682 regs[ra].nodeAddr = addr src.sons[idx] 683 else: 684 stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1)) 685 of opcLdStrIdx: 686 decodeBC(rkInt) 687 let idx = regs[rc].intVal.int 688 let s = regs[rb].node.strVal 689 if idx <% s.len: 690 regs[ra].intVal = s[idx].ord 691 else: 692 stackTrace(c, tos, pc, formatErrorIndexBound(idx, s.len-1)) 693 of opcLdStrIdxAddr: 694 # a = addr(b[c]); similar to opcLdArrAddr 695 decodeBC(rkNode) 696 if regs[rc].intVal > high(int): 697 stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int))) 698 let idx = regs[rc].intVal.int 699 let s = regs[rb].node.strVal.addr # or `byaddr` 700 if idx <% s[].len: 701 # `makePtrType` not accessible from vm.nim 702 let typ = newType(tyPtr, nextTypeId c.idgen, c.module.owner) 703 typ.add getSysType(c.graph, c.debug[pc], tyChar) 704 let node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit 705 node.intVal = cast[int](s[][idx].addr) 706 node.flags.incl nfIsPtr 707 regs[ra].node = node 708 else: 709 stackTrace(c, tos, pc, formatErrorIndexBound(idx, s[].len-1)) 710 of opcWrArr: 711 # a[b] = c 712 decodeBC(rkNode) 713 let idx = regs[rb].intVal.int 714 let arr = regs[ra].node 715 if arr.kind in {nkStrLit..nkTripleStrLit}: 716 if idx <% arr.strVal.len: 717 arr.strVal[idx] = chr(regs[rc].intVal) 718 else: 719 stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.strVal.len-1)) 720 elif idx <% arr.len: 721 writeField(arr[idx], regs[rc]) 722 else: 723 stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.safeLen-1)) 724 of opcLdObj: 725 # a = b.c 726 decodeBC(rkNode) 727 let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[] 728 case src.kind 729 of nkEmpty..nkNilLit: 730 # for nkPtrLit, this could be supported in the future, use something like: 731 # derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false) 732 # where we compute the offset in bytes for field rc 733 stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc)) 734 of nkObjConstr: 735 let n = src[rc + 1].skipColon 736 regs[ra].node = n 737 else: 738 let n = src[rc] 739 regs[ra].node = n 740 of opcLdObjAddr: 741 # a = addr(b.c) 742 decodeBC(rkNodeAddr) 743 let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[] 744 case src.kind 745 of nkEmpty..nkNilLit: 746 stackTrace(c, tos, pc, errNilAccess) 747 of nkObjConstr: 748 let n = src.sons[rc + 1] 749 if n.kind == nkExprColonExpr: 750 regs[ra].nodeAddr = addr n.sons[1] 751 else: 752 regs[ra].nodeAddr = addr src.sons[rc + 1] 753 else: 754 regs[ra].nodeAddr = addr src.sons[rc] 755 of opcWrObj: 756 # a.b = c 757 decodeBC(rkNode) 758 assert regs[ra].node != nil 759 let shiftedRb = rb + ord(regs[ra].node.kind == nkObjConstr) 760 let dest = regs[ra].node 761 if dest.kind == nkNilLit: 762 stackTrace(c, tos, pc, errNilAccess) 763 elif dest[shiftedRb].kind == nkExprColonExpr: 764 writeField(dest[shiftedRb][1], regs[rc]) 765 else: 766 writeField(dest[shiftedRb], regs[rc]) 767 of opcWrStrIdx: 768 decodeBC(rkNode) 769 let idx = regs[rb].intVal.int 770 if idx <% regs[ra].node.strVal.len: 771 regs[ra].node.strVal[idx] = chr(regs[rc].intVal) 772 else: 773 stackTrace(c, tos, pc, formatErrorIndexBound(idx, regs[ra].node.strVal.len-1)) 774 of opcAddrReg: 775 decodeB(rkRegisterAddr) 776 regs[ra].regAddr = addr(regs[rb]) 777 of opcAddrNode: 778 decodeB(rkNodeAddr) 779 case regs[rb].kind 780 of rkNode: 781 regs[ra].nodeAddr = addr(regs[rb].node) 782 of rkNodeAddr: # bug #14339 783 regs[ra].nodeAddr = regs[rb].nodeAddr 784 else: 785 stackTrace(c, tos, pc, "limited VM support for 'addr', got kind: " & $regs[rb].kind) 786 of opcLdDeref: 787 # a = b[] 788 let ra = instr.regA 789 let rb = instr.regB 790 case regs[rb].kind 791 of rkNodeAddr: 792 ensureKind(rkNode) 793 regs[ra].node = regs[rb].nodeAddr[] 794 of rkRegisterAddr: 795 ensureKind(regs[rb].regAddr.kind) 796 regs[ra] = regs[rb].regAddr[] 797 of rkNode: 798 if regs[rb].node.kind == nkRefTy: 799 regs[ra].node = regs[rb].node[0] 800 elif not maybeHandlePtr(regs[rb].node, regs[ra], false): 801 ## e.g.: typ.kind = tyObject 802 ensureKind(rkNode) 803 regs[ra].node = regs[rb].node 804 else: 805 stackTrace(c, tos, pc, errNilAccess & " kind: " & $regs[rb].kind) 806 of opcWrDeref: 807 # a[] = c; b unused 808 let ra = instr.regA 809 let rc = instr.regC 810 case regs[ra].kind 811 of rkNodeAddr: 812 let n = regs[rc].regToNode 813 # `var object` parameters are sent as rkNodeAddr. When they are mutated 814 # vmgen generates opcWrDeref, which means that we must dereference 815 # twice. 816 # TODO: This should likely be handled differently in vmgen. 817 let nAddr = regs[ra].nodeAddr 818 if nAddr[] == nil: stackTrace(c, tos, pc, "opcWrDeref internal error") # refs bug #16613 819 if (nfIsRef notin nAddr[].flags and nfIsRef notin n.flags): nAddr[][] = n[] 820 else: nAddr[] = n 821 of rkRegisterAddr: regs[ra].regAddr[] = regs[rc] 822 of rkNode: 823 # xxx: also check for nkRefTy as in opcLdDeref? 824 if not maybeHandlePtr(regs[ra].node, regs[rc], true): 825 regs[ra].node[] = regs[rc].regToNode[] 826 regs[ra].node.flags.incl nfIsRef 827 else: stackTrace(c, tos, pc, errNilAccess) 828 of opcAddInt: 829 decodeBC(rkInt) 830 let 831 bVal = regs[rb].intVal 832 cVal = regs[rc].intVal 833 sum = bVal +% cVal 834 if (sum xor bVal) >= 0 or (sum xor cVal) >= 0: 835 regs[ra].intVal = sum 836 else: 837 stackTrace(c, tos, pc, errOverOrUnderflow) 838 of opcAddImmInt: 839 decodeBImm(rkInt) 840 #message(c.config, c.debug[pc], warnUser, "came here") 841 #debug regs[rb].node 842 let 843 bVal = regs[rb].intVal 844 cVal = imm 845 sum = bVal +% cVal 846 if (sum xor bVal) >= 0 or (sum xor cVal) >= 0: 847 regs[ra].intVal = sum 848 else: 849 stackTrace(c, tos, pc, errOverOrUnderflow) 850 of opcSubInt: 851 decodeBC(rkInt) 852 let 853 bVal = regs[rb].intVal 854 cVal = regs[rc].intVal 855 diff = bVal -% cVal 856 if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0: 857 regs[ra].intVal = diff 858 else: 859 stackTrace(c, tos, pc, errOverOrUnderflow) 860 of opcSubImmInt: 861 decodeBImm(rkInt) 862 let 863 bVal = regs[rb].intVal 864 cVal = imm 865 diff = bVal -% cVal 866 if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0: 867 regs[ra].intVal = diff 868 else: 869 stackTrace(c, tos, pc, errOverOrUnderflow) 870 of opcLenSeq: 871 decodeBImm(rkInt) 872 #assert regs[rb].kind == nkBracket 873 let high = (imm and 1) # discard flags 874 if (imm and nimNodeFlag) != 0: 875 # used by mNLen (NimNode.len) 876 regs[ra].intVal = regs[rb].node.safeLen - high 877 else: 878 # safeArrLen also return string node len 879 # used when string is passed as openArray in VM 880 regs[ra].intVal = regs[rb].node.safeArrLen - high 881 of opcLenStr: 882 decodeBImm(rkInt) 883 assert regs[rb].kind == rkNode 884 regs[ra].intVal = regs[rb].node.strVal.len - imm 885 of opcLenCstring: 886 decodeBImm(rkInt) 887 assert regs[rb].kind == rkNode 888 regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm 889 of opcIncl: 890 decodeB(rkNode) 891 let b = regs[rb].regToNode 892 if not inSet(regs[ra].node, b): 893 regs[ra].node.add copyTree(b) 894 of opcInclRange: 895 decodeBC(rkNode) 896 var r = newNode(nkRange) 897 r.add regs[rb].regToNode 898 r.add regs[rc].regToNode 899 regs[ra].node.add r.copyTree 900 of opcExcl: 901 decodeB(rkNode) 902 var b = newNodeIT(nkCurly, regs[ra].node.info, regs[ra].node.typ) 903 b.add regs[rb].regToNode 904 var r = diffSets(c.config, regs[ra].node, b) 905 discardSons(regs[ra].node) 906 for i in 0..<r.len: regs[ra].node.add r[i] 907 of opcCard: 908 decodeB(rkInt) 909 regs[ra].intVal = nimsets.cardSet(c.config, regs[rb].node) 910 of opcMulInt: 911 decodeBC(rkInt) 912 let 913 bVal = regs[rb].intVal 914 cVal = regs[rc].intVal 915 product = bVal *% cVal 916 floatProd = toBiggestFloat(bVal) * toBiggestFloat(cVal) 917 resAsFloat = toBiggestFloat(product) 918 if resAsFloat == floatProd: 919 regs[ra].intVal = product 920 elif 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): 921 regs[ra].intVal = product 922 else: 923 stackTrace(c, tos, pc, errOverOrUnderflow) 924 of opcDivInt: 925 decodeBC(rkInt) 926 if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero) 927 else: regs[ra].intVal = regs[rb].intVal div regs[rc].intVal 928 of opcModInt: 929 decodeBC(rkInt) 930 if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero) 931 else: regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal 932 of opcAddFloat: 933 decodeBC(rkFloat) 934 regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal 935 of opcSubFloat: 936 decodeBC(rkFloat) 937 regs[ra].floatVal = regs[rb].floatVal - regs[rc].floatVal 938 of opcMulFloat: 939 decodeBC(rkFloat) 940 regs[ra].floatVal = regs[rb].floatVal * regs[rc].floatVal 941 of opcDivFloat: 942 decodeBC(rkFloat) 943 regs[ra].floatVal = regs[rb].floatVal / regs[rc].floatVal 944 of opcShrInt: 945 decodeBC(rkInt) 946 let b = cast[uint64](regs[rb].intVal) 947 let c = cast[uint64](regs[rc].intVal) 948 let a = cast[int64](b shr c) 949 regs[ra].intVal = a 950 of opcShlInt: 951 decodeBC(rkInt) 952 regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal 953 of opcAshrInt: 954 decodeBC(rkInt) 955 regs[ra].intVal = ashr(regs[rb].intVal, regs[rc].intVal) 956 of opcBitandInt: 957 decodeBC(rkInt) 958 regs[ra].intVal = regs[rb].intVal and regs[rc].intVal 959 of opcBitorInt: 960 decodeBC(rkInt) 961 regs[ra].intVal = regs[rb].intVal or regs[rc].intVal 962 of opcBitxorInt: 963 decodeBC(rkInt) 964 regs[ra].intVal = regs[rb].intVal xor regs[rc].intVal 965 of opcAddu: 966 decodeBC(rkInt) 967 regs[ra].intVal = regs[rb].intVal +% regs[rc].intVal 968 of opcSubu: 969 decodeBC(rkInt) 970 regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal 971 of opcMulu: 972 decodeBC(rkInt) 973 regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal 974 of opcDivu: 975 decodeBC(rkInt) 976 regs[ra].intVal = regs[rb].intVal /% regs[rc].intVal 977 of opcModu: 978 decodeBC(rkInt) 979 regs[ra].intVal = regs[rb].intVal %% regs[rc].intVal 980 of opcEqInt: 981 decodeBC(rkInt) 982 regs[ra].intVal = ord(regs[rb].intVal == regs[rc].intVal) 983 of opcLeInt: 984 decodeBC(rkInt) 985 regs[ra].intVal = ord(regs[rb].intVal <= regs[rc].intVal) 986 of opcLtInt: 987 decodeBC(rkInt) 988 regs[ra].intVal = ord(regs[rb].intVal < regs[rc].intVal) 989 of opcEqFloat: 990 decodeBC(rkInt) 991 regs[ra].intVal = ord(regs[rb].floatVal == regs[rc].floatVal) 992 of opcLeFloat: 993 decodeBC(rkInt) 994 regs[ra].intVal = ord(regs[rb].floatVal <= regs[rc].floatVal) 995 of opcLtFloat: 996 decodeBC(rkInt) 997 regs[ra].intVal = ord(regs[rb].floatVal < regs[rc].floatVal) 998 of opcLeu: 999 decodeBC(rkInt) 1000 regs[ra].intVal = ord(regs[rb].intVal <=% regs[rc].intVal) 1001 of opcLtu: 1002 decodeBC(rkInt) 1003 regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal) 1004 of opcEqRef: 1005 var ret = false 1006 decodeBC(rkInt) 1007 template getTyp(n): untyped = 1008 n.typ.skipTypes(abstractInst) 1009 proc ptrEquality(n1: ptr PNode, n2: PNode): bool = 1010 ## true if n2.intVal represents a ptr equal to n1 1011 let p1 = cast[int](n1) 1012 case n2.kind 1013 of nkNilLit: return p1 == 0 1014 of nkIntLit: # TODO: nkPtrLit 1015 # for example, n1.kind == nkFloatLit (ptr float) 1016 # the problem is that n1.typ == nil so we can't compare n1.typ and n2.typ 1017 # this is the best we can do (pending making sure we assign a valid n1.typ to nodeAddr's) 1018 let t2 = n2.getTyp 1019 return t2.kind in PtrLikeKinds and n2.intVal == p1 1020 else: return false 1021 1022 if regs[rb].kind == rkNodeAddr: 1023 if regs[rc].kind == rkNodeAddr: 1024 ret = regs[rb].nodeAddr == regs[rc].nodeAddr 1025 else: 1026 ret = ptrEquality(regs[rb].nodeAddr, regs[rc].node) 1027 elif regs[rc].kind == rkNodeAddr: 1028 ret = ptrEquality(regs[rc].nodeAddr, regs[rb].node) 1029 else: 1030 let nb = regs[rb].node 1031 let nc = regs[rc].node 1032 if nb.kind != nc.kind: discard 1033 elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional 1034 elif nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ != nil and nb.typ.kind == tyProc and sameConstant(nb, nc): 1035 ret = true 1036 # this also takes care of procvar's, represented as nkTupleConstr, e.g. (nil, nil) 1037 elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit 1038 let tb = nb.getTyp 1039 let tc = nc.getTyp 1040 ret = tb.kind in PtrLikeKinds and tc.kind == tb.kind 1041 regs[ra].intVal = ord(ret) 1042 of opcEqNimNode: 1043 decodeBC(rkInt) 1044 regs[ra].intVal = 1045 ord(exprStructuralEquivalent(regs[rb].node, regs[rc].node, 1046 strictSymEquality=true)) 1047 of opcSameNodeType: 1048 decodeBC(rkInt) 1049 regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil regs[rc].node.typ) 1050 of opcXor: 1051 decodeBC(rkInt) 1052 regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal) 1053 of opcNot: 1054 decodeB(rkInt) 1055 assert regs[rb].kind == rkInt 1056 regs[ra].intVal = 1 - regs[rb].intVal 1057 of opcUnaryMinusInt: 1058 decodeB(rkInt) 1059 assert regs[rb].kind == rkInt 1060 let val = regs[rb].intVal 1061 if val != int64.low: 1062 regs[ra].intVal = -val 1063 else: 1064 stackTrace(c, tos, pc, errOverOrUnderflow) 1065 of opcUnaryMinusFloat: 1066 decodeB(rkFloat) 1067 assert regs[rb].kind == rkFloat 1068 regs[ra].floatVal = -regs[rb].floatVal 1069 of opcBitnotInt: 1070 decodeB(rkInt) 1071 assert regs[rb].kind == rkInt 1072 regs[ra].intVal = not regs[rb].intVal 1073 of opcEqStr: 1074 decodeBC(rkInt) 1075 regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal) 1076 of opcLeStr: 1077 decodeBC(rkInt) 1078 regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal) 1079 of opcLtStr: 1080 decodeBC(rkInt) 1081 regs[ra].intVal = ord(regs[rb].node.strVal < regs[rc].node.strVal) 1082 of opcLeSet: 1083 decodeBC(rkInt) 1084 regs[ra].intVal = ord(containsSets(c.config, regs[rb].node, regs[rc].node)) 1085 of opcEqSet: 1086 decodeBC(rkInt) 1087 regs[ra].intVal = ord(equalSets(c.config, regs[rb].node, regs[rc].node)) 1088 of opcLtSet: 1089 decodeBC(rkInt) 1090 let a = regs[rb].node 1091 let b = regs[rc].node 1092 regs[ra].intVal = ord(containsSets(c.config, a, b) and not equalSets(c.config, a, b)) 1093 of opcMulSet: 1094 decodeBC(rkNode) 1095 createSet(regs[ra]) 1096 move(regs[ra].node.sons, 1097 nimsets.intersectSets(c.config, regs[rb].node, regs[rc].node).sons) 1098 of opcPlusSet: 1099 decodeBC(rkNode) 1100 createSet(regs[ra]) 1101 move(regs[ra].node.sons, 1102 nimsets.unionSets(c.config, regs[rb].node, regs[rc].node).sons) 1103 of opcMinusSet: 1104 decodeBC(rkNode) 1105 createSet(regs[ra]) 1106 move(regs[ra].node.sons, 1107 nimsets.diffSets(c.config, regs[rb].node, regs[rc].node).sons) 1108 of opcConcatStr: 1109 decodeBC(rkNode) 1110 createStr regs[ra] 1111 regs[ra].node.strVal = getstr(regs[rb]) 1112 for i in rb+1..rb+rc-1: 1113 regs[ra].node.strVal.add getstr(regs[i]) 1114 of opcAddStrCh: 1115 decodeB(rkNode) 1116 regs[ra].node.strVal.add(regs[rb].intVal.chr) 1117 of opcAddStrStr: 1118 decodeB(rkNode) 1119 regs[ra].node.strVal.add(regs[rb].node.strVal) 1120 of opcAddSeqElem: 1121 decodeB(rkNode) 1122 if regs[ra].node.kind == nkBracket: 1123 regs[ra].node.add(copyValue(regs[rb].regToNode)) 1124 else: 1125 stackTrace(c, tos, pc, errNilAccess) 1126 of opcGetImpl: 1127 decodeB(rkNode) 1128 var a = regs[rb].node 1129 if a.kind == nkVarTy: a = a[0] 1130 if a.kind == nkSym: 1131 regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit) 1132 else: copyTree(a.sym.ast) 1133 regs[ra].node.flags.incl nfIsRef 1134 else: 1135 stackTrace(c, tos, pc, "node is not a symbol") 1136 of opcGetImplTransf: 1137 decodeB(rkNode) 1138 let a = regs[rb].node 1139 if a.kind == nkSym: 1140 regs[ra].node = 1141 if a.sym.ast.isNil: 1142 newNode(nkNilLit) 1143 else: 1144 let ast = a.sym.ast.shallowCopy 1145 for i in 0..<a.sym.ast.len: 1146 ast[i] = a.sym.ast[i] 1147 ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, cache=true) 1148 ast.copyTree() 1149 of opcSymOwner: 1150 decodeB(rkNode) 1151 let a = regs[rb].node 1152 if a.kind == nkSym: 1153 regs[ra].node = if a.sym.owner.isNil: newNode(nkNilLit) 1154 else: newSymNode(a.sym.skipGenericOwner) 1155 regs[ra].node.flags.incl nfIsRef 1156 else: 1157 stackTrace(c, tos, pc, "node is not a symbol") 1158 of opcSymIsInstantiationOf: 1159 decodeBC(rkInt) 1160 let a = regs[rb].node 1161 let b = regs[rc].node 1162 if a.kind == nkSym and a.sym.kind in skProcKinds and 1163 b.kind == nkSym and b.sym.kind in skProcKinds: 1164 regs[ra].intVal = 1165 if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1 1166 else: 0 1167 else: 1168 stackTrace(c, tos, pc, "node is not a proc symbol") 1169 of opcEcho: 1170 let rb = instr.regB 1171 template fn(s) = msgWriteln(c.config, s, {msgStdout, msgNoUnitSep}) 1172 if rb == 1: fn(regs[ra].node.strVal) 1173 else: 1174 var outp = "" 1175 for i in ra..ra+rb-1: 1176 #if regs[i].kind != rkNode: debug regs[i] 1177 outp.add(regs[i].node.strVal) 1178 fn(outp) 1179 of opcContainsSet: 1180 decodeBC(rkInt) 1181 regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) 1182 of opcSubStr: 1183 decodeBC(rkNode) 1184 inc pc 1185 assert c.code[pc].opcode == opcSubStr 1186 let rd = c.code[pc].regA 1187 createStr regs[ra] 1188 regs[ra].node.strVal = substr(regs[rb].node.strVal, 1189 regs[rc].intVal.int, regs[rd].intVal.int) 1190 of opcParseFloat: 1191 decodeBC(rkInt) 1192 inc pc 1193 assert c.code[pc].opcode == opcParseFloat 1194 let rd = c.code[pc].regA 1195 var rcAddr = addr(regs[rc]) 1196 if rcAddr.kind == rkRegisterAddr: rcAddr = rcAddr.regAddr 1197 elif regs[rc].kind != rkFloat: 1198 regs[rc] = TFullReg(kind: rkFloat) 1199 regs[ra].intVal = parseBiggestFloat(regs[rb].node.strVal, 1200 rcAddr.floatVal, regs[rd].intVal.int) 1201 of opcRangeChck: 1202 let rb = instr.regB 1203 let rc = instr.regC 1204 if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and 1205 leValueConv(regs[ra].regToNode, regs[rc].regToNode)): 1206 stackTrace(c, tos, pc, 1207 errIllegalConvFromXtoY % [ 1208 $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"]) 1209 of opcIndCall, opcIndCallAsgn: 1210 # dest = call regStart, n; where regStart = fn, arg1, ... 1211 let rb = instr.regB 1212 let rc = instr.regC 1213 let bb = regs[rb].node 1214 let isClosure = bb.kind == nkTupleConstr 1215 let prc = if not isClosure: bb.sym else: bb[0].sym 1216 if prc.offset < -1: 1217 # it's a callback: 1218 c.callbacks[-prc.offset-2].value( 1219 VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), 1220 currentException: c.currentExceptionA, 1221 currentLineInfo: c.debug[pc])) 1222 elif importcCond(c, prc): 1223 if compiletimeFFI notin c.config.features: 1224 globalError(c.config, c.debug[pc], "VM not allowed to do FFI, see `compiletimeFFI`") 1225 # we pass 'tos.slots' instead of 'regs' so that the compiler can keep 1226 # 'regs' in a register: 1227 when hasFFI: 1228 if prc.position - 1 < 0: 1229 globalError(c.config, c.debug[pc], 1230 "VM call invalid: prc.position: " & $prc.position) 1231 let prcValue = c.globals[prc.position-1] 1232 if prcValue.kind == nkEmpty: 1233 globalError(c.config, c.debug[pc], "cannot run " & prc.name.s) 1234 var slots2: TNodeSeq 1235 slots2.setLen(tos.slots.len) 1236 for i in 0..<tos.slots.len: 1237 slots2[i] = regToNode(tos.slots[i]) 1238 let newValue = callForeignFunction(c.config, prcValue, prc.typ, slots2, 1239 rb+1, rc-1, c.debug[pc]) 1240 if newValue.kind != nkEmpty: 1241 assert instr.opcode == opcIndCallAsgn 1242 putIntoReg(regs[ra], newValue) 1243 else: 1244 globalError(c.config, c.debug[pc], "VM not built with FFI support") 1245 elif prc.kind != skTemplate: 1246 let newPc = compile(c, prc) 1247 # tricky: a recursion is also a jump back, so we use the same 1248 # logic as for loops: 1249 if newPc < pc: handleJmpBack() 1250 #echo "new pc ", newPc, " calling: ", prc.name.s 1251 var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) 1252 newSeq(newFrame.slots, prc.offset+ord(isClosure)) 1253 if not isEmptyType(prc.typ[0]): 1254 putIntoReg(newFrame.slots[0], getNullValue(prc.typ[0], prc.info, c.config)) 1255 for i in 1..rc-1: 1256 newFrame.slots[i] = regs[rb+i] 1257 if isClosure: 1258 newFrame.slots[rc] = TFullReg(kind: rkNode, node: regs[rb].node[1]) 1259 tos = newFrame 1260 updateRegsAlias 1261 # -1 for the following 'inc pc' 1262 pc = newPc-1 1263 else: 1264 # for 'getAst' support we need to support template expansion here: 1265 let genSymOwner = if tos.next != nil and tos.next.prc != nil: 1266 tos.next.prc 1267 else: 1268 c.module 1269 var macroCall = newNodeI(nkCall, c.debug[pc]) 1270 macroCall.add(newSymNode(prc)) 1271 for i in 1..rc-1: 1272 let node = regs[rb+i].regToNode 1273 node.info = c.debug[pc] 1274 macroCall.add(node) 1275 var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen) 1276 if a.kind == nkStmtList and a.len == 1: a = a[0] 1277 a.recSetFlagIsRef 1278 ensureKind(rkNode) 1279 regs[ra].node = a 1280 of opcTJmp: 1281 # jump Bx if A != 0 1282 let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' 1283 if regs[ra].intVal != 0: 1284 inc pc, rbx 1285 of opcFJmp: 1286 # jump Bx if A == 0 1287 let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' 1288 if regs[ra].intVal == 0: 1289 inc pc, rbx 1290 of opcJmp: 1291 # jump Bx 1292 let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' 1293 inc pc, rbx 1294 of opcJmpBack: 1295 let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' 1296 inc pc, rbx 1297 handleJmpBack() 1298 of opcBranch: 1299 # we know the next instruction is a 'fjmp': 1300 let branch = c.constants[instr.regBx-wordExcess] 1301 var cond = false 1302 for j in 0..<branch.len - 1: 1303 if overlap(regs[ra].regToNode, branch[j]): 1304 cond = true 1305 break 1306 assert c.code[pc+1].opcode == opcFJmp 1307 inc pc 1308 # we skip this instruction so that the final 'inc(pc)' skips 1309 # the following jump 1310 if not cond: 1311 let instr2 = c.code[pc] 1312 let rbx = instr2.regBx - wordExcess - 1 # -1 for the following 'inc pc' 1313 inc pc, rbx 1314 of opcTry: 1315 let rbx = instr.regBx - wordExcess 1316 tos.pushSafePoint(pc + rbx) 1317 assert c.code[pc+rbx].opcode in {opcExcept, opcFinally} 1318 of opcExcept: 1319 # This opcode is never executed, it only holds information for the 1320 # exception handling routines. 1321 doAssert(false) 1322 of opcFinally: 1323 # Pop the last safepoint introduced by a opcTry. This opcode is only 1324 # executed _iff_ no exception was raised in the body of the `try` 1325 # statement hence the need to pop the safepoint here. 1326 doAssert(savedPC < 0) 1327 tos.popSafePoint() 1328 of opcFinallyEnd: 1329 # The control flow may not resume at the next instruction since we may be 1330 # raising an exception or performing a cleanup. 1331 if savedPC >= 0: 1332 pc = savedPC - 1 1333 savedPC = -1 1334 if tos != savedFrame: 1335 tos = savedFrame 1336 updateRegsAlias 1337 of opcRaise: 1338 let raised = 1339 # Empty `raise` statement - reraise current exception 1340 if regs[ra].kind == rkNone: 1341 c.currentExceptionA 1342 else: 1343 regs[ra].node 1344 c.currentExceptionA = raised 1345 # Set the `name` field of the exception 1346 c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s 1347 c.exceptionInstr = pc 1348 1349 var frame = tos 1350 var jumpTo = findExceptionHandler(c, frame, raised) 1351 while jumpTo.why == ExceptionGotoUnhandled and not frame.next.isNil: 1352 frame = frame.next 1353 jumpTo = findExceptionHandler(c, frame, raised) 1354 1355 case jumpTo.why: 1356 of ExceptionGotoHandler: 1357 # Jump to the handler, do nothing when the `finally` block ends. 1358 savedPC = -1 1359 pc = jumpTo.where - 1 1360 if tos != frame: 1361 tos = frame 1362 updateRegsAlias 1363 of ExceptionGotoFinally: 1364 # Jump to the `finally` block first then re-jump here to continue the 1365 # traversal of the exception chain 1366 savedPC = pc 1367 savedFrame = tos 1368 pc = jumpTo.where - 1 1369 if tos != frame: 1370 tos = frame 1371 updateRegsAlias 1372 of ExceptionGotoUnhandled: 1373 # Nobody handled this exception, error out. 1374 bailOut(c, tos) 1375 of opcNew: 1376 ensureKind(rkNode) 1377 let typ = c.types[instr.regBx - wordExcess] 1378 regs[ra].node = getNullValue(typ, c.debug[pc], c.config) 1379 regs[ra].node.flags.incl nfIsRef 1380 of opcNewSeq: 1381 let typ = c.types[instr.regBx - wordExcess] 1382 inc pc 1383 ensureKind(rkNode) 1384 let instr2 = c.code[pc] 1385 let count = regs[instr2.regA].intVal.int 1386 regs[ra].node = newNodeI(nkBracket, c.debug[pc]) 1387 regs[ra].node.typ = typ 1388 newSeq(regs[ra].node.sons, count) 1389 for i in 0..<count: 1390 regs[ra].node[i] = getNullValue(typ[0], c.debug[pc], c.config) 1391 of opcNewStr: 1392 decodeB(rkNode) 1393 regs[ra].node = newNodeI(nkStrLit, c.debug[pc]) 1394 regs[ra].node.strVal = newString(regs[rb].intVal.int) 1395 of opcLdImmInt: 1396 # dest = immediate value 1397 decodeBx(rkInt) 1398 regs[ra].intVal = rbx 1399 of opcLdNull: 1400 ensureKind(rkNode) 1401 let typ = c.types[instr.regBx - wordExcess] 1402 regs[ra].node = getNullValue(typ, c.debug[pc], c.config) 1403 # opcLdNull really is the gist of the VM's problems: should it load 1404 # a fresh null to regs[ra].node or to regs[ra].node[]? This really 1405 # depends on whether regs[ra] represents the variable itself or whether 1406 # it holds the indirection! Due to the way registers are re-used we cannot 1407 # say for sure here! --> The codegen has to deal with it 1408 # via 'genAsgnPatch'. 1409 of opcLdNullReg: 1410 let typ = c.types[instr.regBx - wordExcess] 1411 if typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}).kind in { 1412 tyFloat..tyFloat128}: 1413 ensureKind(rkFloat) 1414 regs[ra].floatVal = 0.0 1415 else: 1416 ensureKind(rkInt) 1417 regs[ra].intVal = 0 1418 of opcLdConst: 1419 let rb = instr.regBx - wordExcess 1420 let cnst = c.constants[rb] 1421 if fitsRegister(cnst.typ): 1422 reset(regs[ra]) 1423 putIntoReg(regs[ra], cnst) 1424 else: 1425 ensureKind(rkNode) 1426 regs[ra].node = cnst 1427 of opcAsgnConst: 1428 let rb = instr.regBx - wordExcess 1429 let cnst = c.constants[rb] 1430 if fitsRegister(cnst.typ): 1431 putIntoReg(regs[ra], cnst) 1432 else: 1433 ensureKind(rkNode) 1434 regs[ra].node = cnst.copyTree 1435 of opcLdGlobal: 1436 let rb = instr.regBx - wordExcess - 1 1437 ensureKind(rkNode) 1438 regs[ra].node = c.globals[rb] 1439 of opcLdGlobalDerefFFI: 1440 let rb = instr.regBx - wordExcess - 1 1441 let node = c.globals[rb] 1442 let typ = node.typ 1443 doAssert node.kind == nkIntLit, $(node.kind) 1444 if typ.kind == tyPtr: 1445 ensureKind(rkNode) 1446 # use nkPtrLit once this is added 1447 let node2 = newNodeIT(nkIntLit, c.debug[pc], typ) 1448 node2.intVal = cast[ptr int](node.intVal)[] 1449 node2.flags.incl nfIsPtr 1450 regs[ra].node = node2 1451 elif not derefPtrToReg(node.intVal, typ, regs[ra], isAssign = false): 1452 stackTrace(c, tos, pc, "opcLdDeref unsupported type: " & $(typeToString(typ), typ[0].kind)) 1453 of opcLdGlobalAddrDerefFFI: 1454 let rb = instr.regBx - wordExcess - 1 1455 let node = c.globals[rb] 1456 let typ = node.typ 1457 var node2 = newNodeIT(nkIntLit, node.info, typ) 1458 node2.intVal = node.intVal 1459 node2.flags.incl nfIsPtr 1460 ensureKind(rkNode) 1461 regs[ra].node = node2 1462 of opcLdGlobalAddr: 1463 let rb = instr.regBx - wordExcess - 1 1464 ensureKind(rkNodeAddr) 1465 regs[ra].nodeAddr = addr(c.globals[rb]) 1466 of opcRepr: 1467 decodeB(rkNode) 1468 createStr regs[ra] 1469 regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments}) 1470 of opcQuit: 1471 if c.mode in {emRepl, emStaticExpr, emStaticStmt}: 1472 message(c.config, c.debug[pc], hintQuitCalled) 1473 msgQuit(int8(toInt(getOrdValue(regs[ra].regToNode, onError = toInt128(1))))) 1474 else: 1475 return TFullReg(kind: rkNone) 1476 of opcInvalidField: 1477 let msg = regs[ra].node.strVal 1478 let disc = regs[instr.regB].regToNode 1479 let msg2 = formatFieldDefect(msg, $disc) 1480 stackTrace(c, tos, pc, msg2) 1481 of opcSetLenStr: 1482 decodeB(rkNode) 1483 #createStrKeepNode regs[ra] 1484 regs[ra].node.strVal.setLen(regs[rb].intVal.int) 1485 of opcOf: 1486 decodeBC(rkInt) 1487 let typ = c.types[regs[rc].intVal.int] 1488 regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) <= 0) 1489 of opcIs: 1490 decodeBC(rkInt) 1491 let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc}) 1492 let t2 = c.types[regs[rc].intVal.int] 1493 # XXX: This should use the standard isOpImpl 1494 let match = if t2.kind == tyUserTypeClass: true 1495 else: sameType(t1, t2) 1496 regs[ra].intVal = ord(match) 1497 of opcSetLenSeq: 1498 decodeB(rkNode) 1499 let newLen = regs[rb].intVal.int 1500 if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess) 1501 else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc]) 1502 of opcNarrowS: 1503 decodeB(rkInt) 1504 let min = -(1.BiggestInt shl (rb-1)) 1505 let max = (1.BiggestInt shl (rb-1))-1 1506 if regs[ra].intVal < min or regs[ra].intVal > max: 1507 stackTrace(c, tos, pc, "unhandled exception: value out of range") 1508 of opcNarrowU: 1509 decodeB(rkInt) 1510 regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1) 1511 of opcSignExtend: 1512 # like opcNarrowS, but no out of range possible 1513 decodeB(rkInt) 1514 let imm = 64 - rb 1515 regs[ra].intVal = ashr(regs[ra].intVal shl imm, imm) 1516 of opcIsNil: 1517 decodeB(rkInt) 1518 let node = regs[rb].node 1519 regs[ra].intVal = ord( 1520 # Note that `nfIsRef` + `nkNilLit` represents an allocated 1521 # reference with the value `nil`, so `isNil` should be false! 1522 (node.kind == nkNilLit and nfIsRef notin node.flags) or 1523 (not node.typ.isNil and node.typ.kind == tyProc and 1524 node.typ.callConv == ccClosure and node.safeLen > 0 and 1525 node[0].kind == nkNilLit and node[1].kind == nkNilLit)) 1526 of opcNBindSym: 1527 # cannot use this simple check 1528 # if dynamicBindSym notin c.config.features: 1529 1530 # bindSym with static input 1531 decodeBx(rkNode) 1532 regs[ra].node = copyTree(c.constants[rbx]) 1533 regs[ra].node.flags.incl nfIsRef 1534 of opcNDynBindSym: 1535 # experimental bindSym 1536 let 1537 rb = instr.regB 1538 rc = instr.regC 1539 idx = int(regs[rb+rc-1].intVal) 1540 callback = c.callbacks[idx].value 1541 args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), 1542 currentException: c.currentExceptionA, 1543 currentLineInfo: c.debug[pc]) 1544 callback(args) 1545 regs[ra].node.flags.incl nfIsRef 1546 of opcNChild: 1547 decodeBC(rkNode) 1548 let idx = regs[rc].intVal.int 1549 let src = regs[rb].node 1550 if src.kind in {nkEmpty..nkNilLit}: 1551 stackTrace(c, tos, pc, "cannot get child of node kind: n" & $src.kind) 1552 elif idx >=% src.len: 1553 stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1)) 1554 else: 1555 regs[ra].node = src[idx] 1556 of opcNSetChild: 1557 decodeBC(rkNode) 1558 let idx = regs[rb].intVal.int 1559 var dest = regs[ra].node 1560 if nfSem in dest.flags and allowSemcheckedAstModification notin c.config.legacyFeatures: 1561 stackTrace(c, tos, pc, "typechecked nodes may not be modified") 1562 elif dest.kind in {nkEmpty..nkNilLit}: 1563 stackTrace(c, tos, pc, "cannot set child of node kind: n" & $dest.kind) 1564 elif idx >=% dest.len: 1565 stackTrace(c, tos, pc, formatErrorIndexBound(idx, dest.len-1)) 1566 else: 1567 dest[idx] = regs[rc].node 1568 of opcNAdd: 1569 decodeBC(rkNode) 1570 var u = regs[rb].node 1571 if nfSem in u.flags and allowSemcheckedAstModification notin c.config.legacyFeatures: 1572 stackTrace(c, tos, pc, "typechecked nodes may not be modified") 1573 elif u.kind in {nkEmpty..nkNilLit}: 1574 stackTrace(c, tos, pc, "cannot add to node kind: n" & $u.kind) 1575 else: 1576 u.add(regs[rc].node) 1577 regs[ra].node = u 1578 of opcNAddMultiple: 1579 decodeBC(rkNode) 1580 let x = regs[rc].node 1581 var u = regs[rb].node 1582 if nfSem in u.flags and allowSemcheckedAstModification notin c.config.legacyFeatures: 1583 stackTrace(c, tos, pc, "typechecked nodes may not be modified") 1584 elif u.kind in {nkEmpty..nkNilLit}: 1585 stackTrace(c, tos, pc, "cannot add to node kind: n" & $u.kind) 1586 else: 1587 for i in 0..<x.len: u.add(x[i]) 1588 regs[ra].node = u 1589 of opcNKind: 1590 decodeB(rkInt) 1591 regs[ra].intVal = ord(regs[rb].node.kind) 1592 c.comesFromHeuristic = regs[rb].node.info 1593 of opcNSymKind: 1594 decodeB(rkInt) 1595 let a = regs[rb].node 1596 if a.kind == nkSym: 1597 regs[ra].intVal = ord(a.sym.kind) 1598 else: 1599 stackTrace(c, tos, pc, "node is not a symbol") 1600 c.comesFromHeuristic = regs[rb].node.info 1601 of opcNIntVal: 1602 decodeB(rkInt) 1603 let a = regs[rb].node 1604 if a.kind in {nkCharLit..nkUInt64Lit}: 1605 regs[ra].intVal = a.intVal 1606 elif a.kind == nkSym and a.sym.kind == skEnumField: 1607 regs[ra].intVal = a.sym.position 1608 else: 1609 stackTrace(c, tos, pc, errFieldXNotFound & "intVal") 1610 of opcNFloatVal: 1611 decodeB(rkFloat) 1612 let a = regs[rb].node 1613 case a.kind 1614 of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal 1615 else: stackTrace(c, tos, pc, errFieldXNotFound & "floatVal") 1616 of opcNSymbol: 1617 decodeB(rkNode) 1618 let a = regs[rb].node 1619 if a.kind == nkSym: 1620 regs[ra].node = copyNode(a) 1621 else: 1622 stackTrace(c, tos, pc, errFieldXNotFound & "symbol") 1623 of opcNIdent: 1624 decodeB(rkNode) 1625 let a = regs[rb].node 1626 if a.kind == nkIdent: 1627 regs[ra].node = copyNode(a) 1628 else: 1629 stackTrace(c, tos, pc, errFieldXNotFound & "ident") 1630 of opcNodeId: 1631 decodeB(rkInt) 1632 when defined(useNodeIds): 1633 regs[ra].intVal = regs[rb].node.id 1634 else: 1635 regs[ra].intVal = -1 1636 of opcNGetType: 1637 let rb = instr.regB 1638 let rc = instr.regC 1639 case rc 1640 of 0: 1641 # getType opcode: 1642 ensureKind(rkNode) 1643 if regs[rb].kind == rkNode and regs[rb].node.typ != nil: 1644 regs[ra].node = opMapTypeToAst(c.cache, regs[rb].node.typ, c.debug[pc], c.idgen) 1645 elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil: 1646 regs[ra].node = opMapTypeToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc], c.idgen) 1647 else: 1648 stackTrace(c, tos, pc, "node has no type") 1649 of 1: 1650 # typeKind opcode: 1651 ensureKind(rkInt) 1652 if regs[rb].kind == rkNode and regs[rb].node.typ != nil: 1653 regs[ra].intVal = ord(regs[rb].node.typ.kind) 1654 elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil: 1655 regs[ra].intVal = ord(regs[rb].node.sym.typ.kind) 1656 #else: 1657 # stackTrace(c, tos, pc, "node has no type") 1658 of 2: 1659 # getTypeInst opcode: 1660 ensureKind(rkNode) 1661 if regs[rb].kind == rkNode and regs[rb].node.typ != nil: 1662 regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.typ, c.debug[pc], c.idgen) 1663 elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil: 1664 regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc], c.idgen) 1665 else: 1666 stackTrace(c, tos, pc, "node has no type") 1667 else: 1668 # getTypeImpl opcode: 1669 ensureKind(rkNode) 1670 if regs[rb].kind == rkNode and regs[rb].node.typ != nil: 1671 regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.typ, c.debug[pc], c.idgen) 1672 elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil: 1673 regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc], c.idgen) 1674 else: 1675 stackTrace(c, tos, pc, "node has no type") 1676 of opcNGetSize: 1677 decodeBImm(rkInt) 1678 let n = regs[rb].node 1679 case imm 1680 of 0: # size 1681 if n.typ == nil: 1682 stackTrace(c, tos, pc, "node has no type") 1683 else: 1684 regs[ra].intVal = getSize(c.config, n.typ) 1685 of 1: # align 1686 if n.typ == nil: 1687 stackTrace(c, tos, pc, "node has no type") 1688 else: 1689 regs[ra].intVal = getAlign(c.config, n.typ) 1690 else: # offset 1691 if n.kind != nkSym: 1692 stackTrace(c, tos, pc, "node is not a symbol") 1693 elif n.sym.kind != skField: 1694 stackTrace(c, tos, pc, "symbol is not a field (nskField)") 1695 else: 1696 regs[ra].intVal = n.sym.offset 1697 of opcNStrVal: 1698 decodeB(rkNode) 1699 createStr regs[ra] 1700 let a = regs[rb].node 1701 case a.kind 1702 of nkStrLit..nkTripleStrLit: 1703 regs[ra].node.strVal = a.strVal 1704 of nkCommentStmt: 1705 regs[ra].node.strVal = a.comment 1706 of nkIdent: 1707 regs[ra].node.strVal = a.ident.s 1708 of nkSym: 1709 regs[ra].node.strVal = a.sym.name.s 1710 else: 1711 stackTrace(c, tos, pc, errFieldXNotFound & "strVal") 1712 of opcNSigHash: 1713 decodeB(rkNode) 1714 createStr regs[ra] 1715 if regs[rb].node.kind != nkSym: 1716 stackTrace(c, tos, pc, "node is not a symbol") 1717 else: 1718 regs[ra].node.strVal = $sigHash(regs[rb].node.sym) 1719 of opcSlurp: 1720 decodeB(rkNode) 1721 createStr regs[ra] 1722 regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc], 1723 c.module, c.config) 1724 of opcGorge: 1725 decodeBC(rkNode) 1726 inc pc 1727 let rd = c.code[pc].regA 1728 createStr regs[ra] 1729 if defined(nimsuggest) or c.config.cmd == cmdCheck: 1730 discard "don't run staticExec for 'nim suggest'" 1731 regs[ra].node.strVal = "" 1732 else: 1733 when defined(nimcore): 1734 regs[ra].node.strVal = opGorge(regs[rb].node.strVal, 1735 regs[rc].node.strVal, regs[rd].node.strVal, 1736 c.debug[pc], c.config)[0] 1737 else: 1738 regs[ra].node.strVal = "" 1739 globalError(c.config, c.debug[pc], "VM is not built with 'gorge' support") 1740 of opcNError, opcNWarning, opcNHint: 1741 decodeB(rkNode) 1742 let a = regs[ra].node 1743 let b = regs[rb].node 1744 let info = if b.kind == nkNilLit: c.debug[pc] else: b.info 1745 if instr.opcode == opcNError: 1746 stackTrace(c, tos, pc, a.strVal, info) 1747 elif instr.opcode == opcNWarning: 1748 message(c.config, info, warnUser, a.strVal) 1749 elif instr.opcode == opcNHint: 1750 message(c.config, info, hintUser, a.strVal) 1751 of opcParseExprToAst: 1752 decodeB(rkNode) 1753 # c.debug[pc].line.int - countLines(regs[rb].strVal) ? 1754 var error: string 1755 let ast = parseString(regs[rb].node.strVal, c.cache, c.config, 1756 toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, 1757 proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = 1758 if error.len == 0 and msg <= errMax: 1759 error = formatMsg(conf, info, msg, arg)) 1760 if error.len > 0: 1761 c.errorFlag = error 1762 elif ast.len != 1: 1763 c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated, 1764 "expected expression, but got multiple statements") 1765 else: 1766 regs[ra].node = ast[0] 1767 of opcParseStmtToAst: 1768 decodeB(rkNode) 1769 var error: string 1770 let ast = parseString(regs[rb].node.strVal, c.cache, c.config, 1771 toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, 1772 proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} = 1773 if error.len == 0 and msg <= errMax: 1774 error = formatMsg(conf, info, msg, arg)) 1775 if error.len > 0: 1776 c.errorFlag = error 1777 else: 1778 regs[ra].node = ast 1779 of opcQueryErrorFlag: 1780 createStr regs[ra] 1781 regs[ra].node.strVal = c.errorFlag 1782 c.errorFlag.setLen 0 1783 of opcCallSite: 1784 ensureKind(rkNode) 1785 if c.callsite != nil: regs[ra].node = c.callsite 1786 else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite") 1787 of opcNGetLineInfo: 1788 decodeBImm(rkNode) 1789 let n = regs[rb].node 1790 case imm 1791 of 0: # getFile 1792 regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info)) 1793 of 1: # getLine 1794 regs[ra].node = newIntNode(nkIntLit, n.info.line.int) 1795 of 2: # getColumn 1796 regs[ra].node = newIntNode(nkIntLit, n.info.col) 1797 else: 1798 internalAssert c.config, false 1799 regs[ra].node.info = n.info 1800 regs[ra].node.typ = n.typ 1801 of opcNSetLineInfo: 1802 decodeB(rkNode) 1803 regs[ra].node.info = regs[rb].node.info 1804 of opcEqIdent: 1805 decodeBC(rkInt) 1806 # aliases for shorter and easier to understand code below 1807 var aNode = regs[rb].node 1808 var bNode = regs[rc].node 1809 # Skipping both, `nkPostfix` and `nkAccQuoted` for both 1810 # arguments. `nkPostfix` exists only to tag exported symbols 1811 # and therefor it can be safely skipped. Nim has no postfix 1812 # operator. `nkAccQuoted` is used to quote an identifier that 1813 # wouldn't be allowed to use in an unquoted context. 1814 if aNode.kind == nkPostfix: 1815 aNode = aNode[1] 1816 if aNode.kind == nkAccQuoted: 1817 aNode = aNode[0] 1818 if bNode.kind == nkPostfix: 1819 bNode = bNode[1] 1820 if bNode.kind == nkAccQuoted: 1821 bNode = bNode[0] 1822 # These vars are of type `cstring` to prevent unnecessary string copy. 1823 var aStrVal: cstring = nil 1824 var bStrVal: cstring = nil 1825 # extract strVal from argument ``a`` 1826 case aNode.kind 1827 of nkStrLit..nkTripleStrLit: 1828 aStrVal = aNode.strVal.cstring 1829 of nkIdent: 1830 aStrVal = aNode.ident.s.cstring 1831 of nkSym: 1832 aStrVal = aNode.sym.name.s.cstring 1833 of nkOpenSymChoice, nkClosedSymChoice: 1834 aStrVal = aNode[0].sym.name.s.cstring 1835 else: 1836 discard 1837 # extract strVal from argument ``b`` 1838 case bNode.kind 1839 of nkStrLit..nkTripleStrLit: 1840 bStrVal = bNode.strVal.cstring 1841 of nkIdent: 1842 bStrVal = bNode.ident.s.cstring 1843 of nkSym: 1844 bStrVal = bNode.sym.name.s.cstring 1845 of nkOpenSymChoice, nkClosedSymChoice: 1846 bStrVal = bNode[0].sym.name.s.cstring 1847 else: 1848 discard 1849 regs[ra].intVal = 1850 if aStrVal != nil and bStrVal != nil: 1851 ord(idents.cmpIgnoreStyle(aStrVal, bStrVal, high(int)) == 0) 1852 else: 1853 0 1854 1855 of opcStrToIdent: 1856 decodeB(rkNode) 1857 if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}: 1858 stackTrace(c, tos, pc, errFieldXNotFound & "strVal") 1859 else: 1860 regs[ra].node = newNodeI(nkIdent, c.debug[pc]) 1861 regs[ra].node.ident = getIdent(c.cache, regs[rb].node.strVal) 1862 regs[ra].node.flags.incl nfIsRef 1863 of opcSetType: 1864 let typ = c.types[instr.regBx - wordExcess] 1865 if regs[ra].kind != rkNode: 1866 let temp = regToNode(regs[ra]) 1867 ensureKind(rkNode) 1868 regs[ra].node = temp 1869 regs[ra].node.info = c.debug[pc] 1870 regs[ra].node.typ = typ 1871 of opcConv: 1872 let rb = instr.regB 1873 inc pc 1874 let desttyp = c.types[c.code[pc].regBx - wordExcess] 1875 inc pc 1876 let srctyp = c.types[c.code[pc].regBx - wordExcess] 1877 1878 if opConv(c, regs[ra], regs[rb], desttyp, srctyp): 1879 stackTrace(c, tos, pc, 1880 errIllegalConvFromXtoY % [ 1881 typeToString(srctyp), typeToString(desttyp)]) 1882 of opcCast: 1883 let rb = instr.regB 1884 inc pc 1885 let desttyp = c.types[c.code[pc].regBx - wordExcess] 1886 inc pc 1887 let srctyp = c.types[c.code[pc].regBx - wordExcess] 1888 1889 when hasFFI: 1890 let dest = fficast(c.config, regs[rb].node, desttyp) 1891 # todo: check whether this is correct 1892 # asgnRef(regs[ra], dest) 1893 putIntoReg(regs[ra], dest) 1894 else: 1895 globalError(c.config, c.debug[pc], "cannot evaluate cast") 1896 of opcNSetIntVal: 1897 decodeB(rkNode) 1898 var dest = regs[ra].node 1899 if dest.kind in {nkCharLit..nkUInt64Lit} and 1900 regs[rb].kind in {rkInt}: 1901 dest.intVal = regs[rb].intVal 1902 elif dest.kind == nkSym and dest.sym.kind == skEnumField: 1903 stackTrace(c, tos, pc, "`intVal` cannot be changed for an enum symbol.") 1904 else: 1905 stackTrace(c, tos, pc, errFieldXNotFound & "intVal") 1906 of opcNSetFloatVal: 1907 decodeB(rkNode) 1908 var dest = regs[ra].node 1909 if dest.kind in {nkFloatLit..nkFloat64Lit} and 1910 regs[rb].kind in {rkFloat}: 1911 dest.floatVal = regs[rb].floatVal 1912 else: 1913 stackTrace(c, tos, pc, errFieldXNotFound & "floatVal") 1914 of opcNSetSymbol: 1915 decodeB(rkNode) 1916 var dest = regs[ra].node 1917 if dest.kind == nkSym and regs[rb].node.kind == nkSym: 1918 dest.sym = regs[rb].node.sym 1919 else: 1920 stackTrace(c, tos, pc, errFieldXNotFound & "symbol") 1921 of opcNSetIdent: 1922 decodeB(rkNode) 1923 var dest = regs[ra].node 1924 if dest.kind == nkIdent and regs[rb].node.kind == nkIdent: 1925 dest.ident = regs[rb].node.ident 1926 else: 1927 stackTrace(c, tos, pc, errFieldXNotFound & "ident") 1928 of opcNSetType: 1929 decodeB(rkNode) 1930 let b = regs[rb].node 1931 internalAssert c.config, b.kind == nkSym and b.sym.kind == skType 1932 internalAssert c.config, regs[ra].node != nil 1933 regs[ra].node.typ = b.sym.typ 1934 of opcNSetStrVal: 1935 decodeB(rkNode) 1936 var dest = regs[ra].node 1937 if dest.kind in {nkStrLit..nkTripleStrLit} and 1938 regs[rb].kind in {rkNode}: 1939 dest.strVal = regs[rb].node.strVal 1940 elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}: 1941 dest.comment = regs[rb].node.strVal 1942 else: 1943 stackTrace(c, tos, pc, errFieldXNotFound & "strVal") 1944 of opcNNewNimNode: 1945 decodeBC(rkNode) 1946 var k = regs[rb].intVal 1947 if k < 0 or k > ord(high(TNodeKind)): 1948 internalError(c.config, c.debug[pc], 1949 "request to create a NimNode of invalid kind") 1950 let cc = regs[rc].node 1951 1952 let x = newNodeI(TNodeKind(int(k)), 1953 if cc.kind != nkNilLit: 1954 cc.info 1955 elif c.comesFromHeuristic.line != 0'u16: 1956 c.comesFromHeuristic 1957 elif c.callsite != nil and c.callsite.safeLen > 1: 1958 c.callsite[1].info 1959 else: 1960 c.debug[pc]) 1961 x.flags.incl nfIsRef 1962 # prevent crashes in the compiler resulting from wrong macros: 1963 if x.kind == nkIdent: x.ident = c.cache.emptyIdent 1964 regs[ra].node = x 1965 of opcNCopyNimNode: 1966 decodeB(rkNode) 1967 regs[ra].node = copyNode(regs[rb].node) 1968 of opcNCopyNimTree: 1969 decodeB(rkNode) 1970 regs[ra].node = copyTree(regs[rb].node) 1971 of opcNDel: 1972 decodeBC(rkNode) 1973 let bb = regs[rb].intVal.int 1974 for i in 0..<regs[rc].intVal.int: 1975 delSon(regs[ra].node, bb) 1976 of opcGenSym: 1977 decodeBC(rkNode) 1978 let k = regs[rb].intVal 1979 let name = if regs[rc].node.strVal.len == 0: ":tmp" 1980 else: regs[rc].node.strVal 1981 if k < 0 or k > ord(high(TSymKind)): 1982 internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") 1983 var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextSymId c.idgen, c.module.owner, c.debug[pc]) 1984 incl(sym.flags, sfGenSym) 1985 regs[ra].node = newSymNode(sym) 1986 regs[ra].node.flags.incl nfIsRef 1987 of opcNccValue: 1988 decodeB(rkInt) 1989 let destKey = regs[rb].node.strVal 1990 regs[ra].intVal = getOrDefault(c.graph.cacheCounters, destKey) 1991 of opcNccInc: 1992 let g = c.graph 1993 declBC() 1994 let destKey = regs[rb].node.strVal 1995 let by = regs[rc].intVal 1996 let v = getOrDefault(g.cacheCounters, destKey) 1997 g.cacheCounters[destKey] = v+by 1998 recordInc(c, c.debug[pc], destKey, by) 1999 of opcNcsAdd: 2000 let g = c.graph 2001 declBC() 2002 let destKey = regs[rb].node.strVal 2003 let val = regs[rc].node 2004 if not contains(g.cacheSeqs, destKey): 2005 g.cacheSeqs[destKey] = newTree(nkStmtList, val) 2006 else: 2007 g.cacheSeqs[destKey].add val 2008 recordAdd(c, c.debug[pc], destKey, val) 2009 of opcNcsIncl: 2010 let g = c.graph 2011 declBC() 2012 let destKey = regs[rb].node.strVal 2013 let val = regs[rc].node 2014 if not contains(g.cacheSeqs, destKey): 2015 g.cacheSeqs[destKey] = newTree(nkStmtList, val) 2016 else: 2017 block search: 2018 for existing in g.cacheSeqs[destKey]: 2019 if exprStructuralEquivalent(existing, val, strictSymEquality=true): 2020 break search 2021 g.cacheSeqs[destKey].add val 2022 recordIncl(c, c.debug[pc], destKey, val) 2023 of opcNcsLen: 2024 let g = c.graph 2025 decodeB(rkInt) 2026 let destKey = regs[rb].node.strVal 2027 regs[ra].intVal = 2028 if contains(g.cacheSeqs, destKey): g.cacheSeqs[destKey].len else: 0 2029 of opcNcsAt: 2030 let g = c.graph 2031 decodeBC(rkNode) 2032 let idx = regs[rc].intVal 2033 let destKey = regs[rb].node.strVal 2034 if contains(g.cacheSeqs, destKey) and idx <% g.cacheSeqs[destKey].len: 2035 regs[ra].node = g.cacheSeqs[destKey][idx.int] 2036 else: 2037 stackTrace(c, tos, pc, formatErrorIndexBound(idx, g.cacheSeqs[destKey].len-1)) 2038 of opcNctPut: 2039 let g = c.graph 2040 let destKey = regs[ra].node.strVal 2041 let key = regs[instr.regB].node.strVal 2042 let val = regs[instr.regC].node 2043 if not contains(g.cacheTables, destKey): 2044 g.cacheTables[destKey] = initBTree[string, PNode]() 2045 if not contains(g.cacheTables[destKey], key): 2046 g.cacheTables[destKey].add(key, val) 2047 recordPut(c, c.debug[pc], destKey, key, val) 2048 else: 2049 stackTrace(c, tos, pc, "key already exists: " & key) 2050 of opcNctLen: 2051 let g = c.graph 2052 decodeB(rkInt) 2053 let destKey = regs[rb].node.strVal 2054 regs[ra].intVal = 2055 if contains(g.cacheTables, destKey): g.cacheTables[destKey].len else: 0 2056 of opcNctGet: 2057 let g = c.graph 2058 decodeBC(rkNode) 2059 let destKey = regs[rb].node.strVal 2060 let key = regs[rc].node.strVal 2061 if contains(g.cacheTables, destKey): 2062 if contains(g.cacheTables[destKey], key): 2063 regs[ra].node = getOrDefault(g.cacheTables[destKey], key) 2064 else: 2065 stackTrace(c, tos, pc, "key does not exist: " & key) 2066 else: 2067 stackTrace(c, tos, pc, "key does not exist: " & destKey) 2068 of opcNctHasNext: 2069 let g = c.graph 2070 decodeBC(rkInt) 2071 let destKey = regs[rb].node.strVal 2072 regs[ra].intVal = 2073 if g.cacheTables.contains(destKey): 2074 ord(btrees.hasNext(g.cacheTables[destKey], regs[rc].intVal.int)) 2075 else: 2076 0 2077 of opcNctNext: 2078 let g = c.graph 2079 decodeBC(rkNode) 2080 let destKey = regs[rb].node.strVal 2081 let index = regs[rc].intVal 2082 if contains(g.cacheTables, destKey): 2083 let (k, v, nextIndex) = btrees.next(g.cacheTables[destKey], index.int) 2084 regs[ra].node = newTree(nkTupleConstr, newStrNode(k, c.debug[pc]), v, 2085 newIntNode(nkIntLit, nextIndex)) 2086 else: 2087 stackTrace(c, tos, pc, "key does not exist: " & destKey) 2088 2089 of opcTypeTrait: 2090 # XXX only supports 'name' for now; we can use regC to encode the 2091 # type trait operation 2092 decodeB(rkNode) 2093 var typ = regs[rb].node.typ 2094 internalAssert c.config, typ != nil 2095 while typ.kind == tyTypeDesc and typ.len > 0: typ = typ[0] 2096 createStr regs[ra] 2097 regs[ra].node.strVal = typ.typeToString(preferExported) 2098 of opcMarshalLoad: 2099 let ra = instr.regA 2100 let rb = instr.regB 2101 inc pc 2102 let typ = c.types[c.code[pc].regBx - wordExcess] 2103 putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.cache, c.config, c.idgen)) 2104 of opcMarshalStore: 2105 decodeB(rkNode) 2106 inc pc 2107 let typ = c.types[c.code[pc].regBx - wordExcess] 2108 createStrKeepNode(regs[ra]) 2109 storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) 2110 2111 c.profiler.leave(c) 2112 2113 inc pc 2114 2115proc execute(c: PCtx, start: int): PNode = 2116 var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil) 2117 newSeq(tos.slots, c.prc.regInfo.len) 2118 result = rawExecute(c, start, tos).regToNode 2119 2120proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = 2121 c.loopIterations = c.config.maxLoopIterationsVM 2122 if sym.kind in routineKinds: 2123 if sym.typ.len-1 != args.len: 2124 localError(c.config, sym.info, 2125 "NimScript: expected $# arguments, but got $#" % [ 2126 $(sym.typ.len-1), $args.len]) 2127 else: 2128 let start = genProc(c, sym) 2129 2130 var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil) 2131 let maxSlots = sym.offset 2132 newSeq(tos.slots, maxSlots) 2133 2134 # setup parameters: 2135 if not isEmptyType(sym.typ[0]) or sym.kind == skMacro: 2136 putIntoReg(tos.slots[0], getNullValue(sym.typ[0], sym.info, c.config)) 2137 # XXX We could perform some type checking here. 2138 for i in 1..<sym.typ.len: 2139 putIntoReg(tos.slots[i], args[i-1]) 2140 2141 result = rawExecute(c, start, tos).regToNode 2142 else: 2143 localError(c.config, sym.info, 2144 "NimScript: attempt to call non-routine: " & sym.name.s) 2145 2146proc evalStmt*(c: PCtx, n: PNode) = 2147 let n = transformExpr(c.graph, c.idgen, c.module, n) 2148 let start = genStmt(c, n) 2149 # execute new instructions; this redundant opcEof check saves us lots 2150 # of allocations in 'execute': 2151 if c.code[start].opcode != opcEof: 2152 discard execute(c, start) 2153 2154proc evalExpr*(c: PCtx, n: PNode): PNode = 2155 # deadcode 2156 # `nim --eval:"expr"` might've used it at some point for idetools; could 2157 # be revived for nimsuggest 2158 let n = transformExpr(c.graph, c.idgen, c.module, n) 2159 let start = genExpr(c, n) 2160 assert c.code[start].opcode != opcEof 2161 result = execute(c, start) 2162 2163proc getGlobalValue*(c: PCtx; s: PSym): PNode = 2164 internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags 2165 result = c.globals[s.position-1] 2166 2167proc setGlobalValue*(c: PCtx; s: PSym, val: PNode) = 2168 ## Does not do type checking so ensure the `val` matches the `s.typ` 2169 internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags 2170 c.globals[s.position-1] = val 2171 2172include vmops 2173 2174proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) = 2175 if graph.vm.isNil: 2176 graph.vm = newCtx(module, graph.cache, graph, idgen) 2177 registerAdditionalOps(PCtx graph.vm) 2178 else: 2179 refresh(PCtx graph.vm, module, idgen) 2180 2181proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = 2182 #var c = newEvalContext(module, emRepl) 2183 #c.features = {allowCast, allowInfiniteLoops} 2184 #pushStackFrame(c, newStackFrame()) 2185 2186 # XXX produce a new 'globals' environment here: 2187 setupGlobalCtx(module, graph, idgen) 2188 result = PCtx graph.vm 2189 2190proc myProcess(c: PPassContext, n: PNode): PNode = 2191 let c = PCtx(c) 2192 # don't eval errornous code: 2193 if c.oldErrorCount == c.config.errorCounter: 2194 evalStmt(c, n) 2195 result = newNodeI(nkEmpty, n.info) 2196 else: 2197 result = n 2198 c.oldErrorCount = c.config.errorCounter 2199 2200proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = 2201 result = myProcess(c, n) 2202 2203const evalPass* = makePass(myOpen, myProcess, myClose) 2204 2205proc evalConstExprAux(module: PSym; idgen: IdGenerator; 2206 g: ModuleGraph; prc: PSym, n: PNode, 2207 mode: TEvalMode): PNode = 2208 #if g.config.errorCounter > 0: return n 2209 let n = transformExpr(g, idgen, module, n) 2210 setupGlobalCtx(module, g, idgen) 2211 var c = PCtx g.vm 2212 let oldMode = c.mode 2213 c.mode = mode 2214 let start = genExpr(c, n, requiresValue = mode!=emStaticStmt) 2215 if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info) 2216 assert c.code[start].opcode != opcEof 2217 when debugEchoCode: c.echoCode start 2218 var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil) 2219 newSeq(tos.slots, c.prc.regInfo.len) 2220 #for i in 0..<c.prc.regInfo.len: tos.slots[i] = newNode(nkEmpty) 2221 result = rawExecute(c, start, tos).regToNode 2222 if result.info.col < 0: result.info = n.info 2223 c.mode = oldMode 2224 2225proc evalConstExpr*(module: PSym; idgen: IdGenerator; g: ModuleGraph; e: PNode): PNode = 2226 result = evalConstExprAux(module, idgen, g, nil, e, emConst) 2227 2228proc evalStaticExpr*(module: PSym; idgen: IdGenerator; g: ModuleGraph; e: PNode, prc: PSym): PNode = 2229 result = evalConstExprAux(module, idgen, g, prc, e, emStaticExpr) 2230 2231proc evalStaticStmt*(module: PSym; idgen: IdGenerator; g: ModuleGraph; e: PNode, prc: PSym) = 2232 discard evalConstExprAux(module, idgen, g, prc, e, emStaticStmt) 2233 2234proc setupCompileTimeVar*(module: PSym; idgen: IdGenerator; g: ModuleGraph; n: PNode) = 2235 discard evalConstExprAux(module, idgen, g, nil, n, emStaticStmt) 2236 2237proc prepareVMValue(arg: PNode): PNode = 2238 ## strip nkExprColonExpr from tuple values recursively. That is how 2239 ## they are expected to be stored in the VM. 2240 2241 # Early abort without copy. No transformation takes place. 2242 if arg.kind in nkLiterals: 2243 return arg 2244 2245 if arg.kind == nkExprColonExpr and arg[0].typ != nil and 2246 arg[0].typ.sym != nil and arg[0].typ.sym.magic == mPNimrodNode: 2247 # Poor mans way of protecting static NimNodes 2248 # XXX: Maybe we need a nkNimNode? 2249 return arg 2250 2251 result = copyNode(arg) 2252 if arg.kind == nkTupleConstr: 2253 for child in arg: 2254 if child.kind == nkExprColonExpr: 2255 result.add prepareVMValue(child[1]) 2256 else: 2257 result.add prepareVMValue(child) 2258 else: 2259 for child in arg: 2260 result.add prepareVMValue(child) 2261 2262proc setupMacroParam(x: PNode, typ: PType): TFullReg = 2263 case typ.kind 2264 of tyStatic: 2265 putIntoReg(result, prepareVMValue(x)) 2266 else: 2267 var n = x 2268 if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n[1] 2269 n = n.canonValue 2270 n.flags.incl nfIsRef 2271 n.typ = x.typ 2272 result = TFullReg(kind: rkNode, node: n) 2273 2274iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) = 2275 let gp = macroSym.ast[genericParamsPos] 2276 for i in 0..<gp.len: 2277 let genericParam = gp[i].sym 2278 let posInCall = macroSym.typ.len + i 2279 if posInCall < call.len: 2280 yield (genericParam, call[posInCall]) 2281 2282# to prevent endless recursion in macro instantiation 2283const evalMacroLimit = 1000 2284 2285#proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode = 2286# result = newNodeI(nkEmpty, n.info) 2287# result.typ = newType(tyError, nextTypeId idgen, owner) 2288# result.typ.flags.incl tfCheckedForDestructor 2289 2290proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int; 2291 n, nOrig: PNode, sym: PSym): PNode = 2292 #if g.config.errorCounter > 0: return errorNode(idgen, module, n) 2293 2294 # XXX globalError() is ugly here, but I don't know a better solution for now 2295 inc(g.config.evalMacroCounter) 2296 if g.config.evalMacroCounter > evalMacroLimit: 2297 globalError(g.config, n.info, "macro instantiation too nested") 2298 2299 # immediate macros can bypass any type and arity checking so we check the 2300 # arity here too: 2301 if sym.typ.len > n.safeLen and sym.typ.len > 1: 2302 globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [ 2303 n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) 2304 2305 setupGlobalCtx(module, g, idgen) 2306 var c = PCtx g.vm 2307 let oldMode = c.mode 2308 c.mode = emStaticStmt 2309 c.comesFromHeuristic.line = 0'u16 2310 c.callsite = nOrig 2311 c.templInstCounter = templInstCounter 2312 let start = genProc(c, sym) 2313 2314 var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil) 2315 let maxSlots = sym.offset 2316 newSeq(tos.slots, maxSlots) 2317 # setup arguments: 2318 var L = n.safeLen 2319 if L == 0: L = 1 2320 # This is wrong for tests/reject/tind1.nim where the passed 'else' part 2321 # doesn't end up in the parameter: 2322 #InternalAssert tos.slots.len >= L 2323 2324 # return value: 2325 tos.slots[0] = TFullReg(kind: rkNode, node: newNodeI(nkEmpty, n.info)) 2326 2327 # setup parameters: 2328 for i in 1..<sym.typ.len: 2329 tos.slots[i] = setupMacroParam(n[i], sym.typ[i]) 2330 2331 let gp = sym.ast[genericParamsPos] 2332 for i in 0..<gp.len: 2333 let idx = sym.typ.len + i 2334 if idx < n.len: 2335 tos.slots[idx] = setupMacroParam(n[idx], gp[i].sym.typ) 2336 else: 2337 dec(g.config.evalMacroCounter) 2338 c.callsite = nil 2339 localError(c.config, n.info, "expected " & $gp.len & 2340 " generic parameter(s)") 2341 # temporary storage: 2342 #for i in L..<maxSlots: tos.slots[i] = newNode(nkEmpty) 2343 result = rawExecute(c, start, tos).regToNode 2344 if result.info.line < 0: result.info = n.info 2345 if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree") 2346 dec(g.config.evalMacroCounter) 2347 c.callsite = nil 2348 c.mode = oldMode 2349