diff options
Diffstat (limited to 'compiler/vmops.nim')
-rw-r--r-- | compiler/vmops.nim | 303 |
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) |