summary refs log tree commit diff stats
path: root/compiler/vmops.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/vmops.nim')
-rw-r--r--compiler/vmops.nim303
1 files changed, 201 insertions, 102 deletions
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 5748b41b3..45194e633 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -12,26 +12,36 @@
 from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
   arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
   floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma,
-  lgamma
-
+  lgamma, divmod
+from std/sequtils import toSeq
 when declared(math.copySign):
-  from std/math import copySign
+  # pending bug #18762, avoid renaming math
+  from std/math as math2 import copySign
 
 when declared(math.signbit):
-  from std/math import signbit
+  # ditto
+  from std/math as math3 import signbit
+
 
-from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir,
-                   getAppFilename, raiseOSError, osLastError
+from std/envvars import getEnv, existsEnv, delEnv, putEnv, envPairs
+from std/os import getAppFilename
+from std/private/oscommon import dirExists, fileExists
+from std/private/osdirs import walkDir, createDir
+from std/private/ospaths2 import getCurrentDir
 
-from std/md5 import getMD5
 from std/times import cpuTime
 from std/hashes import hash
 from std/osproc import nil
 
-from sighashes import symBodyDigest
+
+when defined(nimPreviewSlimSystem):
+  import std/syncio
+else:
+  from std/formatfloat import addFloatRoundtrip, addFloatSprintf
+
 
 # There are some useful procs in vmconv.
-import vmconv
+import vmconv, vmmarshal
 
 template mathop(op) {.dirty.} =
   registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
@@ -39,6 +49,15 @@ template mathop(op) {.dirty.} =
 template osop(op) {.dirty.} =
   registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
 
+template oscommonop(op) {.dirty.} =
+  registerCallback(c, "stdlib.oscommon." & astToStr(op), `op Wrapper`)
+
+template osdirsop(op) {.dirty.} =
+  registerCallback(c, "stdlib.osdirs." & astToStr(op), `op Wrapper`)
+
+template envvarsop(op) {.dirty.} =
+  registerCallback(c, "stdlib.envvars." & astToStr(op), `op Wrapper`)
+
 template timesop(op) {.dirty.} =
   registerCallback(c, "stdlib.times." & astToStr(op), `op Wrapper`)
 
@@ -46,25 +65,27 @@ template systemop(op) {.dirty.} =
   registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
 
 template ioop(op) {.dirty.} =
-  registerCallback(c, "stdlib.io." & astToStr(op), `op Wrapper`)
+  registerCallback(c, "stdlib.syncio." & astToStr(op), `op Wrapper`)
 
 template macrosop(op) {.dirty.} =
   registerCallback(c, "stdlib.macros." & astToStr(op), `op Wrapper`)
 
-template md5op(op) {.dirty.} =
-  registerCallback(c, "stdlib.md5." & astToStr(op), `op Wrapper`)
-
-template wrap1f_math(op) {.dirty.} =
+template wrap1fMath(op) {.dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     doAssert a.numArgs == 1
     setResult(a, op(getFloat(a, 0)))
   mathop op
 
-template wrap2f_math(op) {.dirty.} =
+template wrap2fMath(op) {.dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
   mathop op
 
+template wrap2iMath(op) {.dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getInt(a, 0), getInt(a, 1)))
+  mathop op
+
 template wrap0(op, modop) {.dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, op())
@@ -95,7 +116,17 @@ template wrap2svoid(op, modop) {.dirty.} =
     op(getString(a, 0), getString(a, 1))
   modop op
 
-template wrapDangerous(op, modop) {.dirty.} =
+template wrapDangerous1svoid(op, modop) {.dirty.} =
+  if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck):
+    proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+      discard
+    modop op
+  else:
+    proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+      op(getString(a, 0))
+    modop op
+
+template wrapDangerous2svoid(op, modop) {.dirty.} =
   if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck):
     proc `op Wrapper`(a: VmArgs) {.nimcall.} =
       discard
@@ -117,39 +148,53 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
   for k, f in walkDir(path, relative):
     result.add toLit((k, f))
 
