nirvm.nim 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2023 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ##[ NIR is a little too high level to interpret it efficiently. Thus
  10. we compute `addresses` for SymIds, labels and offsets for object fields
  11. in a preprocessing step.
  12. We also split the instruction stream into separate (code, debug) seqs while
  13. we're at it.
  14. ]##
  15. import std / [syncio, assertions, tables, intsets]
  16. import ".." / ic / bitabs
  17. import nirinsts, nirtypes, nirfiles, nirlineinfos
  18. type
  19. OpcodeM = enum
  20. ImmediateValM,
  21. IntValM,
  22. StrValM,
  23. LoadLocalM, # with local ID
  24. LoadGlobalM,
  25. LoadProcM,
  26. TypedM, # with type ID
  27. PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum
  28. NilValM,
  29. AllocLocals,
  30. SummonParamM,
  31. GotoM,
  32. CheckedGotoM, # last atom
  33. ArrayConstrM,
  34. ObjConstrM,
  35. RetM,
  36. YldM,
  37. SelectM,
  38. SelectPairM, # ((values...), Label)
  39. SelectListM, # (values...)
  40. SelectValueM, # (value)
  41. SelectRangeM, # (valueA..valueB)
  42. AddrOfM,
  43. ArrayAtM, # (elemSize, addr(a), i)
  44. DerefArrayAtM,
  45. FieldAtM, # addr(obj.field)
  46. DerefFieldAtM,
  47. LoadM, # a[]
  48. AsgnM, # a = b
  49. StoreM, # a[] = b
  50. SetExcM,
  51. TestExcM,
  52. CheckedRangeM,
  53. CheckedIndexM,
  54. CallM,
  55. CheckedAddM, # with overflow checking etc.
  56. CheckedSubM,
  57. CheckedMulM,
  58. CheckedDivM,
  59. CheckedModM,
  60. AddM,
  61. SubM,
  62. MulM,
  63. DivM,
  64. ModM,
  65. BitShlM,
  66. BitShrM,
  67. BitAndM,
  68. BitOrM,
  69. BitXorM,
  70. BitNotM,
  71. BoolNotM,
  72. EqM,
  73. LeM,
  74. LtM,
  75. CastM,
  76. NumberConvM,
  77. CheckedObjConvM,
  78. ObjConvM,
  79. TestOfM,
  80. ProcDeclM,
  81. PragmaPairM
  82. const
  83. LastAtomicValue = CheckedGotoM
  84. OpcodeBits = 8'u32
  85. OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
  86. type
  87. Instr = distinct uint32
  88. template kind(n: Instr): OpcodeM = OpcodeM(n.uint32 and OpcodeMask)
  89. template operand(n: Instr): uint32 = (n.uint32 shr OpcodeBits)
  90. template toIns(k: OpcodeM; operand: uint32): Instr =
  91. Instr(uint32(k) or (operand shl OpcodeBits))
  92. template toIns(k: OpcodeM; operand: LitId): Instr =
  93. Instr(uint32(k) or (operand.uint32 shl OpcodeBits))
  94. type
  95. NimStrPayloadVM = object
  96. cap: int
  97. data: UncheckedArray[char]
  98. NimStringVM = object
  99. len: int
  100. p: ptr NimStrPayloadVM
  101. const
  102. GlobalsSize = 1024*24
  103. type
  104. PatchPos = distinct int
  105. CodePos = distinct int
  106. Bytecode* = object
  107. code: seq[Instr]
  108. debug: seq[PackedLineInfo]
  109. m: ref NirModule
  110. procs: Table[SymId, CodePos]
  111. globals: Table[SymId, (uint32, int)]
  112. strings: Table[LitId, NimStringVM]
  113. globalData: pointer
  114. globalsAddr: uint32
  115. typeImpls: Table[string, TypeId]
  116. offsets: Table[TypeId, seq[(int, TypeId)]]
  117. sizes: Table[TypeId, (int, int)] # (size, alignment)
  118. oldTypeLen: int
  119. procUsagesToPatch: Table[SymId, seq[CodePos]]
  120. interactive*: bool
  121. Universe* = object ## all units: For interpretation we need that
  122. units: seq[Bytecode]
  123. unitNames: Table[string, int]
  124. current: int
  125. proc initBytecode*(m: ref NirModule): Bytecode = Bytecode(m: m, globalData: alloc0(GlobalsSize))
  126. proc debug(bc: Bytecode; t: TypeId) =
  127. var buf = ""
  128. toString buf, bc.m.types, t
  129. echo buf
  130. proc debug(bc: Bytecode; info: PackedLineInfo) =
  131. let (litId, line, col) = bc.m.man.unpack(info)
  132. echo bc.m.lit.strings[litId], ":", line, ":", col
  133. proc debug(bc: Bytecode; t: Tree; n: NodePos) =
  134. var buf = ""
  135. toString(t, n, bc.m.lit.strings, bc.m.lit.numbers, bc.m.symnames, buf)
  136. echo buf
  137. template `[]`(t: seq[Instr]; n: CodePos): Instr = t[n.int]
  138. proc traverseObject(b: var Bytecode; t, offsetKey: TypeId) =
  139. var size = -1
  140. var align = -1
  141. for x in sons(b.m.types, t):
  142. case b.m.types[x].kind
  143. of FieldDecl:
  144. var offset = -1
  145. for y in sons(b.m.types, x):
  146. if b.m.types[y].kind == OffsetVal:
  147. offset = int(b.m.lit.numbers[b.m.types[y].litId])
  148. break
  149. b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon)
  150. of SizeVal:
  151. size = int(b.m.lit.numbers[b.m.types[x].litId])
  152. of AlignVal:
  153. align = int(b.m.lit.numbers[b.m.types[x].litId])
  154. of ObjectTy:
  155. # inheritance
  156. let impl = b.typeImpls.getOrDefault(b.m.lit.strings[b.m.types[x].litId])
  157. assert impl.int > 0
  158. traverseObject b, impl, offsetKey
  159. else: discard
  160. if t == offsetKey:
  161. b.sizes[t] = (size, align)
  162. proc computeSize(b: var Bytecode; t: TypeId): (int, int) =
  163. case b.m.types[t].kind
  164. of ObjectDecl, UnionDecl:
  165. result = b.sizes[t]
  166. of ObjectTy, UnionTy:
  167. let impl = b.typeImpls[b.m.lit.strings[b.m.types[t].litId]]
  168. result = computeSize(b, impl)
  169. of IntTy, UIntTy, FloatTy, BoolTy, CharTy:
  170. let s = b.m.types[t].integralBits div 8
  171. result = (s, s)
  172. of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ProcTy:
  173. result = (sizeof(pointer), sizeof(pointer))
  174. of ArrayTy:
  175. let e = elementType(b.m.types, t)
  176. let n = arrayLen(b.m.types, t)
  177. let inner = computeSize(b, e)
  178. result = (inner[0] * n.int, inner[1])
  179. else:
  180. result = (0, 0)
  181. proc computeElemSize(b: var Bytecode; t: TypeId): int =
  182. case b.m.types[t].kind
  183. of ArrayTy, APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, LastArrayTy:
  184. result = computeSize(b, elementType(b.m.types, t))[0]
  185. else:
  186. raiseAssert "not an array type"
  187. proc traverseTypes(b: var Bytecode) =
  188. for t in allTypes(b.m.types, b.oldTypeLen):
  189. if b.m.types[t].kind in {ObjectDecl, UnionDecl}:
  190. assert b.m.types[t.firstSon].kind == NameVal
  191. b.typeImpls[b.m.lit.strings[b.m.types[t.firstSon].litId]] = t
  192. for t in allTypes(b.m.types, b.oldTypeLen):
  193. if b.m.types[t].kind in {ObjectDecl, UnionDecl}:
  194. assert b.m.types[t.firstSon].kind == NameVal
  195. traverseObject b, t, t
  196. b.oldTypeLen = b.m.types.len
  197. const
  198. InvalidPatchPos* = PatchPos(-1)
  199. proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
  200. proc prepare(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM): PatchPos =
  201. result = PatchPos bc.code.len
  202. bc.code.add toIns(kind, 1'u32)
  203. bc.debug.add info
  204. proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) =
  205. bc.code.add toIns(kind, raw)
  206. bc.debug.add info
  207. proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) =
  208. add bc, info, kind, uint32(lit)
  209. proc isAtom(bc: Bytecode; pos: int): bool {.inline.} = bc.code[pos].kind <= LastAtomicValue
  210. proc isAtom(bc: Bytecode; pos: CodePos): bool {.inline.} = bc.code[pos.int].kind <= LastAtomicValue
  211. proc patch(bc: var Bytecode; pos: PatchPos) =
  212. let pos = pos.int
  213. let k = bc.code[pos].kind
  214. assert k > LastAtomicValue
  215. let distance = int32(bc.code.len - pos)
  216. assert distance > 0
  217. bc.code[pos] = toIns(k, cast[uint32](distance))
  218. template build(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; body: untyped) =
  219. let pos = prepare(bc, info, kind)
  220. body
  221. patch(bc, pos)
  222. proc len*(bc: Bytecode): int {.inline.} = bc.code.len
  223. template rawSpan(n: Instr): int = int(operand(n))
  224. proc nextChild(bc: Bytecode; pos: var int) {.inline.} =
  225. if bc.code[pos].kind > LastAtomicValue:
  226. assert bc.code[pos].operand > 0'u32
  227. inc pos, bc.code[pos].rawSpan
  228. else:
  229. inc pos
  230. proc next(bc: Bytecode; pos: var CodePos) {.inline.} = nextChild bc, int(pos)
  231. iterator sons(bc: Bytecode; n: CodePos): CodePos =
  232. var pos = n.int
  233. assert bc.code[pos].kind > LastAtomicValue
  234. let last = pos + bc.code[pos].rawSpan
  235. inc pos
  236. while pos < last:
  237. yield CodePos pos
  238. nextChild bc, pos
  239. iterator sonsFrom1(bc: Bytecode; n: CodePos): CodePos =
  240. var pos = n.int
  241. assert bc.code[pos].kind > LastAtomicValue
  242. let last = pos + bc.code[pos].rawSpan
  243. inc pos
  244. nextChild bc, pos
  245. while pos < last:
  246. yield CodePos pos
  247. nextChild bc, pos
  248. iterator sonsFrom2(bc: Bytecode; n: CodePos): CodePos =
  249. var pos = n.int
  250. assert bc.code[pos].kind > LastAtomicValue
  251. let last = pos + bc.code[pos].rawSpan
  252. inc pos
  253. nextChild bc, pos
  254. nextChild bc, pos
  255. while pos < last:
  256. yield CodePos pos
  257. nextChild bc, pos
  258. template firstSon(n: CodePos): CodePos = CodePos(n.int+1)
  259. template `[]`(t: Bytecode; n: CodePos): Instr = t.code[n.int]
  260. proc span(bc: Bytecode; pos: int): int {.inline.} =
  261. if bc.code[pos].kind <= LastAtomicValue: 1 else: int(bc.code[pos].operand)
  262. iterator triples*(bc: Bytecode; n: CodePos): (uint32, int, CodePos) =
  263. var pos = n.int
  264. assert bc.code[pos].kind > LastAtomicValue
  265. let last = pos + bc.code[pos].rawSpan
  266. inc pos
  267. while pos < last:
  268. let offset = bc.code[pos].operand
  269. nextChild bc, pos
  270. let size = bc.code[pos].operand.int
  271. nextChild bc, pos
  272. let val = CodePos pos
  273. yield (offset, size, val)
  274. nextChild bc, pos
  275. proc toString*(t: Bytecode; pos: CodePos;
  276. r: var string; nesting = 0) =
  277. if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
  278. r.add ' '
  279. case t[pos].kind
  280. of ImmediateValM:
  281. r.add $t[pos].operand
  282. of IntValM:
  283. r.add "IntVal "
  284. r.add $t.m.lit.numbers[LitId t[pos].operand]
  285. of StrValM:
  286. escapeToNimLit(t.m.lit.strings[LitId t[pos].operand], r)
  287. of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM:
  288. r.add $t[pos].kind
  289. r.add ' '
  290. r.add $t[pos].operand
  291. of PragmaIdM:
  292. r.add $cast[PragmaKey](t[pos].operand)
  293. of TypedM:
  294. r.add "T<"
  295. r.add $t[pos].operand
  296. r.add ">"
  297. of NilValM:
  298. r.add "NilVal"
  299. of GotoM, CheckedGotoM:
  300. r.add $t[pos].kind
  301. r.add " L"
  302. r.add $t[pos].operand
  303. else:
  304. r.add $t[pos].kind
  305. r.add "{\n"
  306. for i in 0..<(nesting+1)*2: r.add ' '
  307. for p in sons(t, pos):
  308. toString t, p, r, nesting+1
  309. r.add "\n"
  310. for i in 0..<nesting*2: r.add ' '
  311. r.add "}"
  312. proc debug(b: Bytecode; pos: CodePos) =
  313. var buf = ""
  314. toString(b, pos, buf)
  315. echo buf
  316. type
  317. Preprocessing = object
  318. u: ref Universe
  319. known: Table[LabelId, CodePos]
  320. toPatch: Table[LabelId, seq[CodePos]]
  321. locals: Table[SymId, (uint32, int)] # address, size
  322. thisModule: uint32
  323. localsAddr: uint32
  324. markedWithLabel: IntSet
  325. proc align(address, alignment: uint32): uint32 =
  326. result = (address + (alignment - 1'u32)) and not (alignment - 1'u32)
  327. proc genGoto(c: var Preprocessing; bc: var Bytecode; info: PackedLineInfo; lab: LabelId; opc: OpcodeM) =
  328. let dest = c.known.getOrDefault(lab, CodePos(-1))
  329. if dest.int >= 0:
  330. bc.add info, opc, uint32 dest
  331. else:
  332. let here = CodePos(bc.code.len)
  333. c.toPatch.mgetOrPut(lab, @[]).add here
  334. bc.add info, opc, 1u32 # will be patched once we traversed the label
  335. type
  336. AddrMode = enum
  337. InDotExpr, WantAddr
  338. template maybeDeref(doDeref: bool; size: int; body: untyped) =
  339. var pos = PatchPos(-1)
  340. if doDeref:
  341. pos = prepare(bc, info, LoadM)
  342. bc.add info, ImmediateValM, uint32 size
  343. body
  344. if doDeref:
  345. patch(bc, pos)
  346. proc toReadonlyString(s: string): NimStringVM =
  347. if s.len == 0:
  348. result = NimStringVM(len: 0, p: nil)
  349. else:
  350. result = NimStringVM(len: s.len, p: cast[ptr NimStrPayloadVM](alloc(s.len+1+sizeof(int))))
  351. copyMem(addr result.p.data[0], addr s[0], s.len+1)
  352. result.p.cap = s.len or (1 shl (8 * 8 - 2)) # see also NIM_STRLIT_FLAG
  353. const
  354. ForwardedProc = 10_000_000'u32
  355. proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) =
  356. let info = t[n].info
  357. template recurse(opc) =
  358. build bc, info, opc:
  359. for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr})
  360. case t[n].kind
  361. of Nop, ForeignDecl, ForeignProcDecl:
  362. discard "don't use Nop"
  363. of ImmediateVal:
  364. bc.add info, ImmediateValM, t[n].rawOperand
  365. of IntVal:
  366. bc.add info, IntValM, t[n].rawOperand
  367. of StrVal:
  368. let litId = LitId t[n].rawOperand
  369. if not bc.strings.hasKey(litId):
  370. bc.strings[litId] = toReadonlyString(bc.m.lit.strings[litId])
  371. bc.add info, StrValM, t[n].rawOperand
  372. of SymDef:
  373. discard "happens for proc decls. Don't copy the node as we don't need it"
  374. of SymUse:
  375. let s = t[n].symId
  376. if c.locals.hasKey(s):
  377. let (address, size) = c.locals[s]
  378. maybeDeref(WantAddr notin flags, size):
  379. bc.add info, LoadLocalM, address
  380. elif bc.procs.hasKey(s):
  381. bc.add info, LoadProcM, uint32 bc.procs[s]
  382. elif bc.globals.hasKey(s):
  383. let (address, size) = bc.globals[s]
  384. maybeDeref(WantAddr notin flags, size):
  385. bc.add info, LoadGlobalM, address
  386. else:
  387. let here = CodePos(bc.code.len)
  388. bc.add info, LoadProcM, ForwardedProc + uint32(s)
  389. bc.procUsagesToPatch.mgetOrPut(s, @[]).add here
  390. #raiseAssert "don't understand SymUse ID " & $int(s)
  391. of ModuleSymUse:
  392. when false:
  393. let (x, y) = sons2(t, n)
  394. let unit = c.u.unitNames.getOrDefault(bc.m.lit.strings[t[x].litId], -1)
  395. let s = t[y].symId
  396. if c.u.units[unit].procs.hasKey(s):
  397. bc.add info, LoadProcM, uint32 c.u.units[unit].procs[s]
  398. elif bc.globals.hasKey(s):
  399. maybeDeref(WantAddr notin flags):
  400. build bc, info, LoadGlobalM:
  401. bc.add info, ImmediateValM, uint32 unit
  402. bc.add info, LoadLocalM, uint32 s
  403. else:
  404. raiseAssert "don't understand ModuleSymUse ID"
  405. raiseAssert "don't understand ModuleSymUse ID"
  406. of Typed:
  407. bc.add info, TypedM, t[n].rawOperand
  408. of PragmaId:
  409. bc.add info, PragmaIdM, t[n].rawOperand
  410. of NilVal:
  411. bc.add info, NilValM, t[n].rawOperand
  412. of LoopLabel, Label:
  413. let lab = t[n].label
  414. let here = CodePos(bc.code.len)
  415. c.known[lab] = here
  416. var p: seq[CodePos] = @[]
  417. if c.toPatch.take(lab, p):
  418. for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here)
  419. c.markedWithLabel.incl here.int # for toString()
  420. of Goto, GotoLoop:
  421. c.genGoto(bc, info, t[n].label, GotoM)
  422. of CheckedGoto:
  423. c.genGoto(bc, info, t[n].label, CheckedGotoM)
  424. of ArrayConstr:
  425. let typ = t[n.firstSon].typeId
  426. let s = computeElemSize(bc, typ)
  427. build bc, info, ArrayConstrM:
  428. bc.add info, ImmediateValM, uint32 s
  429. for ch in sonsFrom1(t, n):
  430. preprocess(c, bc, t, ch, {WantAddr})
  431. of ObjConstr:
  432. #debug bc, t, n
  433. var i = 0
  434. let typ = t[n.firstSon].typeId
  435. build bc, info, ObjConstrM:
  436. for ch in sons(t, n):
  437. if i > 0:
  438. if (i mod 2) == 1:
  439. let (offset, typ) = bc.offsets[typ][t[ch].immediateVal]
  440. let size = computeSize(bc, typ)[0]
  441. bc.add info, ImmediateValM, uint32(offset)
  442. bc.add info, ImmediateValM, uint32(size)
  443. else:
  444. preprocess(c, bc, t, ch, {WantAddr})
  445. inc i
  446. of Ret:
  447. recurse RetM
  448. of Yld:
  449. recurse YldM
  450. of Select:
  451. recurse SelectM
  452. of SelectPair:
  453. recurse SelectPairM
  454. of SelectList:
  455. recurse SelectListM
  456. of SelectValue:
  457. recurse SelectValueM
  458. of SelectRange:
  459. recurse SelectRangeM
  460. of SummonGlobal, SummonThreadLocal, SummonConst:
  461. let (typ, sym) = sons2(t, n)
  462. let s = t[sym].symId
  463. let tid = t[typ].typeId
  464. let (size, alignment) = computeSize(bc, tid)
  465. let global = align(bc.globalsAddr, uint32 alignment)
  466. bc.globals[s] = (global, size)
  467. bc.globalsAddr += uint32 size
  468. assert bc.globalsAddr < GlobalsSize
  469. of Summon:
  470. let (typ, sym) = sons2(t, n)
  471. let s = t[sym].symId
  472. let tid = t[typ].typeId
  473. let (size, alignment) = computeSize(bc, tid)
  474. let local = align(c.localsAddr, uint32 alignment)
  475. c.locals[s] = (local, size)
  476. c.localsAddr += uint32 size
  477. # allocation is combined into the frame allocation so there is no
  478. # instruction to emit
  479. of SummonParam, SummonResult:
  480. let (typ, sym) = sons2(t, n)
  481. let s = t[sym].symId
  482. let tid = t[typ].typeId
  483. let (size, alignment) = computeSize(bc, tid)
  484. let local = align(c.localsAddr, uint32 alignment)
  485. c.locals[s] = (local, size)
  486. c.localsAddr += uint32 size
  487. bc.add info, SummonParamM, local
  488. bc.add info, ImmediateValM, uint32 size
  489. of Kill:
  490. discard "we don't care about Kill instructions"
  491. of AddrOf:
  492. let (_, arg) = sons2(t, n)
  493. preprocess(c, bc, t, arg, {WantAddr})
  494. # the address of x is what the VM works with all the time so there is
  495. # nothing to compute.
  496. of ArrayAt:
  497. let (arrayType, a, i) = sons3(t, n)
  498. let tid = t[arrayType].typeId
  499. let size = uint32 computeElemSize(bc, tid)
  500. build bc, info, ArrayAtM:
  501. bc.add info, ImmediateValM, size
  502. preprocess(c, bc, t, a, {WantAddr})
  503. preprocess(c, bc, t, i, {WantAddr})
  504. of DerefArrayAt:
  505. let (arrayType, a, i) = sons3(t, n)
  506. let tid = t[arrayType].typeId
  507. let size = uint32 computeElemSize(bc, tid)
  508. build bc, info, DerefArrayAtM:
  509. bc.add info, ImmediateValM, size
  510. preprocess(c, bc, t, a, {WantAddr})
  511. preprocess(c, bc, t, i, {WantAddr})
  512. of FieldAt:
  513. let (typ, a, b) = sons3(t, n)
  514. let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
  515. build bc, info, FieldAtM:
  516. preprocess(c, bc, t, a, flags+{WantAddr})
  517. bc.add info, ImmediateValM, uint32(offset)
  518. of DerefFieldAt:
  519. let (typ, a, b) = sons3(t, n)
  520. let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
  521. build bc, info, DerefFieldAtM:
  522. preprocess(c, bc, t, a, flags+{WantAddr})
  523. bc.add info, ImmediateValM, uint32(offset)
  524. of Load:
  525. let (elemType, a) = sons2(t, n)
  526. let tid = t[elemType].typeId
  527. build bc, info, LoadM:
  528. bc.add info, ImmediateValM, uint32 computeSize(bc, tid)[0]
  529. preprocess(c, bc, t, a, {})
  530. of Store:
  531. raiseAssert "Assumption was that Store is unused!"
  532. of Asgn:
  533. let (elemType, dest, src) = sons3(t, n)
  534. let tid = t[elemType].typeId
  535. if t[src].kind in {Call, IndirectCall}:
  536. # No support for return values, these are mapped to `var T` parameters!
  537. build bc, info, CallM:
  538. preprocess(c, bc, t, src.skipTyped, {WantAddr})
  539. preprocess(c, bc, t, dest, {WantAddr})
  540. for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr})
  541. elif t[src].kind in {CheckedCall, CheckedIndirectCall}:
  542. let (_, gotoInstr, fn) = sons3(t, src)
  543. build bc, info, CallM:
  544. preprocess(c, bc, t, fn, {WantAddr})
  545. preprocess(c, bc, t, dest, {WantAddr})
  546. for ch in sonsFromN(t, src, 3): preprocess(c, bc, t, ch, {WantAddr})
  547. preprocess c, bc, t, gotoInstr, {}
  548. elif t[dest].kind == Load:
  549. let (typ, a) = sons2(t, dest)
  550. let s = computeSize(bc, tid)[0]
  551. build bc, info, StoreM:
  552. bc.add info, ImmediateValM, uint32 s
  553. preprocess(c, bc, t, a, {WantAddr})
  554. preprocess(c, bc, t, src, {})
  555. else:
  556. let s = computeSize(bc, tid)[0]
  557. build bc, info, AsgnM:
  558. bc.add info, ImmediateValM, uint32 s
  559. preprocess(c, bc, t, dest, {WantAddr})
  560. preprocess(c, bc, t, src, {})
  561. of SetExc:
  562. recurse SetExcM
  563. of TestExc:
  564. recurse TestExcM
  565. of CheckedRange:
  566. recurse CheckedRangeM
  567. of CheckedIndex:
  568. recurse CheckedIndexM
  569. of Call, IndirectCall:
  570. # avoid the Typed thing at position 0:
  571. build bc, info, CallM:
  572. for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr})
  573. of CheckedCall, CheckedIndirectCall:
  574. # avoid the Typed thing at position 0:
  575. let (_, gotoInstr, fn) = sons3(t, n)
  576. build bc, info, CallM:
  577. preprocess(c, bc, t, fn, {WantAddr})
  578. for ch in sonsFromN(t, n, 3): preprocess(c, bc, t, ch, {WantAddr})
  579. preprocess c, bc, t, gotoInstr, {WantAddr}
  580. of CheckedAdd:
  581. recurse CheckedAddM
  582. of CheckedSub:
  583. recurse CheckedSubM
  584. of CheckedMul:
  585. recurse CheckedMulM
  586. of CheckedDiv:
  587. recurse CheckedDivM
  588. of CheckedMod:
  589. recurse CheckedModM
  590. of Add:
  591. recurse AddM
  592. of Sub:
  593. recurse SubM
  594. of Mul:
  595. recurse MulM
  596. of Div:
  597. recurse DivM
  598. of Mod:
  599. recurse ModM
  600. of BitShl:
  601. recurse BitShlM
  602. of BitShr:
  603. recurse BitShrM
  604. of BitAnd:
  605. recurse BitAndM
  606. of BitOr:
  607. recurse BitOrM
  608. of BitXor:
  609. recurse BitXorM
  610. of BitNot:
  611. recurse BitNotM
  612. of BoolNot:
  613. recurse BoolNotM
  614. of Eq:
  615. recurse EqM
  616. of Le:
  617. recurse LeM
  618. of Lt:
  619. recurse LtM
  620. of Cast:
  621. recurse CastM
  622. of NumberConv:
  623. recurse NumberConvM
  624. of CheckedObjConv:
  625. recurse CheckedObjConvM
  626. of ObjConv:
  627. recurse ObjConvM
  628. of TestOf:
  629. recurse TestOfM
  630. of Emit:
  631. raiseAssert "cannot interpret: Emit"
  632. of ProcDecl:
  633. var c2 = Preprocessing(u: c.u, thisModule: c.thisModule)
  634. let sym = t[n.firstSon].symId
  635. let here = CodePos(bc.len)
  636. var p: seq[CodePos] = @[]
  637. if bc.procUsagesToPatch.take(sym, p):
  638. for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here)
  639. bc.procs[sym] = here
  640. build bc, info, ProcDeclM:
  641. let toPatch = bc.code.len
  642. bc.add info, AllocLocals, 0'u32
  643. for ch in sons(t, n): preprocess(c2, bc, t, ch, {})
  644. bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr)
  645. when false:
  646. if here.int == 39850:
  647. debug bc, t, n
  648. debug bc, here
  649. of PragmaPair:
  650. recurse PragmaPairM
  651. const PayloadSize = 128
  652. type
  653. StackFrame = ref object
  654. locals: pointer # usually points into `payload` if size is small enough, otherwise it's `alloc`'ed.
  655. payload: array[PayloadSize, byte]
  656. caller: StackFrame
  657. returnAddr: CodePos
  658. jumpTo: CodePos # exception handling
  659. u: ref Universe
  660. proc newStackFrame(size: int; caller: StackFrame; returnAddr: CodePos): StackFrame =
  661. result = StackFrame(caller: caller, returnAddr: returnAddr, u: caller.u)
  662. if size <= PayloadSize:
  663. result.locals = addr(result.payload)
  664. else:
  665. result.locals = alloc0(size)
  666. proc popStackFrame(s: StackFrame): StackFrame =
  667. if s.locals != addr(s.payload):
  668. dealloc s.locals
  669. result = s.caller
  670. template `+!`(p: pointer; diff: uint): pointer = cast[pointer](cast[uint](p) + diff)
  671. proc isAtom(tree: seq[Instr]; pos: CodePos): bool {.inline.} = tree[pos.int].kind <= LastAtomicValue
  672. proc span(bc: seq[Instr]; pos: int): int {.inline.} =
  673. if bc[pos].kind <= LastAtomicValue: 1 else: int(bc[pos].operand)
  674. proc sons2(tree: seq[Instr]; n: CodePos): (CodePos, CodePos) =
  675. assert(not isAtom(tree, n))
  676. let a = n.int+1
  677. let b = a + span(tree, a)
  678. result = (CodePos a, CodePos b)
  679. proc sons3(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos) =
  680. assert(not isAtom(tree, n))
  681. let a = n.int+1
  682. let b = a + span(tree, a)
  683. let c = b + span(tree, b)
  684. result = (CodePos a, CodePos b, CodePos c)
  685. proc sons4(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos, CodePos) =
  686. assert(not isAtom(tree, n))
  687. let a = n.int+1
  688. let b = a + span(tree, a)
  689. let c = b + span(tree, b)
  690. let d = c + span(tree, c)
  691. result = (CodePos a, CodePos b, CodePos c, CodePos d)
  692. proc typeId*(ins: Instr): TypeId {.inline.} =
  693. assert ins.kind == TypedM
  694. result = TypeId(ins.operand)
  695. proc immediateVal*(ins: Instr): int {.inline.} =
  696. assert ins.kind == ImmediateValM
  697. result = cast[int](ins.operand)
  698. proc litId*(ins: Instr): LitId {.inline.} =
  699. assert ins.kind in {StrValM, IntValM}
  700. result = LitId(ins.operand)
  701. proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int)
  702. proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer =
  703. case c.code[pc].kind
  704. of LoadLocalM:
  705. result = s.locals +! c.code[pc].operand
  706. of FieldAtM:
  707. let (x, offset) = sons2(c.code, pc)
  708. result = evalAddr(c, x, s)
  709. result = result +! c.code[offset].operand
  710. of DerefFieldAtM:
  711. let (x, offset) = sons2(c.code, pc)
  712. let p = evalAddr(c, x, s)
  713. result = cast[ptr pointer](p)[] +! c.code[offset].operand
  714. of ArrayAtM:
  715. let (e, a, i) = sons3(c.code, pc)
  716. let elemSize = c.code[e].operand
  717. result = evalAddr(c, a, s)
  718. var idx: int = 0
  719. eval(c, i, s, addr idx, sizeof(int))
  720. result = result +! (uint32(idx) * elemSize)
  721. of DerefArrayAtM:
  722. let (e, a, i) = sons3(c.code, pc)
  723. let elemSize = c.code[e].operand
  724. var p = evalAddr(c, a, s)
  725. var idx: int = 0
  726. eval(c, i, s, addr idx, sizeof(int))
  727. result = cast[ptr pointer](p)[] +! (uint32(idx) * elemSize)
  728. of LoadGlobalM:
  729. result = c.globalData +! c.code[pc].operand
  730. else:
  731. raiseAssert("unimplemented addressing mode")
  732. proc `div`(x, y: float32): float32 {.inline.} = x / y
  733. proc `div`(x, y: float64): float64 {.inline.} = x / y
  734. from std / math import `mod`
  735. template binop(opr) {.dirty.} =
  736. template impl(typ) {.dirty.} =
  737. var x = default(typ)
  738. var y = default(typ)
  739. eval c, a, s, addr x, sizeof(typ)
  740. eval c, b, s, addr y, sizeof(typ)
  741. cast[ptr typ](result)[] = opr(x, y)
  742. let (t, a, b) = sons3(c.code, pc)
  743. let tid = TypeId c.code[t].operand
  744. case tid
  745. of Bool8Id, Char8Id, UInt8Id: impl uint8
  746. of Int8Id: impl int8
  747. of Int16Id: impl int16
  748. of Int32Id: impl int32
  749. of Int64Id: impl int64
  750. of UInt16Id: impl uint16
  751. of UInt32Id: impl uint32
  752. of UInt64Id: impl uint64
  753. of Float32Id: impl float32
  754. of Float64Id: impl float64
  755. else: discard
  756. template checkedBinop(opr) {.dirty.} =
  757. template impl(typ) {.dirty.} =
  758. var x = default(typ)
  759. var y = default(typ)
  760. eval c, a, s, addr x, sizeof(typ)
  761. eval c, b, s, addr y, sizeof(typ)
  762. try:
  763. cast[ptr typ](result)[] = opr(x, y)
  764. except OverflowDefect, DivByZeroDefect:
  765. s.jumpTo = CodePos c.code[j].operand
  766. let (t, j, a, b) = sons4(c.code, pc)
  767. let tid = TypeId c.code[t].operand
  768. case tid
  769. of Bool8Id, Char8Id, UInt8Id: impl uint8
  770. of Int8Id: impl int8
  771. of Int16Id: impl int16
  772. of Int32Id: impl int32
  773. of Int64Id: impl int64
  774. of UInt16Id: impl uint16
  775. of UInt32Id: impl uint32
  776. of UInt64Id: impl uint64
  777. of Float32Id: impl float32
  778. of Float64Id: impl float64
  779. else: discard
  780. template bitop(opr) {.dirty.} =
  781. template impl(typ) {.dirty.} =
  782. var x = default(typ)
  783. var y = default(typ)
  784. eval c, a, s, addr x, sizeof(typ)
  785. eval c, b, s, addr y, sizeof(typ)
  786. cast[ptr typ](result)[] = opr(x, y)
  787. let (t, a, b) = sons3(c.code, pc)
  788. let tid = c.code[t].typeId
  789. case tid
  790. of Bool8Id, Char8Id, UInt8Id: impl uint8
  791. of Int8Id: impl int8
  792. of Int16Id: impl int16
  793. of Int32Id: impl int32
  794. of Int64Id: impl int64
  795. of UInt16Id: impl uint16
  796. of UInt32Id: impl uint32
  797. of UInt64Id: impl uint64
  798. else: discard
  799. template cmpop(opr) {.dirty.} =
  800. template impl(typ) {.dirty.} =
  801. var x = default(typ)
  802. var y = default(typ)
  803. eval c, a, s, addr x, sizeof(typ)
  804. eval c, b, s, addr y, sizeof(typ)
  805. cast[ptr bool](result)[] = opr(x, y)
  806. let (t, a, b) = sons3(c.code, pc)
  807. let tid = c.code[t].typeId
  808. case tid
  809. of Bool8Id, Char8Id, UInt8Id: impl uint8
  810. of Int8Id: impl int8
  811. of Int16Id: impl int16
  812. of Int32Id: impl int32
  813. of Int64Id: impl int64
  814. of UInt16Id: impl uint16
  815. of UInt32Id: impl uint32
  816. of UInt64Id: impl uint64
  817. of Float32Id: impl float32
  818. of Float64Id: impl float64
  819. else: discard
  820. proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
  821. template impl(typ) {.dirty.} =
  822. var selector = default(typ)
  823. eval c, sel, s, addr selector, sizeof(typ)
  824. for pair in sonsFrom2(c, pc):
  825. assert c.code[pair].kind == SelectPairM
  826. let (values, action) = sons2(c.code, pair)
  827. if c.code[values].kind == SelectValueM:
  828. var a = default(typ)
  829. eval c, values.firstSon, s, addr a, sizeof(typ)
  830. if selector == a:
  831. return CodePos c.code[action].operand
  832. else:
  833. assert c.code[values].kind == SelectListM, $c.code[values].kind
  834. for v in sons(c, values):
  835. case c.code[v].kind
  836. of SelectValueM:
  837. var a = default(typ)
  838. eval c, v.firstSon, s, addr a, sizeof(typ)
  839. if selector == a:
  840. return CodePos c.code[action].operand
  841. of SelectRangeM:
  842. let (va, vb) = sons2(c.code, v)
  843. var a = default(typ)
  844. eval c, va, s, addr a, sizeof(typ)
  845. var b = default(typ)
  846. eval c, vb, s, addr a, sizeof(typ)
  847. if a <= selector and selector <= b:
  848. return CodePos c.code[action].operand
  849. else: raiseAssert "unreachable"
  850. result = CodePos(-1)
  851. let (t, sel) = sons2(c.code, pc)
  852. let tid = c.code[t].typeId
  853. case tid
  854. of Bool8Id, Char8Id, UInt8Id: impl uint8
  855. of Int8Id: impl int8
  856. of Int16Id: impl int16
  857. of Int32Id: impl int32
  858. of Int64Id: impl int64
  859. of UInt16Id: impl uint16
  860. of UInt32Id: impl uint32
  861. of UInt64Id: impl uint64
  862. else: raiseAssert "unreachable"
  863. proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) =
  864. case c.code[pc].kind
  865. of LoadLocalM:
  866. let src = s.locals +! c.code[pc].operand
  867. copyMem result, src, size
  868. of FieldAtM, DerefFieldAtM, ArrayAtM, DerefArrayAtM, LoadGlobalM:
  869. let src = evalAddr(c, pc, s)
  870. copyMem result, src, size
  871. of LoadProcM:
  872. let procAddr = c.code[pc].operand
  873. cast[ptr pointer](result)[] = cast[pointer](procAddr)
  874. of LoadM:
  875. let (_, arg) = sons2(c.code, pc)
  876. let src = evalAddr(c, arg, s)
  877. copyMem result, src, size
  878. of CheckedAddM: checkedBinop `+`
  879. of CheckedSubM: checkedBinop `-`
  880. of CheckedMulM: checkedBinop `*`
  881. of CheckedDivM: checkedBinop `div`
  882. of CheckedModM: checkedBinop `mod`
  883. of AddM: binop `+`
  884. of SubM: binop `-`
  885. of MulM: binop `*`
  886. of DivM: binop `div`
  887. of ModM: binop `mod`
  888. of BitShlM: bitop `shl`
  889. of BitShrM: bitop `shr`
  890. of BitAndM: bitop `and`
  891. of BitOrM: bitop `or`
  892. of BitXorM: bitop `xor`
  893. of EqM: cmpop `==`
  894. of LeM: cmpop `<=`
  895. of LtM: cmpop `<`
  896. of StrValM:
  897. # binary compatible and no deep copy required:
  898. copyMem(cast[ptr string](result), addr(c.strings[c[pc].litId]), sizeof(string))
  899. of ObjConstrM:
  900. for offset, size, val in triples(c, pc):
  901. eval c, val, s, result+!offset, size
  902. of ArrayConstrM:
  903. let elemSize = c.code[pc.firstSon].operand
  904. var r = result
  905. for ch in sonsFrom1(c, pc):
  906. eval c, ch, s, r, elemSize.int
  907. r = r+!elemSize # can even do strength reduction here!
  908. of NumberConvM:
  909. let (t, x) = sons2(c.code, pc)
  910. let word = if c[x].kind == NilValM: 0'i64 else: c.m.lit.numbers[c[x].litId]
  911. template impl(typ: typedesc) {.dirty.} =
  912. cast[ptr typ](result)[] = cast[typ](word)
  913. let tid = c.code[t].typeId
  914. case tid
  915. of Bool8Id, Char8Id, UInt8Id: impl uint8
  916. of Int8Id: impl int8
  917. of Int16Id: impl int16
  918. of Int32Id: impl int32
  919. of Int64Id: impl int64
  920. of UInt16Id: impl uint16
  921. of UInt32Id: impl uint32
  922. of UInt64Id: impl uint64
  923. of Float32Id: impl float32
  924. of Float64Id: impl float64
  925. else:
  926. case c.m.types[tid].kind
  927. of ProcTy, UPtrTy, APtrTy, AArrayPtrTy, UArrayPtrTy:
  928. # the VM always uses 64 bit pointers:
  929. impl uint64
  930. else:
  931. raiseAssert "cannot happen: " & $c.m.types[tid].kind
  932. else:
  933. #debug c, c.debug[pc.int]
  934. raiseAssert "cannot happen: " & $c.code[pc].kind
  935. proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
  936. assert c.code[pc].kind == LoadProcM
  937. let procSym = c[pc].operand
  938. when false:
  939. if procSym >= ForwardedProc:
  940. for k, v in c.procUsagesToPatch:
  941. if uint32(k) == procSym - ForwardedProc:
  942. echo k.int, " ", v.len, " <-- this one"
  943. else:
  944. echo k.int, " ", v.len
  945. assert procSym < ForwardedProc
  946. result = CodePos(procSym)
  947. proc echoImpl(c: Bytecode; pc: CodePos; frame: StackFrame) =
  948. var s = default(NimStringVM)
  949. for a in sonsFrom1(c, pc):
  950. assert c[a].kind == ArrayConstrM
  951. let elemSize = c.code[a.firstSon].operand.int
  952. for ch in sonsFrom1(c, a):
  953. eval c, ch, frame, addr s, elemSize
  954. if s.len > 0:
  955. discard stdout.writeBuffer(addr(s.p.data[0]), s.len)
  956. stdout.write "\n"
  957. stdout.flushFile()
  958. type
  959. EvalBuiltinState = enum
  960. DidNothing, DidEval, DidError
  961. proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; state: var EvalBuiltinState): CodePos =
  962. var prc = prc
  963. while true:
  964. case c[prc].kind
  965. of PragmaPairM:
  966. let (x, y) = sons2(c.code, prc)
  967. let key = cast[PragmaKey](c[x].operand)
  968. case key
  969. of CoreName:
  970. let lit = c[y].litId
  971. case c.m.lit.strings[lit]
  972. of "echoBinSafe": echoImpl(c, pc, s)
  973. else:
  974. raiseAssert "cannot eval: " & c.m.lit.strings[lit]
  975. state = DidEval
  976. of HeaderImport, DllImport:
  977. let lit = c[y].litId
  978. raiseAssert "cannot eval: " & c.m.lit.strings[lit]
  979. else: discard
  980. of PragmaIdM, AllocLocals: discard
  981. else: break
  982. next c, prc
  983. result = prc
  984. proc exec(c: Bytecode; pc: CodePos; u: ref Universe) =
  985. var pc = pc
  986. var frame = StackFrame(u: u)
  987. while pc.int < c.code.len:
  988. when false: # c.interactive:
  989. echo "running: ", pc.int
  990. debug c, pc
  991. case c.code[pc].kind
  992. of GotoM:
  993. pc = CodePos(c.code[pc].operand)
  994. of AsgnM:
  995. let (sz, a, b) = sons3(c.code, pc)
  996. let dest = evalAddr(c, a, frame)
  997. eval(c, b, frame, dest, c.code[sz].operand.int)
  998. next c, pc
  999. of StoreM:
  1000. let (sz, a, b) = sons3(c.code, pc)
  1001. let destPtr = evalAddr(c, a, frame)
  1002. let dest = cast[ptr pointer](destPtr)[]
  1003. eval(c, b, frame, dest, c.code[sz].operand.int)
  1004. next c, pc
  1005. of CallM:
  1006. # No support for return values, these are mapped to `var T` parameters!
  1007. var prc = evalProc(c, pc.firstSon, frame)
  1008. assert c.code[prc.firstSon].kind == AllocLocals
  1009. let frameSize = int c.code[prc.firstSon].operand
  1010. # skip stupid stuff:
  1011. var evalState = DidNothing
  1012. prc = evalBuiltin(c, pc, frame, prc.firstSon, evalState)
  1013. if evalState != DidNothing:
  1014. next c, pc
  1015. if pc.int < c.code.len and c.code[pc].kind == CheckedGotoM:
  1016. if evalState == DidEval:
  1017. next c, pc
  1018. else:
  1019. pc = CodePos(c.code[pc].operand)
  1020. else:
  1021. # setup storage for the proc already:
  1022. let callInstr = pc
  1023. next c, pc
  1024. let s2 = newStackFrame(frameSize, frame, pc)
  1025. for a in sonsFrom1(c, callInstr):
  1026. assert c[prc].kind == SummonParamM
  1027. let paramAddr = c[prc].operand
  1028. next c, prc
  1029. assert c[prc].kind == ImmediateValM
  1030. let paramSize = c[prc].operand.int
  1031. next c, prc
  1032. eval(c, a, s2, s2.locals +! paramAddr, paramSize)
  1033. frame = s2
  1034. pc = prc
  1035. of RetM:
  1036. pc = frame.returnAddr
  1037. if c.code[pc].kind == CheckedGotoM:
  1038. pc = frame.jumpTo
  1039. frame = popStackFrame(frame)
  1040. of SelectM:
  1041. let pc2 = evalSelect(c, pc, frame)
  1042. if pc2.int >= 0:
  1043. pc = pc2
  1044. else:
  1045. next c, pc
  1046. of ProcDeclM:
  1047. next c, pc
  1048. else:
  1049. #debug c, c.debug[pc.int]
  1050. raiseAssert "unreachable: " & $c.code[pc].kind
  1051. proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) =
  1052. traverseTypes bc
  1053. var c = Preprocessing(u: nil, thisModule: 1'u32)
  1054. let start = CodePos(bc.code.len)
  1055. var pc = n
  1056. while pc.int < t.len:
  1057. #if bc.interactive:
  1058. # echo "RUnning: "
  1059. # debug bc, t, pc
  1060. preprocess c, bc, t, pc, {}
  1061. next t, pc
  1062. exec bc, start, nil