From 6fcb3784c08f9845126b62b4524cabaf280d97d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Tue, 16 Apr 2024 10:02:08 +0200 Subject: [PATCH 1/2] Fix #105: Take the `runtimeClassNameMapper` into account. It allows to configure the `Class.getName()` result, typically in order to obfuscate and/or reduce code size. --- build.sbt | 3 --- wasm/src/main/scala/WebAssemblyLinkerBackend.scala | 2 +- wasm/src/main/scala/ir2wasm/WasmBuilder.scala | 14 ++++++++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/build.sbt b/build.sbt index a4013240..ff54b145 100644 --- a/build.sbt +++ b/build.sbt @@ -226,9 +226,6 @@ lazy val `scalajs-test-suite` = project lazy val IgnoredTestNames: Set[String] = { Set( - // javaLangClassGetNameRenamedThroughSemantics failed: org.junit.ComparisonFailure: - // expected:<[renamed.test.]Class> but was:<[org.scalajs.testsuite.compiler.ReflectionTest$RenamedTest]Class> - "org.scalajs.testsuite.compiler.ReflectionTest", // wellKnownSymbolIterator/testToString failed: scala.scalajs.js.JavaScriptException: TypeError: Cannot convert a Symbol value to a string "org.scalajs.testsuite.jsinterop.SymbolTest", // Cannot call wasmObject.toString() from JavaScript: diff --git a/wasm/src/main/scala/WebAssemblyLinkerBackend.scala b/wasm/src/main/scala/WebAssemblyLinkerBackend.scala index bbc859c5..95955cca 100644 --- a/wasm/src/main/scala/WebAssemblyLinkerBackend.scala +++ b/wasm/src/main/scala/WebAssemblyLinkerBackend.scala @@ -61,7 +61,7 @@ final class WebAssemblyLinkerBackend( ): Future[Report] = { val wasmModule = new WasmModule - val builder = new WasmBuilder() + val builder = new WasmBuilder(coreSpec) implicit val context: WasmContext = new WasmContext(wasmModule) val onlyModule = moduleSet.modules match { diff --git a/wasm/src/main/scala/ir2wasm/WasmBuilder.scala b/wasm/src/main/scala/ir2wasm/WasmBuilder.scala index 48c1b514..52db20b9 100644 --- a/wasm/src/main/scala/ir2wasm/WasmBuilder.scala +++ b/wasm/src/main/scala/ir2wasm/WasmBuilder.scala @@ -13,7 +13,8 @@ import org.scalajs.ir.{Types => IRTypes} import org.scalajs.ir.{Names => IRNames} import org.scalajs.ir.{ClassKind, Position} -import org.scalajs.linker.standard.{LinkedClass, LinkedTopLevelExport} +import org.scalajs.linker.interface.unstable.RuntimeClassNameMapperImpl +import org.scalajs.linker.standard.{CoreSpec, LinkedClass, LinkedTopLevelExport} import collection.mutable import java.awt.Window.Type @@ -21,7 +22,7 @@ import _root_.wasm4s.Defaults import EmbeddedConstants._ -class WasmBuilder { +class WasmBuilder(coreSpec: CoreSpec) { // val module = new WasmModule() def genPrimitiveTypeDataGlobals()(implicit ctx: WasmContext): Unit = { @@ -258,8 +259,13 @@ class WasmBuilder { ctx: WasmContext ): List[WasmInstr] = { val nameStr = typeRef match { - case typeRef: IRTypes.PrimRef => typeRef.displayName - case IRTypes.ClassRef(className) => className.nameString + case typeRef: IRTypes.PrimRef => + typeRef.displayName + case IRTypes.ClassRef(className) => + RuntimeClassNameMapperImpl.map( + coreSpec.semantics.runtimeClassNameMapper, + className.nameString + ) } val nameDataValueItems = nameStr.toList.map(c => I32_CONST(c.toInt)) From 3e6e35d9e4ab87e377bde93787cf4f5591c86c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Tue, 16 Apr 2024 10:22:37 +0200 Subject: [PATCH 2/2] Fix #106: Use an actual `toString()` call for `toString()` on JS value. As opposed to using `"" + x`, which is only valid for string concatenation. In most cases it makes no difference. The difference can only be observed for `symbol`s. --- build.sbt | 2 -- wasm/src/main/scala/ir2wasm/LoaderContent.scala | 3 ++- wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala | 6 +++--- wasm/src/main/scala/wasm4s/Names.scala | 3 ++- wasm/src/main/scala/wasm4s/WasmContext.scala | 3 ++- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/build.sbt b/build.sbt index ff54b145..3a0ec867 100644 --- a/build.sbt +++ b/build.sbt @@ -226,8 +226,6 @@ lazy val `scalajs-test-suite` = project lazy val IgnoredTestNames: Set[String] = { Set( - // wellKnownSymbolIterator/testToString failed: scala.scalajs.js.JavaScriptException: TypeError: Cannot convert a Symbol value to a string - "org.scalajs.testsuite.jsinterop.SymbolTest", // Cannot call wasmObject.toString() from JavaScript: // boxValueClassesGivenToJSInteropMethod failed: scala.scalajs.js.JavaScriptException: TypeError: vc.toString is not a function "org.scalajs.testsuite.compiler.InteroperabilityTest", diff --git a/wasm/src/main/scala/ir2wasm/LoaderContent.scala b/wasm/src/main/scala/ir2wasm/LoaderContent.scala index 28c21dfa..f8cb0885 100644 --- a/wasm/src/main/scala/ir2wasm/LoaderContent.scala +++ b/wasm/src/main/scala/ir2wasm/LoaderContent.scala @@ -121,7 +121,8 @@ const scalaJSHelpers = { emptyString: () => "", stringLength: (s) => s.length, stringCharAt: (s, i) => s.charCodeAt(i), - jsValueToString: (x) => "" + x, + jsValueToString: (x) => (x === void 0) ? "undefined" : x.toString(), + jsValueToStringForConcat: (x) => "" + x, booleanToString: (b) => b ? "true" : "false", charToString: (c) => String.fromCharCode(c), intToString: (i) => "" + i, diff --git a/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala b/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala index d84d1586..d2916e54 100644 --- a/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala +++ b/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala @@ -1239,7 +1239,7 @@ private class WasmExpressionBuilder private ( } // end block labelNotOurObject // Now we have a value that is not one of our objects; the anyref is still on the stack - instrs += CALL(WasmFunctionName.jsValueToString) + instrs += CALL(WasmFunctionName.jsValueToStringForConcat) } // end block labelDone } } @@ -1264,7 +1264,7 @@ private class WasmExpressionBuilder private ( case IRTypes.DoubleType => instrs += CALL(WasmFunctionName.doubleToString) case IRTypes.NullType | IRTypes.UndefType => - instrs += CALL(WasmFunctionName.jsValueToString) + instrs += CALL(WasmFunctionName.jsValueToStringForConcat) case IRTypes.NothingType => () // unreachable case IRTypes.NoType => @@ -1276,7 +1276,7 @@ private class WasmExpressionBuilder private ( case IRTypes.ClassType(IRNames.BoxedStringClass) => // Common case for which we want to avoid the hijacked class dispatch genTreeAuto(tree) - instrs += CALL(WasmFunctionName.jsValueToString) // for `null` + instrs += CALL(WasmFunctionName.jsValueToStringForConcat) // for `null` case IRTypes.ClassType(className) => genWithDispatch(ctx.getClassInfo(className).isAncestorOfHijackedClass) diff --git a/wasm/src/main/scala/wasm4s/Names.scala b/wasm/src/main/scala/wasm4s/Names.scala index 2964e11a..6c748252 100644 --- a/wasm/src/main/scala/wasm4s/Names.scala +++ b/wasm/src/main/scala/wasm4s/Names.scala @@ -179,7 +179,8 @@ object Names { val emptyString = helper("emptyString") val stringLength = helper("stringLength") val stringCharAt = helper("stringCharAt") - val jsValueToString = helper("jsValueToString") + val jsValueToString = helper("jsValueToString") // for actual toString() call + val jsValueToStringForConcat = helper("jsValueToStringForConcat") val booleanToString = helper("booleanToString") val charToString = helper("charToString") val intToString = helper("intToString") diff --git a/wasm/src/main/scala/wasm4s/WasmContext.scala b/wasm/src/main/scala/wasm4s/WasmContext.scala index 07f3c729..6a0d3ab5 100644 --- a/wasm/src/main/scala/wasm4s/WasmContext.scala +++ b/wasm/src/main/scala/wasm4s/WasmContext.scala @@ -420,7 +420,8 @@ class WasmContext(val module: WasmModule) extends TypeDefinableWasmContext { addHelperImport(WasmFunctionName.emptyString, List(), List(WasmRefType.any)) addHelperImport(WasmFunctionName.stringLength, List(WasmRefType.any), List(WasmInt32)) addHelperImport(WasmFunctionName.stringCharAt, List(WasmRefType.any, WasmInt32), List(WasmInt32)) - addHelperImport(WasmFunctionName.jsValueToString, List(anyref), List(WasmRefType.any)) + addHelperImport(WasmFunctionName.jsValueToString, List(WasmRefType.any), List(WasmRefType.any)) + addHelperImport(WasmFunctionName.jsValueToStringForConcat, List(anyref), List(WasmRefType.any)) addHelperImport(WasmFunctionName.booleanToString, List(WasmInt32), List(WasmRefType.any)) addHelperImport(WasmFunctionName.charToString, List(WasmInt32), List(WasmRefType.any)) addHelperImport(WasmFunctionName.intToString, List(WasmInt32), List(WasmRefType.any))