-when defined(nimHasInvariant):
-  from std / compilesettings import SingleValueSetting, MultipleValueSetting
-
-  proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string =
-    case SingleValueSetting(switch)
-    of arguments: result = conf.arguments
-    of outFile: result = conf.outFile.string
-    of outDir: result = conf.outDir.string
-    of nimcacheDir: result = conf.getNimcacheDir().string
-    of projectName: result = conf.projectName
-    of projectPath: result = conf.projectPath.string
-    of projectFull: result = conf.projectFull.string
-    of command: result = conf.command
-    of commandLine: result = conf.commandLine
-    of linkOptions: result = conf.linkOptions
-    of compileOptions: result = conf.compileOptions
-    of ccompilerPath: result = conf.cCompilerPath
-    of backend: result = $conf.backend
-    of libPath: result = conf.libpath.string
-
-  proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] =
-    template copySeq(field: untyped): untyped =
-      for i in field: result.add i.string
-
-    case MultipleValueSetting(switch)
-    of nimblePaths: copySeq(conf.nimblePaths)
-    of searchPaths: copySeq(conf.searchPaths)
-    of lazyPaths: copySeq(conf.lazyPaths)
-    of commandArgs: result = conf.commandArgs
-    of cincludes: copySeq(conf.cIncludes)
-    of clibs: copySeq(conf.cLibs)
+from std / compilesettings import SingleValueSetting, MultipleValueSetting
+
+proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string =
+  {.push warning[Deprecated]:off.}
+  case SingleValueSetting(switch)
+  of arguments: result = conf.arguments
+  of outFile: result = conf.outFile.string
+  of outDir: result = conf.outDir.string
+  of nimcacheDir: result = conf.getNimcacheDir().string
+  of projectName: result = conf.projectName
+  of projectPath: result = conf.projectPath.string
+  of projectFull: result = conf.projectFull.string
+  of command: result = conf.command
+  of commandLine: result = conf.commandLine
+  of linkOptions: result = conf.linkOptions
+  of compileOptions: result = conf.compileOptions
+  of ccompilerPath: result = conf.cCompilerPath
+  of backend: result = $conf.backend
+  of libPath: result = conf.libpath.string
+  of gc: result = $conf.selectedGC
+  of mm: result = $conf.selectedGC
+  {.pop.}
+
+proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] =
+  template copySeq(field: untyped): untyped =
+    result = @[]
+    for i in field: result.add i.string
+
+  case MultipleValueSetting(switch)
+  of nimblePaths: copySeq(conf.nimblePaths)
+  of searchPaths: copySeq(conf.searchPaths)
+  of lazyPaths: copySeq(conf.lazyPaths)
+  of commandArgs: result = conf.commandArgs
+  of cincludes: copySeq(conf.cIncludes)
+  of clibs: copySeq(conf.cLibs)
+
+proc stackTrace2(c: PCtx, msg: string, n: PNode) =
+  stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info)
+
 
 proc registerAdditionalOps*(c: PCtx) =
+
+  template wrapIterator(fqname: string, iter: untyped) =
+    registerCallback c, fqname, proc(a: VmArgs) =
+      setResult(a, toLit(toSeq(iter)))
+
+
   proc gorgeExWrapper(a: VmArgs) =
     let ret = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
                          a.currentLineInfo, c.config)
@@ -158,72 +203,76 @@ proc registerAdditionalOps*(c: PCtx) =
   proc getProjectPathWrapper(a: VmArgs) =
     setResult a, c.config.projectPath.string
 
-  wrap1f_math(sqrt)
-  wrap1f_math(cbrt)
-  wrap1f_math(ln)
-  wrap1f_math(log10)
-  wrap1f_math(log2)
-  wrap1f_math(exp)
-  wrap1f_math(arccos)
-  wrap1f_math(arcsin)
-  wrap1f_math(arctan)
-  wrap1f_math(arcsinh)
-  wrap1f_math(arccosh)
-  wrap1f_math(arctanh)
-  wrap2f_math(arctan2)
-  wrap1f_math(cos)
-  wrap1f_math(cosh)
-  wrap2f_math(hypot)
-  wrap1f_math(sinh)
-  wrap1f_math(sin)
-  wrap1f_math(tan)
-  wrap1f_math(tanh)
-  wrap2f_math(pow)
-  wrap1f_math(trunc)
-  wrap1f_math(floor)
-  wrap1f_math(ceil)
-  wrap1f_math(erf)
-  wrap1f_math(erfc)
-  wrap1f_math(gamma)
-  wrap1f_math(lgamma)
+  wrap1fMath(sqrt)
+  wrap1fMath(cbrt)
+  wrap1fMath(ln)
+  wrap1fMath(log10)
+  wrap1fMath(log2)
+  wrap1fMath(exp)
+  wrap1fMath(arccos)
+  wrap1fMath(arcsin)
+  wrap1fMath(arctan)
+  wrap1fMath(arcsinh)
+  wrap1fMath(arccosh)
+  wrap1fMath(arctanh)
+  wrap2fMath(arctan2)
+  wrap1fMath(cos)
+  wrap1fMath(cosh)
+  wrap2fMath(hypot)
+  wrap1fMath(sinh)
+  wrap1fMath(sin)
+  wrap1fMath(tan)
+  wrap1fMath(tanh)
+  wrap2fMath(pow)
+  wrap1fMath(trunc)
+  wrap1fMath(floor)
+  wrap1fMath(ceil)
+  wrap1fMath(erf)
+  wrap1fMath(erfc)
+  wrap1fMath(gamma)
+  wrap1fMath(lgamma)
+  wrap2iMath(divmod)
 
   when declared(copySign):
