mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14: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>
|
</build>
|
||||||
<modules>
|
<modules>
|
||||||
<module>teavm-core</module>
|
<module>teavm-core</module>
|
||||||
|
<module>teavm-classlib</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<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 {
|
public static void main(String... args) throws IOException {
|
||||||
ClassHolderSource source = new ClassHolderSource();
|
MutableClassHolderSource source = new MutableClassHolderSource();
|
||||||
ClassHolder arrayListCls = Parser.parseClass(readClass(ArrayList.class.getName()));
|
ClassHolder arrayListCls = Parser.parseClass(readClass(ArrayList.class.getName()));
|
||||||
source.putClassHolder(arrayListCls);
|
source.putClassHolder(arrayListCls);
|
||||||
source.putClassHolder(Parser.parseClass(readClass(AbstractList.class.getName())));
|
source.putClassHolder(Parser.parseClass(readClass(AbstractList.class.getName())));
|
||||||
|
|
|
@ -27,7 +27,6 @@ public class RenderableMethod {
|
||||||
private int variableCount;
|
private int variableCount;
|
||||||
|
|
||||||
public RenderableMethod(MethodHolder metadata) {
|
public RenderableMethod(MethodHolder metadata) {
|
||||||
super();
|
|
||||||
this.metadata = metadata;
|
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;
|
package org.teavm.model;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author konsoletyper
|
||||||
*/
|
*/
|
||||||
public class ClassHolderSource {
|
public interface ClassHolderSource {
|
||||||
private Map<String, ClassHolder> classes = new HashMap<>();
|
ClassHolder getClassHolder(String name);
|
||||||
|
|
||||||
public ClassHolder getClassHolder(String name) {
|
|
||||||
return classes.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putClassHolder(ClassHolder classHolder) {
|
|
||||||
classes.put(classHolder.getName(), classHolder);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -49,10 +49,6 @@ public abstract class ElementHolder {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, AnnotationHolder> getAnnotations() {
|
public Map<String, AnnotationHolder> getAnnotations() {
|
||||||
return annotations;
|
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
|
* it allows to disassemble method bodies into three-address code that is very
|
||||||
* close to JVM bytecode (see {@link org.teavm.instructions}.
|
* 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;
|
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