From 5fb1623c4eb7d09acc18c2899d4cdb4555709db9 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 20 Nov 2017 20:08:11 +0300 Subject: [PATCH] Add utility method to automatically register extensions in bootstrap mode --- .../java/org/teavm/vm/TeaVMPluginUtil.java | 143 ++++++++++++++++++ .../teavm/platform/plugin/PlatformPlugin.java | 6 + 2 files changed, 149 insertions(+) create mode 100644 core/src/main/java/org/teavm/vm/TeaVMPluginUtil.java diff --git a/core/src/main/java/org/teavm/vm/TeaVMPluginUtil.java b/core/src/main/java/org/teavm/vm/TeaVMPluginUtil.java new file mode 100644 index 000000000..14159566d --- /dev/null +++ b/core/src/main/java/org/teavm/vm/TeaVMPluginUtil.java @@ -0,0 +1,143 @@ +/* + * 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.vm; + +import static org.teavm.metaprogramming.Metaprogramming.emit; +import static org.teavm.metaprogramming.Metaprogramming.findClass; +import java.lang.reflect.Modifier; +import org.teavm.backend.javascript.TeaVMJavaScriptHost; +import org.teavm.backend.javascript.spi.GeneratedBy; +import org.teavm.backend.javascript.spi.Generator; +import org.teavm.backend.javascript.spi.InjectedBy; +import org.teavm.backend.javascript.spi.Injector; +import org.teavm.dependency.PluggableDependency; +import org.teavm.interop.PlatformMarker; +import org.teavm.metaprogramming.CompileTime; +import org.teavm.metaprogramming.Meta; +import org.teavm.metaprogramming.ReflectClass; +import org.teavm.metaprogramming.Value; +import org.teavm.metaprogramming.reflect.ReflectMethod; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; +import org.teavm.vm.spi.TeaVMHost; + +@CompileTime +public final class TeaVMPluginUtil { + private TeaVMPluginUtil() { + } + + public static void handleNatives(TeaVMHost host, Class cls) { + if (!isBootstrap()) { + return; + } + + handleNativesImpl(host, host.getExtension(TeaVMJavaScriptHost.class), cls); + } + + @PlatformMarker + private static boolean isBootstrap() { + return false; + } + + @Meta + private static native void handleNativesImpl(TeaVMHost host, TeaVMJavaScriptHost jsHost, Class cls); + + private static void handleNativesImpl(Value host, Value jsHost, + ReflectClass cls) { + + + for (ReflectMethod method : cls.getDeclaredMethods()) { + if (!Modifier.isNative(method.getModifiers())) { + continue; + } + + GeneratedBy generatedBy = method.getAnnotation(GeneratedBy.class); + if (generatedBy != null) { + ReflectClass generatorClass = findClass(generatedBy.value().getName()); + ReflectMethod generatorConstructor = generatorClass.getMethod(""); + + Value methodRef = methodToReference(method); + emit(() -> jsHost.get().add(methodRef.get(), (Generator) generatorConstructor.construct())); + } + + InjectedBy injectedBy = method.getAnnotation(InjectedBy.class); + if (injectedBy != null) { + ReflectClass generatorClass = findClass(injectedBy.value().getName()); + ReflectMethod generatorConstructor = generatorClass.getMethod(""); + + Value methodRef = methodToReference(method); + emit(() -> jsHost.get().add(methodRef.get(), (Injector) generatorConstructor.construct())); + } + + PluggableDependency dependency = method.getAnnotation(PluggableDependency.class); + if (dependency != null) { + ReflectClass generatorClass = findClass(dependency.value().getName()); + ReflectMethod generatorConstructor = generatorClass.getMethod(""); + + Value methodRef = methodToReference(method); + //emit(() -> host.get().add(methodRef.get(), (DependencyPlugin) generatorConstructor.construct())); + } + } + } + + private static Value methodToReference(ReflectMethod method) { + int signatureSize = method.getParameterCount() + 1; + Value signature = emit(() -> new ValueType[signatureSize]); + for (int i = 0; i < method.getParameterCount(); ++i) { + Value paramType = classToValueType(method.getParameterType(i)); + int index = i; + emit(() -> signature.get()[index] = paramType.get()); + } + + String className = method.getDeclaringClass().getName(); + String name = method.getName(); + return emit(() -> new MethodReference(className, new MethodDescriptor(name, signature.get()))); + } + + private static Value classToValueType(ReflectClass cls) { + if (cls.isArray()) { + Value itemType = classToValueType(cls.getComponentType()); + return emit(() -> ValueType.arrayOf(itemType.get())); + } else if (cls.isPrimitive()) { + switch (cls.getName()) { + case "boolean": + return emit(() -> ValueType.BOOLEAN); + case "byte": + return emit(() -> ValueType.BYTE); + case "short": + return emit(() -> ValueType.SHORT); + case "char": + return emit(() -> ValueType.CHARACTER); + case "int": + return emit(() -> ValueType.INTEGER); + case "long": + return emit(() -> ValueType.LONG); + case "float": + return emit(() -> ValueType.FLOAT); + case "double": + return emit(() -> ValueType.DOUBLE); + case "void": + return emit(() -> ValueType.VOID); + default: + throw new IllegalArgumentException("Unexpected primitive type: " + cls.getName()); + } + } else { + String name = cls.getName(); + return emit(() -> ValueType.object(name)); + } + } +} diff --git a/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java b/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java index 70a59f9bc..14f6bda5b 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java +++ b/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java @@ -22,7 +22,11 @@ import org.teavm.backend.wasm.intrinsics.WasmIntrinsic; import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.interop.PlatformMarker; +import org.teavm.metaprogramming.Meta; +import org.teavm.metaprogramming.Value; import org.teavm.model.MethodReference; +import org.teavm.platform.Platform; +import org.teavm.vm.TeaVMPluginUtil; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; @@ -65,6 +69,8 @@ public class PlatformPlugin implements TeaVMPlugin { host.add(new EnumDependencySupport()); host.add(new AnnotationDependencySupport()); host.add(new PlatformDependencyListener()); + + TeaVMPluginUtil.handleNatives(host, Platform.class); } @PlatformMarker