Further bootstrapping

This commit is contained in:
Alexey Andreev 2017-11-20 23:05:01 +03:00
parent 5fb1623c4e
commit ff19dc15c9
20 changed files with 298 additions and 37 deletions

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.classlib.impl; package org.teavm.classlib.impl;
import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ServiceLoader; import java.util.ServiceLoader;
@ -22,12 +23,12 @@ import org.teavm.backend.javascript.TeaVMJavaScriptHost;
import org.teavm.classlib.ReflectionSupplier; import org.teavm.classlib.ReflectionSupplier;
import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor; import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor;
import org.teavm.classlib.impl.unicode.CLDRReader; import org.teavm.classlib.impl.unicode.CLDRReader;
import org.teavm.classlib.java.lang.SystemNativeGenerator;
import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener; import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener;
import org.teavm.interop.PlatformMarker; import org.teavm.interop.PlatformMarker;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.platform.PlatformClass; import org.teavm.platform.PlatformClass;
import org.teavm.vm.TeaVMPluginUtil;
import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin; import org.teavm.vm.spi.TeaVMPlugin;
@ -86,9 +87,11 @@ public class JCLPlugin implements TeaVMPlugin {
host.add(new PlatformMarkerSupport()); host.add(new PlatformMarkerSupport());
} }
TeaVMJavaScriptHost jsHost = host.getExtension(TeaVMJavaScriptHost.class); TeaVMPluginUtil.handleNatives(host, Class.class);
jsHost.add(new MethodReference("java.lang.System", "currentTimeMillis", ValueType.LONG), TeaVMPluginUtil.handleNatives(host, ClassLoader.class);
new SystemNativeGenerator()); TeaVMPluginUtil.handleNatives(host, System.class);
TeaVMPluginUtil.handleNatives(host, Array.class);
TeaVMPluginUtil.handleNatives(host, Math.class);
} }
@PlatformMarker @PlatformMarker

View File

