From d2cdd5e1e9f63ee4b1f63ad1bf87368dfb693c48 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 18 Aug 2016 23:47:43 +0300 Subject: [PATCH] Zero memory after allocation --- .../java/org/teavm/runtime/Allocator.java | 4 ++ .../java/org/teavm/runtime/RuntimeArray.java | 1 + .../main/java/org/teavm/wasm/WasmRuntime.java | 44 +++++++++++++++++ .../main/java/org/teavm/wasm/WasmTarget.java | 4 ++ .../teavm/wasm/generate/WasmStringPool.java | 7 ++- .../wasm/intrinsics/AllocatorIntrinsic.java | 49 +++++++++++++++++++ 6 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/teavm/wasm/intrinsics/AllocatorIntrinsic.java diff --git a/core/src/main/java/org/teavm/runtime/Allocator.java b/core/src/main/java/org/teavm/runtime/Allocator.java index 95bbfe80f..2a208c173 100644 --- a/core/src/main/java/org/teavm/runtime/Allocator.java +++ b/core/src/main/java/org/teavm/runtime/Allocator.java @@ -28,6 +28,7 @@ public final class Allocator { public static Address allocate(RuntimeClass tag) { Address result = address; address = result.add(tag.size); + fillZero(result, tag.size); RuntimeObject object = result.toStructure(); object.classReference = tag.toAddress().toInt() >> 3; return result; @@ -37,6 +38,7 @@ public final class Allocator { Address result = address; int sizeInBytes = tag.size * 4 + Structure.sizeOf(RuntimeArray.class); address = result.add(sizeInBytes); + fillZero(result, sizeInBytes); RuntimeArray array = result.toStructure(); array.classReference = tag.toAddress().toInt() >> 3; @@ -44,4 +46,6 @@ public final class Allocator { return result; } + + public static native void fillZero(Address address, int count); } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeArray.java b/core/src/main/java/org/teavm/runtime/RuntimeArray.java index abcdab62e..ae0297548 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeArray.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeArray.java @@ -16,5 +16,6 @@ package org.teavm.runtime; public class RuntimeArray extends RuntimeObject { + RuntimeObject monitor; int size; } diff --git a/core/src/main/java/org/teavm/wasm/WasmRuntime.java b/core/src/main/java/org/teavm/wasm/WasmRuntime.java index 3beee1bb8..a5e7f5655 100644 --- a/core/src/main/java/org/teavm/wasm/WasmRuntime.java +++ b/core/src/main/java/org/teavm/wasm/WasmRuntime.java @@ -191,4 +191,48 @@ public final class WasmRuntime { @Import(name = "print", module = "spectest") public static native void print(int a); + + public static void fillZero(Address address, int count) { + int start = address.toInt(); + + int alignedStart = start >>> 2 << 2; + address = Address.fromInt(alignedStart); + switch (start - alignedStart) { + case 0: + address.putInt(0); + break; + case 1: + address.add(1).putByte((byte) 0); + address.add(2).putShort((short) 0); + break; + case 2: + address.add(2).putShort((short) 0); + break; + case 3: + address.add(3).putByte((byte) 0); + break; + } + + int end = start + count; + int alignedEnd = end >>> 2 << 2; + address = Address.fromInt(alignedEnd); + switch (end - alignedEnd) { + case 0: + break; + case 1: + address.putByte((byte) 0); + break; + case 2: + address.putShort((short) 0); + break; + case 3: + address.putShort((short) 0); + address.add(2).putByte((byte) 0); + break; + } + + for (address = Address.fromInt(alignedStart); address.toInt() < alignedEnd; address = address.add(4)) { + address.putInt(0); + } + } } diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index c9beb04eb..7db413a0a 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -64,6 +64,7 @@ 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.AllocatorIntrinsic; import org.teavm.wasm.intrinsics.WasmAddressIntrinsic; import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic; import org.teavm.wasm.intrinsics.WasmStructureIntrinsic; @@ -116,6 +117,8 @@ public class WasmTarget implements TeaVMTarget { dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "decodeData", Address.class, Address.class, void.class), null).use(); + dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "fillZero", Address.class, int.class, + void.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate", RuntimeClass.class, Address.class), null).use(); @@ -146,6 +149,7 @@ public class WasmTarget implements TeaVMTarget { context.addIntrinsic(new WasmAddressIntrinsic()); context.addIntrinsic(new WasmStructureIntrinsic(classGenerator)); context.addIntrinsic(new WasmRuntimeIntrinsic()); + context.addIntrinsic(new AllocatorIntrinsic()); WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java b/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java index 02a771337..6ce7d7100 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmStringPool.java @@ -28,7 +28,10 @@ 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 arrayHeaderType = new DataStructure((byte) 0, + DataPrimitives.INT, /* class pointer */ + DataPrimitives.ADDRESS, /* monitor */ + DataPrimitives.INT /* size */); private DataStructure stringType = new DataStructure((byte) 0, DataPrimitives.INT, /* class pointer */ DataPrimitives.ADDRESS, /* monitor */ @@ -49,7 +52,7 @@ public class WasmStringPool { DataValue characters = wrapper.getValue(1); header.setInt(0, classGenerator.getClassPointer(ValueType.arrayOf(ValueType.CHARACTER))); - header.setInt(1, str.length()); + header.setInt(2, str.length()); for (int i = 0; i < str.length(); ++i) { characters.setShort(i, (short) str.charAt(i)); } diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/AllocatorIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/AllocatorIntrinsic.java new file mode 100644 index 000000000..371d4493d --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/AllocatorIntrinsic.java @@ -0,0 +1,49 @@ +/* + * 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.intrinsics; + +import java.util.stream.Collectors; +import org.teavm.ast.InvocationExpr; +import org.teavm.interop.Address; +import org.teavm.model.MethodReference; +import org.teavm.runtime.Allocator; +import org.teavm.wasm.WasmRuntime; +import org.teavm.wasm.generate.WasmMangling; +import org.teavm.wasm.model.expression.WasmCall; +import org.teavm.wasm.model.expression.WasmExpression; + +public class AllocatorIntrinsic implements WasmIntrinsic { + @Override + public boolean isApplicable(MethodReference methodReference) { + return methodReference.getClassName().equals(Allocator.class.getName()) && + methodReference.getName().equals("fillZero"); + } + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) { + switch (invocation.getMethod().getName()) { + case "fillZero": { + WasmCall call = new WasmCall(WasmMangling.mangleMethod(new MethodReference(WasmRuntime.class, + "fillZero", Address.class, int.class, void.class))); + call.getArguments().addAll(invocation.getArguments().stream().map(manager::generate) + .collect(Collectors.toList())); + return call; + } + default: + throw new IllegalArgumentException(invocation.getMethod().toString()); + } + } +}