mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 08:24:10 -08:00
Add compressed binary data to store RTTI
This commit is contained in:
parent
421eca8a49
commit
38638bc560
|
@ -20,15 +20,6 @@ import org.teavm.interop.Structure;
|
||||||
public class RuntimeClass extends Structure {
|
public class RuntimeClass extends Structure {
|
||||||
public static int INITIALIZED = 1;
|
public static int INITIALIZED = 1;
|
||||||
|
|
||||||
public static int SIZE_OFFSET = 0;
|
|
||||||
public static int FLAGS_OFFSET = 4;
|
|
||||||
public static int LOWER_TAG_OFFSET = 8;
|
|
||||||
public static int UPPER_TAG_OFFSET = 12;
|
|
||||||
public static int EXCLUDED_RANGE_COUNT_OFFSET = 16;
|
|
||||||
public static int EXCLUDED_RANGE_ADDRESS_OFFSET = 20;
|
|
||||||
public static int CANARY_OFFSET = 24;
|
|
||||||
public static int VIRTUAL_TABLE_OFFSET = 28;
|
|
||||||
|
|
||||||
public static int BOOLEAN_CLASS = -1;
|
public static int BOOLEAN_CLASS = -1;
|
||||||
public static int BYTE_CLASS = -2;
|
public static int BYTE_CLASS = -2;
|
||||||
public static int SHORT_CLASS = -3;
|
public static int SHORT_CLASS = -3;
|
||||||
|
@ -40,17 +31,15 @@ public class RuntimeClass extends Structure {
|
||||||
|
|
||||||
public int size;
|
public int size;
|
||||||
public int flags;
|
public int flags;
|
||||||
public int lowerTag;
|
public int tag;
|
||||||
public int upperTag;
|
public int canary;
|
||||||
public int excludedRangeCount;
|
|
||||||
public int excludedRangesAddress;
|
|
||||||
|
|
||||||
public static int computeCanary(int size, int lowerTag, int upperTag) {
|
public static int computeCanary(int size, int tag) {
|
||||||
return size ^ (lowerTag << 8) ^ (lowerTag >>> 24) ^ (upperTag << 24) ^ (lowerTag >>> 8);
|
return size ^ (tag << 8) ^ (tag >>> 24) ^ (0xAAAAAAAA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int computeCanary() {
|
public int computeCanary() {
|
||||||
return computeCanary(size, lowerTag, upperTag);
|
return computeCanary(size, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native RuntimeClass getArrayClass();
|
public static native RuntimeClass getArrayClass();
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm;
|
package org.teavm.wasm;
|
||||||
|
|
||||||
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
|
|
||||||
public final class WasmRuntime {
|
public final class WasmRuntime {
|
||||||
|
private static Address offset;
|
||||||
|
|
||||||
private WasmRuntime() {
|
private WasmRuntime() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +64,131 @@ public final class WasmRuntime {
|
||||||
|
|
||||||
private static native boolean gt(double a, double b);
|
private static native boolean gt(double a, double b);
|
||||||
|
|
||||||
|
public static void decodeData(Address data, Address metadata) {
|
||||||
|
offset = metadata;
|
||||||
|
int count = decodeLeb();
|
||||||
|
|
||||||
|
while (count-- > 0) {
|
||||||
|
data = decodeDataRec(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Address decodeDataRec(Address data) {
|
||||||
|
Address metadata = offset;
|
||||||
|
int type = metadata.getByte();
|
||||||
|
metadata = metadata.add(1);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
data = data.add(1);
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
data = align(data, 2);
|
||||||
|
byte a = data.getByte();
|
||||||
|
byte b = data.add(1).getByte();
|
||||||
|
int value = (a << 8) | b;
|
||||||
|
data.putShort((short) value);
|
||||||
|
data = data.add(2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 6: {
|
||||||
|
data = align(data, 4);
|
||||||
|
int value = getInt(data);
|
||||||
|
data.putInt(value);
|
||||||
|
data = data.add(4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
case 5: {
|
||||||
|
data = align(data, 8);
|
||||||
|
data.putLong(getLong(data));
|
||||||
|
data = data.add(8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 7: {
|
||||||
|
offset = metadata;
|
||||||
|
int size = decodeLeb();
|
||||||
|
metadata = offset;
|
||||||
|
while (size-- > 0) {
|
||||||
|
offset = metadata;
|
||||||
|
data = decodeDataRec(data);
|
||||||
|
}
|
||||||
|
metadata = offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 8: {
|
||||||
|
int alignment = metadata.getByte();
|
||||||
|
offset = metadata.add(1);
|
||||||
|
int size = decodeLeb();
|
||||||
|
if (alignment > 0) {
|
||||||
|
data = align(data, alignment);
|
||||||
|
}
|
||||||
|
while (size-- > 0) {
|
||||||
|
data = decodeDataRec(data);
|
||||||
|
}
|
||||||
|
metadata = offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 9: {
|
||||||
|
Address start = metadata.add(-1);
|
||||||
|
offset = metadata;
|
||||||
|
int back = decodeLeb();
|
||||||
|
metadata = offset;
|
||||||
|
offset = start.add(-back);
|
||||||
|
data = decodeDataRec(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = metadata;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getInt(Address data) {
|
||||||
|
byte a = data.getByte();
|
||||||
|
byte b = data.add(1).getByte();
|
||||||
|
byte c = data.add(2).getByte();
|
||||||
|
byte d = data.add(3).getByte();
|
||||||
|
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getLong(Address data) {
|
||||||
|
long a = data.getByte();
|
||||||
|
long b = data.add(1).getByte();
|
||||||
|
long c = data.add(2).getByte();
|
||||||
|
long d = data.add(3).getByte();
|
||||||
|
long e = data.add(4).getByte();
|
||||||
|
long f = data.add(5).getByte();
|
||||||
|
long g = data.add(6).getByte();
|
||||||
|
long h = data.add(7).getByte();
|
||||||
|
return (a << 56) | (b << 48) | (c << 40) | (d << 32) | (e << 24) | (f << 16) | (g << 8) | h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Address align(Address address, int alignment) {
|
||||||
|
int value = address.toInt();
|
||||||
|
if (value == 0) {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
value = ((value - 1) / alignment + 1) * alignment;
|
||||||
|
return Address.fromInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int decodeLeb() {
|
||||||
|
Address index = offset;
|
||||||
|
int result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
int value;
|
||||||
|
do {
|
||||||
|
value = index.getByte();
|
||||||
|
index = index.add(1);
|
||||||
|
result |= (value & 0x7F) << shift;
|
||||||
|
} while ((value & 0x80) != 0);
|
||||||
|
offset = index;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Import(name = "print", module = "spectest")
|
@Import(name = "print", module = "spectest")
|
||||||
public static native void print(int a);
|
public static native void print(int a);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ import org.teavm.vm.TeaVMEntryPoint;
|
||||||
import org.teavm.vm.TeaVMTarget;
|
import org.teavm.vm.TeaVMTarget;
|
||||||
import org.teavm.vm.TeaVMTargetController;
|
import org.teavm.vm.TeaVMTargetController;
|
||||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||||
|
import org.teavm.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.wasm.generate.WasmClassGenerator;
|
import org.teavm.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.wasm.generate.WasmGenerationContext;
|
import org.teavm.wasm.generate.WasmGenerationContext;
|
||||||
import org.teavm.wasm.generate.WasmGenerator;
|
import org.teavm.wasm.generate.WasmGenerator;
|
||||||
|
@ -65,6 +66,7 @@ import org.teavm.wasm.intrinsics.WasmRuntimeClassIntrinsic;
|
||||||
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
|
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
|
||||||
import org.teavm.wasm.intrinsics.WasmStructureIntrinsic;
|
import org.teavm.wasm.intrinsics.WasmStructureIntrinsic;
|
||||||
import org.teavm.wasm.model.WasmFunction;
|
import org.teavm.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.wasm.model.WasmMemorySegment;
|
||||||
import org.teavm.wasm.model.WasmModule;
|
import org.teavm.wasm.model.WasmModule;
|
||||||
import org.teavm.wasm.model.WasmType;
|
import org.teavm.wasm.model.WasmType;
|
||||||
import org.teavm.wasm.model.expression.WasmBlock;
|
import org.teavm.wasm.model.expression.WasmBlock;
|
||||||
|
@ -110,6 +112,9 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
dependencyChecker.linkMethod(method, null).use();
|
dependencyChecker.linkMethod(method, null).use();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "decodeData", Address.class,
|
||||||
|
Address.class, void.class), null).use();
|
||||||
|
|
||||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate",
|
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate",
|
||||||
RuntimeClass.class, Address.class), null).use();
|
RuntimeClass.class, Address.class), null).use();
|
||||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocateArray",
|
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||||
|
@ -120,15 +125,14 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
||||||
int address = 256;
|
|
||||||
WasmModule module = new WasmModule();
|
WasmModule module = new WasmModule();
|
||||||
WasmFunction initFunction = new WasmFunction("__start__");
|
WasmFunction initFunction = new WasmFunction("__start__");
|
||||||
|
|
||||||
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
||||||
TagRegistry tagRegistry = new TagRegistry(classes);
|
TagRegistry tagRegistry = new TagRegistry(classes);
|
||||||
|
BinaryWriter binaryWriter = new BinaryWriter(256);
|
||||||
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, tagRegistry,
|
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, tagRegistry,
|
||||||
initFunction.getBody());
|
binaryWriter);
|
||||||
classGenerator.setAddress(address);
|
|
||||||
for (String className : classes.getClassNames()) {
|
for (String className : classes.getClassNames()) {
|
||||||
classGenerator.addClass(className);
|
classGenerator.addClass(className);
|
||||||
if (controller.wasCancelled()) {
|
if (controller.wasCancelled()) {
|
||||||
|
@ -136,7 +140,6 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
classGenerator.addArrayClass();
|
classGenerator.addArrayClass();
|
||||||
address = classGenerator.getAddress();
|
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>());
|
new HashSet<>());
|
||||||
|
@ -181,7 +184,24 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAllocatorInit(module, address);
|
WasmMemorySegment dataSegment = new WasmMemorySegment();
|
||||||
|
dataSegment.setData(binaryWriter.getData());
|
||||||
|
dataSegment.setOffset(256);
|
||||||
|
module.getSegments().add(dataSegment);
|
||||||
|
|
||||||
|
WasmMemorySegment metadataSegment = new WasmMemorySegment();
|
||||||
|
metadataSegment.setData(binaryWriter.getMetadata());
|
||||||
|
metadataSegment.setOffset(binaryWriter.getAddress());
|
||||||
|
module.getSegments().add(metadataSegment);
|
||||||
|
|
||||||
|
MethodReference initData = new MethodReference(WasmRuntime.class, "decodeData", Address.class,
|
||||||
|
Address.class, void.class);
|
||||||
|
WasmCall initDataCall = new WasmCall(WasmMangling.mangleMethod(initData));
|
||||||
|
initDataCall.getArguments().add(new WasmInt32Constant(256));
|
||||||
|
initDataCall.getArguments().add(new WasmInt32Constant(binaryWriter.getAddress()));
|
||||||
|
initFunction.getBody().add(initDataCall);
|
||||||
|
|
||||||
|
renderAllocatorInit(module, binaryWriter.getAddress());
|
||||||
renderClinit(classes, classGenerator, module);
|
renderClinit(classes, classGenerator, module);
|
||||||
if (controller.wasCancelled()) {
|
if (controller.wasCancelled()) {
|
||||||
return;
|
return;
|
||||||
|
|
21
core/src/main/java/org/teavm/wasm/binary/AddressMode.java
Normal file
21
core/src/main/java/org/teavm/wasm/binary/AddressMode.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
public enum AddressMode {
|
||||||
|
ADDRESS_32,
|
||||||
|
ADDRESS_64
|
||||||
|
}
|
184
core/src/main/java/org/teavm/wasm/binary/BinaryWriter.java
Normal file
184
core/src/main/java/org/teavm/wasm/binary/BinaryWriter.java
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BinaryWriter {
|
||||||
|
private int address;
|
||||||
|
private List<DataValue> values = new ArrayList<>();
|
||||||
|
|
||||||
|
public BinaryWriter(int start) {
|
||||||
|
this.address = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int append(DataValue value) {
|
||||||
|
int result = align(address, getAlignment(value.getType()));
|
||||||
|
values.add(value);
|
||||||
|
address = offset(value.getType(), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int offset(DataType type, int index) {
|
||||||
|
if (type == DataPrimitives.BYTE) {
|
||||||
|
return index + 1;
|
||||||
|
} else if (type == DataPrimitives.SHORT) {
|
||||||
|
return align(index, 2) + 2;
|
||||||
|
} else if (type == DataPrimitives.INT) {
|
||||||
|
return align(index, 4) + 4;
|
||||||
|
} else if (type == DataPrimitives.LONG) {
|
||||||
|
return align(index, 8) + 8;
|
||||||
|
} else if (type == DataPrimitives.FLOAT) {
|
||||||
|
return align(index, 4) + 4;
|
||||||
|
} else if (type == DataPrimitives.DOUBLE) {
|
||||||
|
return align(index, 8) + 8;
|
||||||
|
} else if (type == DataPrimitives.ADDRESS) {
|
||||||
|
return align(index, 4) + 4;
|
||||||
|
} else if (type instanceof DataArray) {
|
||||||
|
DataArray array = (DataArray) type;
|
||||||
|
int next = offset(array.getComponentType(), index);
|
||||||
|
return index + (next - index) * array.getSize();
|
||||||
|
} else if (type instanceof DataStructure) {
|
||||||
|
DataStructure structure = (DataStructure) type;
|
||||||
|
if (structure.getAlignment() > 0) {
|
||||||
|
index = align(index, structure.getAlignment());
|
||||||
|
}
|
||||||
|
DataType[] components = structure.getComponents();
|
||||||
|
for (DataType component : components) {
|
||||||
|
index = offset(component, index);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
} else {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int align(int address, int alignment) {
|
||||||
|
if (address == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ((address - 1) / alignment + 1) * alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getAlignment(DataType type) {
|
||||||
|
if (type == DataPrimitives.BYTE) {
|
||||||
|
return 1;
|
||||||
|
} else if (type == DataPrimitives.SHORT) {
|
||||||
|
return 2;
|
||||||
|
} else if (type == DataPrimitives.INT) {
|
||||||
|
return 4;
|
||||||
|
} else if (type == DataPrimitives.LONG) {
|
||||||
|
return 8;
|
||||||
|
} else if (type == DataPrimitives.FLOAT) {
|
||||||
|
return 4;
|
||||||
|
} else if (type == DataPrimitives.DOUBLE) {
|
||||||
|
return 8;
|
||||||
|
} else if (type == DataPrimitives.ADDRESS) {
|
||||||
|
return 4;
|
||||||
|
} else if (type instanceof DataArray) {
|
||||||
|
return getAlignment(((DataArray) type).getComponentType());
|
||||||
|
} else if (type instanceof DataStructure) {
|
||||||
|
DataStructure structure = (DataStructure) type;
|
||||||
|
return Math.max(structure.getAlignment(), getAlignment(structure.getComponents()[0]));
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
byte[] result = new byte[address];
|
||||||
|
int offset = 0;
|
||||||
|
for (DataValue value : values) {
|
||||||
|
offset = writeData(result, offset, value);
|
||||||
|
}
|
||||||
|
return Arrays.copyOf(result, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int writeData(byte[] result, int offset, DataValue value) {
|
||||||
|
DataType type = value.getType();
|
||||||
|
if (type == DataPrimitives.BYTE) {
|
||||||
|
result[offset++] = value.getByte(0);
|
||||||
|
} else if (type == DataPrimitives.SHORT) {
|
||||||
|
offset = align(offset, 2);
|
||||||
|
short v = value.getShort(0);
|
||||||
|
result[offset++] = (byte) (v >> 8);
|
||||||
|
result[offset++] = (byte) v;
|
||||||
|
} else if (type == DataPrimitives.INT) {
|
||||||
|
offset = align(offset, 4);
|
||||||
|
int v = value.getInt(0);
|
||||||
|
result[offset++] = (byte) (v >> 24);
|
||||||
|
result[offset++] = (byte) (v >> 16);
|
||||||
|
result[offset++] = (byte) (v >> 8);
|
||||||
|
result[offset++] = (byte) v;
|
||||||
|
} else if (type == DataPrimitives.LONG) {
|
||||||
|
offset = align(offset, 8);
|
||||||
|
long v = value.getInt(0);
|
||||||
|
result[offset++] = (byte) (v >> 56);
|
||||||
|
result[offset++] = (byte) (v >> 48);
|
||||||
|
result[offset++] = (byte) (v >> 40);
|
||||||
|
result[offset++] = (byte) (v >> 32);
|
||||||
|
result[offset++] = (byte) (v >> 24);
|
||||||
|
result[offset++] = (byte) (v >> 16);
|
||||||
|
result[offset++] = (byte) (v >> 8);
|
||||||
|
result[offset++] = (byte) v;
|
||||||
|
} else if (type == DataPrimitives.FLOAT) {
|
||||||
|
offset = align(offset, 4);
|
||||||
|
int v = Float.floatToRawIntBits(value.getInt(0));
|
||||||
|
result[offset++] = (byte) (v >> 24);
|
||||||
|
result[offset++] = (byte) (v >> 16);
|
||||||
|
result[offset++] = (byte) (v >> 8);
|
||||||
|
result[offset++] = (byte) v;
|
||||||
|
} else if (type == DataPrimitives.DOUBLE) {
|
||||||
|
offset = align(offset, 8);
|
||||||
|
long v = Double.doubleToRawLongBits(value.getDouble(0));
|
||||||
|
result[offset++] = (byte) (v >> 56);
|
||||||
|
result[offset++] = (byte) (v >> 48);
|
||||||
|
result[offset++] = (byte) (v >> 40);
|
||||||
|
result[offset++] = (byte) (v >> 32);
|
||||||
|
result[offset++] = (byte) (v >> 24);
|
||||||
|
result[offset++] = (byte) (v >> 16);
|
||||||
|
result[offset++] = (byte) (v >> 8);
|
||||||
|
result[offset++] = (byte) v;
|
||||||
|
} else if (type instanceof DataArray) {
|
||||||
|
DataArray array = (DataArray) type;
|
||||||
|
for (int i = 0; i < array.getSize(); ++i) {
|
||||||
|
offset = writeData(result, offset, value.getValue(i));
|
||||||
|
}
|
||||||
|
} else if (type instanceof DataStructure) {
|
||||||
|
DataStructure structure = (DataStructure) type;
|
||||||
|
if (structure.getAlignment() > 0) {
|
||||||
|
offset = align(offset, structure.getAlignment());
|
||||||
|
}
|
||||||
|
int componentCount = structure.getComponents().length;
|
||||||
|
for (int i = 0; i < componentCount; ++i) {
|
||||||
|
offset = writeData(result, offset, value.getValue(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getMetadata() {
|
||||||
|
MetadataWriter writer = new MetadataWriter();
|
||||||
|
writer.write(values.stream().map(value -> value.getType()).toArray(DataType[]::new));
|
||||||
|
return writer.getData();
|
||||||
|
}
|
||||||
|
}
|
429
core/src/main/java/org/teavm/wasm/binary/DataArray.java
Normal file
429
core/src/main/java/org/teavm/wasm/binary/DataArray.java
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
public class DataArray extends DataType {
|
||||||
|
private DataType componentType;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
public DataArray(DataType componentType, int size) {
|
||||||
|
this.componentType = componentType;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataType getComponentType() {
|
||||||
|
return componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
if (componentType == DataPrimitives.BYTE) {
|
||||||
|
return new ByteArrayValue(this);
|
||||||
|
} else if (componentType == DataPrimitives.SHORT) {
|
||||||
|
return new ShortArrayValue(this);
|
||||||
|
} else if (componentType == DataPrimitives.INT) {
|
||||||
|
return new IntArrayValue(this);
|
||||||
|
} else if (componentType == DataPrimitives.LONG) {
|
||||||
|
return new LongArrayValue(this);
|
||||||
|
} else if (componentType == DataPrimitives.ADDRESS) {
|
||||||
|
return new AddressArrayValue(this);
|
||||||
|
} else if (componentType == DataPrimitives.FLOAT) {
|
||||||
|
return new FloatArrayValue(this);
|
||||||
|
} else if (componentType == DataPrimitives.DOUBLE) {
|
||||||
|
return new DoubleArrayValue(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayValue(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ByteArrayValue extends DataValue {
|
||||||
|
byte[] data;
|
||||||
|
|
||||||
|
ByteArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new byte[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getByte(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setByte(int index, byte value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.BYTE) {
|
||||||
|
@Override
|
||||||
|
public byte getByte(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setByte(int index, byte value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ShortArrayValue extends DataValue {
|
||||||
|
short[] data;
|
||||||
|
|
||||||
|
ShortArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new short[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getShort(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShort(int index, short value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.SHORT) {
|
||||||
|
@Override
|
||||||
|
public short getShort(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShort(int index, short value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IntArrayValue extends DataValue {
|
||||||
|
int[] data;
|
||||||
|
|
||||||
|
IntArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new int[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInt(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInt(int index, int value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.INT) {
|
||||||
|
@Override
|
||||||
|
public int getInt(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInt(int index, int value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LongArrayValue extends DataValue {
|
||||||
|
long[] data;
|
||||||
|
|
||||||
|
LongArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new long[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLong(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLong(int index, long value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.LONG) {
|
||||||
|
@Override
|
||||||
|
public long getLong(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLong(int index, long value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AddressArrayValue extends DataValue {
|
||||||
|
long[] data;
|
||||||
|
|
||||||
|
AddressArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new long[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getAddress(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAddress(int index, long value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.ADDRESS) {
|
||||||
|
@Override
|
||||||
|
public long getAddress(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAddress(int index, long value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FloatArrayValue extends DataValue {
|
||||||
|
float[] data;
|
||||||
|
|
||||||
|
FloatArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new float[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFloat(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(int index, float value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.FLOAT) {
|
||||||
|
@Override
|
||||||
|
public float getFloat(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(int index, float value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DoubleArrayValue extends DataValue {
|
||||||
|
double[] data;
|
||||||
|
|
||||||
|
DoubleArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new double[type.size];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDouble(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(int index, double value) {
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
int outerIndex = index;
|
||||||
|
return new DataValue(DataPrimitives.DOUBLE) {
|
||||||
|
@Override
|
||||||
|
public double getDouble(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
return data[outerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(int index, double value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0");
|
||||||
|
}
|
||||||
|
data[outerIndex] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ArrayValue extends DataValue {
|
||||||
|
DataValue[] data;
|
||||||
|
|
||||||
|
ArrayValue(DataArray type) {
|
||||||
|
super(type);
|
||||||
|
data = new DataValue[type.size];
|
||||||
|
for (int i = 0; i < data.length; ++i) {
|
||||||
|
data[i] = type.componentType.createValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getByte(int index) {
|
||||||
|
return data[index].getByte(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setByte(int index, byte value) {
|
||||||
|
data[index].setByte(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getShort(int index) {
|
||||||
|
return data[index].getShort(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShort(int index, short value) {
|
||||||
|
data[index].setShort(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInt(int index) {
|
||||||
|
return data[index].getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInt(int index, int value) {
|
||||||
|
data[index].setInt(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLong(int index) {
|
||||||
|
return data[index].getLong(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLong(int index, long value) {
|
||||||
|
data[index].setLong(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getAddress(int index) {
|
||||||
|
return data[index].getAddress(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAddress(int index, long value) {
|
||||||
|
data[index].setAddress(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFloat(int index) {
|
||||||
|
return data[index].getFloat(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(int index, float value) {
|
||||||
|
data[index].setFloat(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDouble(int index) {
|
||||||
|
return data[index].getDouble(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(int index, double value) {
|
||||||
|
data[index].setDouble(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
238
core/src/main/java/org/teavm/wasm/binary/DataPrimitives.java
Normal file
238
core/src/main/java/org/teavm/wasm/binary/DataPrimitives.java
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
public final class DataPrimitives {
|
||||||
|
private DataPrimitives() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final DataType BYTE = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new ByteDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final DataType SHORT = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new ShortDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final DataType INT = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new IntDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final DataType LONG = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new LongDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final DataType ADDRESS = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new AddressDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final DataType FLOAT = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new FloatDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final DataType DOUBLE = new DataType() {
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new DoubleDataValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static class ByteDataValue extends DataValue {
|
||||||
|
byte value;
|
||||||
|
|
||||||
|
ByteDataValue() {
|
||||||
|
super(BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getByte(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setByte(int index, byte value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ShortDataValue extends DataValue {
|
||||||
|
short value;
|
||||||
|
|
||||||
|
ShortDataValue() {
|
||||||
|
super(SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getShort(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShort(int index, short value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IntDataValue extends DataValue {
|
||||||
|
int value;
|
||||||
|
|
||||||
|
IntDataValue() {
|
||||||
|
super(INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInt(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInt(int index, int value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LongDataValue extends DataValue {
|
||||||
|
long value;
|
||||||
|
|
||||||
|
LongDataValue() {
|
||||||
|
super(LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLong(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLong(int index, long value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AddressDataValue extends DataValue {
|
||||||
|
long value;
|
||||||
|
|
||||||
|
AddressDataValue() {
|
||||||
|
super(ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getAddress(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAddress(int index, long value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FloatDataValue extends DataValue {
|
||||||
|
float value;
|
||||||
|
|
||||||
|
FloatDataValue() {
|
||||||
|
super(FLOAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFloat(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(int index, float value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DoubleDataValue extends DataValue {
|
||||||
|
double value;
|
||||||
|
|
||||||
|
DoubleDataValue() {
|
||||||
|
super(DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDouble(int index) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(int index, double value) {
|
||||||
|
if (index != 0) {
|
||||||
|
throw new IllegalArgumentException("Index should be 0 for primitive values");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
core/src/main/java/org/teavm/wasm/binary/DataStructure.java
Normal file
91
core/src/main/java/org/teavm/wasm/binary/DataStructure.java
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
public class DataStructure extends DataType {
|
||||||
|
private byte alignment;
|
||||||
|
private DataType[] components;
|
||||||
|
|
||||||
|
public DataStructure(byte alignment, DataType... components) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
this.components = components.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getAlignment() {
|
||||||
|
return alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataType[] getComponents() {
|
||||||
|
return components.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue createValue() {
|
||||||
|
return new StructureValue(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StructureValue extends DataValue {
|
||||||
|
private DataValue[] components;
|
||||||
|
|
||||||
|
StructureValue(DataStructure type) {
|
||||||
|
super(type);
|
||||||
|
components = new DataValue[type.components.length];
|
||||||
|
for (int i = 0; i < components.length; ++i) {
|
||||||
|
components[i] = type.components[i].createValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setByte(int index, byte value) {
|
||||||
|
components[index].setByte(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShort(int index, short value) {
|
||||||
|
components[index].setShort(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInt(int index, int value) {
|
||||||
|
components[index].setInt(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLong(int index, long value) {
|
||||||
|
components[index].setLong(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAddress(int index, long value) {
|
||||||
|
components[index].setAddress(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(int index, float value) {
|
||||||
|
components[index].setFloat(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(int index, double value) {
|
||||||
|
components[index].setDouble(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
return components[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
core/src/main/java/org/teavm/wasm/binary/DataType.java
Normal file
20
core/src/main/java/org/teavm/wasm/binary/DataType.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
public abstract class DataType {
|
||||||
|
public abstract DataValue createValue();
|
||||||
|
}
|
89
core/src/main/java/org/teavm/wasm/binary/DataValue.java
Normal file
89
core/src/main/java/org/teavm/wasm/binary/DataValue.java
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
public abstract class DataValue {
|
||||||
|
private DataType type;
|
||||||
|
|
||||||
|
DataValue(DataType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getByte(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setByte(int index, byte value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getShort(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShort(int index, short value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInt(int index, int value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLong(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLong(int index, long value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAddress(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(int index, long value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFloat(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFloat(int index, float value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDouble(int index, double value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataValue getValue(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
122
core/src/main/java/org/teavm/wasm/binary/MetadataWriter.java
Normal file
122
core/src/main/java/org/teavm/wasm/binary/MetadataWriter.java
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* 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.binary;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class MetadataWriter {
|
||||||
|
private byte[] data = new byte[256];
|
||||||
|
private int offset;
|
||||||
|
private Map<DataStructure, Integer> structureUsages = new HashMap<>();
|
||||||
|
|
||||||
|
void write(DataType[] types) {
|
||||||
|
writeLeb(types.length);
|
||||||
|
for (DataType type : types) {
|
||||||
|
write(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write(DataType type) {
|
||||||
|
if (type == DataPrimitives.BYTE) {
|
||||||
|
writeByte(0);
|
||||||
|
} else if (type == DataPrimitives.SHORT) {
|
||||||
|
writeByte(1);
|
||||||
|
} else if (type == DataPrimitives.INT) {
|
||||||
|
writeByte(2);
|
||||||
|
} else if (type == DataPrimitives.LONG) {
|
||||||
|
writeByte(3);
|
||||||
|
} else if (type == DataPrimitives.FLOAT) {
|
||||||
|
writeByte(4);
|
||||||
|
} else if (type == DataPrimitives.DOUBLE) {
|
||||||
|
writeByte(5);
|
||||||
|
} else if (type == DataPrimitives.ADDRESS) {
|
||||||
|
writeByte(6);
|
||||||
|
} else if (type instanceof DataArray) {
|
||||||
|
DataArray array = (DataArray) type;
|
||||||
|
writeByte(7);
|
||||||
|
writeLeb(array.getSize());
|
||||||
|
write(array.getComponentType());
|
||||||
|
} else if (type instanceof DataStructure) {
|
||||||
|
DataStructure structure = (DataStructure) type;
|
||||||
|
Integer usage = structureUsages.get(structure);
|
||||||
|
if (usage == null) {
|
||||||
|
structureUsages.put(structure, offset);
|
||||||
|
writeByte(8);
|
||||||
|
writeByte(structure.getAlignment());
|
||||||
|
DataType[] components = structure.getComponents();
|
||||||
|
writeLeb(components.length);
|
||||||
|
for (int i = 0; i < components.length; ++i) {
|
||||||
|
write(components[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int start = offset;
|
||||||
|
structureUsages.put(structure, offset);
|
||||||
|
writeByte(9);
|
||||||
|
writeLeb(start - usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLeb(int value) {
|
||||||
|
if (value >>> 7 == 0) {
|
||||||
|
writeByte(value);
|
||||||
|
} else if (value >>> 14 == 0) {
|
||||||
|
byte first = (byte) ((value & 0x7F) | 0x80);
|
||||||
|
byte second = (byte) (value >>> 7);
|
||||||
|
writeBytes(new byte[] { first, second });
|
||||||
|
} else if (value >>> 21 == 0) {
|
||||||
|
byte first = (byte) ((value & 0x7F) | 0x80);
|
||||||
|
byte second = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
||||||
|
byte third = (byte) (value >>> 14);
|
||||||
|
writeBytes(new byte[] { first, second, third });
|
||||||
|
} else if (value >>> 28 == 0) {
|
||||||
|
byte first = (byte) ((value & 0x7F) | 0x80);
|
||||||
|
byte second = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
||||||
|
byte third = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
||||||
|
byte fourth = (byte) (value >>> 21);
|
||||||
|
writeBytes(new byte[] { first, second, third, fourth });
|
||||||
|
} else {
|
||||||
|
byte first = (byte) ((value & 0x7F) | 0x80);
|
||||||
|
byte second = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
||||||
|
byte third = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
||||||
|
byte fourth = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
||||||
|
byte fifth = (byte) (value >>> 28);
|
||||||
|
writeBytes(new byte[] { first, second, third, fourth, fifth });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeByte(int value) {
|
||||||
|
if (offset >= data.length) {
|
||||||
|
data = Arrays.copyOf(data, data.length * 2);
|
||||||
|
}
|
||||||
|
data[offset++] = (byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeBytes(byte[] values) {
|
||||||
|
int count = values.length;
|
||||||
|
if (offset + count > data.length) {
|
||||||
|
data = Arrays.copyOf(data, data.length * 2);
|
||||||
|
}
|
||||||
|
System.arraycopy(values, 0, data, offset, count);
|
||||||
|
offset += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return Arrays.copyOf(data, offset);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,8 +18,6 @@ package org.teavm.wasm.generate;
|
||||||
import com.carrotsearch.hppc.ObjectIntMap;
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -38,28 +36,35 @@ import org.teavm.model.classes.VirtualTable;
|
||||||
import org.teavm.model.classes.VirtualTableEntry;
|
import org.teavm.model.classes.VirtualTableEntry;
|
||||||
import org.teavm.model.classes.VirtualTableProvider;
|
import org.teavm.model.classes.VirtualTableProvider;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.wasm.model.expression.WasmExpression;
|
import org.teavm.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
import org.teavm.wasm.binary.DataArray;
|
||||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
import org.teavm.wasm.binary.DataPrimitives;
|
||||||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.wasm.binary.DataStructure;
|
||||||
|
import org.teavm.wasm.binary.DataType;
|
||||||
|
import org.teavm.wasm.binary.DataValue;
|
||||||
|
|
||||||
public class WasmClassGenerator {
|
public class WasmClassGenerator {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private int address;
|
|
||||||
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||||
private ClassBinaryData arrayClassData;
|
private ClassBinaryData arrayClassData;
|
||||||
private List<WasmExpression> initializer;
|
private BinaryWriter binaryWriter;
|
||||||
private Map<MethodReference, Integer> functions = new HashMap<>();
|
private Map<MethodReference, Integer> functions = new HashMap<>();
|
||||||
private List<String> functionTable = new ArrayList<>();
|
private List<String> functionTable = new ArrayList<>();
|
||||||
private VirtualTableProvider vtableProvider;
|
private VirtualTableProvider vtableProvider;
|
||||||
private TagRegistry tagRegistry;
|
private TagRegistry tagRegistry;
|
||||||
|
private DataStructure classStructure = new DataStructure(
|
||||||
|
(byte) 8,
|
||||||
|
DataPrimitives.INT, /* size */
|
||||||
|
DataPrimitives.INT, /* flags */
|
||||||
|
DataPrimitives.INT, /* tag */
|
||||||
|
DataPrimitives.INT /* canary */);
|
||||||
|
|
||||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
||||||
TagRegistry tagRegistry, List<WasmExpression> initializer) {
|
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.vtableProvider = vtableProvider;
|
this.vtableProvider = vtableProvider;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
this.initializer = initializer;
|
this.binaryWriter = binaryWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addClass(String className) {
|
public void addClass(String className) {
|
||||||
|
@ -77,9 +82,7 @@ public class WasmClassGenerator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
address = align(address, 8);
|
binaryData.start = binaryWriter.append(createStructure(binaryData));
|
||||||
binaryData.start = address;
|
|
||||||
contributeToInitializer(binaryData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addArrayClass() {
|
public void addArrayClass() {
|
||||||
|
@ -88,37 +91,32 @@ public class WasmClassGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayClassData = new ClassBinaryData();
|
arrayClassData = new ClassBinaryData();
|
||||||
arrayClassData.start = address;
|
arrayClassData.start = binaryWriter.append(classStructure.createValue());
|
||||||
|
|
||||||
address += RuntimeClass.VIRTUAL_TABLE_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddress(int address) {
|
|
||||||
this.address = address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getFunctionTable() {
|
public List<String> getFunctionTable() {
|
||||||
return functionTable;
|
return functionTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contributeToInitializer(ClassBinaryData binaryData) {
|
private DataValue createStructure(ClassBinaryData binaryData) {
|
||||||
contributeInt32Value(binaryData.start + RuntimeClass.SIZE_OFFSET, binaryData.size);
|
|
||||||
|
|
||||||
List<TagRegistry.Range> ranges = tagRegistry.getRanges(binaryData.name);
|
|
||||||
int lower = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
|
||||||
int upper = ranges.stream().mapToInt(range -> range.upper).max().orElse(0);
|
|
||||||
contributeInt32Value(binaryData.start + RuntimeClass.LOWER_TAG_OFFSET, lower);
|
|
||||||
contributeInt32Value(binaryData.start + RuntimeClass.UPPER_TAG_OFFSET, upper);
|
|
||||||
contributeInt32Value(binaryData.start + RuntimeClass.CANARY_OFFSET,
|
|
||||||
RuntimeClass.computeCanary(binaryData.size, lower, upper));
|
|
||||||
|
|
||||||
address = binaryData.start + RuntimeClass.VIRTUAL_TABLE_OFFSET;
|
|
||||||
VirtualTable vtable = vtableProvider.lookup(binaryData.name);
|
VirtualTable vtable = vtableProvider.lookup(binaryData.name);
|
||||||
if (vtable != null) {
|
int vtableSize = vtable != null ? vtable.getEntries().size() : 0;
|
||||||
|
|
||||||
|
DataType arrayType = new DataArray(DataPrimitives.INT, vtableSize);
|
||||||
|
DataValue wrapper = new DataStructure((byte) 0, classStructure, arrayType).createValue();
|
||||||
|
DataValue array = wrapper.getValue(1);
|
||||||
|
DataValue header = wrapper.getValue(0);
|
||||||
|
|
||||||
|
header.setInt(0, binaryData.size);
|
||||||
|
List<TagRegistry.Range> ranges = tagRegistry.getRanges(binaryData.name);
|
||||||
|
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
||||||
|
header.setInt(2, tag);
|
||||||
|
header.setInt(3, RuntimeClass.computeCanary(binaryData.size, tag));
|
||||||
|
if (vtable == null) {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
for (VirtualTableEntry vtableEntry : vtable.getEntries().values()) {
|
for (VirtualTableEntry vtableEntry : vtable.getEntries().values()) {
|
||||||
int methodIndex;
|
int methodIndex;
|
||||||
if (vtableEntry.getImplementor() == null) {
|
if (vtableEntry.getImplementor() == null) {
|
||||||
|
@ -131,28 +129,10 @@ public class WasmClassGenerator {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
contributeInt32Value(address, methodIndex);
|
array.setInt(index++, methodIndex);
|
||||||
address += 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contributeInt32Value(binaryData.start + RuntimeClass.EXCLUDED_RANGE_COUNT_OFFSET, ranges.size() - 1);
|
return wrapper;
|
||||||
|
|
||||||
if (ranges.size() > 1) {
|
|
||||||
contributeInt32Value(binaryData.start + RuntimeClass.EXCLUDED_RANGE_ADDRESS_OFFSET, address);
|
|
||||||
|
|
||||||
Collections.sort(ranges, Comparator.comparingInt(range -> range.lower));
|
|
||||||
for (int i = 1; i < ranges.size(); ++i) {
|
|
||||||
contributeInt32Value(address, ranges.get(i - 1).upper);
|
|
||||||
contributeInt32Value(address + 4, ranges.get(i).lower);
|
|
||||||
address += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void contributeInt32Value(int index, int value) {
|
|
||||||
initializer.add(new WasmStoreInt32(4, new WasmInt32Constant(index), new WasmInt32Constant(value),
|
|
||||||
WasmInt32Subtype.INT32));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getClassPointer(String className) {
|
public int getClassPointer(String className) {
|
||||||
|
@ -197,9 +177,9 @@ public class WasmClassGenerator {
|
||||||
for (FieldReader field : cls.getFields()) {
|
for (FieldReader field : cls.getFields()) {
|
||||||
int desiredAlignment = getDesiredAlignment(field.getType());
|
int desiredAlignment = getDesiredAlignment(field.getType());
|
||||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||||
int offset = align(address, desiredAlignment);
|
/*int offset = align(address, desiredAlignment);
|
||||||
data.fieldLayout.put(field.getName(), offset);
|
data.fieldLayout.put(field.getName(), offset);
|
||||||
address = offset + desiredAlignment;
|
address = offset + desiredAlignment;*/
|
||||||
} else {
|
} else {
|
||||||
int offset = align(data.size, desiredAlignment);
|
int offset = align(data.size, desiredAlignment);
|
||||||
data.fieldLayout.put(field.getName(), offset);
|
data.fieldLayout.put(field.getName(), offset);
|
||||||
|
|
|
@ -256,6 +256,18 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
expr.getSecondOperand().acceptVisitor(this);
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
WasmExpression second = result;
|
WasmExpression second = result;
|
||||||
|
|
||||||
|
if (expr.getType() == OperationType.LONG) {
|
||||||
|
switch (expr.getOperation()) {
|
||||||
|
case LEFT_SHIFT:
|
||||||
|
case RIGHT_SHIFT:
|
||||||
|
case UNSIGNED_RIGHT_SHIFT:
|
||||||
|
second = new WasmConversion(WasmType.INT32, WasmType.INT64, false, second);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (expr.getType()) {
|
switch (expr.getType()) {
|
||||||
case INT:
|
case INT:
|
||||||
result = new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
result = new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||||
|
@ -661,8 +673,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
||||||
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||||
getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4
|
getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + 16));
|
||||||
+ RuntimeClass.VIRTUAL_TABLE_OFFSET));
|
|
||||||
methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32);
|
methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32);
|
||||||
|
|
||||||
WasmIndirectCall call = new WasmIndirectCall(methodIndex);
|
WasmIndirectCall call = new WasmIndirectCall(methodIndex);
|
||||||
|
@ -833,7 +844,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
WasmBlock block = new WasmBlock(false);
|
WasmBlock block = new WasmBlock(false);
|
||||||
WasmLocal tagVar = function.getLocalVariables().get(getTemporaryInt32());
|
WasmLocal tagVar = function.getLocalVariables().get(getTemporaryInt32());
|
||||||
WasmExpression tagPtr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
WasmExpression tagPtr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||||
getReferenceToClass(result), new WasmInt32Constant(RuntimeClass.LOWER_TAG_OFFSET));
|
getReferenceToClass(result), new WasmInt32Constant(8));
|
||||||
block.getBody().add(new WasmSetLocal(tagVar, new WasmLoadInt32(4, tagPtr, WasmInt32Subtype.INT32)));
|
block.getBody().add(new WasmSetLocal(tagVar, new WasmLoadInt32(4, tagPtr, WasmInt32Subtype.INT32)));
|
||||||
|
|
||||||
WasmExpression lowerThanMinCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
WasmExpression lowerThanMinCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||||
|
@ -963,21 +974,56 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return expression instanceof WasmInt32Constant && ((WasmInt32Constant) expression).getValue() == 0;
|
return expression instanceof WasmInt32Constant && ((WasmInt32Constant) expression).getValue() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isBoolean(WasmExpression expression) {
|
||||||
|
if (expression instanceof WasmIntBinary) {
|
||||||
|
WasmIntBinary binary = (WasmIntBinary) expression;
|
||||||
|
switch (binary.getOperation()) {
|
||||||
|
case EQ:
|
||||||
|
case NE:
|
||||||
|
case LT_SIGNED:
|
||||||
|
case LT_UNSIGNED:
|
||||||
|
case LE_SIGNED:
|
||||||
|
case LE_UNSIGNED:
|
||||||
|
case GT_SIGNED:
|
||||||
|
case GT_UNSIGNED:
|
||||||
|
case GE_SIGNED:
|
||||||
|
case GE_UNSIGNED:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (expression instanceof WasmFloatBinary) {
|
||||||
|
WasmFloatBinary binary = (WasmFloatBinary) expression;
|
||||||
|
switch (binary.getOperation()) {
|
||||||
|
case EQ:
|
||||||
|
case NE:
|
||||||
|
case LT:
|
||||||
|
case LE:
|
||||||
|
case GT:
|
||||||
|
case GE:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private WasmExpression forCondition(WasmExpression expression) {
|
private WasmExpression forCondition(WasmExpression expression) {
|
||||||
if (expression instanceof WasmIntBinary) {
|
if (expression instanceof WasmIntBinary) {
|
||||||
WasmIntBinary binary = (WasmIntBinary) expression;
|
WasmIntBinary binary = (WasmIntBinary) expression;
|
||||||
switch (binary.getOperation()) {
|
switch (binary.getOperation()) {
|
||||||
case EQ:
|
case EQ:
|
||||||
if (isZero(binary.getFirst())) {
|
if (isZero(binary.getFirst()) && isBoolean(binary.getSecond())) {
|
||||||
return negate(binary.getSecond());
|
return negate(binary.getSecond());
|
||||||
} else if (isZero(binary.getSecond())) {
|
} else if (isZero(binary.getSecond()) && isBoolean(binary.getFirst())) {
|
||||||
return negate(binary.getFirst());
|
return negate(binary.getFirst());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NE:
|
case NE:
|
||||||
if (isZero(binary.getFirst())) {
|
if (isZero(binary.getFirst()) && isBoolean(binary.getSecond())) {
|
||||||
return binary.getSecond();
|
return binary.getSecond();
|
||||||
} else if (isZero(binary.getSecond())) {
|
} else if (isZero(binary.getSecond()) && isBoolean(binary.getFirst())) {
|
||||||
return binary.getFirst();
|
return binary.getFirst();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,6 +46,6 @@ public class WasmMemorySegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getData(int offset, int size) {
|
public byte[] getData(int offset, int size) {
|
||||||
return Arrays.copyOfRange(data, offset, size);
|
return Arrays.copyOfRange(data, offset, offset + size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,16 +80,16 @@ public class WasmRenderer {
|
||||||
visitor.lf();
|
visitor.lf();
|
||||||
visitor.open().append("memory " + module.getMemorySize());
|
visitor.open().append("memory " + module.getMemorySize());
|
||||||
for (WasmMemorySegment segment : module.getSegments()) {
|
for (WasmMemorySegment segment : module.getSegments()) {
|
||||||
visitor.lf().open().append("segment " + segment.getLength());
|
visitor.lf().open().append("segment " + segment.getOffset());
|
||||||
visitor.indent();
|
visitor.indent();
|
||||||
for (int i = 0; i < segment.getLength(); i += 256) {
|
for (int i = 0; i < segment.getLength(); i += 256) {
|
||||||
visitor.lf().append("\"");
|
visitor.lf().append("\"");
|
||||||
byte[] part = segment.getData(i, Math.max(segment.getLength(), i + 256) - i);
|
byte[] part = segment.getData(i, Math.min(segment.getLength(), i + 256) - i);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int j = 0; j < part.length; ++j) {
|
for (int j = 0; j < part.length; ++j) {
|
||||||
int b = part[j] << 24 >>> 24;
|
int b = part[j] << 24 >>> 24;
|
||||||
if (b < ' ' || b > 126) {
|
if (b < ' ' || b > 126) {
|
||||||
sb.append("\\0x" + Character.forDigit(b >> 4, 16) + Character.forDigit(b & 0xF, 16));
|
sb.append("\\" + Character.forDigit(b >> 4, 16) + Character.forDigit(b & 0xF, 16));
|
||||||
} else if (b == '\\') {
|
} else if (b == '\\') {
|
||||||
sb.append("\\\\");
|
sb.append("\\\\");
|
||||||
} else if (b == '"') {
|
} else if (b == '"') {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user