-    wrap2f_math(copySign)
+    wrap2fMath(copySign)
 
   when declared(signbit):
-    wrap1f_math(signbit)
+    wrap1fMath(signbit)
 
   registerCallback c, "stdlib.math.round", proc (a: VmArgs) {.nimcall.} =
     let n = a.numArgs
     case n
     of 1: setResult(a, round(getFloat(a, 0)))
     of 2: setResult(a, round(getFloat(a, 0), getInt(a, 1).int))
-    else: doAssert false, $n
-
-  wrap1s(getMD5, md5op)
+    else: raiseAssert $n
 
   proc `mod Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1)))
   registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
 
   when defined(nimcore):
-    wrap2s(getEnv, osop)
-    wrap1s(existsEnv, osop)
-    wrap2svoid(putEnv, osop)
-    wrap1s(dirExists, osop)
-    wrap1s(fileExists, osop)
-    wrapDangerous(writeFile, ioop)
+    wrap2s(getEnv, envvarsop)
+    wrap1s(existsEnv, envvarsop)
+    wrap2svoid(putEnv, envvarsop)
+    wrap1svoid(delEnv, envvarsop)
+    wrap1s(dirExists, oscommonop)
+    wrap1s(fileExists, oscommonop)
+    wrapDangerous2svoid(writeFile, ioop)
+    wrapDangerous1svoid(createDir, osdirsop)
     wrap1s(readFile, ioop)
     wrap2si(readLines, ioop)
     systemop getCurrentExceptionMsg
     systemop getCurrentException
-    registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
+    registerCallback c, "stdlib.osdirs.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
       setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
-    when defined(nimHasInvariant):
-      registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) =
-        setResult(a, querySettingImpl(c.config, getInt(a, 0)))
-      registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) =
-        setResult(a, querySettingSeqImpl(c.config, getInt(a, 0)))
+    registerCallback c, "stdlib.staticos.staticDirExists", proc (a: VmArgs) {.nimcall.} =
+      setResult(a, dirExists(getString(a, 0)))
+    registerCallback c, "stdlib.staticos.staticFileExists", proc (a: VmArgs) {.nimcall.} =
+      setResult(a, fileExists(getString(a, 0)))
+    registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) =
+      setResult(a, querySettingImpl(c.config, getInt(a, 0)))
+    registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) =
+      setResult(a, querySettingSeqImpl(c.config, getInt(a, 0)))
 
     if defined(nimsuggest) or c.config.cmd == cmdCheck:
       discard "don't run staticExec for 'nim suggest'"
@@ -237,17 +286,24 @@ proc registerAdditionalOps*(c: PCtx) =
   registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) =
     let n = getNode(a, 0)
     if n.kind != nkSym:
-      stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr,
-                  "symBodyHash() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info)
+      stackTrace2(c, "symBodyHash() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n)
     setResult(a, $symBodyDigest(c.graph, n.sym))
 
   registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) =
     let n = getNode(a, 0)
     if n.kind != nkSym:
-      stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr,
-                  "isExported() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info)
+      stackTrace2(c, "isExported() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n)
     setResult(a, sfExported in n.sym.flags)
 
+  registerCallback c, "stdlib.macrocache.hasKey", proc (a: VmArgs) =
+    let
+      table = getString(a, 0)
+      key = getString(a, 1)
+    setResult(a, table in c.graph.cacheTables and key in c.graph.cacheTables[table])
+
+  registerCallback c, "stdlib.vmutils.vmTrace", proc (a: VmArgs) =
+    c.config.isVmTrace = getBool(a, 0)
+
   proc hashVmImpl(a: VmArgs) =
     var res = hashes.hash(a.getString(0), a.getInt(1).int, a.getInt(2).int)
     if c.config.backend == backendJs:
@@ -286,27 +342,33 @@ proc registerAdditionalOps*(c: PCtx) =
     ## reproducible builds and users need to understand that this runs at CT.
     ## Note that `staticExec` can already do equal amount of damage so it's more
     ## of a semantic issue than a security issue.
-    registerCallback c, "stdlib.os.getCurrentDir", proc (a: VmArgs) {.nimcall.} =
-      setResult(a, os.getCurrentDir())
+    registerCallback c, "stdlib.ospaths2.getCurrentDir", proc (a: VmArgs) {.nimcall.} =
+      setResult(a, getCurrentDir())
     registerCallback c, "stdlib.osproc.execCmdEx", proc (a: VmArgs) {.nimcall.} =
       let options = getNode(a, 1).fromLit(set[osproc.ProcessOption])
       a.setResult osproc.execCmdEx(getString(a, 0), options).toLit
-    registerCallback c, "stdlib.times.getTime", proc (a: VmArgs) {.nimcall.} =
-      setResult(a, times.getTime().toLit)
+    registerCallback c, "stdlib.times.getTimeImpl", proc (a: VmArgs) =
+      let obj = a.getNode(0).typ.n
+      setResult(a, times.getTime().toTimeLit(c, obj, a.currentLineInfo))
 
   proc getEffectList(c: PCtx; a: VmArgs; effectIndex: int) =
     let fn = getNode(a, 0)
+    var list = newNodeI(nkBracket, fn.info)
     if fn.typ != nil and fn.typ.n != nil and fn.typ.n[0].len >= effectListLen and
         fn.typ.n[0][effectIndex] != nil:
-      var list = newNodeI(nkBracket, fn.info)
       for e in fn.typ.n[0][effectIndex]:
         list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info, c.idgen)
-      setResult(a, list)
+    else:
+      list.add newIdentNode(getIdent(c.cache, "UncomputedEffects"), fn.info)
+
+    setResult(a, list)
 
   registerCallback c, "stdlib.effecttraits.getRaisesListImpl", proc (a: VmArgs) =
     getEffectList(c, a, exceptionEffects)
   registerCallback c, "stdlib.effecttraits.getTagsListImpl", proc (a: VmArgs) =
     getEffectList(c, a, tagEffects)
+  registerCallback c, "stdlib.effecttraits.getForbidsListImpl", proc (a: VmArgs) =
+    getEffectList(c, a, forbiddenEffects)
 
   registerCallback c, "stdlib.effecttraits.isGcSafeImpl", proc (a: VmArgs) =
     let fn = getNode(a, 0)
@@ -316,3 +378,40 @@ proc registerAdditionalOps*(c: PCtx) =
     let fn = getNode(a, 0)
     setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or
                  (fn.kind == nkSym and fn.sym.kind == skFunc))
+
+  registerCallback c, "stdlib.typetraits.hasClosureImpl", proc (a: VmArgs) =
+    let fn = getNode(a, 0)
+    setResult(a, fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure))
+
+  registerCallback c, "stdlib.formatfloat.addFloatRoundtrip", proc(a: VmArgs) =
+    let p = a.getVar(0)
+    let x = a.getFloat(1)
+    addFloatRoundtrip(p.strVal, x)
+
+  registerCallback c, "stdlib.formatfloat.addFloatSprintf", proc(a: VmArgs) =
+    let p = a.getVar(0)
+    let x = a.getFloat(1)
+    addFloatSprintf(p.strVal, x)
+
+  registerCallback c, "stdlib.strutils.formatBiggestFloat", proc(a: VmArgs) =
+    setResult(a, formatBiggestFloat(a.getFloat(0), FloatFormatMode(a.getInt(1)),
+                                    a.getInt(2), chr(a.getInt(3))))
+
+  wrapIterator("stdlib.envvars.envPairsImplSeq"): envPairs()
+
+  registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) =
+    let typ = a.getNode(0).typ
+    case typ.kind
+    of tyInt..tyInt64, tyUInt..tyUInt64:
+      setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen).intVal)
+    of tyFloat..tyFloat128:
+      setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen).floatVal)
+    else:
+      setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen))
+
+  registerCallback c, "stdlib.marshal.loadVM", proc(a: VmArgs) =
+    let typ = a.getNode(0).typ
+    let p = a.getReg(1)
+    var res: string = ""
+    storeAny(res, typ, regToNode(p[]), c.config)
+    setResult(a, res)