From 91a50605bce3a01f884bd7f51e1019c35c958e3c Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 17 Nov 2013 16:20:23 +0400 Subject: [PATCH] Dependency plugin support added --- .../java/lang/ObjectNativeGenerator.java | 29 ++++++++++++++- .../org/teavm/classlib/java/lang/TObject.java | 3 ++ .../teavm/codegen/ConcurrentCachedMapper.java | 14 ++++++++ .../teavm/dependency/DependencyChecker.java | 35 ++++++++++++++++++- .../teavm/dependency/DependencyPlugin.java | 11 ++++++ .../teavm/dependency/PluggableDependency.java | 16 +++++++++ 6 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java create mode 100644 teavm-core/src/main/java/org/teavm/dependency/PluggableDependency.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java index 026202330..48258dc2f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java @@ -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 */ -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()); + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index dfd3affd6..b0a2083c7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -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") diff --git a/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java b/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java index e172598fb..10f6e2dec 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java +++ b/teavm-core/src/main/java/org/teavm/codegen/ConcurrentCachedMapper.java @@ -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 implements Mapper { private Mapper innerMapper; private ConcurrentMap> cache = new ConcurrentHashMap<>(); + private List> keyListeners = new ArrayList<>(); private static class Wrapper { volatile S value; @@ -33,6 +36,9 @@ public class ConcurrentCachedMapper implements Mapper { wrapper.value = innerMapper.map(preimage); wrapper.latch.countDown(); wrapper.latch = null; + for (KeyListener listener : keyListeners) { + listener.keyAdded(preimage); + } } else { CountDownLatch latch = oldWrapper.latch; try { @@ -52,4 +58,12 @@ public class ConcurrentCachedMapper implements Mapper { public Collection getCachedPreimages() { return new HashSet<>(cache.keySet()); } + + public void addKeyListener(KeyListener listener) { + keyListeners.add(listener); + } + + public static interface KeyListener { + void keyAdded(S key); + } } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java index 99c12487c..33a91dd19 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -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() { + @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); + } } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java new file mode 100644 index 000000000..c6c3fbae2 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java @@ -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); +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/PluggableDependency.java b/teavm-core/src/main/java/org/teavm/dependency/PluggableDependency.java new file mode 100644 index 000000000..d7ab81691 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/PluggableDependency.java @@ -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 value(); +}