mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
Doing a lot of things
This commit is contained in:
parent
3d12aed446
commit
df05104e3c
1
pom.xml
1
pom.xml
|
@ -27,5 +27,6 @@
|
|||
</build>
|
||||
<modules>
|
||||
<module>teavm-core</module>
|
||||
<module>teavm-classlib</module>
|
||||
</modules>
|
||||
</project>
|
4
teavm-classlib/.gitignore
vendored
Normal file
4
teavm-classlib/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
target
|
||||
.settings
|
||||
.project
|
||||
.classpath
|
20
teavm-classlib/pom.xml
Normal file
20
teavm-classlib/pom.xml
Normal 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>
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class TString {
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
packagePrefix.java=org.teavm.classlib
|
||||
classPrefix.java=T
|
||||
packagePrefix.org.junit=org.teavm.classlib
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
9
teavm-core/src/main/java/org/teavm/codegen/Mapper.java
Normal file
9
teavm-core/src/main/java/org/teavm/codegen/Mapper.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
package org.teavm.codegen;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface Mapper<T, R> {
|
||||
R map(T preimage);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
188
teavm-core/src/main/java/org/teavm/dependency/TypeAnalyzer.java
Normal file
188
teavm-core/src/main/java/org/teavm/dependency/TypeAnalyzer.java
Normal 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) {
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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())));
|
||||
|
|
|
@ -27,7 +27,6 @@ public class RenderableMethod {
|
|||
private int variableCount;
|
||||
|
||||
public RenderableMethod(MethodHolder metadata) {
|
||||
super();
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.teavm.javascript.ni;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface GeneratorContext {
|
||||
String getParameterName(int index);
|
||||
}
|
16
teavm-core/src/main/java/org/teavm/javascript/ni/Rename.java
Normal file
16
teavm-core/src/main/java/org/teavm/javascript/ni/Rename.java
Normal 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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
40
teavm-core/src/main/java/org/teavm/model/FieldReference.java
Normal file
40
teavm-core/src/main/java/org/teavm/model/FieldReference.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
316
teavm-core/src/main/resources/org/teavm/javascript/runtime.js
Normal file
316
teavm-core/src/main/resources/org/teavm/javascript/runtime.js
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user