vmops.nim 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Unfortunately this cannot be a module yet:
  10. #import vmdeps, vm
  11. from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
  12. arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
  13. floor, ceil, `mod`
  14. from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename
  15. from md5 import getMD5
  16. from sighashes import symBodyDigest
  17. from times import cpuTime
  18. from hashes import hash
  19. from osproc import nil
  20. import vmconv
  21. template mathop(op) {.dirty.} =
  22. registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
  23. template osop(op) {.dirty.} =
  24. registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
  25. template timesop(op) {.dirty.} =
  26. registerCallback(c, "stdlib.times." & astToStr(op), `op Wrapper`)
  27. template systemop(op) {.dirty.} =
  28. registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
  29. template ioop(op) {.dirty.} =
  30. registerCallback(c, "stdlib.io." & astToStr(op), `op Wrapper`)
  31. template macrosop(op) {.dirty.} =
  32. registerCallback(c, "stdlib.macros." & astToStr(op), `op Wrapper`)
  33. template md5op(op) {.dirty.} =
  34. registerCallback(c, "stdlib.md5." & astToStr(op), `op Wrapper`)
  35. template wrap1f_math(op) {.dirty.} =
  36. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  37. setResult(a, op(getFloat(a, 0)))
  38. mathop op
  39. template wrap2f_math(op) {.dirty.} =
  40. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  41. setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
  42. mathop op
  43. template wrap0(op, modop) {.dirty.} =
  44. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  45. setResult(a, op())
  46. modop op
  47. template wrap1s(op, modop) {.dirty.} =
  48. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  49. setResult(a, op(getString(a, 0)))
  50. modop op
  51. template wrap2s(op, modop) {.dirty.} =
  52. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  53. setResult(a, op(getString(a, 0), getString(a, 1)))
  54. modop op
  55. template wrap2si(op, modop) {.dirty.} =
  56. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  57. setResult(a, op(getString(a, 0), getInt(a, 1)))
  58. modop op
  59. template wrap1svoid(op, modop) {.dirty.} =
  60. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  61. op(getString(a, 0))
  62. modop op
  63. template wrap2svoid(op, modop) {.dirty.} =
  64. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  65. op(getString(a, 0), getString(a, 1))
  66. modop op
  67. template wrapDangerous(op, modop) {.dirty.} =
  68. proc `op Wrapper`(a: VmArgs) {.nimcall.} =
  69. if defined(nimsuggest) or c.config.cmd == cmdCheck:
  70. discard
  71. else:
  72. op(getString(a, 0), getString(a, 1))
  73. modop op
  74. proc getCurrentExceptionMsgWrapper(a: VmArgs) {.nimcall.} =
  75. setResult(a, if a.currentException.isNil: ""
  76. else: a.currentException[3].skipColon.strVal)
  77. proc getCurrentExceptionWrapper(a: VmArgs) {.nimcall.} =
  78. setResult(a, a.currentException)
  79. proc staticWalkDirImpl(path: string, relative: bool): PNode =
  80. result = newNode(nkBracket)
  81. for k, f in walkDir(path, relative):
  82. result.add toLit((k, f))
  83. when defined(nimHasInvariant):
  84. from std / compilesettings import SingleValueSetting, MultipleValueSetting
  85. proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string =
  86. case SingleValueSetting(switch)
  87. of arguments: result = conf.arguments
  88. of outFile: result = conf.outFile.string
  89. of outDir: result = conf.outDir.string
  90. of nimcacheDir: result = conf.getNimcacheDir().string
  91. of projectName: result = conf.projectName
  92. of projectPath: result = conf.projectPath.string
  93. of projectFull: result = conf.projectFull.string
  94. of command: result = conf.command
  95. of commandLine: result = conf.commandLine
  96. of linkOptions: result = conf.linkOptions
  97. of compileOptions: result = conf.compileOptions
  98. of ccompilerPath: result = conf.cCompilerPath
  99. of backend: result = $conf.backend
  100. proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] =
  101. template copySeq(field: untyped): untyped =
  102. for i in field: result.add i.string
  103. case MultipleValueSetting(switch)
  104. of nimblePaths: copySeq(conf.nimblePaths)
  105. of searchPaths: copySeq(conf.searchPaths)
  106. of lazyPaths: copySeq(conf.lazyPaths)
  107. of commandArgs: result = conf.commandArgs
  108. of cincludes: copySeq(conf.cIncludes)
  109. of clibs: copySeq(conf.cLibs)
  110. proc registerAdditionalOps*(c: PCtx) =
  111. proc gorgeExWrapper(a: VmArgs) =
  112. let ret = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
  113. a.currentLineInfo, c.config)
  114. setResult a, ret.toLit
  115. proc getProjectPathWrapper(a: VmArgs) =
  116. setResult a, c.config.projectPath.string
  117. wrap1f_math(sqrt)
  118. wrap1f_math(ln)
  119. wrap1f_math(log10)
  120. wrap1f_math(log2)
  121. wrap1f_math(exp)
  122. wrap1f_math(round)
  123. wrap1f_math(arccos)
  124. wrap1f_math(arcsin)
  125. wrap1f_math(arctan)
  126. wrap2f_math(arctan2)
  127. wrap1f_math(cos)
  128. wrap1f_math(cosh)
  129. wrap2f_math(hypot)
  130. wrap1f_math(sinh)
  131. wrap1f_math(sin)
  132. wrap1f_math(tan)
  133. wrap1f_math(tanh)
  134. wrap2f_math(pow)
  135. wrap1f_math(trunc)
  136. wrap1f_math(floor)
  137. wrap1f_math(ceil)
  138. wrap1s(getMD5, md5op)
  139. proc `mod Wrapper`(a: VmArgs) {.nimcall.} =
  140. setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1)))
  141. registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
  142. when defined(nimcore):
  143. wrap2s(getEnv, osop)
  144. wrap1s(existsEnv, osop)
  145. wrap2svoid(putEnv, osop)
  146. wrap1s(dirExists, osop)
  147. wrap1s(fileExists, osop)
  148. wrapDangerous(writeFile, ioop)
  149. wrap1s(readFile, ioop)
  150. wrap2si(readLines, ioop)
  151. systemop getCurrentExceptionMsg
  152. systemop getCurrentException
  153. registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
  154. setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
  155. when defined(nimHasInvariant):
  156. registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} =
  157. setResult(a, querySettingImpl(c.config, getInt(a, 0)))
  158. registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} =
  159. setResult(a, querySettingSeqImpl(c.config, getInt(a, 0)))
  160. if defined(nimsuggest) or c.config.cmd == cmdCheck:
  161. discard "don't run staticExec for 'nim suggest'"
  162. else:
  163. systemop gorgeEx
  164. macrosop getProjectPath
  165. registerCallback c, "stdlib.os.getCurrentCompilerExe", proc (a: VmArgs) {.nimcall.} =
  166. setResult(a, getAppFilename())
  167. registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) {.nimcall.} =
  168. let n = getNode(a, 0)
  169. if n.kind != nkSym:
  170. stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr,
  171. "symBodyHash() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info)
  172. setResult(a, $symBodyDigest(c.graph, n.sym))
  173. registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) {.nimcall.} =
  174. let n = getNode(a, 0)
  175. if n.kind != nkSym:
  176. stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr,
  177. "isExported() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info)
  178. setResult(a, sfExported in n.sym.flags)
  179. proc hashVmImpl(a: VmArgs) =
  180. var res = hashes.hash(a.getString(0), a.getInt(1).int, a.getInt(2).int)
  181. if c.config.backend == backendJs:
  182. # emulate JS's terrible integers:
  183. res = cast[int32](res)
  184. setResult(a, res)
  185. registerCallback c, "stdlib.hashes.hashVmImpl", hashVmImpl
  186. proc hashVmImplByte(a: VmArgs) =
  187. # nkBracket[...]
  188. let sPos = a.getInt(1).int
  189. let ePos = a.getInt(2).int
  190. let arr = a.getNode(0)
  191. var bytes = newSeq[byte](arr.len)
  192. for i in 0..<arr.len:
  193. bytes[i] = byte(arr[i].intVal and 0xff)
  194. var res = hashes.hash(bytes, sPos, ePos)
  195. if c.config.backend == backendJs:
  196. # emulate JS's terrible integers:
  197. res = cast[int32](res)
  198. setResult(a, res)
  199. registerCallback c, "stdlib.hashes.hashVmImplByte", hashVmImplByte
  200. registerCallback c, "stdlib.hashes.hashVmImplChar", hashVmImplByte
  201. if optBenchmarkVM in c.config.globalOptions or vmopsDanger in c.config.features:
  202. wrap0(cpuTime, timesop)
  203. else:
  204. proc cpuTime(): float = 5.391245e-44 # Randomly chosen
  205. wrap0(cpuTime, timesop)
  206. if vmopsDanger in c.config.features:
  207. ## useful procs but these should be opt-in because they may impact
  208. ## reproducible builds and users need to understand that this runs at CT.
  209. ## Note that `staticExec` can already do equal amount of damage so it's more
  210. ## of a semantic issue than a security issue.
  211. registerCallback c, "stdlib.os.getCurrentDir", proc (a: VmArgs) {.nimcall.} =
  212. setResult(a, os.getCurrentDir())
  213. registerCallback c, "stdlib.osproc.execCmdEx", proc (a: VmArgs) {.nimcall.} =
  214. let options = getNode(a, 1).fromLit(set[osproc.ProcessOption])
  215. a.setResult osproc.execCmdEx(getString(a, 0), options).toLit
  216. registerCallback c, "stdlib.times.getTime", proc (a: VmArgs) {.nimcall.} =
  217. setResult(a, times.getTime().toLit)