Dependency plugin support added

This commit is contained in:
Alexey Andreev 2013-11-17 16:20:23 +04:00
parent 59358dcd8d
commit 91a50605bc
6 changed files with 106 additions and 2 deletions

View File

@ -1,6 +1,9 @@
package org.teavm.classlib.java.lang;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodGraph;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodDescriptor;
@ -11,7 +14,7 @@ import org.teavm.model.ValueType;
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ObjectNativeGenerator implements Generator {
public class ObjectNativeGenerator implements Generator, DependencyPlugin {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getDescriptor().getName()) {
@ -33,6 +36,18 @@ public class ObjectNativeGenerator implements Generator {
}
}
@Override
public void methodAchieved(DependencyChecker checker, MethodReference method) {
switch (method.getDescriptor().getName()) {
case "clone":
achieveClone(checker, method);
break;
case "getClass":
achieveGetClass(checker);
break;
}
}
private void generateInit(GeneratorContext context, SourceWriter writer) {
writer.append(context.getParameterName(0)).append(".$id = $rt_nextId();").newLine();
}
@ -50,6 +65,13 @@ public class ObjectNativeGenerator implements Generator {
writer.append("return cls;").newLine();
}
private void achieveGetClass(DependencyChecker checker) {
String classClass = "java.lang.Class";
MethodReference method = new MethodReference(classClass, new MethodDescriptor("createNew",
ValueType.object(classClass)));
checker.addEntryPoint(method);
}
private void generateHashCode(GeneratorContext context, SourceWriter writer) {
writer.append("return ").append(context.getParameterName(0)).append(".$id;").newLine();
}
@ -67,4 +89,9 @@ public class ObjectNativeGenerator implements Generator {
writer.append("copy[field] = obj[field];").newLine().outdent().append("}").newLine();
writer.append("return copy;").newLine();
}
private void achieveClone(DependencyChecker checker, MethodReference method) {
MethodGraph graph = checker.attachMethodGraph(method);
graph.getVariableNode(0).connect(graph.getResultNode());
}
}

View File

@ -1,5 +1,6 @@
package org.teavm.classlib.java.lang;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.ni.Superclass;
@ -20,6 +21,7 @@ public class TObject {
@GeneratedBy(ObjectNativeGenerator.class)
@Rename("getClass")
@PluggableDependency(ObjectNativeGenerator.class)
public native final TClass<?> getClass0();
@Override
@ -31,6 +33,7 @@ public class TObject {
@Override
@GeneratedBy(ObjectNativeGenerator.class)
@PluggableDependency(ObjectNativeGenerator.class)
protected native TObject clone();
@Rename("notify")

View File

@ -1,7 +1,9 @@
package org.teavm.codegen;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
@ -13,6 +15,7 @@ import java.util.concurrent.CountDownLatch;
public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
private Mapper<T, R> innerMapper;
private ConcurrentMap<T, Wrapper<R>> cache = new ConcurrentHashMap<>();
private List<KeyListener<T>> keyListeners = new ArrayList<>();
private static class Wrapper<S> {
volatile S value;
@ -33,6 +36,9 @@ public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
wrapper.value = innerMapper.map(preimage);
wrapper.latch.countDown();
wrapper.latch = null;
for (KeyListener<T> listener : keyListeners) {
listener.keyAdded(preimage);
}
} else {
CountDownLatch latch = oldWrapper.latch;
try {
@ -52,4 +58,12 @@ public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
public Collection<T> getCachedPreimages() {
return new HashSet<>(cache.keySet());
}
public void addKeyListener(KeyListener<T> listener) {
keyListeners.add(listener);
}
public static interface KeyListener<S> {
void keyAdded(S key);
}
}

View File

@ -17,8 +17,12 @@ package org.teavm.dependency;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.teavm.codegen.ConcurrentCachedMapper;
import org.teavm.codegen.ConcurrentCachedMapper.KeyListener;
import org.teavm.codegen.Mapper;
import org.teavm.model.*;
@ -54,6 +58,11 @@ public class DependencyChecker {
return createFieldNode(preimage);
}
});
methodCache.addKeyListener(new KeyListener<MethodReference>() {
@Override public void keyAdded(MethodReference key) {
activateDependencyPlugin(key);
}
});
}
public DependencyNode createNode() {
@ -198,4 +207,28 @@ public class DependencyChecker {
}
return node;
}
private void activateDependencyPlugin(MethodReference methodRef) {
ClassHolder cls = classSource.getClassHolder(methodRef.getClassName());
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
AnnotationHolder depAnnot = method.getAnnotations().get(PluggableDependency.class.getName());
if (depAnnot == null) {
return;
}
ValueType depType = depAnnot.getValues().get("value").getJavaClass();
String depClassName = ((ValueType.Object)depType).getClassName();
Class<?> depClass;
try {
depClass = Class.forName(depClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Dependency plugin not found: " + depClassName, e);
}
DependencyPlugin plugin;
try {
plugin = (DependencyPlugin)depClass.newInstance();
} catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e);
}
plugin.methodAchieved(this, methodRef);
}
}

View File

@ -0,0 +1,11 @@
package org.teavm.dependency;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public interface DependencyPlugin {
void methodAchieved(DependencyChecker checker, MethodReference method);
}

View File

@ -0,0 +1,16 @@
package org.teavm.dependency;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Alexey Andreev
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PluggableDependency {
Class<? extends DependencyPlugin> value();
}