@ -102,6 +102,7 @@ public final class TSystem extends TObject {
} }
@DelegateTo("currentTimeMillisLowLevel") @DelegateTo("currentTimeMillisLowLevel")
@GeneratedBy(SystemNativeGenerator.class)
public static native long currentTimeMillis(); public static native long currentTimeMillis();
private static long currentTimeMillisLowLevel() { private static long currentTimeMillisLowLevel() {

View File

@ -53,6 +53,7 @@ import org.teavm.common.GraphIndexer;
import org.teavm.common.Loop; import org.teavm.common.Loop;
import org.teavm.common.LoopGraph; import org.teavm.common.LoopGraph;
import org.teavm.common.RangeTree; import org.teavm.common.RangeTree;
import org.teavm.interop.PlatformMarker;
import org.teavm.model.AnnotationHolder; import org.teavm.model.AnnotationHolder;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderSource;
@ -200,7 +201,7 @@ public class Decompiler {
if (method.getModifiers().contains(ElementModifier.ABSTRACT)) { if (method.getModifiers().contains(ElementModifier.ABSTRACT)) {
continue; continue;
} }
if (method.getAnnotations().get(InjectedBy.class.getName()) != null if ((!isBootstrap() && method.getAnnotations().get(InjectedBy.class.getName()) != null)
|| methodsToSkip.contains(method.getReference())) { || methodsToSkip.contains(method.getReference())) {
continue; continue;
} }
@ -220,7 +221,7 @@ public class Decompiler {
public NativeMethodNode decompileNative(MethodHolder method) { public NativeMethodNode decompileNative(MethodHolder method) {
Generator generator = generators.get(method.getReference()); Generator generator = generators.get(method.getReference());
if (generator == null) { if (generator == null && !isBootstrap()) {
AnnotationHolder annotHolder = method.getAnnotations().get(GeneratedBy.class.getName()); AnnotationHolder annotHolder = method.getAnnotations().get(GeneratedBy.class.getName());
if (annotHolder == null) { if (annotHolder == null) {
throw new DecompilationException("Method " + method.getOwnerName() + "." + method.getDescriptor() throw new DecompilationException("Method " + method.getOwnerName() + "." + method.getDescriptor()
@ -244,6 +245,11 @@ public class Decompiler {
return methodNode; return methodNode;
} }
@PlatformMarker
private static boolean isBootstrap() {
return false;
}
public RegularMethodNode decompileRegular(MethodHolder method) { public RegularMethodNode decompileRegular(MethodHolder method) {
if (regularMethodCache == null || method.getAnnotations().get(NoCache.class.getName()) != null) { if (regularMethodCache == null || method.getAnnotations().get(NoCache.class.getName()) != null) {
return decompileRegularCacheMiss(method); return decompileRegularCacheMiss(method);

View File

@ -26,6 +26,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import org.teavm.ast.ClassNode; import org.teavm.ast.ClassNode;
import org.teavm.ast.cache.EmptyRegularMethodNodeCache; import org.teavm.ast.cache.EmptyRegularMethodNodeCache;
import org.teavm.ast.cache.MethodNodeCache; import org.teavm.ast.cache.MethodNodeCache;
@ -48,10 +49,12 @@ import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.DependencyAnalyzer; import org.teavm.dependency.DependencyAnalyzer;
import org.teavm.dependency.DependencyListener; import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.MethodDependency; import org.teavm.dependency.MethodDependency;
import org.teavm.interop.PlatformMarker;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.ListableClassHolderSource; import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.ListableClassReaderSource; import org.teavm.model.ListableClassReaderSource;
@ -83,6 +86,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
private boolean minifying = true; private boolean minifying = true;
private final Map<MethodReference, Generator> methodGenerators = new HashMap<>(); private final Map<MethodReference, Generator> methodGenerators = new HashMap<>();
private final Map<MethodReference, Injector> methodInjectors = new HashMap<>(); private final Map<MethodReference, Injector> methodInjectors = new HashMap<>();
private final List<Function<ProviderContext, Generator>> generatorProviders = new ArrayList<>();
private final List<Function<ProviderContext, Injector>> injectorProviders = new ArrayList<>();
private final List<RendererListener> rendererListeners = new ArrayList<>(); private final List<RendererListener> rendererListeners = new ArrayList<>();
private DebugInformationEmitter debugEmitter; private DebugInformationEmitter debugEmitter;
private MethodNodeCache astCache = new EmptyRegularMethodNodeCache(); private MethodNodeCache astCache = new EmptyRegularMethodNodeCache();
@ -121,6 +126,16 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
methodInjectors.put(methodRef, injector); methodInjectors.put(methodRef, injector);
} }
@Override
public void addGeneratorProvider(Function<ProviderContext, Generator> provider) {
generatorProviders.add(provider);
}
@Override
public void addInjectorProvider(Function<ProviderContext, Injector> provider) {
injectorProviders.add(provider);
}
/** /**
* Reports whether this TeaVM instance uses obfuscation when generating the JavaScript code. * Reports whether this TeaVM instance uses obfuscation when generating the JavaScript code.
* *
@ -309,7 +324,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
for (String className : classOrder) { for (String className : classOrder) {
ClassHolder cls = classes.get(className); ClassHolder cls = classes.get(className);
for (MethodHolder method : cls.getMethods()) { for (MethodHolder method : cls.getMethods()) {
preprocessNativeMethod(method); preprocessNativeMethod(method, decompiler);
if (controller.wasCancelled()) { if (controller.wasCancelled()) {
break; break;
} }
@ -319,14 +334,44 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
return classNodes; return classNodes;
} }
private void preprocessNativeMethod(MethodHolder method) { private void preprocessNativeMethod(MethodHolder method, Decompiler decompiler) {
if (!method.getModifiers().contains(ElementModifier.NATIVE) if (!method.getModifiers().contains(ElementModifier.NATIVE)
|| methodGenerators.get(method.getReference()) != null || methodGenerators.get(method.getReference()) != null
|| methodInjectors.get(method.getReference()) != null || methodInjectors.get(method.getReference()) != null) {
|| method.getAnnotations().get(GeneratedBy.class.getName()) != null return;
}
boolean found = false;
ProviderContext context = new ProviderContextImpl(method.getReference());
for (Function<ProviderContext, Generator> provider : generatorProviders) {
Generator generator = provider.apply(context);
if (generator != null) {
methodGenerators.put(method.getReference(), generator);
decompiler.addGenerator(method.getReference(), generator);
found = true;
break;
}
}
for (Function<ProviderContext, Injector> provider : injectorProviders) {
Injector injector = provider.apply(context);
if (injector != null) {
methodInjectors.put(method.getReference(), injector);
decompiler.addMethodToSkip(method.getReference());
found = true;
break;
}
}
if (found) {
return;
}
if (!isBootstrap()) {
if (method.getAnnotations().get(GeneratedBy.class.getName()) != null
|| method.getAnnotations().get(InjectedBy.class.getName()) != null) { || method.getAnnotations().get(InjectedBy.class.getName()) != null) {
return; return;
} }
}
method.getModifiers().remove(ElementModifier.NATIVE); method.getModifiers().remove(ElementModifier.NATIVE);
Program program = new Program(); Program program = new Program();
@ -364,6 +409,29 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
"Native method {{m0}} has no implementation", method.getReference()); "Native method {{m0}} has no implementation", method.getReference());
} }
class ProviderContextImpl implements ProviderContext {
private MethodReference method;
ProviderContextImpl(MethodReference method) {
this.method = method;
}
@Override
public MethodReference getMethod() {
return method;
}
@Override
public ClassReaderSource getClassSource() {
return controller.getUnprocessedClassSource();
}
}
@PlatformMarker
private static boolean isBootstrap() {
return false;
}
private void emitCFG(DebugInformationEmitter emitter, Program program) { private void emitCFG(DebugInformationEmitter emitter, Program program) {
Map<TextLocation, TextLocation[]> cfg = ProgramUtils.getLocationCFG(program); Map<TextLocation, TextLocation[]> cfg = ProgramUtils.getLocationCFG(program);
for (Map.Entry<TextLocation, TextLocation[]> entry : cfg.entrySet()) { for (Map.Entry<TextLocation, TextLocation[]> entry : cfg.entrySet()) {

View File

@ -0,0 +1,25 @@
/*
* Copyright 2017 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.javascript;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference;
public interface ProviderContext {
MethodReference getMethod();
ClassReaderSource getClassSource();
}

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.backend.javascript; package org.teavm.backend.javascript;
import java.util.function.Function;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.Injector; import org.teavm.backend.javascript.spi.Injector;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -26,5 +27,9 @@ public interface TeaVMJavaScriptHost extends TeaVMHostExtension {
void add(MethodReference methodRef, Injector injector); void add(MethodReference methodRef, Injector injector);
void addGeneratorProvider(Function<ProviderContext, Generator> provider);
void addInjectorProvider(Function<ProviderContext, Injector> provider);
void add(RendererListener listener); void add(RendererListener listener);
} }

View File

@ -176,7 +176,7 @@ public class Renderer implements RenderingManager {
private void renderSetCloneMethod() throws IOException { private void renderSetCloneMethod() throws IOException {
writer.append("function $rt_setCloneMethod(target, f)").ws().append("{").softNewLine().indent(); writer.append("function $rt_setCloneMethod(target, f)").ws().append("{").softNewLine().indent();
writer.append("target.").appendMethod("clone", Object.class).ws().append('=').ws().append("f;"). writer.append("target.").appendMethod("clone", Object.class).ws().append('=').ws().append("f;").
softNewLine().indent(); softNewLine();
writer.outdent().append("}").newLine(); writer.outdent().append("}").newLine();
} }

View File

@ -30,6 +30,7 @@ import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.backend.javascript.spi.Injector; import org.teavm.backend.javascript.spi.Injector;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.interop.PlatformMarker;
import org.teavm.model.AnnotationReader; import org.teavm.model.AnnotationReader;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ListableClassReaderSource; import org.teavm.model.ListableClassReaderSource;
@ -243,6 +244,7 @@ public class RenderingContext {
InjectorHolder holder = injectorMap.get(ref); InjectorHolder holder = injectorMap.get(ref);
if (holder == null) { if (holder == null) {
holder = new InjectorHolder(null); holder = new InjectorHolder(null);
if (!isBootstrap()) {
ClassReader cls = classSource.get(ref.getClassName()); ClassReader cls = classSource.get(ref.getClassName());
if (cls != null) { if (cls != null) {
MethodReader method = cls.getMethod(ref.getDescriptor()); MethodReader method = cls.getMethod(ref.getDescriptor());
@ -254,11 +256,17 @@ public class RenderingContext {
} }
} }
} }
}
injectorMap.put(ref, holder); injectorMap.put(ref, holder);
} }
return holder.injector; return holder.injector;
} }
@PlatformMarker
private static boolean isBootstrap() {
return false;
}
private Injector instantiateInjector(String type) { private Injector instantiateInjector(String type) {
try { try {
Class<? extends Injector> cls = Class.forName(type, true, classLoader).asSubclass(Injector.class); Class<? extends Injector> cls = Class.forName(type, true, classLoader).asSubclass(Injector.class);

View File

@ -35,6 +35,7 @@ import org.teavm.common.CachedMapper;
import org.teavm.common.Mapper; import org.teavm.common.Mapper;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.PlatformMarker;
import org.teavm.model.AnnotationReader; import org.teavm.model.AnnotationReader;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
@ -83,6 +84,7 @@ public class DependencyAnalyzer implements DependencyInfo {
DefaultCallGraph callGraph = new DefaultCallGraph(); DefaultCallGraph callGraph = new DefaultCallGraph();
private DependencyAgent agent; private DependencyAgent agent;
Map<MethodReference, BootstrapMethodSubstitutor> bootstrapMethodSubstitutors = new HashMap<>(); Map<MethodReference, BootstrapMethodSubstitutor> bootstrapMethodSubstitutors = new HashMap<>();
Map<MethodReference, DependencyPlugin> dependencyPlugins = new HashMap<>();
private boolean completing; private boolean completing;
private Map<String, SuperClassFilter> superClassFilters = new HashMap<>(); private Map<String, SuperClassFilter> superClassFilters = new HashMap<>();
@ -320,6 +322,10 @@ public class DependencyAnalyzer implements DependencyInfo {
private Set<String> classesAddedByRoot = new HashSet<>(); private Set<String> classesAddedByRoot = new HashSet<>();
public void defer(Runnable task) {
deferredTasks.add(task);
}
public ClassDependency linkClass(String className, CallLocation callLocation) { public ClassDependency linkClass(String className, CallLocation callLocation) {
if (completing && getClass(className) == null) { if (completing && getClass(className) == null) {
throw new IllegalStateException("Can't link class during completion phase"); throw new IllegalStateException("Can't link class during completion phase");
@ -526,6 +532,12 @@ public class DependencyAnalyzer implements DependencyInfo {
return; return;
} }
methodDep.dependencyPluginAttached = true; methodDep.dependencyPluginAttached = true;
methodDep.dependencyPlugin = dependencyPlugins.get(methodDep.getReference());
if (methodDep.dependencyPlugin != null || isBootstrap()) {
return;
}
AnnotationReader depAnnot = methodDep.getMethod().getAnnotations().get(PluggableDependency.class.getName()); AnnotationReader depAnnot = methodDep.getMethod().getAnnotations().get(PluggableDependency.class.getName());
if (depAnnot == null) { if (depAnnot == null) {
return; return;
@ -545,6 +557,11 @@ public class DependencyAnalyzer implements DependencyInfo {
} }
} }
@PlatformMarker
private static boolean isBootstrap() {
return false;
}
@Override @Override
public MethodDependency getMethod(MethodReference methodRef) { public MethodDependency getMethod(MethodReference methodRef) {
return methodCache.getKnown(methodRef); return methodCache.getKnown(methodRef);
@ -660,6 +677,10 @@ public class DependencyAnalyzer implements DependencyInfo {
bootstrapMethodSubstitutors.put(method, substitutor); bootstrapMethodSubstitutors.put(method, substitutor);
} }
public void addDependencyPlugin(MethodReference method, DependencyPlugin dependencyPlugin) {
dependencyPlugins.put(method, dependencyPlugin);
}
SuperClassFilter getSuperClassFilter(String superClass) { SuperClassFilter getSuperClassFilter(String superClass) {
return superClassFilters.computeIfAbsent(superClass, s -> new SuperClassFilter(classSource, s)); return superClassFilters.computeIfAbsent(superClass, s -> new SuperClassFilter(classSource, s));
} }

View File

@ -164,7 +164,7 @@ public class AsyncMethodFinder {
return; return;
} else { } else {
diagnostics.warning(new CallLocation(methodRef), "Error as Warning because " diagnostics.warning(new CallLocation(methodRef), "Error as Warning because "
+ " Method {{m0}} has @SuppressSyncErrors annoation. Method {{m0}} " + " Method {{m0}} has @SuppressSyncErrors annotation. Method {{m0}} "
+ "is claimed to be synchronous, but it is has invocations of " + "is claimed to be synchronous, but it is has invocations of "
+ "asynchronous methods:" + stack.toString(), methodRef); + "asynchronous methods:" + stack.toString(), methodRef);
} }

View File

@ -33,6 +33,7 @@ import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DependencyAnalyzer; import org.teavm.dependency.DependencyAnalyzer;
import org.teavm.dependency.DependencyInfo; import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.DependencyListener; import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.Linker; import org.teavm.dependency.Linker;
import org.teavm.diagnostics.AccumulationDiagnostics; import org.teavm.diagnostics.AccumulationDiagnostics;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
@ -164,6 +165,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
dependencyAnalyzer.addBootstrapMethodSubstitutor(methodRef, substitutor); dependencyAnalyzer.addBootstrapMethodSubstitutor(methodRef, substitutor);
} }
@Override
public void add(MethodReference methodRef, DependencyPlugin dependencyPlugin) {
dependencyAnalyzer.addDependencyPlugin(methodRef, dependencyPlugin);
}
@Override @Override
public ClassLoader getClassLoader() { public ClassLoader getClassLoader() {
return classLoader; return classLoader;
@ -249,7 +255,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
} }
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyAnalyzer.linkMethod(ref, null)); TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyAnalyzer.linkMethod(ref, null));
dependencyAnalyzer.defer(() -> {
dependencyAnalyzer.linkClass(ref.getClassName(), null).initClass(null); dependencyAnalyzer.linkClass(ref.getClassName(), null).initClass(null);
});
if (name != null) { if (name != null) {
entryPoints.put(name, entryPoint); entryPoints.put(name, entryPoint);
} }
@ -274,7 +282,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
public TeaVMEntryPoint linkMethod(MethodReference ref) { public TeaVMEntryPoint linkMethod(MethodReference ref) {
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, dependencyAnalyzer.linkMethod(ref, null)); TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, dependencyAnalyzer.linkMethod(ref, null));
dependencyAnalyzer.defer(() -> {
dependencyAnalyzer.linkClass(ref.getClassName(), null).initClass(null); dependencyAnalyzer.linkClass(ref.getClassName(), null).initClass(null);
});
return entryPoint; return entryPoint;
} }
@ -283,7 +293,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class "
+ className); + className);
} }
dependencyAnalyzer.defer(() -> {
dependencyAnalyzer.linkClass(className, null).initClass(null); dependencyAnalyzer.linkClass(className, null).initClass(null);
});
exportedClasses.put(name, className); exportedClasses.put(name, className);
} }

View File

@ -23,6 +23,7 @@ import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.backend.javascript.spi.Injector; import org.teavm.backend.javascript.spi.Injector;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.PluggableDependency; import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.PlatformMarker; import org.teavm.interop.PlatformMarker;
import org.teavm.metaprogramming.CompileTime; import org.teavm.metaprogramming.CompileTime;
@ -58,8 +59,6 @@ public final class TeaVMPluginUtil {
private static void handleNativesImpl(Value<TeaVMHost> host, Value<TeaVMJavaScriptHost> jsHost, private static void handleNativesImpl(Value<TeaVMHost> host, Value<TeaVMJavaScriptHost> jsHost,
ReflectClass<?> cls) { ReflectClass<?> cls) {
for (ReflectMethod method : cls.getDeclaredMethods()) { for (ReflectMethod method : cls.getDeclaredMethods()) {
if (!Modifier.isNative(method.getModifiers())) { if (!Modifier.isNative(method.getModifiers())) {
continue; continue;
@ -89,7 +88,7 @@ public final class TeaVMPluginUtil {
ReflectMethod generatorConstructor = generatorClass.getMethod("<init>"); ReflectMethod generatorConstructor = generatorClass.getMethod("<init>");
Value<MethodReference> methodRef = methodToReference(method); Value<MethodReference> methodRef = methodToReference(method);
//emit(() -> host.get().add(methodRef.get(), (DependencyPlugin) generatorConstructor.construct())); emit(() -> host.get().add(methodRef.get(), (DependencyPlugin) generatorConstructor.construct()));
} }
} }
} }
@ -102,6 +101,8 @@ public final class TeaVMPluginUtil {
int index = i; int index = i;
emit(() -> signature.get()[index] = paramType.get()); emit(() -> signature.get()[index] = paramType.get());
} }
Value<ValueType> returnType = classToValueType(method.getReturnType());
emit(() -> signature.get()[signatureSize - 1] = returnType.get());
String className = method.getDeclaringClass().getName(); String className = method.getDeclaringClass().getName();
String name = method.getName(); String name = method.getName();

View File

@ -18,6 +18,7 @@ package org.teavm.vm.spi;
import java.util.Properties; import java.util.Properties;
import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DependencyListener; import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.vm.TeaVM; import org.teavm.vm.TeaVM;
@ -36,6 +37,8 @@ public interface TeaVMHost {
void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor); void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor);
void add(MethodReference methodRef, DependencyPlugin dependencyPlugin);
<T extends TeaVMHostExtension> T getExtension(Class<T> extensionType); <T extends TeaVMHostExtension> T getExtension(Class<T> extensionType);
<T> void registerService(Class<T> type, T instance); <T> void registerService(Class<T> type, T instance);

View File

@ -0,0 +1,26 @@
/*
* Copyright 2017 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
@interface DynamicGenerator {
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2017 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
@interface DynamicInjector {
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2017 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
import java.util.function.Function;
import org.teavm.backend.javascript.ProviderContext;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
class GeneratorAnnotationInstaller<T> implements Function<ProviderContext, T> {
private T generator;
private String annotationName;
GeneratorAnnotationInstaller(T generator, String annotationName) {
this.generator = generator;
this.annotationName = annotationName;
}
@Override
public T apply(ProviderContext providerContext) {
ClassReaderSource classSource = providerContext.getClassSource();
MethodReference methodRef = providerContext.getMethod();
ClassReader cls = classSource.get(methodRef.getClassName());
if (cls == null) {
return null;
}
MethodReader method = cls.getMethod(methodRef.getDescriptor());
if (method == null) {
return null;
}
return method.getAnnotations().get(annotationName) != null ? generator : null;
}
}

View File

@ -30,8 +30,6 @@ import org.mozilla.javascript.Context;
import org.mozilla.javascript.ast.AstNode; import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.FunctionNode; import org.mozilla.javascript.ast.FunctionNode;
import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.cache.NoCache; import org.teavm.cache.NoCache;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Sync; import org.teavm.interop.Sync;
@ -592,9 +590,7 @@ class JSClassProcessor {
proxyMethod.getModifiers().add(ElementModifier.STATIC); proxyMethod.getModifiers().add(ElementModifier.STATIC);
boolean inline = repository.inlineMethods.contains(methodRef); boolean inline = repository.inlineMethods.contains(methodRef);
AnnotationHolder generatorAnnot = new AnnotationHolder(inline AnnotationHolder generatorAnnot = new AnnotationHolder(inline
? InjectedBy.class.getName() : GeneratedBy.class.getName()); ? DynamicInjector.class.getName() : DynamicGenerator.class.getName());
generatorAnnot.getValues().put("value",
new AnnotationValue(ValueType.parse(JSBodyGenerator.class)));
proxyMethod.getAnnotations().add(generatorAnnot); proxyMethod.getAnnotations().add(generatorAnnot);
cls.addMethod(proxyMethod); cls.addMethod(proxyMethod);

View File

@ -16,13 +16,15 @@
package org.teavm.jso.impl; package org.teavm.jso.impl;
import org.teavm.backend.javascript.TeaVMJavaScriptHost; import org.teavm.backend.javascript.TeaVMJavaScriptHost;
import org.teavm.vm.TeaVMPluginUtil;
import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin; import org.teavm.vm.spi.TeaVMPlugin;
public class JSOPlugin implements TeaVMPlugin { public class JSOPlugin implements TeaVMPlugin {
@Override @Override
public void install(TeaVMHost host) { public void install(TeaVMHost host) {
if (host.getExtension(TeaVMJavaScriptHost.class) == null) { TeaVMJavaScriptHost jsHost = host.getExtension(TeaVMJavaScriptHost.class);
if (jsHost == null) {
return; return;
} }
@ -32,6 +34,14 @@ public class JSOPlugin implements TeaVMPlugin {
JSDependencyListener dependencyListener = new JSDependencyListener(repository); JSDependencyListener dependencyListener = new JSDependencyListener(repository);
JSAliasRenderer aliasRenderer = new JSAliasRenderer(); JSAliasRenderer aliasRenderer = new JSAliasRenderer();
host.add(dependencyListener); host.add(dependencyListener);
host.getExtension(TeaVMJavaScriptHost.class).add(aliasRenderer);
jsHost.add(aliasRenderer);
jsHost.addGeneratorProvider(new GeneratorAnnotationInstaller<>(new JSBodyGenerator(),
DynamicGenerator.class.getName()));
jsHost.addInjectorProvider(new GeneratorAnnotationInstaller<>(new JSBodyGenerator(),
DynamicInjector.class.getName()));
TeaVMPluginUtil.handleNatives(host, JS.class);
} }
} }

View File

@ -60,7 +60,7 @@ public class ReflectClassImpl<T> implements ReflectClass<T> {
@Override @Override
public boolean isPrimitive() { public boolean isPrimitive() {
return type instanceof ValueType.Primitive; return type instanceof ValueType.Primitive || type == ValueType.VOID;
} }
@Override @Override

View File

@ -22,10 +22,9 @@ import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager; import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.interop.PlatformMarker; import org.teavm.interop.PlatformMarker;
import org.teavm.metaprogramming.Meta;
import org.teavm.metaprogramming.Value;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
import org.teavm.platform.PlatformQueue;
import org.teavm.vm.TeaVMPluginUtil; import org.teavm.vm.TeaVMPluginUtil;
import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin; import org.teavm.vm.spi.TeaVMPlugin;
@ -71,6 +70,7 @@ public class PlatformPlugin implements TeaVMPlugin {
host.add(new PlatformDependencyListener()); host.add(new PlatformDependencyListener());
TeaVMPluginUtil.handleNatives(host, Platform.class); TeaVMPluginUtil.handleNatives(host, Platform.class);
TeaVMPluginUtil.handleNatives(host, PlatformQueue.class);
} }
@PlatformMarker @PlatformMarker