mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Improves dependency checking. Adds some core runtime functions
This commit is contained in:
parent
c244c596c9
commit
e32da9316f
|
@ -53,6 +53,9 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
ClassHolder clsHolder = classSource.getClassHolder(method.getClassName());
|
ClassHolder clsHolder = classSource.getClassHolder(method.getClassName());
|
||||||
MethodHolder methodHolder = clsHolder.getMethod(method.getDescriptor());
|
MethodHolder methodHolder = clsHolder.getMethod(method.getDescriptor());
|
||||||
|
if (methodHolder == null) {
|
||||||
|
throw new RuntimeException("Method not found: " + method);
|
||||||
|
}
|
||||||
if (methodHolder.getModifiers().contains(ElementModifier.STATIC) ||
|
if (methodHolder.getModifiers().contains(ElementModifier.STATIC) ||
|
||||||
method.getDescriptor().getName().equals("<init>") ||
|
method.getDescriptor().getName().equals("<init>") ||
|
||||||
methodHolder.getLevel() == AccessLevel.PRIVATE) {
|
methodHolder.getLevel() == AccessLevel.PRIVATE) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class DependencyChecker {
|
||||||
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
||||||
private ClassHolderSource classSource;
|
private ClassHolderSource classSource;
|
||||||
private ScheduledThreadPoolExecutor executor;
|
private ScheduledThreadPoolExecutor executor;
|
||||||
|
private ConcurrentMap<MethodReference, Object> abstractMethods = new ConcurrentHashMap<>();
|
||||||
private ConcurrentCachedMapper<MethodReference, MethodGraph> methodCache;
|
private ConcurrentCachedMapper<MethodReference, MethodGraph> methodCache;
|
||||||
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
|
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
|
||||||
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
||||||
|
@ -210,6 +211,10 @@ public class DependencyChecker {
|
||||||
return methodCache.caches(methodRef);
|
return methodCache.caches(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAbstractMethodAchievable(MethodReference methodRef) {
|
||||||
|
return abstractMethods.containsKey(methodRef);
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<MethodReference> getAchievableMethods() {
|
public Collection<MethodReference> getAchievableMethods() {
|
||||||
return methodCache.getCachedPreimages();
|
return methodCache.getCachedPreimages();
|
||||||
}
|
}
|
||||||
|
@ -262,6 +267,24 @@ public class DependencyChecker {
|
||||||
plugin.methodAchieved(this, methodRef);
|
plugin.methodAchieved(this, methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addAbstractMethod(MethodReference methodRef) {
|
||||||
|
if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) {
|
||||||
|
String className = methodRef.getClassName();
|
||||||
|
while (className != null) {
|
||||||
|
ClassHolder cls = classSource.getClassHolder(className);
|
||||||
|
if (cls == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
|
||||||
|
if (method != null) {
|
||||||
|
abstractMethods.put(methodRef, methodRef);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
className = cls.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ListableClassHolderSource cutUnachievableClasses() {
|
public ListableClassHolderSource cutUnachievableClasses() {
|
||||||
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
||||||
for (String className : achievableClasses.keySet()) {
|
for (String className : achievableClasses.keySet()) {
|
||||||
|
@ -269,9 +292,14 @@ public class DependencyChecker {
|
||||||
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
|
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
|
||||||
MethodReference methodRef = new MethodReference(className, method.getDescriptor());
|
MethodReference methodRef = new MethodReference(className, method.getDescriptor());
|
||||||
if (!methodCache.getCachedPreimages().contains(methodRef)) {
|
if (!methodCache.getCachedPreimages().contains(methodRef)) {
|
||||||
|
if (abstractMethods.containsKey(methodRef)) {
|
||||||
|
method.getModifiers().add(ElementModifier.ABSTRACT);
|
||||||
|
method.setProgram(null);
|
||||||
|
} else {
|
||||||
classHolder.removeMethod(method);
|
classHolder.removeMethod(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {
|
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {
|
||||||
FieldReference fieldRef = new FieldReference(className, field.getName());
|
FieldReference fieldRef = new FieldReference(className, field.getName());
|
||||||
if (!fieldCache.getCachedPreimages().contains(fieldRef)) {
|
if (!fieldCache.getCachedPreimages().contains(fieldRef)) {
|
||||||
|
|
|
@ -156,6 +156,7 @@ class DependencyGraphBuilder {
|
||||||
DependencyConsumer listener = new VirtualCallPropagationListener(nodes[insn.getInstance().getIndex()],
|
DependencyConsumer listener = new VirtualCallPropagationListener(nodes[insn.getInstance().getIndex()],
|
||||||
insn.getMethod().getDescriptor(), dependencyChecker, actualArgs,
|
insn.getMethod().getDescriptor(), dependencyChecker, actualArgs,
|
||||||
insn.getReceiver() != null ? nodes[insn.getReceiver().getIndex()] : null);
|
insn.getReceiver() != null ? nodes[insn.getReceiver().getIndex()] : null);
|
||||||
|
dependencyChecker.addAbstractMethod(insn.getMethod());
|
||||||
nodes[insn.getInstance().getIndex()].addConsumer(listener);
|
nodes[insn.getInstance().getIndex()].addConsumer(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +281,8 @@ class DependencyGraphBuilder {
|
||||||
@Override
|
@Override
|
||||||
public void visit(StringConstantInstruction insn) {
|
public void visit(StringConstantInstruction insn) {
|
||||||
nodes[insn.getReceiver().getIndex()].propagate("java.lang.String");
|
nodes[insn.getReceiver().getIndex()].propagate("java.lang.String");
|
||||||
|
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor(
|
||||||
|
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
||||||
|
|
||||||
public void renderRuntime() {
|
public void renderRuntime() {
|
||||||
renderRuntimeCls();
|
renderRuntimeCls();
|
||||||
|
renderRuntimeString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRuntimeCls() {
|
private void renderRuntimeCls() {
|
||||||
|
@ -65,6 +66,20 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderRuntimeString() {
|
||||||
|
String stringClass = "java.lang.String";
|
||||||
|
MethodReference stringCons = new MethodReference(stringClass, new MethodDescriptor("<init>",
|
||||||
|
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID));
|
||||||
|
writer.append("$rt_str = function(str) {").indent().newLine();
|
||||||
|
writer.append("var characters = $rt_createNumericArray($rt_charcls(), str.length);").newLine();
|
||||||
|
writer.append("for (var i = 0; i < str.length; i = (i + 1) | 0) {").indent().newLine();
|
||||||
|
writer.append("characters[i] = str.charCodeAt(i);").newLine();
|
||||||
|
writer.outdent().append("}").newLine();
|
||||||
|
writer.append("return $rt_init(").appendClass("java.lang.String").append(", '")
|
||||||
|
.appendMethod(stringCons).append("', characters);").newLine();
|
||||||
|
writer.outdent().append("}").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
public void render(ClassNode cls) {
|
public void render(ClassNode cls) {
|
||||||
writer.appendClass(cls.getName()).append(" = function() {").indent().newLine();
|
writer.appendClass(cls.getName()).append(" = function() {").indent().newLine();
|
||||||
for (FieldNode field : cls.getFields()) {
|
for (FieldNode field : cls.getFields()) {
|
||||||
|
|
|
@ -116,7 +116,7 @@ public abstract class ValueType {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (reprCache == null) {
|
if (reprCache == null) {
|
||||||
reprCache = itemType.toString();
|
reprCache = "[" + itemType.toString();
|
||||||
}
|
}
|
||||||
return reprCache;
|
return reprCache;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,20 @@ $rt_createArray = function(cls, sz) {
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
$rt_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;
|
||||||
|
}
|
||||||
|
$rt_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;
|
||||||
|
},
|
||||||
$rt_arraycls = function(cls) {
|
$rt_arraycls = function(cls) {
|
||||||
if (cls.$array == undefined) {
|
if (cls.$array == undefined) {
|
||||||
cls.$array = {
|
cls.$array = {
|
||||||
|
@ -40,6 +54,109 @@ $rt_arraycls = function(cls) {
|
||||||
}
|
}
|
||||||
return cls.$array;
|
return cls.$array;
|
||||||
}
|
}
|
||||||
|
$rt_createcls = function() {
|
||||||
|
return {
|
||||||
|
$meta : {
|
||||||
|
supertypes : []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
$rt_booleanclsCache = null;
|
||||||
|
$rt_booleancls = function() {
|
||||||
|
if ($rt_booleanclsCache == null) {
|
||||||
|
$rt_booleanclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_booleanclsCache;
|
||||||
|
}
|
||||||
|
$rt_booleanclsCache = null;
|
||||||
|
$rt_booleancls = function() {
|
||||||
|
if ($rt_booleanclsCache == null) {
|
||||||
|
$rt_booleanclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_booleanclsCache;
|
||||||
|
}
|
||||||
|
$rt_charclsCache = null;
|
||||||
|
$rt_charcls = function() {
|
||||||
|
if ($rt_charclsCache == null) {
|
||||||
|
$rt_charclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_charclsCache;
|
||||||
|
}
|
||||||
|
$rt_byteclsCache = null;
|
||||||
|
$rt_bytecls = function() {
|
||||||
|
if ($rt_byteclsCache == null) {
|
||||||
|
$rt_byteclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_byteclsCache;
|
||||||
|
}
|
||||||
|
$rt_shortclsCache = null;
|
||||||
|
$rt_shortcls = function() {
|
||||||
|
if ($rt_shortclsCache == null) {
|
||||||
|
$rt_shortclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_shortclsCache;
|
||||||
|
}
|
||||||
|
$rt_intclsCache = null;
|
||||||
|
$rt_intcls = function() {
|
||||||
|
if ($rt_intclsCache == null) {
|
||||||
|
$rt_intclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_intclsCache;
|
||||||
|
}
|
||||||
|
$rt_longclsCache = null;
|
||||||
|
$rt_longcls = function() {
|
||||||
|
if ($rt_longclsCache == null) {
|
||||||
|
$rt_longclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_longclsCache;
|
||||||
|
}
|
||||||
|
$rt_floatclsCache = null;
|
||||||
|
$rt_floatcls = function() {
|
||||||
|
if ($rt_floatclsCache == null) {
|
||||||
|
$rt_floatclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_floatclsCache;
|
||||||
|
}
|
||||||
|
$rt_doubleclsCache = null;
|
||||||
|
$rt_doublecls = function() {
|
||||||
|
if ($rt_doubleclsCache == null) {
|
||||||
|
$rt_doubleclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_doubleclsCache;
|
||||||
|
}
|
||||||
|
$rt_voidclsCache = null;
|
||||||
|
$rt_voidcls = function() {
|
||||||
|
if ($rt_voidclsCache == null) {
|
||||||
|
$rt_voidclsCache = $rt_createcls();
|
||||||
|
}
|
||||||
|
return $rt_voidclsCache;
|
||||||
|
}
|
||||||
|
$rt_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rt_clinit = function(cls) {
|
||||||
|
if (cls.$clinit) {
|
||||||
|
var f = cls.$clinit;
|
||||||
|
delete cls.$clinit;
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
$rt_init = function(cls, constructor, args) {
|
||||||
|
var obj = new cls();
|
||||||
|
cls.prototype[constructor].apply(obj, args);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
$rt = {
|
$rt = {
|
||||||
createBooleanArray : function(cls, sz) {
|
createBooleanArray : function(cls, sz) {
|
||||||
|
@ -49,20 +166,6 @@ $rt = {
|
||||||
}
|
}
|
||||||
return arr;
|
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;
|
|
||||||
},
|
|
||||||
createMultiArray : function(cls, dimensions) {
|
createMultiArray : function(cls, dimensions) {
|
||||||
for (var i = 1; i < dimensions.length; i = (i + 1) | 0) {
|
for (var i = 1; i < dimensions.length; i = (i + 1) | 0) {
|
||||||
cls = $rt.arraycls(cls);
|
cls = $rt.arraycls(cls);
|
||||||
|
@ -86,93 +189,6 @@ $rt = {
|
||||||
$rt.setId(arr, $rt.lastObjectId++);
|
$rt.setId(arr, $rt.lastObjectId++);
|
||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
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) {
|
assertNotNaN : function(value) {
|
||||||
if (typeof value == 'number' && isNaN(value)) {
|
if (typeof value == 'number' && isNaN(value)) {
|
||||||
throw "NaN";
|
throw "NaN";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user