diff --git a/test-suite/src/main/scala/testsuite/core/HijackedClassesDispatchTest.scala b/test-suite/src/main/scala/testsuite/core/HijackedClassesDispatchTest.scala index 9f273b7b..0f191968 100644 --- a/test-suite/src/main/scala/testsuite/core/HijackedClassesDispatchTest.scala +++ b/test-suite/src/main/scala/testsuite/core/HijackedClassesDispatchTest.scala @@ -12,7 +12,7 @@ object HijackedClassesDispatchTest { testToString(true, "true") && testToString(54321, "54321") && testToString(obj, "Test class") && - testToString(obj2, "[object]") && + testToStringStartsWith(obj2, "testsuite.core.HijackedClassesDispatchTest$Test2@") && testToString('A', "A") && testHashCode(true, 1231) && testHashCode(54321, 54321) && @@ -43,6 +43,9 @@ object HijackedClassesDispatchTest { def testToString(x: Any, expected: String): Boolean = x.toString() == expected + def testToStringStartsWith(x: Any, expectedPrefix: String): Boolean = + x.toString().startsWith(expectedPrefix) + def testHashCode(x: Any, expected: Int): Boolean = x.hashCode() == expected diff --git a/wasm/src/main/scala/ir2wasm/LibraryPatches.scala b/wasm/src/main/scala/ir2wasm/LibraryPatches.scala index b14feb4e..2b26e7e8 100644 --- a/wasm/src/main/scala/ir2wasm/LibraryPatches.scala +++ b/wasm/src/main/scala/ir2wasm/LibraryPatches.scala @@ -17,125 +17,25 @@ import wasm.utils.MemClassDefIRFile /** Patches that we apply to the standard library classes to make them wasm-friendly. */ object LibraryPatches { def patchIRFiles(irFiles: Seq[IRFile])(implicit ec: ExecutionContext): Future[Seq[IRFile]] = { - val derivedCharBox = new java.util.concurrent.atomic.AtomicReference[IRFile](null) - val derivedLongBox = new java.util.concurrent.atomic.AtomicReference[IRFile](null) - - val patched1: Future[Seq[IRFile]] = Future.traverse(irFiles) { irFile => + val derivedIRFiles: Future[Seq[Option[IRFile]]] = Future.traverse(irFiles) { irFile => val irFileImpl = IRFileImpl.fromIRFile(irFile) irFileImpl.entryPointsInfo.flatMap { entryPointsInfo => - MethodPatches.get(entryPointsInfo.className) match { - case None => - entryPointsInfo.className match { - case BoxedCharacterClass | BoxedLongClass => - irFileImpl.tree.map { classDef => - val derivedBox = MemClassDefIRFile(deriveBoxClass(classDef)) - if (classDef.className == BoxedCharacterClass) - derivedCharBox.set(derivedBox) - else - derivedLongBox.set(derivedBox) - irFile - } - case _ => - Future.successful(irFile) + entryPointsInfo.className match { + case BoxedCharacterClass | BoxedLongClass => + irFileImpl.tree.map { classDef => + Some(MemClassDefIRFile(deriveBoxClass(classDef))) } - case Some(patches) => - irFileImpl.tree.map(classDef => MemClassDefIRFile(applyMethodPatches(classDef, patches))) + case _ => + Future.successful(None) } } } - patched1.map { irFiles1 => - val extra = List(FloatingPointBitsIRFile, derivedCharBox.get(), derivedLongBox.get()) - extra ++ irFiles1 + derivedIRFiles.map { derived => + derived.flatten ++ irFiles } } - private val FloatingPointBitsIRFile: IRFile = { - val classDef = ClassDef( - ClassIdent("java.lang.FloatingPointBits$"), - NON, - ModuleClass, - None, - Some(ClassIdent(ObjectClass)), - Nil, - None, - None, - Nil, - List( - trivialCtor("java.lang.FloatingPointBits$"), - MethodDef( - EMF, MethodIdent(m("numberHashCode", List(D), I)), NON, - List(paramDef("value", DoubleType)), IntType, - Some(Block( - // TODO This is not a compliant but it's good enough for now - UnaryOp(UnaryOp.DoubleToInt, VarRef("value")(DoubleType)) - )) - )(EOH, NOV) - ), - None, - Nil, - Nil, - Nil - )(EOH) - - MemClassDefIRFile(classDef) - } - - private val MethodPatches: Map[ClassName, List[MethodDef]] = { - Map( - ObjectClass -> List( - // TODO Remove this patch when we support getClass() and full string concatenation - MethodDef( - EMF, m("toString", Nil, T), NON, - Nil, ClassType(BoxedStringClass), - Some(StringLiteral("[object]")) - )(EOH, NOV) - ), - - BoxedCharacterClass.withSuffix("$") -> List( - MethodDef( - EMF, m("toString", List(C), T), NON, - List(paramDef("c", CharType)), ClassType(BoxedStringClass), - Some(BinaryOp(BinaryOp.String_+, StringLiteral(""), VarRef("c")(CharType))) - )(EOH, NOV) - ), - - BoxedIntegerClass.withSuffix("$") -> List( - MethodDef( - EMF, m("toHexString", List(I), T), NON, - List(paramDef("i", IntType)), ClassType(BoxedStringClass), - Some( - // TODO Write a compliant implementation - BinaryOp(BinaryOp.String_+, StringLiteral(""), VarRef("i")(IntType)) - ) - )(EOH, NOV) - ) - ) - } - - private def applyMethodPatches(classDef: ClassDef, patches: List[MethodDef]): ClassDef = { - val patchesMap = patches.map(m => m.name.name -> m).toMap - val patchedMethods = classDef.methods.map(m => patchesMap.getOrElse(m.name.name, m)) - - import classDef._ - ClassDef( - name, - originalName, - kind, - jsClassCaptures, - superClass, - interfaces, - jsSuperClass, - jsNativeLoadSpec, - fields, - patchedMethods, - jsConstructor, - jsMethodProps, - jsNativeMembers, - topLevelExportDefs - )(EOH)(pos) - } - /** Generates the accompanying Box class of `Character` or `Long`. * * These box classes will be used as the generic representation of `char`s diff --git a/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala b/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala index fb094149..ad9ec753 100644 --- a/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala +++ b/wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala @@ -697,7 +697,7 @@ private class WasmExpressionBuilder private ( case CharToInt | ByteToInt | ShortToInt => () // these are no-ops because they are all represented as i32's with the right mathematical value case IntToLong => - instrs += I64_EXTEND32_S + instrs += I64_EXTEND_I32_S case IntToDouble => instrs += F64_CONVERT_I32_S case FloatToDouble =>