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; package org.teavm.classlib.java.lang;
import org.teavm.codegen.SourceWriter; 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.Generator;
import org.teavm.javascript.ni.GeneratorContext; import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
@ -11,7 +14,7 @@ import org.teavm.model.ValueType;
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class ObjectNativeGenerator implements Generator { public class ObjectNativeGenerator implements Generator, DependencyPlugin {
@Override @Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) { public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
switch (methodRef.getDescriptor().getName()) { 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) { private void generateInit(GeneratorContext context, SourceWriter writer) {
writer.append(context.getParameterName(0)).append(".$id = $rt_nextId();").newLine(); writer.append(context.getParameterName(0)).append(".$id = $rt_nextId();").newLine();
} }
@ -50,6 +65,13 @@ public class ObjectNativeGenerator implements Generator {
writer.append("return cls;").newLine(); 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) { private void generateHashCode(GeneratorContext context, SourceWriter writer) {
writer.append("return ").append(context.getParameterName(0)).append(".$id;").newLine(); 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("copy[field] = obj[field];").newLine().outdent().append("}").newLine();
writer.append("return copy;").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; package org.teavm.classlib.java.lang;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy; import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.Rename; import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.ni.Superclass; import org.teavm.javascript.ni.Superclass;
@ -20,6 +21,7 @@ public class TObject {
@GeneratedBy(ObjectNativeGenerator.class) @GeneratedBy(ObjectNativeGenerator.class)
@Rename("getClass") @Rename("getClass")
@PluggableDependency(ObjectNativeGenerator.class)
public native final TClass<?> getClass0(); public native final TClass<?> getClass0();
@Override @Override
@ -31,6 +33,7 @@ public class TObject {
@Override @Override
@GeneratedBy(ObjectNativeGenerator.class) @GeneratedBy(ObjectNativeGenerator.class)
@PluggableDependency(ObjectNativeGenerator.class)
protected native TObject clone(); protected native TObject clone();
@Rename("notify") @Rename("notify")

View File

@ -1,7 +1,9 @@
package org.teavm.codegen; package org.teavm.codegen;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -13,6 +15,7 @@ import java.util.concurrent.CountDownLatch;
public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> { public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
private Mapper<T, R> innerMapper; private Mapper<T, R> innerMapper;
private ConcurrentMap<T, Wrapper<R>> cache = new ConcurrentHashMap<>(); private ConcurrentMap<T, Wrapper<R>> cache = new ConcurrentHashMap<>();
private List<KeyListener<T>> keyListeners = new ArrayList<>();
private static class Wrapper<S> { private static class Wrapper<S> {
volatile S value; volatile S value;
@ -33,6 +36,9 @@ public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
wrapper.value = innerMapper.map(preimage); wrapper.value = innerMapper.map(preimage);
wrapper.latch.countDown(); wrapper.latch.countDown();
wrapper.latch = null; wrapper.latch = null;
for (KeyListener<T> listener : keyListeners) {
listener.keyAdded(preimage);
}
} else { } else {
CountDownLatch latch = oldWrapper.latch; CountDownLatch latch = oldWrapper.latch;
try { try {
@ -52,4 +58,12 @@ public class ConcurrentCachedMapper<T, R> implements Mapper<T, R> {
public Collection<T> getCachedPreimages() { public Collection<T> getCachedPreimages() {
return new HashSet<>(cache.keySet()); 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.Collection;
import java.util.HashSet; 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;
import org.teavm.codegen.ConcurrentCachedMapper.KeyListener;
import org.teavm.codegen.Mapper; import org.teavm.codegen.Mapper;
import org.teavm.model.*; import org.teavm.model.*;
@ -54,6 +58,11 @@ public class DependencyChecker {
return createFieldNode(preimage); return createFieldNode(preimage);
} }
}); });
methodCache.addKeyListener(new KeyListener<MethodReference>() {
@Override public void keyAdded(MethodReference key) {
activateDependencyPlugin(key);
}
});
} }
public DependencyNode createNode() { public DependencyNode createNode() {
@ -198,4 +207,28 @@ public class DependencyChecker {
} }
return node; 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();
}