vmdef.nim 11 KB

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