Doing a lot of things

This commit is contained in:
konsoletyper 2013-10-27 12:16:07 +04:00
parent 3d12aed446
commit df05104e3c
45 changed files with 2028 additions and 38 deletions

View File

@ -27,5 +27,6 @@
</build>
<modules>
<module>teavm-core</module>
<module>teavm-classlib</module>
</modules>
</project>

4
teavm-classlib/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
target
.settings
.project
.classpath

20
teavm-classlib/pom.xml Normal file
View File

@ -0,0 +1,20 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.teavm</groupId>
<artifactId>teavm</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>teavm-classlib</artifactId>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,12 @@
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TClass<T> extends TObject {
@GeneratedBy(TClassNativeGenerator.class)
public native boolean isInstance(TObject obj);
}

View File

@ -0,0 +1,34 @@
package org.teavm.classlib.java.lang;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TClassNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getClassName()) {
case "isInstance":
generateIsInstance(context, writer);
break;
case "isAssignable":
generateIsAssignableFrom(context, writer);
break;
}
}
private void generateIsInstance(GeneratorContext context, SourceWriter writer) {
writer.append("return $rt_isInstance(").append(context.getParameterName(1)).append(", ")
.append(context.getParameterName(0)).append(".$data);").newLine();
}
private void generateIsAssignableFrom(GeneratorContext context, SourceWriter writer) {
writer.append("return $rt_isAssignable(").append(context.getParameterName(1)).append(".$data, ")
.append(context.getParameterName(0)).append(".$data;").newLine();
}
}

View File

@ -0,0 +1,9 @@
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TInterruptedException extends Exception {
private static final long serialVersionUID = -7832805114281254695L;
}

View File

@ -0,0 +1,59 @@
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.Rename;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TObject {
public TObject() {
init();
}
@GeneratedBy(TObjectNativeGenerator.class)
private native void init();
@GeneratedBy(TObjectNativeGenerator.class)
@Rename("getClass")
public native final TClass<?> getClass0();
@Override
@GeneratedBy(TObjectNativeGenerator.class)
public native int hashCode();
@GeneratedBy(TObjectNativeGenerator.class)
public native boolean equals(TObject other);
@Override
@GeneratedBy(TObjectNativeGenerator.class)
protected native TObject clone();
@Rename("notify")
public final void notify0() {
}
@Rename("notifyAll")
public final void notifyAll0() {
}
@SuppressWarnings("unused")
@Rename("wait")
public final void wait0(long timeout) throws TInterruptedException {
}
@SuppressWarnings("unused")
@Rename("wait")
public final void wait0(long timeout, int nanos) throws TInterruptedException {
}
@SuppressWarnings("unused")
@Rename("wait")
public final void wait0() throws TInterruptedException {
}
@Override
protected void finalize() throws TThrowable {
}
}

View File

@ -0,0 +1,69 @@
package org.teavm.classlib.java.lang;
import org.teavm.codegen.SourceWriter;
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 <konsoletyper@gmail.com>
*/
public class TObjectNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getDescriptor().getName()) {
case "init":
generateInit(context, writer);
break;
case "getClass":
generateGetClass(context, writer);
break;
case "hashCode":
generateHashCode(context, writer);
break;
case "equals":
generateEquals(context, writer);
break;
case "clone":
generateClone(context, writer);
break;
}
}
private void generateInit(GeneratorContext context, SourceWriter writer) {
writer.append(context.getParameterName(0)).append(".$id = $rt_nextId();").newLine();
}
private void generateGetClass(GeneratorContext context, SourceWriter writer) {
String thisArg = context.getParameterName(0);
String classClass = "java.lang.Class";
writer.append("var cls = ").append(thisArg).append(".$class.classObject;").newLine();
writer.append("if (cls === undefined) {").newLine().indent();
writer.append("cls = ").appendClass(classClass)
.appendMethod(classClass, new MethodDescriptor("createNew", ValueType.object(classClass)))
.append("();").newLine();
writer.append("cls.$data = ").append(thisArg).append(".$class;").newLine().outdent().append("}").newLine();
writer.append("return cls;").newLine();
}
private void generateHashCode(GeneratorContext context, SourceWriter writer) {
writer.append("return ").append(context.getParameterName(0)).append(".$id;").newLine();
}
private void generateEquals(GeneratorContext context, SourceWriter writer) {
writer.append("return ").append(context.getParameterName(0)).append(" == ")
.append(context.getParameterName(1)).append(";").newLine();
}
private void generateClone(GeneratorContext context, SourceWriter writer) {
writer.append("var copy = new ").append(context.getParameterName(0)).append("obj.$class();").newLine();
writer.append("for (var field in obj) {").newLine().indent();
writer.append("if (!obj.hasOwnProperty(field)) {").newLine().indent();
writer.append("continue;").newLine().outdent().append("}").newLine();
writer.append("copy[field] = obj[field];").newLine().outdent().append("}").newLine();
writer.append("return copy;").newLine();
}
}

View File

@ -0,0 +1,9 @@
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TString {
}

View File

@ -0,0 +1,9 @@
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TThrowable extends Throwable {
private static final long serialVersionUID = 2026791432677149320L;
}

View File

