vmdef.nim 9.7 KB

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