mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 00:14: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 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 BYTE_CLASS = -2;
|
||||
public static int SHORT_CLASS = -3;
|
||||
|
@ -40,17 +31,15 @@ public class RuntimeClass extends Structure {
|
|||
|
||||
public int size;
|
||||
public int flags;
|
||||
public int lowerTag;
|
||||
public int upperTag;
|
||||
public int excludedRangeCount;
|
||||
public int excludedRangesAddress;
|
||||
public int tag;
|
||||
public int canary;
|
||||
|
||||
public static int computeCanary(int size, int lowerTag, int upperTag) {
|
||||
return size ^ (lowerTag << 8) ^ (lowerTag >>> 24) ^ (upperTag << 24) ^ (lowerTag >>> 8);
|
||||
public static int computeCanary(int size, int tag) {
|
||||
return size ^ (tag << 8) ^ (tag >>> 24) ^ (0xAAAAAAAA);
|
||||
}
|
||||
|
||||
public int computeCanary() {
|
||||
return computeCanary(size, lowerTag, upperTag);
|
||||
return computeCanary(size, tag);
|
||||
}
|
||||
|
||||
public static native RuntimeClass getArrayClass();
|
||||
|
|
|
@ -15,9 +15,12 @@
|
|||
*/
|
||||
package org.teavm.wasm;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Import;
|
||||
|
||||
public final class WasmRuntime {
|
||||
private static Address offset;
|
||||
|
||||
private WasmRuntime() {
|
||||
}
|
||||
|
||||
|
@ -61,6 +64,131 @@ public final class WasmRuntime {
|
|||
|
||||
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")
|
||||
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.TeaVMTargetController;
|
||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||
import org.teavm.wasm.binary.BinaryWriter;
|
||||
import org.teavm.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.wasm.generate.WasmGenerationContext;
|
||||
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.WasmStructureIntrinsic;
|
||||
import org.teavm.wasm.model.WasmFunction;
|
||||
import org.teavm.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.wasm.model.WasmModule;
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
|
@ -110,6 +112,9 @@ public class WasmTarget implements TeaVMTarget {
|
|||
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",
|
||||
RuntimeClass.class, Address.class), null).use();
|
||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
|
@ -120,15 +125,14 @@ public class WasmTarget implements TeaVMTarget {
|
|||
|
||||
@Override
|
||||
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
||||
int address = 256;
|
||||
WasmModule module = new WasmModule();
|
||||
WasmFunction initFunction = new WasmFunction("__start__");
|
||||
|
||||
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
||||
TagRegistry tagRegistry = new TagRegistry(classes);
|
||||
BinaryWriter binaryWriter = new BinaryWriter(256);
|
||||
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, tagRegistry,
|
||||
initFunction.getBody());
|
||||
classGenerator.setAddress(address);
|
||||
binaryWriter);
|
||||
for (String className : classes.getClassNames()) {
|
||||
classGenerator.addClass(className);
|
||||
if (controller.wasCancelled()) {
|
||||
|
@ -136,7 +140,6 @@ public class WasmTarget implements TeaVMTarget {
|
|||
}
|
||||
}
|
||||
classGenerator.addArrayClass();
|
||||
address = classGenerator.getAddress();
|
||||
|
||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), 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);
|
||||
if (controller.wasCancelled()) {
|
||||
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.ObjectIntOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
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.VirtualTableProvider;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||
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.DataType;
|
||||
import org.teavm.wasm.binary.DataValue;
|
||||
|
||||
public class WasmClassGenerator {
|
||||
private ClassReaderSource classSource;
|
||||
private int address;
|
||||
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||
private ClassBinaryData arrayClassData;
|
||||
private List<WasmExpression> initializer;
|
||||
private BinaryWriter binaryWriter;
|
||||
private Map<MethodReference, Integer> functions = new HashMap<>();
|
||||
private List<String> functionTable = new ArrayList<>();
|
||||
private VirtualTableProvider vtableProvider;
|
||||
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,
|
||||
TagRegistry tagRegistry, List<WasmExpression> initializer) {
|
||||
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
||||
this.classSource = classSource;
|
||||
this.vtableProvider = vtableProvider;
|
||||
this.tagRegistry = tagRegistry;
|
||||
this.initializer = initializer;
|
||||
this.binaryWriter = binaryWriter;
|
||||
}
|
||||
|
||||
public void addClass(String className) {
|
||||
|
@ -77,9 +82,7 @@ public class WasmClassGenerator {
|
|||
return;
|
||||
}
|
||||
|
||||
address = align(address, 8);
|
||||
binaryData.start = address;
|
||||
contributeToInitializer(binaryData);
|
||||
binaryData.start = binaryWriter.append(createStructure(binaryData));
|
||||
}
|
||||
|
||||
public void addArrayClass() {
|
||||
|
@ -88,37 +91,32 @@ public class WasmClassGenerator {
|
|||
}
|
||||
|
||||
arrayClassData = new ClassBinaryData();
|
||||
arrayClassData.start = address;
|
||||
|
||||
address += RuntimeClass.VIRTUAL_TABLE_OFFSET;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(int address) {
|
||||
this.address = address;
|
||||
arrayClassData.start = binaryWriter.append(classStructure.createValue());
|
||||
}
|
||||
|
||||
public List<String> getFunctionTable() {
|
||||
return functionTable;
|
||||
}
|
||||
|
||||
private void contributeToInitializer(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;
|
||||
private DataValue createStructure(ClassBinaryData binaryData) {
|
||||
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()) {
|
||||
int methodIndex;
|
||||
if (vtableEntry.getImplementor() == null) {
|
||||
|
@ -131,28 +129,10 @@ public class WasmClassGenerator {
|
|||
});
|
||||
}
|
||||
|
||||
contributeInt32Value(address, methodIndex);
|
||||
address += 4;
|
||||
}
|
||||
array.setInt(index++, methodIndex);
|
||||
}
|
||||
|
||||
contributeInt32Value(binaryData.start + RuntimeClass.EXCLUDED_RANGE_COUNT_OFFSET, ranges.size() - 1);
|
||||
|
||||
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));
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
public int getClassPointer(String className) {
|
||||
|
@ -197,9 +177,9 @@ public class WasmClassGenerator {
|
|||
for (FieldReader field : cls.getFields()) {
|
||||
int desiredAlignment = getDesiredAlignment(field.getType());
|
||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||
int offset = align(address, desiredAlignment);
|
||||
/*int offset = align(address, desiredAlignment);
|
||||
data.fieldLayout.put(field.getName(), offset);
|
||||
address = offset + desiredAlignment;
|
||||
address = offset + desiredAlignment;*/
|
||||
} else {
|
||||
int offset = align(data.size, desiredAlignment);
|
||||
data.fieldLayout.put(field.getName(), offset);
|
||||
|
|
|
@ -256,6 +256,18 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
expr.getSecondOperand().acceptVisitor(this);
|
||||
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()) {
|
||||
case INT:
|
||||
result = new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||
|
@ -661,8 +673,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
||||
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||
getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4
|
||||
+ RuntimeClass.VIRTUAL_TABLE_OFFSET));
|
||||
getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + 16));
|
||||
methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32);
|
||||
|
||||
WasmIndirectCall call = new WasmIndirectCall(methodIndex);
|
||||
|
@ -833,7 +844,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
WasmBlock block = new WasmBlock(false);
|
||||
WasmLocal tagVar = function.getLocalVariables().get(getTemporaryInt32());
|
||||
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)));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (expression instanceof WasmIntBinary) {
|
||||
WasmIntBinary binary = (WasmIntBinary) expression;
|
||||
switch (binary.getOperation()) {
|
||||
case EQ:
|
||||
if (isZero(binary.getFirst())) {
|
||||
if (isZero(binary.getFirst()) && isBoolean(binary.getSecond())) {
|
||||
return negate(binary.getSecond());
|
||||
} else if (isZero(binary.getSecond())) {
|
||||
} else if (isZero(binary.getSecond()) && isBoolean(binary.getFirst())) {
|
||||
return negate(binary.getFirst());
|
||||
}
|
||||
break;
|
||||
case NE:
|
||||
if (isZero(binary.getFirst())) {
|
||||
if (isZero(binary.getFirst()) && isBoolean(binary.getSecond())) {
|
||||
return binary.getSecond();
|
||||
} else if (isZero(binary.getSecond())) {
|
||||
} else if (isZero(binary.getSecond()) && isBoolean(binary.getFirst())) {
|
||||
return binary.getFirst();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -46,6 +46,6 @@ public class WasmMemorySegment {
|
|||
}
|
||||
|
||||
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.open().append("memory " + module.getMemorySize());
|
||||
for (WasmMemorySegment segment : module.getSegments()) {
|
||||
visitor.lf().open().append("segment " + segment.getLength());
|
||||
visitor.lf().open().append("segment " + segment.getOffset());
|
||||
visitor.indent();
|
||||
for (int i = 0; i < segment.getLength(); i += 256) {
|
||||
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();
|
||||
for (int j = 0; j < part.length; ++j) {
|
||||
int b = part[j] << 24 >>> 24;
|
||||
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 == '\\') {
|
||||
sb.append("\\\\");
|
||||
} else if (b == '"') {
|
||||
|
|
Loading…
Reference in New Issue
Block a user