@ -0,0 +1,60 @@
package org.teavm.classlib.org.junit;
import org.teavm.javascript.ni.GeneratedBy;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class Assert {
public static void assertTrue(boolean condition) {
if (!condition) {
fail();
}
}
public static void assertFalse(boolean condition) {
if (condition) {
fail();
}
}
@GeneratedBy(AssertNativeGenerator.class)
public static native void fail();
public static void assertEquals(Object expected, Object actual) {
if (expected != null ? !expected.equals(actual) : actual != null) {
fail();
}
}
public static void assertNotEquals(Object expected, Object actual) {
if (expected != null ? expected.equals(actual) : actual == null) {
fail();
}
}
public static void assertNotNull(Object object) {
if (object == null) {
fail();
}
}
public static void assertNull(Object object) {
if (object != null) {
fail();
}
}
public static void assertSame(Object expected, Object actual) {
if (expected != actual) {
fail();
}
}
public static void assertNotSame(Object expected, Object actual) {
if (expected == actual) {
fail();
}
}
}

View File

@ -0,0 +1,25 @@
package org.teavm.classlib.org.junit;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class AssertNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getDescriptor().getName()) {
case "fail":
generateFail(writer);
break;
}
}
private void generateFail(SourceWriter writer) {
writer.append("throw new JUnitAssertionFailure();").newLine();
}
}

View File

@ -0,0 +1,15 @@
package org.teavm.classlib.org.junit;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}

View File

@ -0,0 +1,35 @@
package org.teavm.classlibgen;
import org.teavm.codegen.DefaultAliasProvider;
import org.teavm.codegen.DefaultNamingStrategy;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.MethodDecompiler;
import org.teavm.javascript.Optimizer;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.ast.RenderableMethod;
import org.teavm.model.ClassHolder;
import org.teavm.model.MethodHolder;
import org.teavm.model.resource.ClasspathClassHolderSource;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClasslibTestGenerator {
public static void main(String[] args) {
ClasspathClassHolderSource source = new ClasspathClassHolderSource();
MethodDecompiler decompiler = new MethodDecompiler(source);
DefaultAliasProvider aliasProvider = new DefaultAliasProvider();
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, source);
SourceWriter writer = new SourceWriter(naming);
Renderer renderer = new Renderer(writer, source);
Optimizer optimizer = new Optimizer();
ClassHolder cls = source.getClassHolder("java.lang.Object");
for (MethodHolder method : cls.getMethods()) {
RenderableMethod renderableMethod = decompiler.decompile(method);
optimizer.optimize(renderableMethod);
renderer.render(renderableMethod);
}
System.out.println(writer);
}
}

View File

@ -0,0 +1,3 @@
packagePrefix.java=org.teavm.classlib
classPrefix.java=T
packagePrefix.org.junit=org.teavm.classlib

View File

@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>

View File

