From f347de44a98c83f6bac9c4ec5be53043a1cee7e8 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 17 Apr 2017 00:09:00 +0300 Subject: [PATCH] WASM: fix metadata intrinsics --- .../classlib/impl/unicode/UnicodeHelper.java | 4 - .../java/org/teavm/backend/wasm/Example.java | 3 +- .../backend/wasm/binary/BinaryWriter.java | 2 +- .../wasm/generate/WasmClassGenerator.java | 4 +- .../plugin/BuildTimeResourceProxyBuilder.java | 2 +- .../plugin/BuildTimeResourceSetter.java | 4 - .../teavm/platform/plugin/PlatformPlugin.java | 19 +++++ .../plugin/ResourceReadIntrinsic.java | 26 +------ .../platform/plugin/StringAmplifier.java | 26 +++++++ .../StringAmplifierDependencyPlugin.java | 28 +++++++ .../plugin/StringAmplifierTransformer.java | 74 +++++++++++++++++++ 11 files changed, 156 insertions(+), 36 deletions(-) create mode 100644 platform/src/main/java/org/teavm/platform/plugin/StringAmplifier.java create mode 100644 platform/src/main/java/org/teavm/platform/plugin/StringAmplifierDependencyPlugin.java create mode 100644 platform/src/main/java/org/teavm/platform/plugin/StringAmplifierTransformer.java diff --git a/classlib/src/main/java/org/teavm/classlib/impl/unicode/UnicodeHelper.java b/classlib/src/main/java/org/teavm/classlib/impl/unicode/UnicodeHelper.java index c5e8f4f93..0a4779f12 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/unicode/UnicodeHelper.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/unicode/UnicodeHelper.java @@ -20,10 +20,6 @@ import java.util.Arrays; import org.teavm.classlib.impl.Base46; import org.teavm.classlib.impl.CharFlow; -/** - * - * @author Alexey Andreev - */ public final class UnicodeHelper { private UnicodeHelper() { } diff --git a/core/src/main/java/org/teavm/backend/wasm/Example.java b/core/src/main/java/org/teavm/backend/wasm/Example.java index 7a082b802..43c9e673f 100644 --- a/core/src/main/java/org/teavm/backend/wasm/Example.java +++ b/core/src/main/java/org/teavm/backend/wasm/Example.java @@ -26,7 +26,6 @@ public final class Example { } public static void main(String[] args) { - System.out.println(Integer.parseInt("123")); testFibonacci(); testClasses(); testVirtualCall(); @@ -39,7 +38,7 @@ public final class Example { testArrayIsObject(); testIsAssignableFrom(); testExceptions(); - //testBigInteger(); + testBigInteger(); testGC(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java b/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java index 79a089a03..32d7e8d23 100644 --- a/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java @@ -72,7 +72,7 @@ public class BinaryWriter { } } - private static int align(int address, int alignment) { + public static int align(int address, int alignment) { if (address == 0) { return 0; } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index 7b3a2b1a9..09852ebaf 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -406,7 +406,7 @@ public class WasmClassGenerator { data.cls = cls; for (FieldReader field : cls.getFields()) { - int desiredAlignment = getDesiredAlignment(field.getType()); + int desiredAlignment = getTypeSize(field.getType()); if (field.hasModifier(ElementModifier.STATIC)) { DataType type = asDataType(field.getType()); data.fieldLayout.put(field.getName(), binaryWriter.append(type.createValue())); @@ -450,7 +450,7 @@ public class WasmClassGenerator { return ((base - 1) / alignment + 1) * alignment; } - private int getDesiredAlignment(ValueType type) { + public static int getTypeSize(ValueType type) { if (type instanceof ValueType.Primitive) { switch (((ValueType.Primitive) type).getKind()) { case BOOLEAN: diff --git a/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java b/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java index 7196ac1fc..3d80269c3 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java +++ b/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java @@ -95,7 +95,7 @@ class BuildTimeResourceProxyBuilder { methods.put(method, (proxy, args) -> descriptor); break; case "getValues": - methods.put(method, (proxy, args) -> initialData.clone()); + methods.put(method, (proxy, args) -> proxy.data.clone()); break; case "getPropertyIndex": methods.put(method, (proxy, args) -> propertyIndexes.getOrDefault(args[0], -1)); diff --git a/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceSetter.java b/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceSetter.java index e8caaa40d..d43e807c4 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceSetter.java +++ b/platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceSetter.java @@ -15,10 +15,6 @@ */ package org.teavm.platform.plugin; -/** - * - * @author Alexey Andreev - */ class BuildTimeResourceSetter implements BuildTimeResourceMethod { private int index; diff --git a/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java b/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java index 44a26dfdb..15a76de3f 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java +++ b/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java @@ -15,8 +15,13 @@ */ package org.teavm.platform.plugin; +import org.teavm.ast.InvocationExpr; import org.teavm.backend.javascript.TeaVMJavaScriptHost; import org.teavm.backend.wasm.TeaVMWasmHost; +import org.teavm.backend.wasm.intrinsics.WasmIntrinsic; +import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.model.MethodReference; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; @@ -28,6 +33,8 @@ public class PlatformPlugin implements TeaVMPlugin { host.add(new ResourceTransformer()); host.add(new ResourceAccessorTransformer(host)); host.add(new ResourceAccessorDependencyListener()); + } else { + host.add(new StringAmplifierTransformer()); } TeaVMWasmHost wasmHost = host.getExtension(TeaVMWasmHost.class); @@ -35,6 +42,18 @@ public class PlatformPlugin implements TeaVMPlugin { wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(), ctx.getServices(), ctx.getProperties())); wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource(), ctx.getClassLoader())); + + wasmHost.add(ctx -> new WasmIntrinsic() { + @Override + public boolean isApplicable(MethodReference methodReference) { + return methodReference.getClassName().equals(StringAmplifier.class.getName()); + } + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) { + return manager.generate(invocation.getArguments().get(0)); + } + }); } host.add(new AsyncMethodProcessor()); diff --git a/platform/src/main/java/org/teavm/platform/plugin/ResourceReadIntrinsic.java b/platform/src/main/java/org/teavm/platform/plugin/ResourceReadIntrinsic.java index 1a64ec14e..9723dca5f 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/ResourceReadIntrinsic.java +++ b/platform/src/main/java/org/teavm/platform/plugin/ResourceReadIntrinsic.java @@ -21,6 +21,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.teavm.ast.InvocationExpr; +import org.teavm.backend.wasm.binary.BinaryWriter; +import org.teavm.backend.wasm.generate.WasmClassGenerator; import org.teavm.backend.wasm.intrinsics.WasmIntrinsic; import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager; import org.teavm.backend.wasm.model.expression.WasmExpression; @@ -119,8 +121,8 @@ public class ResourceReadIntrinsic implements WasmIntrinsic { for (Method method : methods) { MethodReference methodRef = MethodReference.parse(method); ValueType propertyType = methodRef.getReturnType(); - int size = getPropertySize(propertyType); - currentOffset = ((currentOffset + size - 1) / size + 1) * size; + int size = WasmClassGenerator.getTypeSize(propertyType); + currentOffset = BinaryWriter.align(currentOffset, size); PropertyDescriptor propertyDescriptor = new PropertyDescriptor(); propertyDescriptor.offset = currentOffset; @@ -131,26 +133,6 @@ public class ResourceReadIntrinsic implements WasmIntrinsic { } } - private int getPropertySize(ValueType type) { - if (type instanceof ValueType.Primitive) { - switch (((ValueType.Primitive) type).getKind()) { - case BOOLEAN: - case BYTE: - return 1; - case SHORT: - case CHARACTER: - return 2; - case INTEGER: - case FLOAT: - return 4; - case LONG: - case DOUBLE: - return 8; - } - } - return 4; - } - static class StructureDescriptor { ResourceTypeDescriptor typeDescriptor; Map layout = new HashMap<>(); diff --git a/platform/src/main/java/org/teavm/platform/plugin/StringAmplifier.java b/platform/src/main/java/org/teavm/platform/plugin/StringAmplifier.java new file mode 100644 index 000000000..682de40f5 --- /dev/null +++ b/platform/src/main/java/org/teavm/platform/plugin/StringAmplifier.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.platform.plugin; + +import org.teavm.dependency.PluggableDependency; + +final class StringAmplifier { + private StringAmplifier() { + } + + @PluggableDependency(StringAmplifierDependencyPlugin.class) + static native String amplify(String string); +} diff --git a/platform/src/main/java/org/teavm/platform/plugin/StringAmplifierDependencyPlugin.java b/platform/src/main/java/org/teavm/platform/plugin/StringAmplifierDependencyPlugin.java new file mode 100644 index 000000000..949b6df23 --- /dev/null +++ b/platform/src/main/java/org/teavm/platform/plugin/StringAmplifierDependencyPlugin.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.platform.plugin; + +import org.teavm.dependency.DependencyAgent; +import org.teavm.dependency.DependencyPlugin; +import org.teavm.dependency.MethodDependency; +import org.teavm.model.CallLocation; + +public class StringAmplifierDependencyPlugin implements DependencyPlugin { + @Override + public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) { + method.getResult().propagate(agent.getType("java.lang.String")); + } +} diff --git a/platform/src/main/java/org/teavm/platform/plugin/StringAmplifierTransformer.java b/platform/src/main/java/org/teavm/platform/plugin/StringAmplifierTransformer.java new file mode 100644 index 000000000..202d6d4e4 --- /dev/null +++ b/platform/src/main/java/org/teavm/platform/plugin/StringAmplifierTransformer.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.platform.plugin; + +import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.BasicBlock; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.Instruction; +import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReference; +import org.teavm.model.Program; +import org.teavm.model.Variable; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.InvokeInstruction; +import org.teavm.platform.metadata.Resource; + +public class StringAmplifierTransformer implements ClassHolderTransformer { + @Override + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { + for (MethodHolder method : cls.getMethods()) { + if (method.getProgram() != null) { + transformProgram(innerSource, method.getProgram()); + } + } + } + + private void transformProgram(ClassReaderSource classSource, Program program) { + for (BasicBlock block : program.getBasicBlocks()) { + for (Instruction instruction : block) { + if (!(instruction instanceof InvokeInstruction)) { + continue; + } + + InvokeInstruction invoke = (InvokeInstruction) instruction; + if (invoke.getReceiver() == null) { + continue; + } + + MethodReference method = invoke.getMethod(); + String owningClass = method.getClassName(); + if (classSource.isSuperType(Resource.class.getName(), owningClass).orElse(false)) { + if (method.getReturnType().isObject(String.class)) { + Variable var = program.createVariable(); + InvokeInstruction amplifyInstruction = new InvokeInstruction(); + amplifyInstruction.setMethod(new MethodReference(StringAmplifier.class, "amplify", + String.class, String.class)); + amplifyInstruction.setType(InvocationType.SPECIAL); + amplifyInstruction.getArguments().add(var); + amplifyInstruction.setReceiver(invoke.getReceiver()); + amplifyInstruction.setLocation(invoke.getLocation()); + + invoke.setReceiver(var); + invoke.insertNext(amplifyInstruction); + } + } + } + } + } +}