mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Wasm backend: fix more tests. Implement Array.get. Implement x instanceof C for all cases.
This commit is contained in:
parent
f23128bb13
commit
c9ebe2e2e9
|
@ -27,6 +27,7 @@ import org.teavm.ast.RegularMethodNode;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.backend.c.generators.Generator;
|
import org.teavm.backend.c.generators.Generator;
|
||||||
import org.teavm.backend.c.generators.GeneratorContext;
|
import org.teavm.backend.c.generators.GeneratorContext;
|
||||||
|
import org.teavm.backend.lowlevel.generate.ClassGeneratorUtil;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.DelegateTo;
|
import org.teavm.interop.DelegateTo;
|
||||||
|
@ -442,11 +443,7 @@ public class ClassGenerator {
|
||||||
tag = 0;
|
tag = 0;
|
||||||
sizeExpr = "sizeof(" + CodeWriter.strictTypeAsString(type) + ")";
|
sizeExpr = "sizeof(" + CodeWriter.strictTypeAsString(type) + ")";
|
||||||
flags |= RuntimeClass.PRIMITIVE;
|
flags |= RuntimeClass.PRIMITIVE;
|
||||||
if (type instanceof ValueType.Primitive) {
|
flags = ClassGeneratorUtil.applyPrimitiveFlags(flags, type);
|
||||||
flags |= getPrimitiveFlag((ValueType.Primitive) type) << RuntimeClass.PRIMITIVE_SHIFT;
|
|
||||||
} else {
|
|
||||||
flags |= RuntimeClass.VOID_PRIMITIVE << RuntimeClass.PRIMITIVE_SHIFT;
|
|
||||||
}
|
|
||||||
itemTypeExpr = "NULL";
|
itemTypeExpr = "NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,29 +548,6 @@ public class ClassGenerator {
|
||||||
layoutWriter.println().outdent().println("};");
|
layoutWriter.println().outdent().println("};");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPrimitiveFlag(ValueType.Primitive type) {
|
|
||||||
switch (type.getKind()) {
|
|
||||||
case BOOLEAN:
|
|
||||||
return RuntimeClass.BOOLEAN_PRIMITIVE;
|
|
||||||
case BYTE:
|
|
||||||
return RuntimeClass.BYTE_PRIMITIVE;
|
|
||||||
case SHORT:
|
|
||||||
return RuntimeClass.SHORT_PRIMITIVE;
|
|
||||||
case CHARACTER:
|
|
||||||
return RuntimeClass.CHAR_PRIMITIVE;
|
|
||||||
case INTEGER:
|
|
||||||
return RuntimeClass.INT_PRIMITIVE;
|
|
||||||
case LONG:
|
|
||||||
return RuntimeClass.LONG_PRIMITIVE;
|
|
||||||
case FLOAT:
|
|
||||||
return RuntimeClass.FLOAT_PRIMITIVE;
|
|
||||||
case DOUBLE:
|
|
||||||
return RuntimeClass.DOUBLE_PRIMITIVE;
|
|
||||||
default:
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String classFieldName(String field) {
|
private String classFieldName(String field) {
|
||||||
return context.getNames().forMemberField(new FieldReference(RuntimeClass.class.getName(), field));
|
return context.getNames().forMemberField(new FieldReference(RuntimeClass.class.getName(), field));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.backend.lowlevel.generate;
|
||||||
|
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
|
||||||
|
public final class ClassGeneratorUtil {
|
||||||
|
private ClassGeneratorUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int applyPrimitiveFlags(int flags, ValueType type) {
|
||||||
|
if (type instanceof ValueType.Primitive) {
|
||||||
|
flags |= getPrimitiveFlag((ValueType.Primitive) type) << RuntimeClass.PRIMITIVE_SHIFT;
|
||||||
|
} else {
|
||||||
|
flags |= RuntimeClass.VOID_PRIMITIVE << RuntimeClass.PRIMITIVE_SHIFT;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPrimitiveFlag(ValueType.Primitive type) {
|
||||||
|
switch (type.getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return RuntimeClass.BOOLEAN_PRIMITIVE;
|
||||||
|
case BYTE:
|
||||||
|
return RuntimeClass.BYTE_PRIMITIVE;
|
||||||
|
case SHORT:
|
||||||
|
return RuntimeClass.SHORT_PRIMITIVE;
|
||||||
|
case CHARACTER:
|
||||||
|
return RuntimeClass.CHAR_PRIMITIVE;
|
||||||
|
case INTEGER:
|
||||||
|
return RuntimeClass.INT_PRIMITIVE;
|
||||||
|
case LONG:
|
||||||
|
return RuntimeClass.LONG_PRIMITIVE;
|
||||||
|
case FLOAT:
|
||||||
|
return RuntimeClass.FLOAT_PRIMITIVE;
|
||||||
|
case DOUBLE:
|
||||||
|
return RuntimeClass.DOUBLE_PRIMITIVE;
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -203,24 +203,21 @@ public final class WasmRuntime {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (alignedSourceEnd.toInt() > alignedSourceStart.toInt()) {
|
while (alignedSourceEnd.toInt() > alignedSourceStart.toInt()) {
|
||||||
alignedTargetEnd.putInt(alignedSourceEnd.getInt());
|
|
||||||
alignedSourceEnd = alignedSourceEnd.add(-4);
|
alignedSourceEnd = alignedSourceEnd.add(-4);
|
||||||
alignedTargetEnd = alignedTargetEnd.add(-4);
|
alignedTargetEnd = alignedTargetEnd.add(-4);
|
||||||
|
alignedTargetEnd.putInt(alignedSourceEnd.getInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (source.toInt() - alignedSourceStart.toInt()) {
|
switch (source.toInt() - alignedSourceStart.toInt()) {
|
||||||
case 0:
|
|
||||||
alignedTargetStart.putInt(alignedSourceStart.getInt());
|
|
||||||
break;
|
|
||||||
case 1:
|
case 1:
|
||||||
alignedTargetStart.add(2).putShort(alignedSourceStart.add(2).getShort());
|
alignedTargetStart.add(-2).putShort(alignedSourceStart.add(-2).getShort());
|
||||||
alignedTargetStart.add(1).putByte(alignedSourceStart.add(1).getByte());
|
alignedTargetStart.add(-3).putByte(alignedSourceStart.add(-3).getByte());
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
alignedTargetStart.add(2).putShort(alignedSourceStart.add(2).getShort());
|
alignedTargetStart.add(-2).putShort(alignedSourceStart.add(-2).getShort());
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
alignedTargetStart.add(3).putByte(alignedSourceStart.add(3).getByte());
|
alignedTargetStart.add(-1).putByte(alignedSourceStart.add(-1).getByte());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ import org.teavm.backend.wasm.generate.WasmDependencyListener;
|
||||||
import org.teavm.backend.wasm.generate.WasmGenerationContext;
|
import org.teavm.backend.wasm.generate.WasmGenerationContext;
|
||||||
import org.teavm.backend.wasm.generate.WasmGenerator;
|
import org.teavm.backend.wasm.generate.WasmGenerator;
|
||||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||||
|
import org.teavm.backend.wasm.generators.ArrayGenerator;
|
||||||
|
import org.teavm.backend.wasm.generators.WasmMethodGenerator;
|
||||||
|
import org.teavm.backend.wasm.generators.WasmMethodGeneratorContext;
|
||||||
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.ClassIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.ClassIntrinsic;
|
||||||
|
@ -83,6 +86,7 @@ import org.teavm.common.ServiceRepository;
|
||||||
import org.teavm.dependency.ClassDependency;
|
import org.teavm.dependency.ClassDependency;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.DelegateTo;
|
import org.teavm.interop.DelegateTo;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
|
@ -305,8 +309,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
TagRegistry tagRegistry = new TagRegistry(classes);
|
TagRegistry tagRegistry = new TagRegistry(classes);
|
||||||
BinaryWriter binaryWriter = new BinaryWriter(256);
|
BinaryWriter binaryWriter = new BinaryWriter(256);
|
||||||
NameProvider names = new NameProvider(controller.getUnprocessedClassSource());
|
NameProvider names = new NameProvider(controller.getUnprocessedClassSource());
|
||||||
WasmClassGenerator classGenerator = new WasmClassGenerator(
|
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),
|
||||||
controller.getUnprocessedClassSource(), vtableProvider, tagRegistry, binaryWriter, names);
|
vtableProvider, tagRegistry, binaryWriter, names);
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>(), false, true);
|
new HashSet<>(), false, true);
|
||||||
|
@ -325,6 +329,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator));
|
context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator));
|
||||||
context.addIntrinsic(new PlatformClassMetadataIntrinsic());
|
context.addIntrinsic(new PlatformClassMetadataIntrinsic());
|
||||||
context.addIntrinsic(new ClassIntrinsic());
|
context.addIntrinsic(new ClassIntrinsic());
|
||||||
|
context.addGenerator(new ArrayGenerator());
|
||||||
|
|
||||||
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
|
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
|
||||||
for (WasmIntrinsicFactory additionalIntrinsicFactory : additionalIntrinsics) {
|
for (WasmIntrinsicFactory additionalIntrinsicFactory : additionalIntrinsics) {
|
||||||
|
@ -345,7 +350,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
int pageSize = 1 << 16;
|
int pageSize = 1 << 16;
|
||||||
int pages = (minHeapSize + pageSize - 1) / pageSize;
|
int pages = (minHeapSize + pageSize - 1) / pageSize;
|
||||||
module.setMemorySize(pages);
|
module.setMemorySize(pages);
|
||||||
generateMethods(classes, context, generator, module);
|
generateMethods(classes, context, generator, classGenerator, binaryWriter, module);
|
||||||
exceptionHandlingIntrinsic.postProcess(shadowStackTransformer.getCallSites());
|
exceptionHandlingIntrinsic.postProcess(shadowStackTransformer.getCallSites());
|
||||||
generateIsSupertypeFunctions(tagRegistry, module, classGenerator);
|
generateIsSupertypeFunctions(tagRegistry, module, classGenerator);
|
||||||
classGenerator.postProcess();
|
classGenerator.postProcess();
|
||||||
|
@ -465,7 +470,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateMethods(ListableClassHolderSource classes, WasmGenerationContext context,
|
private void generateMethods(ListableClassHolderSource classes, WasmGenerationContext context,
|
||||||
WasmGenerator generator, WasmModule module) {
|
WasmGenerator generator, WasmClassGenerator classGenerator, BinaryWriter binaryWriter, WasmModule module) {
|
||||||
List<MethodHolder> methods = new ArrayList<>();
|
List<MethodHolder> methods = new ArrayList<>();
|
||||||
for (String className : classes.getClassNames()) {
|
for (String className : classes.getClassNames()) {
|
||||||
ClassHolder cls = classes.get(className);
|
ClassHolder cls = classes.get(className);
|
||||||
|
@ -478,6 +483,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MethodGeneratorContextImpl methodGeneratorContext = new MethodGeneratorContextImpl(binaryWriter,
|
||||||
|
context.getStringPool(), context.getDiagnostics(), context.names, classGenerator, classes);
|
||||||
|
|
||||||
for (MethodHolder method : methods) {
|
for (MethodHolder method : methods) {
|
||||||
ClassHolder cls = classes.get(method.getOwnerName());
|
ClassHolder cls = classes.get(method.getOwnerName());
|
||||||
|
|
||||||
|
@ -501,12 +509,18 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (implementor.hasModifier(ElementModifier.NATIVE)) {
|
if (implementor.hasModifier(ElementModifier.NATIVE)) {
|
||||||
if (context.getImportedMethod(method.getReference()) == null) {
|
WasmMethodGenerator methodGenerator = context.getGenerator(method.getReference());
|
||||||
CallLocation location = new CallLocation(method.getReference());
|
if (methodGenerator != null) {
|
||||||
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
|
WasmFunction function = context.getFunction(context.names.forMethod(method.getReference()));
|
||||||
+ "has no {{c1}} annotation on it", method.getReference(), Import.class.getName());
|
methodGenerator.apply(method.getReference(), function, methodGeneratorContext);
|
||||||
|
} else {
|
||||||
|
if (context.getImportedMethod(method.getReference()) == null) {
|
||||||
|
CallLocation location = new CallLocation(method.getReference());
|
||||||
|
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
|
||||||
|
+ "has no {{c1}} annotation on it", method.getReference(), Import.class.getName());
|
||||||
|
}
|
||||||
|
generator.generateNative(method.getReference());
|
||||||
}
|
}
|
||||||
generator.generateNative(method.getReference());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (implementor.getProgram() == null || implementor.getProgram().basicBlockCount() == 0) {
|
if (implementor.getProgram() == null || implementor.getProgram().basicBlockCount() == 0) {
|
||||||
|
@ -757,4 +771,54 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
public boolean isAsyncSupported() {
|
public boolean isAsyncSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class MethodGeneratorContextImpl implements WasmMethodGeneratorContext {
|
||||||
|
private BinaryWriter binaryWriter;
|
||||||
|
private WasmStringPool stringPool;
|
||||||
|
private Diagnostics diagnostics;
|
||||||
|
private NameProvider names;
|
||||||
|
private WasmClassGenerator classGenerator;
|
||||||
|
private ClassReaderSource classSource;
|
||||||
|
|
||||||
|
MethodGeneratorContextImpl(BinaryWriter binaryWriter, WasmStringPool stringPool,
|
||||||
|
Diagnostics diagnostics, NameProvider names, WasmClassGenerator classGenerator,
|
||||||
|
ClassReaderSource classSource) {
|
||||||
|
this.binaryWriter = binaryWriter;
|
||||||
|
this.stringPool = stringPool;
|
||||||
|
this.diagnostics = diagnostics;
|
||||||
|
this.names = names;
|
||||||
|
this.classGenerator = classGenerator;
|
||||||
|
this.classSource = classSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryWriter getBinaryWriter() {
|
||||||
|
return binaryWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmStringPool getStringPool() {
|
||||||
|
return stringPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Diagnostics getDiagnostics() {
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NameProvider getNames() {
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmClassGenerator getClassGenerator() {
|
||||||
|
return classGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassReaderSource getClassSource() {
|
||||||
|
return classSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -50,6 +50,7 @@ import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.RuntimeObject;
|
import org.teavm.runtime.RuntimeObject;
|
||||||
|
|
||||||
public class WasmClassGenerator {
|
public class WasmClassGenerator {
|
||||||
|
private ClassReaderSource processedClassSource;
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
public final NameProvider names;
|
public final NameProvider names;
|
||||||
private Map<ValueType, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
private Map<ValueType, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||||
|
@ -95,8 +96,10 @@ public class WasmClassGenerator {
|
||||||
private static final int CLASS_LAYOUT = 12;
|
private static final int CLASS_LAYOUT = 12;
|
||||||
private static final int CLASS_SIMPLE_NAME = 13;
|
private static final int CLASS_SIMPLE_NAME = 13;
|
||||||
|
|
||||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource,
|
||||||
TagRegistry tagRegistry, BinaryWriter binaryWriter, NameProvider names) {
|
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter,
|
||||||
|
NameProvider names) {
|
||||||
|
this.processedClassSource = processedClassSource;
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.vtableProvider = vtableProvider;
|
this.vtableProvider = vtableProvider;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
|
@ -175,7 +178,7 @@ public class WasmClassGenerator {
|
||||||
binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||||
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
||||||
functionTable.add(names.forSupertypeFunction(type));
|
functionTable.add(names.forSupertypeFunction(type));
|
||||||
binaryData.data.setAddress(CLASS_NAME, stringPool.getStringPointer(type.toString()));
|
binaryData.data.setAddress(CLASS_NAME, stringPool.getStringPointer(type.toString().replace('/', '.')));
|
||||||
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||||
binaryData.data.setInt(CLASS_INIT, -1);
|
binaryData.data.setInt(CLASS_INIT, -1);
|
||||||
binaryData.data.setAddress(CLASS_PARENT, getClassPointer(ValueType.object("java.lang.Object")));
|
binaryData.data.setAddress(CLASS_PARENT, getClassPointer(ValueType.object("java.lang.Object")));
|
||||||
|
@ -193,6 +196,43 @@ public class WasmClassGenerator {
|
||||||
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||||
value.setInt(CLASS_INIT, -1);
|
value.setInt(CLASS_INIT, -1);
|
||||||
functionTable.add(names.forSupertypeFunction(type));
|
functionTable.add(names.forSupertypeFunction(type));
|
||||||
|
|
||||||
|
String name;
|
||||||
|
if (type == ValueType.VOID) {
|
||||||
|
name = "void";
|
||||||
|
} else {
|
||||||
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
name = "boolean";
|
||||||
|
break;
|
||||||
|
case BYTE:
|
||||||
|
name = "byte";
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
name = "short";
|
||||||
|
break;
|
||||||
|
case CHARACTER:
|
||||||
|
name = "char";
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
name = "int";
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
name = "long";
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
name = "float";
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
name = "double";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
name = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +293,7 @@ public class WasmClassGenerator {
|
||||||
staticGcRoots.add(binaryData.fieldLayout.get(field.getFieldName()));
|
staticGcRoots.add(binaryData.fieldLayout.get(field.getFieldName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassReader cls = classSource.get(name);
|
ClassReader cls = processedClassSource.get(name);
|
||||||
if (cls != null && cls.hasModifier(ElementModifier.ENUM)) {
|
if (cls != null && cls.hasModifier(ElementModifier.ENUM)) {
|
||||||
header.setAddress(CLASS_ENUM_VALUES, generateEnumValues(cls, binaryData));
|
header.setAddress(CLASS_ENUM_VALUES, generateEnumValues(cls, binaryData));
|
||||||
flags |= RuntimeClass.ENUM;
|
flags |= RuntimeClass.ENUM;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.teavm.backend.wasm.generators.WasmMethodGenerator;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
@ -46,7 +47,9 @@ public class WasmGenerationContext {
|
||||||
public final NameProvider names;
|
public final NameProvider names;
|
||||||
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
||||||
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
||||||
private Map<MethodReference, WasmIntrinsicHolder> intrinsicCache = new HashMap<>();
|
private List<WasmMethodGenerator> generators = new ArrayList<>();
|
||||||
|
private Map<MethodReference, IntrinsicHolder> intrinsicCache = new HashMap<>();
|
||||||
|
private Map<MethodReference, GeneratorHolder> generatorCache = new HashMap<>();
|
||||||
|
|
||||||
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
||||||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool,
|
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool,
|
||||||
|
@ -64,17 +67,36 @@ public class WasmGenerationContext {
|
||||||
intrinsics.add(intrinsic);
|
intrinsics.add(intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addGenerator(WasmMethodGenerator generator) {
|
||||||
|
generators.add(generator);
|
||||||
|
}
|
||||||
|
|
||||||
public WasmIntrinsic getIntrinsic(MethodReference method) {
|
public WasmIntrinsic getIntrinsic(MethodReference method) {
|
||||||
return intrinsicCache.computeIfAbsent(method, key -> new WasmIntrinsicHolder(intrinsics.stream()
|
return intrinsicCache.computeIfAbsent(method, key -> new IntrinsicHolder(intrinsics.stream()
|
||||||
.filter(intrinsic -> intrinsic.isApplicable(key))
|
.filter(intrinsic -> intrinsic.isApplicable(key))
|
||||||
.findFirst().orElse(null)))
|
.findFirst().orElse(null)))
|
||||||
.value;
|
.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WasmIntrinsicHolder {
|
public WasmMethodGenerator getGenerator(MethodReference method) {
|
||||||
|
return generatorCache.computeIfAbsent(method, key -> new GeneratorHolder(generators.stream()
|
||||||
|
.filter(generator -> generator.isApplicable(key))
|
||||||
|
.findFirst().orElse(null)))
|
||||||
|
.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IntrinsicHolder {
|
||||||
WasmIntrinsic value;
|
WasmIntrinsic value;
|
||||||
|
|
||||||
public WasmIntrinsicHolder(WasmIntrinsic value) {
|
IntrinsicHolder(WasmIntrinsic value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GeneratorHolder {
|
||||||
|
WasmMethodGenerator value;
|
||||||
|
|
||||||
|
GeneratorHolder(WasmMethodGenerator value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@ import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.classes.TagRegistry;
|
|
||||||
import org.teavm.model.classes.VirtualTableEntry;
|
import org.teavm.model.classes.VirtualTableEntry;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
import org.teavm.runtime.RuntimeArray;
|
import org.teavm.runtime.RuntimeArray;
|
||||||
|
@ -690,7 +689,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int base = classGenerator.getClassSize(RuntimeArray.class.getName());
|
int base = BinaryWriter.align(classGenerator.getClassSize(RuntimeArray.class.getName()), 1 << size);
|
||||||
array = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, new WasmInt32Constant(base));
|
array = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, new WasmInt32Constant(base));
|
||||||
if (size != 0) {
|
if (size != 0) {
|
||||||
index = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, index,
|
index = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, index,
|
||||||
|
@ -1270,58 +1269,24 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
public void visit(InstanceOfExpr expr) {
|
public void visit(InstanceOfExpr expr) {
|
||||||
accept(expr.getExpr());
|
accept(expr.getExpr());
|
||||||
|
|
||||||
if (expr.getType() instanceof ValueType.Object) {
|
WasmBlock block = new WasmBlock(false);
|
||||||
ValueType.Object cls = (ValueType.Object) expr.getType();
|
block.setType(WasmType.INT32);
|
||||||
List<TagRegistry.Range> ranges = context.getTagRegistry().getRanges(cls.getClassName());
|
block.setLocation(expr.getLocation());
|
||||||
ranges.sort(Comparator.comparingInt(range -> range.lower));
|
|
||||||
|
|
||||||
WasmBlock block = new WasmBlock(false);
|
WasmLocal objectVar = getTemporary(WasmType.INT32);
|
||||||
block.setType(WasmType.INT32);
|
block.getBody().add(new WasmSetLocal(objectVar, result));
|
||||||
block.setLocation(expr.getLocation());
|
|
||||||
|
|
||||||
WasmLocal tagVar = getTemporary(WasmType.INT32);
|
WasmBranch ifNull = new WasmBranch(new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ,
|
||||||
int tagOffset = classGenerator.getFieldOffset(tagField);
|
new WasmGetLocal(objectVar), new WasmInt32Constant(0)), block);
|
||||||
WasmExpression tagPtr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
ifNull.setResult(new WasmInt32Constant(0));
|
||||||
getReferenceToClass(result), new WasmInt32Constant(tagOffset));
|
block.getBody().add(ifNull);
|
||||||
block.getBody().add(new WasmSetLocal(tagVar, new WasmLoadInt32(4, tagPtr, WasmInt32Subtype.INT32)));
|
|
||||||
|
|
||||||
WasmExpression lowerThanMinCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
WasmCall supertypeCall = new WasmCall(context.names.forSupertypeFunction(expr.getType()));
|
||||||
new WasmGetLocal(tagVar), new WasmInt32Constant(ranges.get(0).lower));
|
int tagOffset = classGenerator.getFieldOffset(tagField);
|
||||||
WasmBranch lowerThanMin = new WasmBranch(lowerThanMinCond, block);
|
WasmExpression classRef = new WasmLoadInt32(4, result, WasmInt32Subtype.INT32, tagOffset);
|
||||||
lowerThanMin.setResult(new WasmInt32Constant(0));
|
classRef = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classRef, new WasmInt32Constant(3));
|
||||||
block.getBody().add(new WasmDrop(lowerThanMin));
|
supertypeCall.getArguments().add(classRef);
|
||||||
|
block.getBody().add(supertypeCall);
|
||||||
WasmExpression upperThanMaxCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GT_SIGNED,
|
|
||||||
new WasmGetLocal(tagVar), new WasmInt32Constant(ranges.get(ranges.size() - 1).upper));
|
|
||||||
WasmBranch upperThanMax = new WasmBranch(upperThanMaxCond, block);
|
|
||||||
upperThanMax.setResult(new WasmInt32Constant(0));
|
|
||||||
block.getBody().add(new WasmDrop(upperThanMax));
|
|
||||||
|
|
||||||
for (int i = 1; i < ranges.size(); ++i) {
|
|
||||||
WasmExpression upperThanExcluded = new WasmIntBinary(WasmIntType.INT32,
|
|
||||||
WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(tagVar),
|
|
||||||
new WasmInt32Constant(ranges.get(i - 1).upper));
|
|
||||||
WasmConditional conditional = new WasmConditional(upperThanExcluded);
|
|
||||||
WasmExpression lowerThanExcluded = new WasmIntBinary(WasmIntType.INT32,
|
|
||||||
WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(tagVar),
|
|
||||||
new WasmInt32Constant(ranges.get(i).lower));
|
|
||||||
|
|
||||||
WasmBranch branch = new WasmBranch(lowerThanExcluded, block);
|
|
||||||
branch.setResult(new WasmInt32Constant(0));
|
|
||||||
conditional.getThenBlock().getBody().add(new WasmDrop(branch));
|
|
||||||
|
|
||||||
block.getBody().add(conditional);
|
|
||||||
}
|
|
||||||
|
|
||||||
block.getBody().add(new WasmInt32Constant(1));
|
|
||||||
releaseTemporary(tagVar);
|
|
||||||
|
|
||||||
result = block;
|
|
||||||
} else if (expr.getType() instanceof ValueType.Array) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
} else {
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.backend.wasm.generators;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadFloat32;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.runtime.RuntimeArray;
|
||||||
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
|
||||||
|
public class ArrayGenerator implements WasmMethodGenerator {
|
||||||
|
private static FieldReference tagField = new FieldReference(RuntimeClass.class.getName(), "tag");
|
||||||
|
private static FieldReference componentField = new FieldReference(RuntimeClass.class.getName(), "itemType");
|
||||||
|
private static FieldReference flagsField = new FieldReference(RuntimeClass.class.getName(), "flags");
|
||||||
|
private static final int[] primitives = {
|
||||||
|
RuntimeClass.BYTE_PRIMITIVE,
|
||||||
|
RuntimeClass.SHORT_PRIMITIVE,
|
||||||
|
RuntimeClass.CHAR_PRIMITIVE,
|
||||||
|
RuntimeClass.INT_PRIMITIVE,
|
||||||
|
RuntimeClass.LONG_PRIMITIVE,
|
||||||
|
RuntimeClass.FLOAT_PRIMITIVE,
|
||||||
|
RuntimeClass.DOUBLE_PRIMITIVE,
|
||||||
|
RuntimeClass.BOOLEAN_PRIMITIVE
|
||||||
|
};
|
||||||
|
private static final String[] primitiveWrappers = { "Byte", "Short", "Character", "Integer", "Long",
|
||||||
|
"Float", "Double", "Boolean" };
|
||||||
|
private static final ValueType.Primitive[] primitiveTypes = { ValueType.BYTE, ValueType.SHORT, ValueType.CHARACTER,
|
||||||
|
ValueType.INTEGER, ValueType.LONG, ValueType.FLOAT, ValueType.DOUBLE, ValueType.BOOLEAN };
|
||||||
|
private static final int[] shift = new int[] { 0, 1, 1, 2, 3, 2, 3, 0 };
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
if (!methodReference.getClassName().equals(Array.class.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (methodReference.getName()) {
|
||||||
|
case "getImpl":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(MethodReference method, WasmFunction function, WasmMethodGeneratorContext context) {
|
||||||
|
WasmLocal arrayVar = new WasmLocal(WasmType.INT32, "_array");
|
||||||
|
WasmLocal indexVar = new WasmLocal(WasmType.INT32, "_index");
|
||||||
|
WasmLocal flagsVar = new WasmLocal(WasmType.INT32, "_flags");
|
||||||
|
function.add(arrayVar);
|
||||||
|
function.add(indexVar);
|
||||||
|
function.add(flagsVar);
|
||||||
|
|
||||||
|
int tagOffset = context.getClassGenerator().getFieldOffset(tagField);
|
||||||
|
WasmExpression arrayClass = new WasmLoadInt32(4, new WasmGetLocal(arrayVar),
|
||||||
|
WasmInt32Subtype.INT32, tagOffset);
|
||||||
|
arrayClass = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, arrayClass,
|
||||||
|
new WasmInt32Constant(3));
|
||||||
|
|
||||||
|
int componentOffset = context.getClassGenerator().getFieldOffset(componentField);
|
||||||
|
WasmExpression componentClass = new WasmLoadInt32(4, arrayClass, WasmInt32Subtype.INT32, componentOffset);
|
||||||
|
|
||||||
|
int flagsOffset = context.getClassGenerator().getFieldOffset(flagsField);
|
||||||
|
WasmExpression flags = new WasmLoadInt32(4, componentClass, WasmInt32Subtype.INT32, flagsOffset);
|
||||||
|
function.getBody().add(new WasmSetLocal(flagsVar, flags));
|
||||||
|
|
||||||
|
WasmExpression isPrimitive = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
|
||||||
|
new WasmGetLocal(flagsVar), new WasmInt32Constant(RuntimeClass.PRIMITIVE));
|
||||||
|
WasmBlock objectBlock = new WasmBlock(false);
|
||||||
|
objectBlock.getBody().add(new WasmBranch(isPrimitive, objectBlock));
|
||||||
|
function.getBody().add(objectBlock);
|
||||||
|
int base = context.getClassGenerator().getClassSize(RuntimeArray.class.getName());
|
||||||
|
|
||||||
|
WasmBlock currentBlock = new WasmBlock(false);
|
||||||
|
function.getBody().add(currentBlock);
|
||||||
|
function.getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
|
|
||||||
|
WasmSwitch primitiveSwitch = new WasmSwitch(new WasmGetLocal(flagsVar), currentBlock);
|
||||||
|
for (int i = 0; i <= 8; ++i) {
|
||||||
|
primitiveSwitch.getTargets().add(currentBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < primitiveWrappers.length; ++i) {
|
||||||
|
String wrapper = "java.lang." + primitiveWrappers[i];
|
||||||
|
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
|
||||||
|
primitiveTypes[i], ValueType.object(wrapper));
|
||||||
|
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
||||||
|
if (cls == null || cls.getMethod(methodRef.getDescriptor()) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WasmBlock nextBlock = new WasmBlock(false);
|
||||||
|
primitiveSwitch.getTargets().set(i, nextBlock);
|
||||||
|
|
||||||
|
WasmExpression offset = new WasmGetLocal(indexVar);
|
||||||
|
if (shift[i] != 0) {
|
||||||
|
offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||||
|
new WasmGetLocal(indexVar), new WasmInt32Constant(shift[i]));
|
||||||
|
}
|
||||||
|
offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, offset,
|
||||||
|
new WasmGetLocal(arrayVar));
|
||||||
|
int baseAddr = BinaryWriter.align(base, 1 << shift[i]);
|
||||||
|
|
||||||
|
WasmCall call = new WasmCall(context.getNames().forMethod(methodRef));
|
||||||
|
|
||||||
|
switch (primitiveTypes[i].getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BYTE:
|
||||||
|
call.getArguments().add(new WasmLoadInt32(0, offset, WasmInt32Subtype.INT8, baseAddr));
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
call.getArguments().add(new WasmLoadInt32(1, offset, WasmInt32Subtype.INT16, baseAddr));
|
||||||
|
break;
|
||||||
|
case CHARACTER:
|
||||||
|
call.getArguments().add(new WasmLoadInt32(1, offset, WasmInt32Subtype.UINT16, baseAddr));
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
call.getArguments().add(new WasmLoadInt32(2, offset, WasmInt32Subtype.INT16, baseAddr));
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
call.getArguments().add(new WasmLoadInt64(3, offset, WasmInt64Subtype.INT64, baseAddr));
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
call.getArguments().add(new WasmLoadFloat32(2, offset, baseAddr));
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
call.getArguments().add(new WasmLoadFloat32(3, offset, baseAddr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBlock.getBody().add(nextBlock);
|
||||||
|
currentBlock.getBody().add(new WasmReturn(call));
|
||||||
|
currentBlock = nextBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBlock.getBody().add(primitiveSwitch);
|
||||||
|
|
||||||
|
WasmExpression objectOffset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||||
|
new WasmGetLocal(indexVar), new WasmInt32Constant(2));
|
||||||
|
objectOffset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, objectOffset,
|
||||||
|
new WasmGetLocal(arrayVar));
|
||||||
|
objectBlock.getBody().add(new WasmReturn(
|
||||||
|
new WasmLoadInt32(4, objectOffset, WasmInt32Subtype.INT32, BinaryWriter.align(base, 4))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.backend.wasm.generators;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
public interface WasmMethodGenerator {
|
||||||
|
boolean isApplicable(MethodReference methodReference);
|
||||||
|
|
||||||
|
void apply(MethodReference method, WasmFunction function, WasmMethodGeneratorContext context);
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.backend.wasm.generators;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
|
import org.teavm.backend.wasm.generate.NameProvider;
|
||||||
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
|
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
|
||||||
|
public interface WasmMethodGeneratorContext {
|
||||||
|
BinaryWriter getBinaryWriter();
|
||||||
|
|
||||||
|
WasmStringPool getStringPool();
|
||||||
|
|
||||||
|
Diagnostics getDiagnostics();
|
||||||
|
|
||||||
|
NameProvider getNames();
|
||||||
|
|
||||||
|
ClassReaderSource getClassSource();
|
||||||
|
|
||||||
|
WasmClassGenerator getClassGenerator();
|
||||||
|
}
|
|
@ -214,10 +214,9 @@ public class BigIntegerOperateBitsTest {
|
||||||
byte[] rBytes = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, 92, -26};
|
byte[] rBytes = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, 92, -26};
|
||||||
BigInteger aNumber = new BigInteger(aSign, aBytes);
|
BigInteger aNumber = new BigInteger(aSign, aBytes);
|
||||||
BigInteger result = aNumber.clearBit(number);
|
BigInteger result = aNumber.clearBit(number);
|
||||||
byte[] resBytes = new byte[rBytes.length];
|
byte[] resBytes = result.toByteArray();
|
||||||
resBytes = result.toByteArray();
|
|
||||||
for (int i = 0; i < resBytes.length; i++) {
|
for (int i = 0; i < resBytes.length; i++) {
|
||||||
assertTrue(resBytes[i] == rBytes[i]);
|
assertEquals("Byte " + i, rBytes[i], resBytes[i]);
|
||||||
}
|
}
|
||||||
assertEquals("incorrect sign", -1, result.signum());
|
assertEquals("incorrect sign", -1, result.signum());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user