Improves dependency checking. Adds some core runtime functions

This commit is contained in:
Alexey Andreev 2013-11-27 17:30:16 +04:00
parent c244c596c9
commit e32da9316f
6 changed files with 168 additions and 103 deletions

View File

@ -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) {

View File

@ -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,7 +292,12 @@ 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)) {
classHolder.removeMethod(method); if (abstractMethods.containsKey(methodRef)) {
method.getModifiers().add(ElementModifier.ABSTRACT);
method.setProgram(null);
} else {
classHolder.removeMethod(method);
}
} }
} }
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) { for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {

View File

@ -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

View File

@ -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()) {

View File

@ -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;
} }

View File

@ -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";