vmdef.nim 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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* = 10_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,
  66. opcNarrowS, opcNarrowU,
  67. opcSignExtend,
  68. opcAddStrCh,
  69. opcAddStrStr,
  70. opcAddSeqElem,
  71. opcRangeChck,
  72. opcNAdd,
  73. opcNAddMultiple,
  74. opcNKind,
  75. opcNSymKind,
  76. opcNIntVal,
  77. opcNFloatVal,
  78. opcNSymbol,
  79. opcNIdent,
  80. opcNGetType,
  81. opcNStrVal,
  82. opcNSigHash,
  83. opcNGetSize,
  84. opcNSetIntVal,
  85. opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
  86. opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
  87. opcNccValue, opcNccInc, opcNcsAdd, opcNcsIncl, opcNcsLen, opcNcsAt,
  88. opcNctPut, opcNctLen, opcNctGet, opcNctHasNext, opcNctNext,
  89. opcSlurp,
  90. opcGorge,
  91. opcParseExprToAst,
  92. opcParseStmtToAst,
  93. opcQueryErrorFlag,
  94. opcNError,
  95. opcNWarning,
  96. opcNHint,
  97. opcNGetLineInfo, opcNSetLineInfo,
  98. opcEqIdent,
  99. opcStrToIdent,
  100. opcGetImpl,
  101. opcGetImplTransf
  102. opcEcho,
  103. opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
  104. opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
  105. opcRaise,
  106. opcNChild,
  107. opcNSetChild,
  108. opcCallSite,
  109. opcNewStr,
  110. opcTJmp, # jump Bx if A != 0
  111. opcFJmp, # jump Bx if A == 0
  112. opcJmp, # jump Bx
  113. opcJmpBack, # jump Bx; resulting from a while loop
  114. opcBranch, # branch for 'case'
  115. opcTry,
  116. opcExcept,
  117. opcFinally,
  118. opcFinallyEnd,
  119. opcNew,
  120. opcNewSeq,
  121. opcLdNull, # dest = nullvalue(types[Bx])
  122. opcLdNullReg,
  123. opcLdConst, # dest = constants[Bx]
  124. opcAsgnConst, # dest = copy(constants[Bx])
  125. opcLdGlobal, # dest = globals[Bx]
  126. opcLdGlobalAddr, # dest = addr(globals[Bx])
  127. opcLdImmInt, # dest = immediate value
  128. opcNBindSym, opcNDynBindSym,
  129. opcSetType, # dest.typ = types[Bx]
  130. opcTypeTrait,
  131. opcMarshalLoad, opcMarshalStore,
  132. opcSymOwner,
  133. opcSymIsInstantiationOf
  134. TBlock* = object
  135. label*: PSym
  136. fixups*: seq[TPosition]
  137. TEvalMode* = enum ## reason for evaluation
  138. emRepl, ## evaluate because in REPL mode
  139. emConst, ## evaluate for 'const' according to spec
  140. emOptimize, ## evaluate for optimization purposes (same as
  141. ## emConst?)
  142. emStaticExpr, ## evaluate for enforced compile time eval
  143. ## ('static' context)
  144. emStaticStmt ## 'static' as an expression
  145. TSandboxFlag* = enum ## what the evaluation engine should allow
  146. allowCast, ## allow unsafe language feature: 'cast'
  147. allowInfiniteLoops ## allow endless loops
  148. TSandboxFlags* = set[TSandboxFlag]
  149. TSlotKind* = enum # We try to re-use slots in a smart way to
  150. # minimize allocations; however the VM supports arbitrary
  151. # temporary slot usage. This is required for the parameter
  152. # passing implementation.
  153. slotEmpty, # slot is unused
  154. slotFixedVar, # slot is used for a fixed var/result (requires copy then)
  155. slotFixedLet, # slot is used for a fixed param/let
  156. slotTempUnknown, # slot but type unknown (argument of proc call)
  157. slotTempInt, # some temporary int
  158. slotTempFloat, # some temporary float
  159. slotTempStr, # some temporary string
  160. slotTempComplex, # some complex temporary (s.node field is used)
  161. slotTempPerm # slot is temporary but permanent (hack)
  162. PProc* = ref object
  163. blocks*: seq[TBlock] # blocks; temp data structure
  164. sym*: PSym
  165. slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
  166. maxSlots*: int
  167. VmArgs* = object
  168. ra*, rb*, rc*: Natural
  169. slots*: pointer
  170. currentException*: PNode
  171. currentLineInfo*: TLineInfo
  172. VmCallback* = proc (args: VmArgs) {.closure.}
  173. PCtx* = ref TCtx
  174. TCtx* = object of TPassContext # code gen context
  175. code*: seq[TInstr]
  176. debug*: seq[TLineInfo] # line info for every instruction; kept separate
  177. # to not slow down interpretation
  178. globals*: PNode #
  179. constants*: PNode # constant data
  180. types*: seq[PType] # some instructions reference types (e.g. 'except')
  181. currentExceptionA*, currentExceptionB*: PNode
  182. exceptionInstr*: int # index of instruction that raised the exception
  183. prc*: PProc
  184. module*: PSym
  185. callsite*: PNode
  186. mode*: TEvalMode
  187. features*: TSandboxFlags
  188. traceActive*: bool
  189. loopIterations*: int
  190. comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
  191. callbacks*: seq[tuple[key: string, value: VmCallback]]
  192. errorFlag*: string
  193. cache*: IdentCache
  194. config*: ConfigRef
  195. graph*: ModuleGraph
  196. oldErrorCount*: int
  197. TPosition* = distinct int
  198. PEvalContext* = PCtx
  199. proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
  200. PCtx(code: @[], debug: @[],
  201. globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
  202. prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
  203. comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
  204. cache: cache, config: g.config, graph: g)
  205. proc refresh*(c: PCtx, module: PSym) =
  206. c.module = module
  207. c.prc = PProc(blocks: @[])
  208. c.loopIterations = MaxLoopIterations
  209. proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} =
  210. result = c.callbacks.len
  211. c.callbacks.add((name, callback))
  212. const
  213. firstABxInstr* = opcTJmp
  214. largeInstrs* = { # instructions which use 2 int32s instead of 1:
  215. opcSubStr, opcConv, opcCast, opcNewSeq, opcOf,
  216. opcMarshalLoad, opcMarshalStore}
  217. slotSomeTemp* = slotTempUnknown
  218. relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
  219. # flag is used to signal opcSeqLen if node is NimNode.
  220. const nimNodeFlag* = 16
  221. template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32)
  222. template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
  223. template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
  224. template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32)
  225. template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int
  226. template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess