vmdef.nim 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. opcSymIsInstantiationOf
  132. TBlock* = object
  133. label*: PSym
  134. fixups*: seq[TPosition]
  135. TEvalMode* = enum ## reason for evaluation
  136. emRepl, ## evaluate because in REPL mode
  137. emConst, ## evaluate for 'const' according to spec
  138. emOptimize, ## evaluate for optimization purposes (same as
  139. ## emConst?)
  140. emStaticExpr, ## evaluate for enforced compile time eval
  141. ## ('static' context)
  142. emStaticStmt ## 'static' as an expression
  143. TSandboxFlag* = enum ## what the evaluation engine should allow
  144. allowCast, ## allow unsafe language feature: 'cast'
  145. allowFFI, ## allow the FFI
  146. allowInfiniteLoops ## allow endless loops
  147. TSandboxFlags* = set[TSandboxFlag]
  148. TSlotKind* = enum # We try to re-use slots in a smart way to
  149. # minimize allocations; however the VM supports arbitrary
  150. # temporary slot usage. This is required for the parameter
  151. # passing implementation.
  152. slotEmpty, # slot is unused
  153. slotFixedVar, # slot is used for a fixed var/result (requires copy then)
  154. slotFixedLet, # slot is used for a fixed param/let
  155. slotTempUnknown, # slot but type unknown (argument of proc call)
  156. slotTempInt, # some temporary int
  157. slotTempFloat, # some temporary float
  158. slotTempStr, # some temporary string
  159. slotTempComplex, # some complex temporary (s.node field is used)
  160. slotTempPerm # slot is temporary but permanent (hack)
  161. PProc* = ref object
  162. blocks*: seq[TBlock] # blocks; temp data structure
  163. sym*: PSym
  164. slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
  165. maxSlots*: int
  166. VmArgs* = object
  167. ra*, rb*, rc*: Natural
  168. slots*: pointer
  169. currentException*: PNode
  170. currentLineInfo*: TLineInfo
  171. VmCallback* = proc (args: VmArgs) {.closure.}
  172. PCtx* = ref TCtx
  173. TCtx* = object of TPassContext # code gen context
  174. code*: seq[TInstr]
  175. debug*: seq[TLineInfo] # line info for every instruction; kept separate
  176. # to not slow down interpretation
  177. globals*: PNode #
  178. constants*: PNode # constant data
  179. types*: seq[PType] # some instructions reference types (e.g. 'except')
  180. currentExceptionA*, currentExceptionB*: PNode
  181. exceptionInstr*: int # index of instruction that raised the exception
  182. prc*: PProc
  183. module*: PSym
  184. callsite*: PNode
  185. mode*: TEvalMode
  186. features*: TSandboxFlags
  187. traceActive*: bool
  188. loopIterations*: int
  189. comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
  190. callbacks*: seq[tuple[key: string, value: VmCallback]]
  191. errorFlag*: string
  192. cache*: IdentCache
  193. config*: ConfigRef
  194. graph*: ModuleGraph
  195. oldErrorCount*: int
  196. TPosition* = distinct int
  197. PEvalContext* = PCtx
  198. proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
  199. PCtx(code: @[], debug: @[],
  200. globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
  201. prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
  202. comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
  203. cache: cache, config: g.config, graph: g)
  204. proc refresh*(c: PCtx, module: PSym) =
  205. c.module = module
  206. c.prc = PProc(blocks: @[])
  207. c.loopIterations = MaxLoopIterations
  208. proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} =
  209. result = c.callbacks.len
  210. c.callbacks.add((name, callback))
  211. const
  212. firstABxInstr* = opcTJmp
  213. largeInstrs* = { # instructions which use 2 int32s instead of 1:
  214. opcSubStr, opcConv, opcCast, opcNewSeq, opcOf,
  215. opcMarshalLoad, opcMarshalStore}
  216. slotSomeTemp* = slotTempUnknown
  217. relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
  218. # flag is used to signal opcSeqLen if node is NimNode.
  219. const nimNodeFlag* = 16
  220. template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32)
  221. template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
  222. template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
  223. template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32)
  224. template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int
  225. template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess