vmdef.nim 7.6 KB

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