vmdef.nim 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module contains the type definitions for the new evaluation engine.
  10. ## An instruction is 1-3 int32s in memory, it is a register based VM.
  11. import ast, passes, msgs, idents, intsets, options, modulegraphs, lineinfos,
  12. tables, btrees
  13. const
  14. byteExcess* = 128 # we use excess-K for immediates
  15. wordExcess* = 32768
  16. MaxLoopIterations* = 3_000_000 # max iterations of all loops
  17. type
  18. TRegister* = range[0..255]
  19. TDest* = range[-1 .. 255]
  20. TInstr* = distinct uint32
  21. TOpcode* = enum
  22. opcEof, # end of code
  23. opcRet, # return
  24. opcYldYoid, # yield with no value
  25. opcYldVal, # yield with a value
  26. opcAsgnInt,
  27. opcAsgnStr,
  28. opcAsgnFloat,
  29. opcAsgnRef,
  30. opcAsgnIntFromFloat32, # int and float must be of the same byte size
  31. opcAsgnIntFromFloat64, # int and float must be of the same byte size
  32. opcAsgnFloat32FromInt, # int and float must be of the same byte size
  33. opcAsgnFloat64FromInt, # int and float must be of the same byte size
  34. opcAsgnComplex,
  35. opcNodeToReg,
  36. opcLdArr, # a = b[c]
  37. opcWrArr, # a[b] = c
  38. opcLdObj, # a = b.c
  39. opcWrObj, # a.b = c
  40. opcAddrReg,
  41. opcAddrNode,
  42. opcLdDeref,
  43. opcWrDeref,
  44. opcWrStrIdx,
  45. opcLdStrIdx, # a = b[c]
  46. opcAddInt,
  47. opcAddImmInt,
  48. opcSubInt,
  49. opcSubImmInt,
  50. opcLenSeq,
  51. opcLenStr,
  52. opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
  53. opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat,
  54. opcShrInt, opcShlInt, opcAshrInt,
  55. opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
  56. opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
  57. opcLeFloat, opcLtFloat, opcLeu, opcLtu,
  58. opcEqRef, opcEqNimNode, opcSameNodeType,
  59. opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
  60. opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
  61. opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
  62. opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
  63. opcIsNil, opcOf, opcIs,
  64. opcSubStr, opcParseFloat, opcConv, opcCast,
  65. opcQuit, opcReset,
  66. opcNarrowS, opcNarrowU,
  67. opcAddStrCh,
  68. opcAddStrStr,
  69. opcAddSeqElem,
  70. opcRangeChck,
  71. opcNAdd,
  72. opcNAddMultiple,
  73. opcNKind,
  74. opcNSymKind,
  75. opcNIntVal,
  76. opcNFloatVal,
  77. opcNSymbol,
  78. opcNIdent,
  79. opcNGetType,
  80. opcNStrVal,
  81. opcNSetIntVal,
  82. opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
  83. opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
  84. opcNccValue, opcNccInc, opcNcsAdd, opcNcsIncl, opcNcsLen, opcNcsAt,
  85. opcNctPut, opcNctLen, opcNctGet, opcNctHasNext, opcNctNext,
  86. opcSlurp,
  87. opcGorge,
  88. opcParseExprToAst,
  89. opcParseStmtToAst,
  90. opcQueryErrorFlag,
  91. opcNError,
  92. opcNWarning,
  93. opcNHint,
  94. opcNGetLineInfo, opcNSetLineInfo,
  95. opcEqIdent,
  96. opcStrToIdent,
  97. opcGetImpl,
  98. opcGetImplTransf
  99. opcEcho,
  100. opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
  101. opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
  102. opcRaise,
  103. opcNChild,
  104. opcNSetChild,
  105. opcCallSite,
  106. opcNewStr,
  107. opcTJmp, # jump Bx if A != 0
  108. opcFJmp, # jump Bx if A == 0
  109. opcJmp, # jump Bx
  110. opcJmpBack, # jump Bx; resulting from a while loop
  111. opcBranch, # branch for 'case'
  112. opcTry,
  113. opcExcept,
  114. opcFinally,
  115. opcFinallyEnd,
  116. opcNew,
  117. opcNewSeq,
  118. opcLdNull, # dest = nullvalue(types[Bx])
  119. opcLdNullReg,
  120. opcLdConst, # dest = constants[Bx]
  121. opcAsgnConst, # dest = copy(constants[Bx])
  122. opcLdGlobal, # dest = globals[Bx]
  123. opcLdGlobalAddr, # dest = addr(globals[Bx])
  124. opcLdImmInt, # dest = immediate value
  125. opcNBindSym, opcNDynBindSym,
  126. opcSetType, # dest.typ = types[Bx]
  127. opcTypeTrait,
  128. opcMarshalLoad, opcMarshalStore,
  129. opcToNarrowInt,
  130. opcSymOwner
  131. TBlock* = object
  132. label*: PSym
  133. fixups*: seq[TPosition]
  134. TEvalMode* = enum ## reason for evaluation
  135. emRepl, ## evaluate because in REPL mode
  136. emConst, ## evaluate for 'const' according to spec
  137. emOptimize, ## evaluate for optimization purposes (same as
  138. ## emConst?)
  139. emStaticExpr, ## evaluate for enforced compile time eval
  140. ## ('static' context)
  141. emStaticStmt ## 'static' as an expression
  142. TSandboxFlag* = enum ## what the evaluation engine should allow
  143. allowCast, ## allow unsafe language feature: 'cast'
  144. allowFFI, ## allow the FFI
  145. allowInfiniteLoops ## allow endless loops
  146. TSandboxFlags* = set[TSandboxFlag]
  147. TSlotKind* = enum # We try to re-use slots in a smart way to
  148. # minimize allocations; however the VM supports arbitrary
  149. # temporary slot usage. This is required for the parameter
  150. # passing implementation.
  151. slotEmpty, # slot is unused
  152. slotFixedVar, # slot is used for a fixed var/result (requires copy then)
  153. slotFixedLet, # slot is used for a fixed param/let
  154. slotTempUnknown, # slot but type unknown (argument of proc call)
  155. slotTempInt, # some temporary int
  156. slotTempFloat, # some temporary float
  157. slotTempStr, # some temporary string
  158. slotTempComplex, # some complex temporary (s.node field is used)
  159. slotTempPerm # slot is temporary but permanent (hack)
  160. PProc* = ref object
  161. blocks*: seq[TBlock] # blocks; temp data structure
  162. sym*: PSym
  163. slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
  164. maxSlots*: int
  165. VmArgs* = object
  166. ra*, rb*, rc*: Natural
  167. slots*: pointer
  168. currentException*: PNode
  169. currentLineInfo*: TLineInfo
  170. VmCallback* = proc (args: VmArgs) {.closure.}
  171. PCtx* = ref TCtx
  172. TCtx* = object of TPassContext # code gen context
  173. code*: seq[TInstr]
  174. debug*: seq[TLineInfo] # line info for every instruction; kept separate
  175. # to not slow down interpretation
  176. globals*: PNode #
  177. constants*: PNode # constant data
  178. types*: seq[PType] # some instructions reference types (e.g. 'except')
  179. currentExceptionA*, currentExceptionB*: PNode
  180. exceptionInstr*: int # index of instruction that raised the exception
  181. prc*: PProc
  182. module*: PSym
  183. callsite*: PNode
  184. mode*: TEvalMode
  185. features*: TSandboxFlags
  186. traceActive*: bool
  187. loopIterations*: int
  188. comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
  189. callbacks*: seq[tuple[key: string, value: VmCallback]]
  190. errorFlag*: string
  191. cache*: IdentCache
  192. config*: ConfigRef
  193. graph*: ModuleGraph
  194. oldErrorCount*: int
  195. TPosition* = distinct int
  196. PEvalContext* = PCtx
  197. proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
  198. PCtx(code: @[], debug: @[],
  199. globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
  200. prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
  201. comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
  202. cache: cache, config: g.config, graph: g)
  203. proc refresh*(c: PCtx, module: PSym) =
  204. c.module = module
  205. c.prc = PProc(blocks: @[])
  206. c.loopIterations = MaxLoopIterations
  207. proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} =
  208. result = c.callbacks.len
  209. c.callbacks.add((name, callback))
  210. const
  211. firstABxInstr* = opcTJmp
  212. largeInstrs* = { # instructions which use 2 int32s instead of 1:
  213. opcSubStr, opcConv, opcCast, opcNewSeq, opcOf,
  214. opcMarshalLoad, opcMarshalStore}
  215. slotSomeTemp* = slotTempUnknown
  216. relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
  217. # flag is used to signal opcSeqLen if node is NimNode.
  218. const nimNodeFlag* = 16
  219. template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32)
  220. template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
  221. template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
  222. template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32)
  223. template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int
  224. template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess