From fc2c6b9e077d9cb95dd9caf92c2b67f0cf555507 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 16 Aug 2016 23:30:14 +0300 Subject: [PATCH] Add support of strings (breaks compilation for some reason) --- .../src/main/java/org/teavm/wasm/Example.java | 6 ++ .../main/java/org/teavm/wasm/WasmTarget.java | 4 +- .../wasm/generate/WasmGenerationContext.java | 9 ++- .../wasm/generate/WasmGenerationVisitor.java | 3 + .../teavm/wasm/generate/WasmStringPool.java | 65 +++++++++++++++++++ 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java diff --git a/core/src/main/java/org/teavm/wasm/Example.java b/core/src/main/java/org/teavm/wasm/Example.java index 1e58a67d8..0c19f1805 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -50,6 +50,12 @@ public final class Example { for (byte bt : bytes) { WasmRuntime.print(bt); } + + String str = "foobar"; + WasmRuntime.print(str.length()); + for (int i = 0; i < str.length(); ++i) { + WasmRuntime.print(str.charAt(i)); + } } private static Base instance(int index) { diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index 9e102e800..f3c31c726 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -62,6 +62,7 @@ import org.teavm.wasm.generate.WasmClassGenerator; import org.teavm.wasm.generate.WasmGenerationContext; import org.teavm.wasm.generate.WasmGenerator; import org.teavm.wasm.generate.WasmMangling; +import org.teavm.wasm.generate.WasmStringPool; import org.teavm.wasm.intrinsics.WasmAddressIntrinsic; import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic; import org.teavm.wasm.intrinsics.WasmStructureIntrinsic; @@ -136,7 +137,8 @@ public class WasmTarget implements TeaVMTarget { Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); - WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry); + WasmStringPool stringPool = new WasmStringPool(classGenerator, binaryWriter); + WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry, stringPool); context.addIntrinsic(new WasmAddressIntrinsic()); context.addIntrinsic(new WasmStructureIntrinsic(classGenerator)); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java index 7e2ad5956..48ab011b7 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java @@ -31,21 +31,24 @@ import org.teavm.model.MethodReference; import org.teavm.model.ValueType; import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTableProvider; +import org.teavm.wasm.binary.BinaryWriter; import org.teavm.wasm.intrinsics.WasmIntrinsic; public class WasmGenerationContext { private ClassReaderSource classSource; private VirtualTableProvider vtableProvider; private TagRegistry tagRegistry; + private WasmStringPool stringPool; private Map importedMethods = new HashMap<>(); private List intrinsics = new ArrayList<>(); private Map intrinsicCache = new HashMap<>(); public WasmGenerationContext(ClassReaderSource classSource, VirtualTableProvider vtableProvider, - TagRegistry tagRegistry) { + TagRegistry tagRegistry, WasmStringPool stringPool) { this.classSource = classSource; this.vtableProvider = vtableProvider; this.tagRegistry = tagRegistry; + this.stringPool = stringPool; } public void addIntrinsic(WasmIntrinsic intrinsic) { @@ -101,6 +104,10 @@ public class WasmGenerationContext { return tagRegistry; } + public WasmStringPool getStringPool() { + return stringPool; + } + public class ImportedMethod { public final String name; public final String module; diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java index 9995ac850..26bd79ef4 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -511,6 +511,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { result = new WasmFloat32Constant((Float) expr.getValue()); } else if (expr.getValue() instanceof Double) { result = new WasmFloat64Constant((Double) expr.getValue()); + } else if (expr.getValue() instanceof String) { + String str = (String) expr.getValue(); + result = new WasmInt32Constant(context.getStringPool().getStringPointer(str)); } else { throw new IllegalArgumentException("Constant unsupported: " + expr.getValue()); } diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java b/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java new file mode 100644 index 000000000..02a771337 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java @@ -0,0 +1,65 @@ +/* + * Copyright 2016 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.wasm.generate; + +import java.util.HashMap; +import java.util.Map; +import org.teavm.model.ValueType; +import org.teavm.wasm.binary.BinaryWriter; +import org.teavm.wasm.binary.DataArray; +import org.teavm.wasm.binary.DataPrimitives; +import org.teavm.wasm.binary.DataStructure; +import org.teavm.wasm.binary.DataValue; + +public class WasmStringPool { + private WasmClassGenerator classGenerator; + private BinaryWriter binaryWriter; + private Map stringMap = new HashMap<>(); + private DataStructure arrayHeaderType = new DataStructure((byte) 0, DataPrimitives.INT, DataPrimitives.INT); + private DataStructure stringType = new DataStructure((byte) 0, + DataPrimitives.INT, /* class pointer */ + DataPrimitives.ADDRESS, /* monitor */ + DataPrimitives.ADDRESS, /* characters */ + DataPrimitives.INT /* hash code */); + + public WasmStringPool(WasmClassGenerator classGenerator, BinaryWriter binaryWriter) { + this.classGenerator = classGenerator; + this.binaryWriter = binaryWriter; + } + + public int getStringPointer(String value) { + return stringMap.computeIfAbsent(value, str -> { + DataArray charactersType = new DataArray(DataPrimitives.SHORT, str.length()); + DataStructure wrapperType = new DataStructure((byte) 0, arrayHeaderType, charactersType); + DataValue wrapper = wrapperType.createValue(); + DataValue header = wrapper.getValue(0); + DataValue characters = wrapper.getValue(1); + + header.setInt(0, classGenerator.getClassPointer(ValueType.arrayOf(ValueType.CHARACTER))); + header.setInt(1, str.length()); + for (int i = 0; i < str.length(); ++i) { + characters.setShort(i, (short) str.charAt(i)); + } + + DataValue stringObject = stringType.createValue(); + int stringPointer = binaryWriter.append(stringObject); + stringObject.setInt(0, classGenerator.getClassPointer(ValueType.object(String.class.getName()))); + stringObject.setAddress(2, binaryWriter.append(wrapper)); + + return stringPointer; + }); + } +}