@ -0,0 +1,55 @@
package org.teavm.codegen;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
private Mapper<T, R> innerMapper;
private ConcurrentMap<T, Wrapper<R>> cache = new ConcurrentHashMap<>();
private static class Wrapper<S> {
volatile S value;
volatile CountDownLatch latch = new CountDownLatch(1);
}
public ConcurrentCachedMapper(Mapper<T, R> innerMapper) {
this.innerMapper = innerMapper;
}
@Override
public R map(T preimage) {
Wrapper<R> wrapper = cache.get(preimage);
if (wrapper == null) {
wrapper = new Wrapper<>();
Wrapper<R> oldWrapper = cache.putIfAbsent(preimage, wrapper);
if (oldWrapper == null) {
wrapper.value = innerMapper.map(preimage);
wrapper.latch.countDown();
wrapper.latch = null;
} else {
CountDownLatch latch = oldWrapper.latch;
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
return wrapper.value;
}
public boolean caches(T preimage) {
return cache.get(preimage) != null;
}
public Collection<T> getCachedPreimages() {
return new HashSet<>(cache.keySet());
}
}

View File

@ -0,0 +1,9 @@
package org.teavm.codegen;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface Mapper<T, R> {
R map(T preimage);
}

View File

@ -0,0 +1,200 @@
/*
* Copyright 2012 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.dependency;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.*;
import org.teavm.codegen.ConcurrentCachedMapper;
import org.teavm.codegen.Mapper;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class DependencyChecker {
private static Object dummyValue = new Object();
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
private ClassHolderSource classSource;
private ScheduledThreadPoolExecutor executor;
private ConcurrentCachedMapper<MethodReference, MethodGraph> methodCache;
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
private volatile RuntimeException exceptionOccured;
public DependencyChecker(ClassHolderSource classSource) {
this(classSource, 1);
}
public DependencyChecker(ClassHolderSource classSource, int numThreads) {
this.classSource = classSource;
executor = new ScheduledThreadPoolExecutor(numThreads);
methodCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodGraph>() {
@Override public MethodGraph map(MethodReference preimage) {
return createMethodGraph(preimage);
}
});
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, DependencyNode>() {
@Override public DependencyNode map(FieldReference preimage) {
return createFieldNode(preimage);
}
});
}
public DependencyNode createNode() {
return new DependencyNode(this);
}
public ClassHolderSource getClassSource() {
return classSource;
}
public void addEntryPoint(MethodReference methodRef, String... argumentTypes) {
ValueType[] parameters = methodRef.getDescriptor().getParameterTypes();
if (parameters.length != argumentTypes.length) {
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
}
MethodGraph graph = attachMethodGraph(methodRef);
DependencyNode[] varNodes = graph.getVariableNodes();
schedulePropagation(varNodes[0], methodRef.getClassName());
for (int i = 0; i < argumentTypes.length; ++i) {
schedulePropagation(varNodes[i + 1], argumentTypes[i]);
}
}
public void schedulePropagation(final DependencyConsumer targetNode, final String type) {
schedule(new Runnable() {
@Override public void run() {
targetNode.propagate(type);
}
});
}
void schedule(final Runnable runnable) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
runnable.run();
} catch (RuntimeException e) {
exceptionOccured = e;
executor.shutdownNow();
}
}
});
}
public void checkDependencies() {
exceptionOccured = null;
while (true) {
try {
if (executor.awaitTermination(1, TimeUnit.SECONDS)) {
break;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
if (exceptionOccured != null) {
throw exceptionOccured;
}
}
void achieveClass(String className) {
achievableClasses.put(className, dummyValue);
}
public MethodGraph attachMethodGraph(MethodReference methodRef) {
return methodCache.map(methodRef);
}
private void initClass(String className) {
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>");
while (className != null) {
if (initializedClasses.putIfAbsent(className, clinitDesc) != null) {
break;
}
ClassHolder cls = classSource.getClassHolder(className);
if (cls.getMethod(clinitDesc) != null) {
attachMethodGraph(new MethodReference(className, clinitDesc));
}
className = cls.getParent();
}
}
private MethodGraph createMethodGraph(MethodReference methodRef) {
initClass(methodRef.getClassName());
ClassHolder cls = classSource.getClassHolder(methodRef.getClassName());
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
ValueType[] arguments = method.getParameterTypes();
int paramCount = arguments.length + 1;
int varCount = Math.max(paramCount, method.getProgram().variableCount());
DependencyNode[] parameterNodes = new DependencyNode[varCount];
for (int i = 0; i < varCount; ++i) {
parameterNodes[i] = new DependencyNode(this);
if (shouldLog) {
parameterNodes[i].setTag(method.getOwner().getName() + "#" +
method.getName() + method.getDescriptor() + ":" + i);
}
}
DependencyNode resultNode;
if (method.getResultType() == ValueType.VOID) {
resultNode = null;
} else {
resultNode = new DependencyNode(this);
if (shouldLog) {
resultNode.setTag(method.getOwner().getName() + "#" +
method.getName() + MethodDescriptor.get(method) + ":RESULT");
}
}
MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this);
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(this);
graphBuilder.buildGraph(method, graph);
return graph;
}
public boolean isMethodAchievable(MethodReference methodRef) {
return methodCache.caches(methodRef);
}
public Collection<MethodReference> getAchievableMethods() {
return methodCache.getCachedPreimages();
}
public Collection<FieldReference> getAchievableFields() {
return fieldCache.getCachedPreimages();
}
public Collection<String> getAchievableClasses() {
return new HashSet<>(achievableClasses.keySet());
}
public DependencyNode getFieldNode(FieldReference fieldRef) {
return fieldCache.map(fieldRef);
}
private DependencyNode createFieldNode(FieldReference fieldRef) {
initClass(fieldRef.getClassName());
DependencyNode node = new DependencyNode(this);
if (shouldLog) {
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
}
return node;
}
}

View File

@ -0,0 +1,11 @@
package org.teavm.dependency;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface DependencyConsumer {
void propagate(String type);
boolean hasType(String type);
}

View File

@ -0,0 +1,294 @@
/*
* Copyright 2012 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.dependency;
import java.util.Set;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
class DependencyGraphBuilder {
private DependencyChecker dependencyChecker;
private ClassHolderSource classSource;
private DependencyNode[] nodes;
private DependencyNode resultNode;
private Program program;
private ValueType resultType;
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
this.dependencyChecker = dependencyChecker;
this.classSource = dependencyChecker.getClassSource();
}
public void buildGraph(MethodHolder method, MethodGraph graph) {
if (method.getProgram().basicBlockCount() == 0) {
return;
}
program = method.getProgram();
resultType = method.getResultType();
resultNode = graph.getResultNode();
nodes = graph.getVariableNodes();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(visitor);
}
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]);
}
}
}
}
private static boolean hasBody(MethodHolder method) {
Set<ElementModifier> modifiers = method.getModifiers();
return !modifiers.contains(ElementModifier.ABSTRACT) &&
!modifiers.contains(ElementModifier.NATIVE);
}
private static class VirtualCallPropagationListener implements DependencyConsumer {
private final DependencyNode node;
private final MethodDescriptor methodDesc;
private final DependencyChecker checker;
private final ValueType[] paramTypes;
private final DependencyNode[] parameters;
private final ValueType resultType;
private final DependencyNode result;
public VirtualCallPropagationListener(DependencyNode node, MethodDescriptor methodDesc,
DependencyChecker checker, ValueType[] paramTypes, DependencyNode[] parameters,
ValueType resultType, DependencyNode result) {
this.node = node;
this.methodDesc = methodDesc;
this.checker = checker;
this.paramTypes = paramTypes;
this.parameters = parameters;
this.resultType = resultType;
this.result = result;
}
@Override
public void propagate(String className) {
if (DependencyChecker.shouldLog) {
System.out.println("Virtual call of " + methodDesc + " detected on " +
node.getTag() + ". Target class is " + className);
}
MethodReference methodRef = new MethodReference(className, methodDesc);
MethodHolder method = findMethod(methodRef, checker.getClassSource());
if (method == null) {
return;
}
MethodGraph targetGraph = checker.attachMethodGraph(methodRef);
DependencyNode[] targetParams = targetGraph.getVariableNodes();
for (int i = 0; i < parameters.length; ++i) {
parameters[i].connect(targetParams[i]);
if (hasBody(method)) {// && isPossibleArrayPair(paramTypes[i], method.getProgram().variableAt(i))) {
targetParams[i].connect(parameters[i]);
}
}
if (targetGraph.getResultNode() != null) {
targetGraph.getResultNode().connect(result);
if (isPossibleArrayPair(method.getResultType(), resultType)) {
result.connect(targetGraph.getResultNode());
}
}
}
@Override
public boolean hasType(String type) {
return false;
}
}
private static MethodHolder findMethod(MethodReference methodRef, ClassHolderSource classSource) {
String className = methodRef.getClassName();
while (className != null) {
ClassHolder cls = classSource.getClassHolder(className);
if (cls == null) {
break;
}
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
if (method != null) {
return method;
}
className = cls.getParent();
}
return null;
}
private static MethodHolder requireMethod(MethodReference methodRef, ClassHolderSource classSource) {
MethodHolder method = findMethod(methodRef, classSource);
if (method == null) {
throw new IllegalStateException("Method not found: " + methodRef);
}
return method;
}
private static FieldHolder findField(FieldReference fieldRef, ClassHolderSource classSource) {
String className = fieldRef.getClassName();
while (className != null) {
ClassHolder cls = classSource.getClassHolder(className);
if (cls == null) {
break;
}
FieldHolder field = cls.getField(fieldRef.getFieldName());
if (field != null) {
return field;
}
className = cls.getParent();
}
return null;
}
private static boolean isPossibleArrayPair(ValueType a, ValueType b) {
if (a instanceof ValueType.Array || b instanceof ValueType.Array) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.toString().equals("Ljava/lang/Object;") && b.toString().equals("Ljava/lang/Object;")) {
return true;
}
return false;
}
private InstructionVisitor visitor = new InstructionVisitor() {
@Override
public void visit(IsInstanceInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(GetElementInstruction insn) {
}
@Override
public void visit(CloneArrayInstruction insn) {
}
@Override
public void visit(ArrayLengthInstruction insn) {
}
@Override
public void visit(PutFieldInstruction insn) {
}
@Override
public void visit(GetFieldInstruction insn) {
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
}
@Override
public void visit(ConstructInstruction insn) {
}
@Override
public void visit(ConstructArrayInstruction insn) {
}
@Override
public void visit(RaiseInstruction insn) {
}
@Override
public void visit(ExitInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(BinaryBranchingInstruction insn) {
}
@Override
public void visit(BranchingInstruction insn) {
}
@Override
public void visit(CastNumberInstruction insn) {
}
@Override
public void visit(CastInstruction insn) {
}
@Override
public void visit(AssignInstruction insn) {
}
@Override
public void visit(NegateInstruction insn) {
}
@Override
public void visit(BinaryInstruction insn) {
}
@Override
public void visit(StringConstantInstruction insn) {
}
@Override
public void visit(DoubleConstantInstruction insn) {
}
@Override
public void visit(FloatConstantInstruction insn) {
}
@Override
public void visit(LongConstantInstruction insn) {
}
@Override
public void visit(IntegerConstantInstruction insn) {
}
@Override
public void visit(NullConstantInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
}
@Override
public void visit(EmptyInstruction insn) {
}
};
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2012 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.dependency;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
*
* @author Alexey Andreev
*/
public class DependencyNode implements DependencyConsumer {
private DependencyChecker dependencyChecker;
private static final Object mapValue = new Object();
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();
private ConcurrentMap<String, Object> types = new ConcurrentHashMap<>();
private volatile String tag;
DependencyNode(DependencyChecker dependencyChecker) {
this.dependencyChecker = dependencyChecker;
}
@Override
public void propagate(String type) {
if (types.putIfAbsent(type, mapValue) == null) {
if (DependencyChecker.shouldLog) {
System.out.println(tag + " -> " + type);
}
for (DependencyConsumer follower : followers.keySet().toArray(new DependencyConsumer[0])) {
if (follower.hasType(type)) {
dependencyChecker.schedulePropagation(follower, type);
}
}
}
}
public void connect(DependencyConsumer follower) {
if (followers.putIfAbsent(follower, mapValue) == null) {
for (String type : types.keySet().toArray(new String[0])) {
if (follower.hasType(type)) {
dependencyChecker.schedulePropagation(follower, type);
}
}
}
}
@Override
public boolean hasType(String type) {
return types.containsKey(type);
}
public String[] getTypes() {
return types != null ? types.keySet().toArray(new String[types.size()]) : new String[0];
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2012 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.dependency;
import java.util.Arrays;
/**
*
* @author Alexey Andreev
*/
public class MethodGraph {
private DependencyNode[] variableNodes;
private int parameterCount;
private DependencyNode resultNode;
private DependencyNode sideEffectNode;
MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
DependencyChecker checker) {
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
this.parameterCount = parameterCount;
this.resultNode = resultNode;
this.sideEffectNode = checker.createNode();
}
public DependencyNode[] getVariableNodes() {
return Arrays.copyOf(variableNodes, variableNodes.length);
}
public int getVariableNodesCount() {
return variableNodes.length;
}
public DependencyNode getVariableNode(int index) {
return variableNodes[index];
}
public int getParameterCount() {
return parameterCount;
}
public DependencyNode getResultNode() {
return resultNode;
}
public DependencyNode getSideEffectNode() {
return sideEffectNode;
}
}

View File

@ -0,0 +1,188 @@
package org.teavm.dependency;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.MethodHolder;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
class TypeAnalyzer implements InstructionVisitor {
private ClassHolderSource classSource;
private ValueType[] types;
private int[] definedVars;
public TypeAnalyzer(ClassHolderSource classSource, int variableCount) {
types = new ValueType[variableCount];
}
@Override
public void visit(EmptyInstruction insn) {
}
private void define(Variable var, ValueType type) {
types[var.getIndex()] = type;
definedVars = new int[] { var.getIndex() };
}
@Override
public void visit(ClassConstantInstruction insn) {
define(insn.getReceiver(), ValueType.object("java.lang.Class"));
}
@Override
public void visit(NullConstantInstruction insn) {
define(insn.getReceiver(), ValueType.NULL);
}
@Override
public void visit(IntegerConstantInstruction insn) {
define(insn.getReceiver(), ValueType.INTEGER);
}
@Override
public void visit(LongConstantInstruction insn) {
define(insn.getReceiver(), ValueType.LONG);
}
@Override
public void visit(FloatConstantInstruction insn) {
define(insn.getReceiver(), ValueType.FLOAT);
}
@Override
public void visit(DoubleConstantInstruction insn) {
define(insn.getReceiver(), ValueType.DOUBLE);
}
@Override
public void visit(StringConstantInstruction insn) {
define(insn.getReceiver(), ValueType.object("java.lang.String"));
}
@Override
public void visit(BinaryInstruction insn) {
switch (insn.getOperation()) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case MODULO:
case SHIFT_LEFT:
case SHIFT_RIGHT:
case SHIFT_RIGHT_UNSIGNED:
case AND:
case OR:
case XOR:
define(insn.getReceiver(), map(insn.getOperandType()));
break;
case COMPARE:
define(insn.getReceiver(), ValueType.INTEGER);
break;
}
}
private ValueType map(NumericOperandType type) {
switch (type) {
case INT:
return ValueType.INTEGER;
case LONG:
return ValueType.LONG;
case FLOAT:
return ValueType.FLOAT;
case DOUBLE:
return ValueType.DOUBLE;
}
throw new AssertionError("Unknown type: " + type);
}
@Override
public void visit(NegateInstruction insn) {
define(insn.getReceiver(), map(insn.getOperandType()));
}
@Override
public void visit(AssignInstruction insn) {
define(insn.getReceiver(), types[insn.getAssignee().getIndex()]);
}
@Override
public void visit(CastInstruction insn) {
define(insn.getReceiver(), insn.getTargetType());
}
@Override
public void visit(CastNumberInstruction insn) {
}
@Override
public void visit(BranchingInstruction insn) {
}
@Override
public void visit(BinaryBranchingInstruction insn) {
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
}
@Override
public void visit(ExitInstruction insn) {
}
@Override
public void visit(RaiseInstruction insn) {
}
@Override
public void visit(ConstructArrayInstruction insn) {
}
@Override
public void visit(ConstructInstruction insn) {
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
}
@Override
public void visit(GetFieldInstruction insn) {
}
@Override
public void visit(PutFieldInstruction insn) {
}
@Override
public void visit(ArrayLengthInstruction insn) {
}
@Override
public void visit(CloneArrayInstruction insn) {
}
@Override
public void visit(GetElementInstruction insn) {
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
}
@Override
public void visit(IsInstanceInstruction insn) {
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2012 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.dependency;
/**
*
* @author Alexey Andreev
*/
public interface TypePropagationListener {
void typeAdded(DependencyNode node, String type);
}

View File

@ -232,7 +232,7 @@ public class MethodDecompiler {
}
public static void main(String... args) throws IOException {
ClassHolderSource source = new ClassHolderSource();
MutableClassHolderSource source = new MutableClassHolderSource();
ClassHolder arrayListCls = Parser.parseClass(readClass(ArrayList.class.getName()));
source.putClassHolder(arrayListCls);
source.putClassHolder(Parser.parseClass(readClass(AbstractList.class.getName())));

View File

@ -27,7 +27,6 @@ public class RenderableMethod {
private int variableCount;
public RenderableMethod(MethodHolder metadata) {
super();
this.metadata = metadata;
}

View File

@ -0,0 +1,16 @@
package org.teavm.javascript.ni;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface GeneratedBy {
Class<? extends Generator> value();
}

View File

@ -0,0 +1,12 @@
package org.teavm.javascript.ni;
import org.teavm.codegen.SourceWriter;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface Generator {
void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef);
}

View File

@ -0,0 +1,9 @@
package org.teavm.javascript.ni;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface GeneratorContext {
String getParameterName(int index);
}

View File

@ -0,0 +1,16 @@
package org.teavm.javascript.ni;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Rename {
String value();
}

View File

@ -1,35 +1,9 @@
/*
* Copyright 2012 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.model;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Alexey Andreev
* @author konsoletyper
*/
public class ClassHolderSource {
private Map<String, ClassHolder> classes = new HashMap<>();
public ClassHolder getClassHolder(String name) {
return classes.get(name);
}
public void putClassHolder(ClassHolder classHolder) {
classes.put(classHolder.getName(), classHolder);
}
public interface ClassHolderSource {
ClassHolder getClassHolder(String name);
}

View File

@ -49,10 +49,6 @@ public abstract class ElementHolder {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, AnnotationHolder> getAnnotations() {
return annotations;
}

View File

@ -0,0 +1,40 @@
package org.teavm.model;
/**
*
* @author konsoletyper
*/
public class FieldReference {
private String className;
private String fieldName;
public FieldReference(String className, String fieldName) {
this.className = className;
this.fieldName = fieldName;
}
public String getClassName() {
return className;
}
public String getFieldName() {
return fieldName;
}
@Override
public int hashCode() {
return className.hashCode() ^ fieldName.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof FieldReference)) {
return false;
}
FieldReference other = (FieldReference)obj;
return className.equals(other.className) && fieldName.equals(other.fieldName);
}
}

View File

@ -0,0 +1,45 @@
package org.teavm.model;
/**
*
* @author konsoletyper
*/
public class MethodReference {
private String className;
private MethodDescriptor descriptor;
public MethodReference(String className, MethodDescriptor descriptor) {
this.className = className;
this.descriptor = descriptor;
}
public String getClassName() {
return className;
}
public MethodDescriptor getDescriptor() {
return descriptor;
}
@Override
public int hashCode() {
return className.hashCode() ^ descriptor.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return false;
}
if (!(obj instanceof MethodReference)) {
return false;
}
MethodReference other = (MethodReference)obj;
return className.equals(other.className) && descriptor.equals(other.descriptor);
}
@Override
public String toString() {
return className + "." + descriptor;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2012 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.model;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
*
* @author Alexey Andreev
*/
public class MutableClassHolderSource implements ClassHolderSource {
private ConcurrentMap<String, ClassHolder> classes = new ConcurrentHashMap<>();
@Override
public ClassHolder getClassHolder(String name) {
return classes.get(name);
}
public void putClassHolder(ClassHolder classHolder) {
classes.put(classHolder.getName(), classHolder);
}
}

View File

@ -4,7 +4,7 @@
* it allows to disassemble method bodies into three-address code that is very
* close to JVM bytecode (see {@link org.teavm.instructions}.
*
* <p>The entry point is some implementation of {@link ClassHolderSource} class.
* <p>The entry point is some implementation of {@link MutableClassHolderSource} class.
*
*/
package org.teavm.model;

View File

@ -0,0 +1,28 @@
package org.teavm.model.resource;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClasspathClassHolderSource implements ClassHolderSource {
private MapperClassHolderSource innerClassSource;
public ClasspathClassHolderSource(ClassLoader classLoader) {
ClasspathResourceReader reader = new ClasspathResourceReader();
ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader);
ClasspathResourceMapper classPathMapper = new ClasspathResourceMapper(classLoader, rawMapper);
innerClassSource = new MapperClassHolderSource(classPathMapper);
}
public ClasspathClassHolderSource() {
this(ClasspathClassHolderSource.class.getClassLoader());
}
@Override
public ClassHolder getClassHolder(String name) {
return innerClassSource.getClassHolder(name);
}
}

View File

@ -0,0 +1,83 @@
package org.teavm.model.resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import org.teavm.codegen.Mapper;
import org.teavm.model.ClassHolder;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClasspathResourceMapper implements Mapper<String, ClassHolder> {
private static String PACKAGE_PREFIX = "packagePrefix.";
private static String CLASS_PREFIX = "classPrefix.";
private Mapper<String, ClassHolder> innerMapper;
private List<Transformation> transformations = new ArrayList<>();
private static class Transformation {
String packageName;
String packagePrefix = "";
String classPrefix = "";
}
public ClasspathResourceMapper(ClassLoader classLoader, Mapper<String, ClassHolder> innerMapper) {
this.innerMapper = innerMapper;
try {
Enumeration<URL> resources = classLoader.getResources("META-INF/teavm.properties");
Map<String, Transformation> transformationMap = new HashMap<>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
Properties properties = new Properties();
try (InputStream input = resource.openStream()) {
properties.load(input);
}
loadProperties(properties, transformationMap);
}
transformations.addAll(transformationMap.values());
} catch (IOException e) {
throw new RuntimeException("Error reading resources", e);
}
}
private void loadProperties(Properties properties, Map<String, Transformation> cache) {
for (String propertyName : properties.stringPropertyNames()) {
if (propertyName.startsWith(PACKAGE_PREFIX)) {
String packageName = propertyName.substring(PACKAGE_PREFIX.length());
Transformation transformation = getTransformation(cache, packageName);
transformation.packagePrefix = properties.getProperty(propertyName) + ".";
} else if (propertyName.startsWith(CLASS_PREFIX)) {
String packageName = propertyName.substring(CLASS_PREFIX.length());
Transformation transformation = getTransformation(cache, packageName);
transformation.classPrefix = properties.getProperty(propertyName);
}
}
}
private Transformation getTransformation(Map<String, Transformation> cache, String packageName) {
Transformation transformation = cache.get(packageName);
if (transformation == null) {
transformation = new Transformation();
transformation.packageName = packageName;
cache.put(packageName, transformation);
}
return transformation;
}
@Override
public ClassHolder map(String name) {
for (Transformation transformation : transformations) {
if (name.startsWith(transformation.packageName)) {
int index = name.lastIndexOf('.');
String className = name.substring(index + 1);
String packageName = name.substring(0, index);
ClassHolder classHolder = innerMapper.map(transformation.packagePrefix + "." + packageName +
"." + transformation.classPrefix + className);
return classHolder;
}
}
return innerMapper.map(name);
}
}

View File

@ -0,0 +1,30 @@
package org.teavm.model.resource;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClasspathResourceReader implements ResourceReader {
private ClassLoader classLoader;
public ClasspathResourceReader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public ClasspathResourceReader() {
this(ClasspathResourceReader.class.getClassLoader());
}
@Override
public boolean hasResource(String name) {
return classLoader.getResource(name) != null;
}
@Override
public InputStream openResource(String name) throws IOException {
return classLoader.getResourceAsStream(name);
}
}

View File

@ -0,0 +1,23 @@
package org.teavm.model.resource;
import org.teavm.codegen.ConcurrentCachedMapper;
import org.teavm.codegen.Mapper;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class MapperClassHolderSource implements ClassHolderSource {
private Mapper<String, ClassHolder> mapper;
public MapperClassHolderSource(Mapper<String, ClassHolder> mapper) {
this.mapper = new ConcurrentCachedMapper<>(mapper);
}
@Override
public ClassHolder getClassHolder(String name) {
return mapper.map(name);
}
}

View File

@ -0,0 +1,37 @@
package org.teavm.model.resource;
import java.io.IOException;
import java.io.InputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.teavm.codegen.Mapper;
import org.teavm.model.ClassHolder;
import org.teavm.parsing.Parser;
/**
*
* @author konsoletyper
*/
public class ResourceClassHolderMapper implements Mapper<String, ClassHolder> {
private ResourceReader resourceReader;
public ResourceClassHolderMapper(ResourceReader resourceReader) {
this.resourceReader = resourceReader;
}
@Override
public ClassHolder map(String name) {
ClassNode clsNode = new ClassNode();
String resourceName = name.replace('.', '/') + ".class";
if (!resourceReader.hasResource(resourceName)) {
return null;
}
try (InputStream input = resourceReader.openResource(resourceName)) {
ClassReader reader = new ClassReader(input);
reader.accept(clsNode, 0);
} catch (IOException e) {
throw new RuntimeException(e);
}
return Parser.parseClass(clsNode);
}
}

View File

@ -0,0 +1,33 @@
package org.teavm.model.resource;
import java.io.IOException;
import java.io.InputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.teavm.codegen.Mapper;
import org.teavm.model.ClassHolder;
import org.teavm.parsing.Parser;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ResourceParser implements Mapper<String, ClassHolder> {
private ResourceReader resourceReader;
public ResourceParser(ResourceReader resourceReader) {
this.resourceReader = resourceReader;
}
@Override
public ClassHolder map(String name) {
ClassNode clsNode = new ClassNode();
try (InputStream input = resourceReader.openResource(name.replace('.', '/') + ".class")) {
ClassReader reader = new ClassReader(input);
reader.accept(clsNode, 0);
} catch (IOException e) {
throw new RuntimeException(e);
}
return Parser.parseClass(clsNode);
}
}

View File

@ -0,0 +1,14 @@
package org.teavm.model.resource;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author konsoletyper
*/
public interface ResourceReader {
boolean hasResource(String name);
InputStream openResource(String name) throws IOException;
}

View File

@ -0,0 +1,316 @@
$rt_lastObjectId = 0;
$rt_nextId = function() {
return $rt_lastObjectId++;
}
$rt_compare = function(a, b) {
return a > b ? 1 : a < b ? -1 : 0;
}
$rt_isInstance = function(obj, cls) {
return $rt_isAssignable(obj.$class, cls);
}
$rt_isAssignable = function(from, to) {
if (from === to) {
return true;
}
var supertypes = from.$meta.supertypes;
for (var i = 0; i < supertypes.length; i = (i + 1) | 0) {
if ($rt_isAssignable(supertypes[i], to)) {
return true;
}
}
return false;
}
$rt = {
createBooleanArray : function(cls, sz) {
var arr = $rt.createArray(cls, sz);
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = false;
}
return arr;
},
createNumericArray : function(cls, sz) {
var arr = $rt.createArray(cls, sz);
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = 0;
}
return arr;
},
createLongArray : function(sz) {
var arr = $rt.createArray($rt.longcls(), sz);
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = Long.ZERO;
}
return arr;
},
createArray : function(cls, sz) {
var arr = new Array(sz);
arr.$class = $rt.arraycls(cls);
arr.$id = $rt.lastObjectId++;
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = null;
}
return arr;
},
createMultiArray : function(cls, dimensions) {
for (var i = 1; i < dimensions.length; i = (i + 1) | 0) {
cls = $rt.arraycls(cls);
}
return $rt.createMultiArrayImpl(cls, dimensions, 0);
},
createMultiArrayImpl : function(cls, dimensions, offset) {
var result = $rt.createArray(cls, dimensions[offset]);
offset = (offset + 1) | 0;
if (offset < dimensions.length) {
cls = cls.$meta.item;
for (var i = 0; i < result.length; i = (i + 1) | 0) {
result[i] = $rt.createMultiArrayImpl(cls, dimensions, offset);
}
}
return result;
},
initializeArray : function(cls, initial) {
var arr = initial.slice();
arr.$class = $rt.arraycls(cls);
$rt.setId(arr, $rt.lastObjectId++);
return arr;
},
arraycls : function(cls) {
if (cls.$array == undefined) {
cls.$array = {
$meta : { item : cls },
};
if ($rt.objcls) {
cls.$array.$meta.supertypes = [$rt.objcls()];
}
}
return cls.$array;
},
createcls : function() {
return {
$meta : {
supertypes : []
}
};
},
booleancls : function() {
if ($rt.booleanclsCache == null) {
$rt.booleanclsCache = $rt.createcls();
}
return $rt.booleanclsCache;
},
charcls : function() {
if ($rt.charclsCache == null) {
$rt.charclsCache = $rt.createcls();
}
return $rt.charclsCache;
},
bytecls : function() {
if ($rt.byteclsCache == null) {
$rt.byteclsCache = $rt.createcls();
}
return $rt.byteclsCache;
},
shortcls : function() {
if ($rt.shortclsCache == null) {
$rt.shortclsCache = $rt.createcls();
}
return $rt.shortclsCache;
},
intcls : function() {
if ($rt.intclsCache == null) {
$rt.intclsCache = $rt.createcls();
}
return $rt.intclsCache;
},
longcls : function() {
if ($rt.longclsCache == null) {
$rt.longclsCache = $rt.createcls();
}
return $rt.longclsCache;
},
floatcls : function() {
if ($rt.floatclsCache == null) {
$rt.floatclsCache = $rt.createcls();
}
return $rt.floatclsCache;
},
doublecls : function() {
if ($rt.doubleclsCache == null) {
$rt.doubleclsCache = $rt.createcls();
}
return $rt.doubleclsCache;
},
voidcls : function() {
if ($rt.voidclsCache == null) {
$rt.voidclsCache = $rt.createcls();
}
return $rt.voidclsCache;
},
equals : function(a, b) {
if (a === b) {
return true;
}
if (a === null || b === null) {
return false;
}
if (typeof(a) == 'object') {
return a.equals(b);
} else {
return false;
}
},
clinit : function(cls) {
if (cls.$clinit) {
var f = cls.$clinit;
delete cls.$clinit;
f();
}
return cls;
},
init : function(cls, constructor, args) {
var obj = new cls();
cls.prototype[constructor].apply(obj, args);
return obj;
},
assertNotNaN : function(value) {
if (typeof value == 'number' && isNaN(value)) {
throw "NaN";
}
return value;
}
};
Long = function(lo, hi) {
this.lo = lo | 0;
this.hi = hi | 0;
}
Long.ZERO = new Long(0, 0);
Long.fromInt = function(val) {
return new Long(val, 0);
}
Long.fromNumber = function(val) {
return new Long(val | 0, (val / 0x100000000) | 0);
}
Long.toNumber = function(val) {
return val.lo + 0x100000000 * val.hi;
}
Long.add = function(a, b) {
var a_lolo = a.lo & 0xFFFF;
var a_lohi = a.lo >>> 16;
var a_hilo = a.hi & 0xFFFF;
var a_hihi = a.hi >>> 16;
var b_lolo = b.lo & 0xFFFF;
var b_lohi = b.lo >>> 16;
var b_hilo = b.hi & 0xFFFF;
var b_hihi = b.hi >>> 16;
var lolo = (a_lolo + b_lolo) | 0;
var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0;
var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0;
var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0;
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16),
(hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
}
Long.inc = function(a) {
var lo = (a.lo + 1) | 0;
var hi = a.hi;
if (lo === 0) {
hi = (hi + 1) | 0;
}
return new Long(lo, hi);
}
Long.dec = function(a) {
var lo = (a.lo - 1) | 0;
var hi = a.hi;
if (lo === -1) {
hi = (hi - 1) | 0;
}
return new Long(lo, hi);
}
Long.neg = function(a) {
return Long.inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF));
}
Long.sub = function(a, b) {
var a_lolo = a.lo & 0xFFFF;
var a_lohi = a.lo >>> 16;
var a_hilo = a.hi & 0xFFFF;
var a_hihi = a.hi >>> 16;
var b_lolo = b.lo & 0xFFFF;
var b_lohi = b.lo >>> 16;
var b_hilo = b.hi & 0xFFFF;
var b_hihi = b.hi >>> 16;
var lolo = (a_lolo - b_lolo) | 0;
var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0;
var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0;
var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0;
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16),
(hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
}
Long.compare = function(a, b) {
var r = a.hi - a.hi;
if (r != 0) {
return r;
}
return a.lo - b.lo;
}
Long.isNegative = function(a) {
return a.hi < 0;
}
Long.mul = function(a, b) {
var a_lolo = a.lo & 0xFFFF;
var a_lohi = a.lo >>> 16;
var a_hilo = a.hi & 0xFFFF;
var a_hihi = a.hi >>> 16;
var b_lolo = b.lo & 0xFFFF;
var b_lohi = b.lo >>> 16;
var b_hilo = b.hi & 0xFFFF;
var b_hihi = b.hi >>> 16;
var lolo = (a_lolo * b_lolo) | 0;
var lohi = (a_lohi * b_lolo + a_lolo * b_lohi + (lolo >> 16)) | 0;
var hilo = (a_hilo * b_lolo + a_lohi * b_lohi + a_lolo * b_hilo + (lohi >> 16)) | 0;
var hihi = (a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi +
(hilo >> 16)) | 0;
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16),
(hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
}
Long.div = function(a, b) {
var result = (a.hi * 0x100000000 + a.lo) / (b.hi * 0x100000000 + b.lo);
return new Long(result | 0, (result / 0x100000000) | 0);
}
Long.rem = function(a, b) {
var result = (a.hi * 0x100000000 + a.lo) % (b.hi * 0x100000000 + b.lo);
return new Long(result | 0, (result / 0x100000000) | 0);
}
Long.and = function(a, b) {
return new Long(a.lo & b.lo, a.hi & b.hi);
}
Long.or = function(a, b) {
return new Long(a.lo | b.lo, a.hi | b.hi);
}
Long.xor = function(a, b) {
return new Long(a.lo ^ b.lo, a.hi ^ b.hi);
}
Long.shl = function(a, b) {
if (b < 32) {
return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b));
} else {
return new Long(0, a.lo << (b - 32));
}
}
Long.shr = function(a, b) {
if (b < 32) {
return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b);
} else {
return new Long((a.hi >> (b - 32)), -1);
}
}
Long.shru = function(a, b) {
if (b < 32) {
return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b);
} else {
return new Long((a.hi >>> (b - 32)), 0);
}
}