Adds some JVM class library implementation

This commit is contained in:
Alexey Andreev 2013-11-29 19:07:39 +04:00
parent f6927a72af
commit ce56214ed5
10 changed files with 153 additions and 2 deletions

View File

@ -33,6 +33,9 @@ public class ObjectNativeGenerator implements Generator, DependencyPlugin {
case "clone":
generateClone(context, writer);
break;
case "wrap":
generateWrap(context, writer);
break;
}
}
@ -45,6 +48,9 @@ public class ObjectNativeGenerator implements Generator, DependencyPlugin {
case "getClass":
achieveGetClass(checker);
break;
case "wrap":
achieveWrap(checker, method);
break;
}
}
@ -96,4 +102,13 @@ public class ObjectNativeGenerator implements Generator, DependencyPlugin {
MethodGraph graph = checker.attachMethodGraph(method);
graph.getVariableNode(0).connect(graph.getResultNode());
}
private void generateWrap(GeneratorContext context, SourceWriter writer) {
writer.append("return ").append(context.getParameterName(1));
}
private void achieveWrap(DependencyChecker checker, MethodReference method) {
MethodGraph graph = checker.attachMethodGraph(method);
graph.getVariableNode(1).connect(graph.getResultNode());
}
}

View File

@ -0,0 +1,17 @@
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev
*/
public class TNullPointerException extends TRuntimeException {
private static final long serialVersionUID = 2639861320773057190L;
public TNullPointerException(TString message) {
super(message);
}
public TNullPointerException() {
super();
}
}

View File

@ -65,4 +65,8 @@ public class TObject {
@Override
protected void finalize() throws TThrowable {
}
@GeneratedBy(ObjectNativeGenerator.class)
@PluggableDependency(ObjectNativeGenerator.class)
public static native TObject wrap(Object obj);
}

View File

@ -1,5 +1,6 @@
package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.lang.reflect.TArray;
import org.teavm.javascript.ni.GeneratedBy;
/**
@ -10,7 +11,17 @@ public final class TSystem extends TObject {
private TSystem() {
}
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
public static void arraycopy(TObject src, int srcPos, TObject dest, int destPos, int length) {
if (src == null || dest == null) {
throw new TNullPointerException(TString.wrap("Either src or dest is null"));
}
if (src.getClass0() != dest.getClass0()) {
throw new ArrayStoreException();
}
if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > TArray.getLength(src) ||
destPos + length > TArray.getLength(dest)) {
throw new IndexOutOfBoundsException();
}
doArrayCopy(src, srcPos, dest, destPos, length);
}

View File

@ -14,9 +14,19 @@ class TSystemTests {
TObject b = new TObject();
TObject[] src = { a, b, a };
TObject[] dest = new TObject[3];
TSystem.arraycopy(src, 0, dest, 0, 3);
TSystem.arraycopy(TObject.wrap(src), 0, TObject.wrap(dest), 0, 3);
assertSame(a, dest[0]);
assertSame(b, dest[1]);
assertSame(a, dest[2]);
}
@Test
public void failsToCopyArraysWithInvalidIndexes() {
TSystem.arraycopy(TObject.wrap(new TObject[0]), 0, TObject.wrap(new TObject[0]), 0, 1);
}
@Test
public void failsToCopyArraysWithIncompatibleElements() {
TSystem.arraycopy(TObject.wrap(new TObject[1]), 0, TObject.wrap(new int[1]), 0, 1);
}
}

View File

@ -0,0 +1,16 @@
package org.teavm.classlib.java.lang.reflect;
import org.teavm.classlib.java.lang.TIllegalArgumentException;
import org.teavm.classlib.java.lang.TObject;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
/**
*
* @author Alexey Andreev
*/
public final class TArray extends TObject {
@GeneratedBy(TArrayNativeGenerator.class)
@PluggableDependency(TArrayNativeGenerator.class)
public static native int getLength(TObject array) throws TIllegalArgumentException;
}

View File

@ -0,0 +1,58 @@
package org.teavm.classlib.java.lang.reflect;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyConsumer;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodGraph;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
/**
*
* @author Alexey Andreev
*/
public class TArrayNativeGenerator implements Generator, DependencyPlugin {
@Override
public void methodAchieved(DependencyChecker checker, MethodReference method) {
if (method.getName().equals("getLength")) {
achieveGetLength(checker, method);
}
}
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getName()) {
case "getLength":
generateGetLength(context, writer);
break;
}
}
private void generateGetLength(GeneratorContext context, SourceWriter writer) {
String array = context.getParameterName(1);
writer.append("if (" + array + " === null || " + array + " .$cls.$meta.item === undefined) {")
.newLine().indent();
String clsName = "java.lang.IllegalArgumentException";
MethodReference cons = new MethodReference(clsName, new MethodDescriptor("<init>", ValueType.VOID));
writer.append("$rt_throw(").appendClass(clsName).append(".").appendMethod(cons).append("());").newLine();
writer.outdent().append("}").newLine();
writer.append("return array.length");
}
private void achieveGetLength(final DependencyChecker checker, MethodReference methodRef) {
final MethodGraph graph = checker.attachMethodGraph(methodRef);
graph.getVariableNode(1).addConsumer(new DependencyConsumer() {
@Override public void consume(String type) {
if (!type.startsWith("[")) {
MethodReference cons = new MethodReference("java.lang.IllegalArgumentException",
new MethodDescriptor("<init>", ValueType.VOID));
checker.addEntryPoint(cons);
}
}
});
}
}

View File

@ -66,9 +66,12 @@ public class ClasslibTestGenerator {
out.println(IOUtils.toString(input));
}
renderer.renderRuntime();
writer.append("runTests = function() {").newLine().indent();
writer.append("document.getElementById(\"start-button\").style.display = 'none';").newLine();
for (String testClass : testClasses) {
renderClassTest(classSource.getClassHolder(testClass));
}
writer.outdent().append("}").newLine();
out.println(writer);
renderFoot();
}
@ -87,6 +90,16 @@ public class ClasslibTestGenerator {
out.println(" <title>TeaVM JUnit tests</title>");
out.println(" <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/>");
out.println(" <title>TeaVM JUnit tests</title>");
out.println(" <style type=\"text/css\">");
out.println(" table {");
out.println(" border-collapse: collapse;");
out.println(" border: 2px solid black;");
out.println(" margin: 2em 1em 2em 1em;");
out.println(" }");
out.println(" table td {");
out.println(" border: 1px solid gray;");
out.println(" }");
out.println(" </style>");
out.println(" </head>");
out.println(" <body>");
out.println(" <script type=\"text/javascript\">");
@ -94,6 +107,7 @@ public class ClasslibTestGenerator {
private static void renderFoot() {
out.println(" </script>");
out.println(" <button id=\"start-button\" onclick=\"runTests()\">Run tests</button>");
out.println(" </body>");
out.println("</html>");
}

View File

@ -1246,6 +1246,7 @@ public class ProgramParser {
ArrayLengthInstruction insn = new ArrayLengthInstruction();
insn.setArray(getVariable(a));
insn.setReceiver(getVariable(a));
builder.add(insn);
break;
}
case Opcodes.ATHROW: {

View File

@ -157,6 +157,11 @@ $rt_init = function(cls, constructor, args) {
cls.prototype[constructor].apply(obj, args);
return obj;
}
$rt_throw = function(ex) {
var err = new Error("Java exception thrown");
err.$javaException = ex;
throw err;
}
$rt = {
createBooleanArray : function(cls, sz) {