C backend: make more tests pass

This commit is contained in:
Alexey Andreev 2018-04-28 18:49:26 +03:00
parent 18eb3ee058
commit ee2f389027
11 changed files with 211 additions and 90 deletions

View File

@ -29,6 +29,9 @@ public class ClassDependencyListener implements DependencyPlugin {
.linkClass(type.getName(), location) .linkClass(type.getName(), location)
.initClass(location)); .initClass(location));
break; break;
case "getSimpleNameCacheLowLevel":
method.getResult().propagate(agent.getType("java.lang.String"));
break;
} }
} }
} }

View File

@ -0,0 +1,32 @@
/*
* 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.classlib.java.lang;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.CallLocation;
public class ObjectDependencyPlugin implements DependencyPlugin {
@Override
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getMethod().getName()) {
case "clone":
method.getVariable(0).connect(method.getResult());
break;
}
}
}

View File

@ -27,6 +27,7 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.classlib.PlatformDetector;
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator; import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
import org.teavm.classlib.impl.reflection.Flags; import org.teavm.classlib.impl.reflection.Flags;
import org.teavm.classlib.impl.reflection.JSClass; import org.teavm.classlib.impl.reflection.JSClass;
@ -103,24 +104,24 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
return Address.ofObject(this).<RuntimeClass>toStructure().isSupertypeOf.apply(other); return Address.ofObject(this).<RuntimeClass>toStructure().isSupertypeOf.apply(other);
} }
@DelegateTo("getNameLowLevel") @Unmanaged
public TString getName() { public TString getName() {
if (PlatformDetector.isLowLevel()) {
return TString.wrap(Platform.getName(platformClass));
} else {
if (name == null) { if (name == null) {
name = TString.wrap(Platform.getName(platformClass)); name = TString.wrap(Platform.getName(platformClass));
} }
return name; return name;
} }
@Unmanaged
private RuntimeObject getNameLowLevel() {
RuntimeClass runtimeClass = Address.ofObject(this).toStructure();
return runtimeClass.name;
} }
public TString getSimpleName() { public TString getSimpleName() {
TString simpleName = getSimpleNameCache();
if (simpleName == null) { if (simpleName == null) {
if (isArray()) { if (isArray()) {
simpleName = getComponentType().getSimpleName().concat(TString.wrap("[]")); simpleName = getComponentType().getSimpleName().concat(TString.wrap("[]"));
setSimpleNameCache(simpleName);
return simpleName; return simpleName;
} }
String name = Platform.getName(platformClass); String name = Platform.getName(platformClass);
@ -137,10 +138,31 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
} }
} }
simpleName = TString.wrap(name); simpleName = TString.wrap(name);
setSimpleNameCache(simpleName);
} }
return simpleName; return simpleName;
} }
@DelegateTo("getSimpleNameCacheLowLevel")
private TString getSimpleNameCache() {
return simpleName;
}
@Unmanaged
@PluggableDependency(ClassDependencyListener.class)
private RuntimeObject getSimpleNameCacheLowLevel() {
return Address.ofObject(this).<RuntimeClass>toStructure().simpleName;
}
private void setSimpleNameCache(TString value) {
simpleName = value;
}
@Unmanaged
private void setSimpleNameCacheLowLevel(RuntimeObject object) {
Address.ofObject(this).<RuntimeClass>toStructure().simpleName = object;
}
public boolean isPrimitive() { public boolean isPrimitive() {
return Platform.isPrimitive(platformClass); return Platform.isPrimitive(platformClass);
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.classlib.java.lang; package org.teavm.classlib.java.lang;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.interop.Async; import org.teavm.interop.Async;
import org.teavm.interop.DelegateTo; import org.teavm.interop.DelegateTo;
@ -223,6 +224,7 @@ public class TObject {
@Override @Override
@DelegateTo("cloneLowLevel") @DelegateTo("cloneLowLevel")
@PluggableDependency(ObjectDependencyPlugin.class)
protected Object clone() throws TCloneNotSupportedException { protected Object clone() throws TCloneNotSupportedException {
if (!(this instanceof TCloneable) && Platform.getPlatformObject(this) if (!(this instanceof TCloneable) && Platform.getPlatformObject(this)
.getPlatformClass().getMetadata().getArrayItem() == null) { .getPlatformClass().getMetadata().getArrayItem() == null) {

View File

@ -29,6 +29,7 @@ import org.teavm.classlib.java.util.THashMap;
import org.teavm.classlib.java.util.TLocale; import org.teavm.classlib.java.util.TLocale;
import org.teavm.classlib.java.util.TMap; import org.teavm.classlib.java.util.TMap;
import org.teavm.classlib.java.util.regex.TPattern; import org.teavm.classlib.java.util.regex.TPattern;
import org.teavm.interop.Unmanaged;
public class TString extends TObject implements TSerializable, TComparable<TString>, TCharSequence { public class TString extends TObject implements TSerializable, TComparable<TString>, TCharSequence {
public static final TComparator<TString> CASE_INSENSITIVE_ORDER = (o1, o2) -> o1.compareToIgnoreCase(o2); public static final TComparator<TString> CASE_INSENSITIVE_ORDER = (o1, o2) -> o1.compareToIgnoreCase(o2);
@ -578,6 +579,7 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
return hashCode; return hashCode;
} }
@Unmanaged
public static TString wrap(String str) { public static TString wrap(String str) {
return (TString) (Object) str; return (TString) (Object) str;
} }

View File

@ -358,7 +358,9 @@ public class CTarget implements TeaVMTarget {
writer.println("initHeap(" + minHeapSize + ");"); writer.println("initHeap(" + minHeapSize + ");");
generateVirtualTableHeaders(context, writer, types); generateVirtualTableHeaders(context, writer, types);
generateStringPoolHeaders(context, writer); generateStringPoolHeaders(context, writer);
writer.println("initStaticFields();");
generateStaticInitializerCalls(context, writer, classes); generateStaticInitializerCalls(context, writer, classes);
writer.println(context.getNames().forClassInitializer("java.lang.String") + "();");
generateCallToMainMethod(context, writer); generateCallToMainMethod(context, writer);
writer.outdent().println("}"); writer.outdent().println("}");

View File

@ -75,6 +75,7 @@ public class ClassGenerator {
private CodeWriter staticGcRootsWriter; private CodeWriter staticGcRootsWriter;
private CodeWriter callSiteWriter; private CodeWriter callSiteWriter;
private CodeWriter codeWriter; private CodeWriter codeWriter;
private CodeWriter staticFieldInitWriter;
public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource, public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource,
TagRegistry tagRegistry, Decompiler decompiler, CodeWriter writer) { TagRegistry tagRegistry, Decompiler decompiler, CodeWriter writer) {
@ -96,6 +97,10 @@ public class ClassGenerator {
callSiteWriter = writer.fragment(); callSiteWriter = writer.fragment();
codeWriter = writer.fragment(); codeWriter = writer.fragment();
writer.println("static void initStaticFields() {").indent();
staticFieldInitWriter = writer.fragment();
writer.outdent().println("}");
codeGenerator = new CodeGenerator(context, codeWriter, includes); codeGenerator = new CodeGenerator(context, codeWriter, includes);
} }
@ -236,6 +241,14 @@ public class ClassGenerator {
if (isReferenceType(field.getType())) { if (isReferenceType(field.getType())) {
staticFields[staticIndex++] = field.getReference(); staticFields[staticIndex++] = field.getReference();
} }
Object initialValue = field.getInitialValue();
if (initialValue == null) {
initialValue = getDefaultValue(field.getType());
}
staticFieldInitWriter.print(fieldName + " = ");
CodeGeneratorUtil.writeValue(staticFieldInitWriter, context, initialValue);
staticFieldInitWriter.println(";");
} else { } else {
String fieldName = context.getNames().forMemberField(field.getReference()); String fieldName = context.getNames().forMemberField(field.getReference());
structWriter.printStrictType(field.getType()).print(" ").print(fieldName).println(";"); structWriter.printStrictType(field.getType()).print(" ").print(fieldName).println(";");
@ -257,6 +270,31 @@ public class ClassGenerator {
structWriter.outdent().print("} ").print(name).println(";"); structWriter.outdent().print("} ").print(name).println(";");
} }
private static Object getDefaultValue(ValueType type) {
if (type instanceof ValueType.Primitive) {
ValueType.Primitive primitive = (ValueType.Primitive) type;
switch (primitive.getKind()) {
case BOOLEAN:
return false;
case BYTE:
return (byte) 0;
case SHORT:
return (short) 0;
case INTEGER:
return 0;
case CHARACTER:
return '\0';
case LONG:
return 0L;
case FLOAT:
return 0F;
case DOUBLE:
return 0.0;
}
}
return null;
}
private void generateForwardClassStructure(ClassHolder cls) { private void generateForwardClassStructure(ClassHolder cls) {
if (isSystemClass(cls)) { if (isSystemClass(cls)) {
return; return;
@ -418,6 +456,7 @@ public class ClassGenerator {
vtableWriter.print(".").print(classFieldName("tag")).print(" = ").print(String.valueOf(tag)).println(","); vtableWriter.print(".").print(classFieldName("tag")).print(" = ").print(String.valueOf(tag)).println(",");
vtableWriter.print(".").print(classFieldName("canary")).println(" = 0,"); vtableWriter.print(".").print(classFieldName("canary")).println(" = 0,");
vtableWriter.print(".").print(classFieldName("name")).println(" = stringPool + " + nameRef + ","); vtableWriter.print(".").print(classFieldName("name")).println(" = stringPool + " + nameRef + ",");
vtableWriter.print(".").print(classFieldName("simpleName")).println(" = NULL,");
vtableWriter.print(".").print(classFieldName("arrayType")).println(" = " + arrayTypeExpr + ","); vtableWriter.print(".").print(classFieldName("arrayType")).println(" = " + arrayTypeExpr + ",");
vtableWriter.print(".").print(classFieldName("itemType")).println(" = " + itemTypeExpr + ","); vtableWriter.print(".").print(classFieldName("itemType")).println(" = " + itemTypeExpr + ",");
vtableWriter.print(".").print(classFieldName("isSupertypeOf")).println(" = &" + superTypeFunction + ","); vtableWriter.print(".").print(classFieldName("isSupertypeOf")).println(" = &" + superTypeFunction + ",");

View File

@ -266,69 +266,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
@Override @Override
public void visit(ConstantExpr expr) { public void visit(ConstantExpr expr) {
Object value = expr.getValue(); CodeGeneratorUtil.writeValue(writer, context, expr.getValue());
if (value == null) {
writer.print("NULL");
} else if (value instanceof String) {
int index = context.getStringPool().getStringIndex((String) value);
writer.print("(stringPool + " + index + ")");
} else if (value instanceof Integer) {
int i = (Integer) value;
long v = i;
if (i < 0) {
writer.print("-");
v = -i;
}
writer.print("INT32_C(");
writeLongConstant(v);
writer.print(")");
} else if (value instanceof Long) {
long v = (Long) value;
if (v < 0) {
writer.print("-");
v = -v;
}
writer.print("INT64_C(");
writeLongConstant(v);
writer.print(")");
} else if (value instanceof Float) {
float f = (Float) value;
if (Float.isInfinite(f)) {
if (f < 0) {
writer.print("-");
}
writer.print("INFINITY");
} else if (Float.isNaN(f)) {
writer.print("NAN");
} else {
writer.print(f + "f");
}
} else if (value instanceof Double) {
double d = (Double) value;
if (Double.isInfinite(d)) {
if (d < 0) {
writer.print("-");
}
writer.print("INFINITY");
} else if (Double.isNaN(d)) {
writer.print("NAN");
} else {
writer.print(value.toString());
}
} else if (value instanceof Boolean) {
writer.print((Boolean) value ? "1" : "0");
} else if (value instanceof ValueType) {
writer.print("&").print(names.forClassInstance((ValueType) value));
}
}
private void writeLongConstant(long v) {
if (v == Long.MIN_VALUE) {
writer.print("0x8000000000000000");
return;
}
writer.print(String.valueOf(v));
} }
@Override @Override

View File

@ -0,0 +1,88 @@
/*
* 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.c.generate;
import org.teavm.model.ValueType;
public final class CodeGeneratorUtil {
private CodeGeneratorUtil() {
}
public static void writeValue(CodeWriter writer, GenerationContext context, Object value) {
if (value == null) {
writer.print("NULL");
} else if (value instanceof String) {
int index = context.getStringPool().getStringIndex((String) value);
writer.print("(stringPool + " + index + ")");
} else if (value instanceof Integer) {
int i = (Integer) value;
long v = i;
if (i < 0) {
writer.print("-");
v = -i;
}
writer.print("INT32_C(");
writeLongConstant(writer, v);
writer.print(")");
} else if (value instanceof Long) {
long v = (Long) value;
if (v < 0) {
writer.print("-");
v = -v;
}
writer.print("INT64_C(");
writeLongConstant(writer, v);
writer.print(")");
} else if (value instanceof Float) {
float f = (Float) value;
if (Float.isInfinite(f)) {
if (f < 0) {
writer.print("-");
}
writer.print("INFINITY");
} else if (Float.isNaN(f)) {
writer.print("NAN");
} else {
writer.print(f + "f");
}
} else if (value instanceof Double) {
double d = (Double) value;
if (Double.isInfinite(d)) {
if (d < 0) {
writer.print("-");
}
writer.print("INFINITY");
} else if (Double.isNaN(d)) {
writer.print("NAN");
} else {
writer.print(value.toString());
}
} else if (value instanceof Boolean) {
writer.print((Boolean) value ? "1" : "0");
} else if (value instanceof ValueType) {
writer.print("&").print(context.getNames().forClassInstance((ValueType) value));
}
}
private static void writeLongConstant(CodeWriter writer, long v) {
if (v == Long.MIN_VALUE) {
writer.print("0x8000000000000000");
return;
}
writer.print(String.valueOf(v));
}
}

View File

@ -22,10 +22,12 @@ import org.teavm.runtime.RuntimeClass;
public class PlatformClassMetadataIntrinsic implements Intrinsic { public class PlatformClassMetadataIntrinsic implements Intrinsic {
private static final String PLATFORM_CLASS_METADATA = "org.teavm.platform.PlatformClassMetadata"; private static final String PLATFORM_CLASS_METADATA = "org.teavm.platform.PlatformClassMetadata";
private static final FieldReference ARRAY_TYPE_FIELD = new FieldReference( private static final FieldReference ITEM_TYPE_FIELD = new FieldReference(
RuntimeClass.class.getName(), "arrayType"); RuntimeClass.class.getName(), "itemType");
private static final FieldReference SUPERCLASS_FIELD = new FieldReference( private static final FieldReference SUPERCLASS_FIELD = new FieldReference(
RuntimeClass.class.getName(), "parent"); RuntimeClass.class.getName(), "parent");
private static final FieldReference NAME_FIELD = new FieldReference(
RuntimeClass.class.getName(), "name");
@Override @Override
public boolean canHandle(MethodReference method) { public boolean canHandle(MethodReference method) {
@ -35,6 +37,7 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
switch (method.getName()) { switch (method.getName()) {
case "getArrayItem": case "getArrayItem":
case "getSuperclass": case "getSuperclass":
case "getName":
return true; return true;
} }
return false; return false;
@ -44,11 +47,14 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
public void apply(IntrinsicContext context, InvocationExpr invocation) { public void apply(IntrinsicContext context, InvocationExpr invocation) {
switch (invocation.getMethod().getName()) { switch (invocation.getMethod().getName()) {
case "getArrayItem": case "getArrayItem":
printFieldAccess(context, invocation, ARRAY_TYPE_FIELD); printFieldAccess(context, invocation, ITEM_TYPE_FIELD);
break; break;
case "getSuperclass": case "getSuperclass":
printFieldAccess(context, invocation, SUPERCLASS_FIELD); printFieldAccess(context, invocation, SUPERCLASS_FIELD);
break; break;
case "getName":
printFieldAccess(context, invocation, NAME_FIELD);
break;
} }
} }

View File

@ -222,28 +222,15 @@ public final class Platform {
return (cls.flags & RuntimeClass.ENUM) != 0; return (cls.flags & RuntimeClass.ENUM) != 0;
} }
@DelegateTo("getArrayItemLowLevel")
@Unmanaged @Unmanaged
public static PlatformClass getArrayItem(PlatformClass cls) { public static PlatformClass getArrayItem(PlatformClass cls) {
return cls.getMetadata().getArrayItem(); return cls.getMetadata().getArrayItem();
} }
@SuppressWarnings("unused")
@Unmanaged
private static RuntimeClass getArrayItemLowLevel(RuntimeClass cls) {
return cls.itemType;
}
@DelegateTo("getNameLowLevel")
public static String getName(PlatformClass cls) { public static String getName(PlatformClass cls) {
return cls.getMetadata().getName(); return cls.getMetadata().getName();
} }
@Unmanaged
private static RuntimeObject getNameLowLevel(RuntimeClass cls) {
return cls.name;
}
@JSBody(script = "return $rt_global;") @JSBody(script = "return $rt_global;")
private static native JSObject getGlobal(); private static native JSObject getGlobal();
} }