Automatically make all JSObject implementors' methods as @Sync

This commit is contained in:
konsoletyper 2015-02-24 20:12:56 +03:00
parent 4908293e50
commit 0c5fb8d9b0
3 changed files with 86 additions and 3 deletions

View File

@ -28,12 +28,17 @@ public class JSObjectClassTransformer implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
if (processor == null || processor.getClassSource() != innerSource) {
processor = new JavascriptNativeProcessor(innerSource);
}
processor.setDiagnostics(diagnostics);
processor.processClass(cls);
if (processor.isNative(cls.getName())) {
processor.processFinalMethods(cls);
}
if (processor.isNativeImplementation(cls.getName())) {
processor.makeSync(cls);
}
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
if (method.getAnnotations().get(JSBody.class.getName()) != null) {
processor.processJSBody(cls, method);

View File

@ -18,6 +18,7 @@ package org.teavm.jso.plugin;
import java.util.*;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.Sync;
import org.teavm.jso.*;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
@ -41,10 +42,18 @@ class JavascriptNativeProcessor {
nativeRepos = new NativeJavascriptClassRepository(classSource);
}
public ClassReaderSource getClassSource() {
return classSource;
}
public boolean isNative(String className) {
return nativeRepos.isJavaScriptClass(className);
}
public boolean isNativeImplementation(String className) {
return nativeRepos.isJavaScriptImplementation(className);
}
public void setDiagnostics(Diagnostics diagnostics) {
this.diagnostics = diagnostics;
}
@ -111,6 +120,44 @@ class JavascriptNativeProcessor {
}
}
public void makeSync(ClassHolder cls) {
Set<MethodDescriptor> methods = new HashSet<>();
findInheritedMethods(cls, methods, new HashSet<String>());
for (MethodHolder method : cls.getMethods()) {
if (methods.contains(method.getDescriptor()) && method.getAnnotations().get(Sync.class.getName()) == null) {
AnnotationHolder annot = new AnnotationHolder(Sync.class.getName());
method.getAnnotations().add(annot);
}
}
}
private void findInheritedMethods(ClassReader cls, Set<MethodDescriptor> methods, Set<String> visited) {
if (!visited.add(cls.getName())) {
return;
}
if (isNative(cls.getName())) {
for (MethodReader method : cls.getMethods()) {
if (!method.hasModifier(ElementModifier.STATIC) && !method.hasModifier(ElementModifier.FINAL) &&
method.getLevel() != AccessLevel.PRIVATE) {
methods.add(method.getDescriptor());
}
}
} else if (isNativeImplementation(cls.getName())) {
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
ClassReader parentCls = classSource.get(cls.getParent());
if (parentCls != null) {
findInheritedMethods(parentCls, methods, visited);
}
}
for (String iface : cls.getInterfaces()) {
ClassReader parentCls = classSource.get(iface);
if (parentCls != null) {
findInheritedMethods(parentCls, methods, visited);
}
}
}
}
private static ValueType[] getStaticSignature(MethodReference method) {
ValueType[] signature = method.getSignature();
ValueType[] staticSignature = new ValueType[signature.length + 1];

View File

@ -29,6 +29,7 @@ import org.teavm.model.ElementModifier;
class NativeJavascriptClassRepository {
private ClassReaderSource classSource;
private Map<String, Boolean> knownJavaScriptClasses = new HashMap<>();
private Map<String, Boolean> knownJavaScriptImplementations = new HashMap<>();
public NativeJavascriptClassRepository(ClassReaderSource classSource) {
this.classSource = classSource;
@ -38,13 +39,22 @@ class NativeJavascriptClassRepository {
public boolean isJavaScriptClass(String className) {
Boolean known = knownJavaScriptClasses.get(className);
if (known == null) {
known = figureOutIfJavaScriptClass(className);
known = examineIfJavaScriptClass(className);
knownJavaScriptClasses.put(className, known);
}
return known;
}
private boolean figureOutIfJavaScriptClass(String className) {
public boolean isJavaScriptImplementation(String className) {
Boolean known = knownJavaScriptImplementations.get(className);
if (known == null) {
known = examineIfJavaScriptImplementation(className);
knownJavaScriptImplementations.put(className, known);
}
return known;
}
private boolean examineIfJavaScriptClass(String className) {
ClassReader cls = classSource.get(className);
if (cls == null || !(cls.hasModifier(ElementModifier.INTERFACE) || cls.hasModifier(ElementModifier.ABSTRACT))) {
return false;
@ -56,4 +66,25 @@ class NativeJavascriptClassRepository {
}
return false;
}
private boolean examineIfJavaScriptImplementation(String className) {
if (isJavaScriptClass(className)) {
return false;
}
ClassReader cls = classSource.get(className);
if (cls == null) {
return false;
}
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
if (isJavaScriptClass(cls.getParent())) {
return true;
}
}
for (String iface : cls.getInterfaces()) {
if (isJavaScriptClass(iface)) {
return true;
}
}
return false;
}
}