From 18923cf9e97e34e696af9f28ae2e0bf9ef54c1d3 Mon Sep 17 00:00:00 2001 From: tareq97 Date: Mon, 24 Aug 2020 10:58:16 +0200 Subject: [PATCH 1/6] Signature infering as a new command in swam cli --- cli/src/swam/cli/Main.scala | 43 ++++++++++++++++++- cli/src/swam/cli/options.scala | 7 +++ runtime/src/swam/runtime/Module.scala | 4 +- .../internals/compiler/CompiledFunction.scala | 2 +- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/cli/src/swam/cli/Main.scala b/cli/src/swam/cli/Main.scala index e8a1027f..f77b0817 100644 --- a/cli/src/swam/cli/Main.scala +++ b/cli/src/swam/cli/Main.scala @@ -22,6 +22,9 @@ import swam.runtime.wasi.Wasi import swam.runtime.{Engine, Function, Module, Value} import swam.text.Compiler +import swam.binary.custom.FunctionNames +import swam.runtime.internals.compiler.CompiledFunction + private object NoTimestampFormatter extends JFormatter { override def format(x: LogRecord): String = x.getMessage @@ -38,6 +41,9 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm val wasmFile = Opts.argument[Path](metavar = "wasm") + val func_name = + Opts.argument[String](metavar = "functionName") + // Arguments that get passed to the WASM code you execute. They are available through WASI args_get. val restArguments = Opts.arguments[String](metavar = "args").orEmpty @@ -187,6 +193,10 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm (textual, wasmFile, out.orNone).mapN { (textual, wasm, out) => Decompile(wasm, textual, out) } } + val inferOpts: Opts[Options] = Opts.subcommand("infer", "Get the parameters type for functions file in Wasm module.") { + (wasmFile,wat,wasi,func_name).mapN { (wasm, wat, wasi, func_name) => Infer(wasm, wat, wasi, func_name) } + } + val validateOpts: Opts[Options] = Opts.subcommand("validate", "Validate a wasm file") { (wasmFile, wat, dev).mapN(Validate(_, _, _)) } @@ -198,7 +208,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm val outFileOptions = List(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) def main: Opts[IO[ExitCode]] = - runOpts.orElse(serverOpts).orElse(covOpts).orElse(decompileOpts).orElse(validateOpts).orElse(compileOpts).map { + runOpts.orElse(serverOpts).orElse(covOpts).orElse(inferOpts).orElse(decompileOpts).orElse(validateOpts).orElse(compileOpts).map { opts => Blocker[IO].use { blocker => opts match { @@ -318,7 +328,38 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm res <- engine.validate(module).attempt _ <- res.fold(t => logger.error("Module is invalid", t), _ => logger.info("Module is valid")) } yield ExitCode.Success + case Infer(file, wat, wasi, func_name) => + for { + engine <- Engine[IO](blocker) + tcompiler <- swam.text.Compiler[IO](blocker) + module = if (wat) tcompiler.stream(file, false, blocker) else engine.sections(file, blocker) + compiled <- engine.compile(module) + _ <- IO(compiled.functions.zipWithIndex.map { + case (CompiledFunction(typeIndex, tpe, locals, code), fidx) => + val functionName = + compiled.names.flatMap(_.subsections.collectFirstSome { + case FunctionNames(names) => + names.get(typeIndex) + case _ => + None + }) + functionName match { + case Some(x) => { + if(x == func_name){ + println(s"This is function name : $func_name") + println(s"This is param names : ${tpe.params}") + } + } + case None => { + println(s"The function name does not exists.") + } + } + + }) + _ <- IO(Infer) + //_ <- IO(println(module)) + } yield ExitCode.Success case Compile(file, out, debug) => for { tcompiler <- Compiler[IO](blocker) diff --git a/cli/src/swam/cli/options.scala b/cli/src/swam/cli/options.scala index 6df43fea..301ebb7b 100644 --- a/cli/src/swam/cli/options.scala +++ b/cli/src/swam/cli/options.scala @@ -71,3 +71,10 @@ case class WasmCov(file: Path, filter: Boolean, wasmArgTypes: List[String]) extends Options + +case class Infer(file: Path, + wat: Boolean, + wasi: Boolean, + functionName:String + )extends Options + diff --git a/runtime/src/swam/runtime/Module.scala b/runtime/src/swam/runtime/Module.scala index 58500ddf..00bd9740 100644 --- a/runtime/src/swam/runtime/Module.scala +++ b/runtime/src/swam/runtime/Module.scala @@ -45,12 +45,12 @@ class Module[F[_]] private[runtime] ( private[runtime] val tables: Vector[TableType], private[runtime] val memories: Vector[MemType], private[runtime] val start: Option[Int], - private[runtime] val functions: Vector[CompiledFunction[F]], + val functions: Vector[CompiledFunction[F]], private[runtime] val elems: Vector[CompiledElem[F]], private[runtime] val data: Vector[CompiledData[F]])(implicit F: MonadError[F, Throwable]) { self => - private[runtime] lazy val names = { + lazy val names = { val sec = customs.collectFirst { case Custom("name", payload) => payload } diff --git a/runtime/src/swam/runtime/internals/compiler/CompiledFunction.scala b/runtime/src/swam/runtime/internals/compiler/CompiledFunction.scala index 54cd2af8..eff2d374 100644 --- a/runtime/src/swam/runtime/internals/compiler/CompiledFunction.scala +++ b/runtime/src/swam/runtime/internals/compiler/CompiledFunction.scala @@ -23,7 +23,7 @@ import cfg._ import cats.effect.IO import swam.runtime.internals.interpreter.AsmInst -private[runtime] case class CompiledFunction[F[_]](idx: Int, +case class CompiledFunction[F[_]](idx: Int, tpe: FuncType, locals: Vector[ValType], code: Array[AsmInst[F]]) From 324334e2e7f00d2ff4a56a5983a201ecd7899b03 Mon Sep 17 00:00:00 2001 From: tareq97 Date: Mon, 24 Aug 2020 14:59:42 +0200 Subject: [PATCH 2/6] Added the mapping, error message and removed unnecessary messages. --- cli/src/swam/cli/Main.scala | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/cli/src/swam/cli/Main.scala b/cli/src/swam/cli/Main.scala index f77b0817..e8b99c25 100644 --- a/cli/src/swam/cli/Main.scala +++ b/cli/src/swam/cli/Main.scala @@ -340,6 +340,13 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm val functionName = compiled.names.flatMap(_.subsections.collectFirstSome { case FunctionNames(names) => + + val mapList = names.values + val check = mapList.exists(j => {j == func_name}) + if(!check){ + System.err.println("Function name does not exists.") + sys.exit(1) + } names.get(typeIndex) case _ => None @@ -347,18 +354,24 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm functionName match { case Some(x) => { if(x == func_name){ - println(s"This is function name : $func_name") - println(s"This is param names : ${tpe.params}") + val mapping = tpe.params.map(y => { + y match { + case ValType.I32 => "Int32" + case ValType.I64 => "Int64" + case ValType.F32 => "Float32" + case ValType.F64 => "Float64" + } + }) + val resultParams = mapping.mkString(",") + if(resultParams == ""){ + println("void") + } + println(resultParams) } } - case None => { - println(s"The function name does not exists.") - } - } - + case _ => None + } }) - _ <- IO(Infer) - //_ <- IO(println(module)) } yield ExitCode.Success case Compile(file, out, debug) => for { From 20227103558214a9d9c24f192b5870342a9e3b53 Mon Sep 17 00:00:00 2001 From: tareq97 Date: Mon, 24 Aug 2020 15:13:31 +0200 Subject: [PATCH 3/6] Removed lamda body for mapping the data types --- cli/src/swam/cli/Main.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/src/swam/cli/Main.scala b/cli/src/swam/cli/Main.scala index e8b99c25..6278a6dc 100644 --- a/cli/src/swam/cli/Main.scala +++ b/cli/src/swam/cli/Main.scala @@ -342,7 +342,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm case FunctionNames(names) => val mapList = names.values - val check = mapList.exists(j => {j == func_name}) + val check = mapList.exists(j => j == func_name) if(!check){ System.err.println("Function name does not exists.") sys.exit(1) @@ -354,8 +354,8 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm functionName match { case Some(x) => { if(x == func_name){ - val mapping = tpe.params.map(y => { - y match { + val mapping = tpe.params.map({ + _ match { case ValType.I32 => "Int32" case ValType.I64 => "Int64" case ValType.F32 => "Float32" From 3dcbba3f896b0e1af8e50be73b7cdb84d6bf066b Mon Sep 17 00:00:00 2001 From: Jacarte Date: Mon, 24 Aug 2020 15:18:56 +0200 Subject: [PATCH 4/6] Fix lambda empty body --- cli/src/swam/cli/Main.scala | 116 +++++++++++++++++------------------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/cli/src/swam/cli/Main.scala b/cli/src/swam/cli/Main.scala index 6278a6dc..fce6a58e 100644 --- a/cli/src/swam/cli/Main.scala +++ b/cli/src/swam/cli/Main.scala @@ -41,7 +41,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm val wasmFile = Opts.argument[Path](metavar = "wasm") - val func_name = + val func_name = Opts.argument[String](metavar = "functionName") // Arguments that get passed to the WASM code you execute. They are available through WASI args_get. @@ -134,7 +134,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm debug, wasmFile, restArguments, - covOut, + covOut, covfilter, wasmArgTypes).mapN { (main, wat, wasi, time, dirs, trace, traceFile, filter, debug, wasm, args, covOut, covfilter, wasmArgTypes) => @@ -171,21 +171,8 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm restArguments, covfilter, wasmArgTypes) - .mapN { - (main, wat, wasi, time, dirs, trace, traceFile, filter, debug, wasm, args, covfilter, wasmArgTypes) => - RunServer(wasm, - args, - main, - wat, - wasi, - time, - trace, - filter, - traceFile, - dirs, - debug, - covfilter, - wasmArgTypes) + .mapN { (main, wat, wasi, time, dirs, trace, traceFile, filter, debug, wasm, args, covfilter, wasmArgTypes) => + RunServer(wasm, args, main, wat, wasi, time, trace, filter, traceFile, dirs, debug, covfilter, wasmArgTypes) } } @@ -193,9 +180,10 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm (textual, wasmFile, out.orNone).mapN { (textual, wasm, out) => Decompile(wasm, textual, out) } } - val inferOpts: Opts[Options] = Opts.subcommand("infer", "Get the parameters type for functions file in Wasm module.") { - (wasmFile,wat,wasi,func_name).mapN { (wasm, wat, wasi, func_name) => Infer(wasm, wat, wasi, func_name) } - } + val inferOpts: Opts[Options] = + Opts.subcommand("infer", "Get the parameters type for functions file in Wasm module.") { + (wasmFile, wat, wasi, func_name).mapN { (wasm, wat, wasi, func_name) => Infer(wasm, wat, wasi, func_name) } + } val validateOpts: Opts[Options] = Opts.subcommand("validate", "Validate a wasm file") { (wasmFile, wat, dev).mapN(Validate(_, _, _)) @@ -208,8 +196,14 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm val outFileOptions = List(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) def main: Opts[IO[ExitCode]] = - runOpts.orElse(serverOpts).orElse(covOpts).orElse(inferOpts).orElse(decompileOpts).orElse(validateOpts).orElse(compileOpts).map { - opts => + runOpts + .orElse(serverOpts) + .orElse(covOpts) + .orElse(inferOpts) + .orElse(decompileOpts) + .orElse(validateOpts) + .orElse(compileOpts) + .map { opts => Blocker[IO].use { blocker => opts match { case Run(file, args, main, wat, wasi, time, trace, filter, tracef, dirs, debug, wasmArgTypes) => @@ -231,7 +225,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm _ <- IO(executeFunction(IO(preparedFunction), argsParsed, time)) } yield ExitCode.Success - // TODO: Remove this and instead to coverage flag in Run(...) + // TODO: Remove this and instead to coverage flag in Run(...) case WasmCov(file, args, main, @@ -294,8 +288,9 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm module = if (wat) tcompiler.stream(file, debug, blocker) else engine.sections(file, blocker) compiled <- engine.compile(module) preparedFunction <- prepareFunction(compiled, main, dirs, args, wasi, blocker) - _ <- IO(Server - .listen(IO(preparedFunction), wasmArgTypes, time, file, coverageListener)) + _ <- IO( + Server + .listen(IO(preparedFunction), wasmArgTypes, time, file, coverageListener)) } yield ExitCode.Success case Decompile(file, textual, out) => @@ -336,42 +331,39 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm compiled <- engine.compile(module) _ <- IO(compiled.functions.zipWithIndex.map { - case (CompiledFunction(typeIndex, tpe, locals, code), fidx) => - val functionName = - compiled.names.flatMap(_.subsections.collectFirstSome { - case FunctionNames(names) => - - val mapList = names.values - val check = mapList.exists(j => j == func_name) - if(!check){ - System.err.println("Function name does not exists.") - sys.exit(1) - } - names.get(typeIndex) - case _ => - None - }) - functionName match { - case Some(x) => { - if(x == func_name){ - val mapping = tpe.params.map({ - _ match { - case ValType.I32 => "Int32" - case ValType.I64 => "Int64" - case ValType.F32 => "Float32" - case ValType.F64 => "Float64" - } - }) - val resultParams = mapping.mkString(",") - if(resultParams == ""){ - println("void") - } - println(resultParams) - } - } - case _ => None - } - }) + case (CompiledFunction(typeIndex, tpe, locals, code), fidx) => + val functionName = + compiled.names.flatMap(_.subsections.collectFirstSome { + case FunctionNames(names) => + val mapList = names.values + val check = mapList.exists(j => j == func_name) + if (!check) { + System.err.println("Function name does not exists.") + sys.exit(1) + } + names.get(typeIndex) + case _ => + None + }) + functionName match { + case Some(x) => { + if (x == func_name) { + val mapping = tpe.params.map { + case ValType.I32 => "Int32" + case ValType.I64 => "Int64" + case ValType.F32 => "Float32" + case ValType.F64 => "Float64" + } + val resultParams = mapping.mkString(",") + if (resultParams == "") { + println("void") + } + println(resultParams) + } + } + case _ => None + } + }) } yield ExitCode.Success case Compile(file, out, debug) => for { @@ -387,7 +379,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm } } - } + } def prepareFunction(module: Module[IO], functionName: String, From 9527a1d2aa4b048c89ac44a0a37732cf49be03d6 Mon Sep 17 00:00:00 2001 From: Jacarte Date: Mon, 24 Aug 2020 15:19:48 +0200 Subject: [PATCH 5/6] No void parameter type message removal --- cli/src/swam/cli/Main.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/swam/cli/Main.scala b/cli/src/swam/cli/Main.scala index fce6a58e..ccd33214 100644 --- a/cli/src/swam/cli/Main.scala +++ b/cli/src/swam/cli/Main.scala @@ -356,7 +356,7 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm } val resultParams = mapping.mkString(",") if (resultParams == "") { - println("void") + println("") } println(resultParams) } From 75ba976fa3b60abd5d325641cdf5cce5bf091be9 Mon Sep 17 00:00:00 2001 From: Jacarte Date: Mon, 24 Aug 2020 16:03:52 +0200 Subject: [PATCH 6/6] Refactoring and cleaning --- cli/src/swam/cli/Main.scala | 69 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/cli/src/swam/cli/Main.scala b/cli/src/swam/cli/Main.scala index ccd33214..afaf1ac0 100644 --- a/cli/src/swam/cli/Main.scala +++ b/cli/src/swam/cli/Main.scala @@ -13,6 +13,7 @@ import io.odin.formatter.Formatter import io.odin.formatter.options.ThrowableFormat import io.odin.{Logger, consoleLogger} import fs2._ +import swam.ValType.{F32, F64, I32, I64} import swam.binary.ModuleStream import swam.decompilation._ import swam.code_analysis.coverage.{CoverageListener, CoverageReporter} @@ -21,8 +22,7 @@ import swam.runtime.trace._ import swam.runtime.wasi.Wasi import swam.runtime.{Engine, Function, Module, Value} import swam.text.Compiler - -import swam.binary.custom.FunctionNames +import swam.binary.custom.{FunctionNames, ModuleName} import swam.runtime.internals.compiler.CompiledFunction private object NoTimestampFormatter extends JFormatter { @@ -330,41 +330,42 @@ object Main extends CommandIOApp(name = "swam-cli", header = "Swam from the comm module = if (wat) tcompiler.stream(file, false, blocker) else engine.sections(file, blocker) compiled <- engine.compile(module) - _ <- IO(compiled.functions.zipWithIndex.map { - case (CompiledFunction(typeIndex, tpe, locals, code), fidx) => - val functionName = - compiled.names.flatMap(_.subsections.collectFirstSome { - case FunctionNames(names) => - val mapList = names.values - val check = mapList.exists(j => j == func_name) - if (!check) { - System.err.println("Function name does not exists.") - sys.exit(1) - } - names.get(typeIndex) - case _ => - None - }) - functionName match { - case Some(x) => { - if (x == func_name) { - val mapping = tpe.params.map { - case ValType.I32 => "Int32" - case ValType.I64 => "Int64" - case ValType.F32 => "Float32" - case ValType.F64 => "Float64" - } - val resultParams = mapping.mkString(",") - if (resultParams == "") { - println("") - } - println(resultParams) + names <- IO(compiled.names.flatMap(_.subsections.collectFirst { case FunctionNames(n) => n })) + exitCode <- IO( + names match { + case Some(x) => { + val func = x.filter { case (idx, name) => func_name == name } + + if (func.nonEmpty) { + + if (func.size > 1) { + + System.err.println(s"Warning $func_name has more than one definition, taking the first one") + } + + val tpeidx = func.collectFirst { case (tid, _) => tid }.get + + // There is always one at this point + val tpe = compiled.functions.filter(f => f.idx == tpeidx)(0).tpe + + val params = tpe.params.map { + case I32 => "Int32" + case I64 => "Int64" + case F32 => "Float32" + case F64 => "Float64" } + println(params.mkString(",")) + ExitCode.Success + } else { + System.err.println(s"Function '$func_name' does not exist") + ExitCode.Error } - case _ => None } - }) - } yield ExitCode.Success + case None => ExitCode.Error + } + ) + + } yield exitCode case Compile(file, out, debug) => for { tcompiler <- Compiler[IO](blocker)