Get rid of reflection code

This commit is contained in:
Alexey Andreev 2019-03-22 11:32:48 +03:00
parent ac627580c6
commit 955ac92035
19 changed files with 219 additions and 317 deletions

View File

@ -23,18 +23,44 @@ import org.teavm.backend.c.TeaVMCHost;
import org.teavm.backend.javascript.TeaVMJavaScriptHost;
import org.teavm.backend.wasm.TeaVMWasmHost;
import org.teavm.classlib.ReflectionSupplier;
import org.teavm.classlib.impl.currency.CountriesGenerator;
import org.teavm.classlib.impl.currency.CurrenciesGenerator;
import org.teavm.classlib.impl.currency.CurrencyHelper;
import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor;
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
import org.teavm.classlib.impl.tz.DateTimeZoneProviderIntrinsic;
import org.teavm.classlib.impl.tz.TimeZoneGenerator;
import org.teavm.classlib.impl.unicode.AvailableLocalesMetadataGenerator;
import org.teavm.classlib.impl.unicode.CLDRHelper;
import org.teavm.classlib.impl.unicode.CLDRReader;
import org.teavm.classlib.impl.unicode.CountryMetadataGenerator;
import org.teavm.classlib.impl.unicode.CurrencyLocalizationMetadataGenerator;
import org.teavm.classlib.impl.unicode.DateFormatMetadataGenerator;
import org.teavm.classlib.impl.unicode.DateSymbolsMetadataGenerator;
import org.teavm.classlib.impl.unicode.DecimalMetadataGenerator;
import org.teavm.classlib.impl.unicode.DefaultLocaleMetadataGenerator;
import org.teavm.classlib.impl.unicode.LanguageMetadataGenerator;
import org.teavm.classlib.impl.unicode.LikelySubtagsMetadataGenerator;
import org.teavm.classlib.impl.unicode.NumberFormatMetadataGenerator;
import org.teavm.classlib.impl.unicode.TimeZoneLocalizationGenerator;
import org.teavm.classlib.java.lang.CharacterMetadataGenerator;
import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener;
import org.teavm.interop.PlatformMarker;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.platform.PlatformClass;
import org.teavm.platform.metadata.ClassResource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource;
import org.teavm.platform.plugin.MetadataRegistration;
import org.teavm.platform.plugin.PlatformPlugin;
import org.teavm.vm.TeaVMPluginUtil;
import org.teavm.vm.spi.After;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;
@After(PlatformPlugin.class)
public class JCLPlugin implements TeaVMPlugin {
@Override
public void install(TeaVMHost host) {
@ -116,6 +142,74 @@ public class JCLPlugin implements TeaVMPlugin {
TeaVMPluginUtil.handleNatives(host, System.class);
TeaVMPluginUtil.handleNatives(host, Array.class);
TeaVMPluginUtil.handleNatives(host, Math.class);
installMetadata(host.getService(MetadataRegistration.class));
}
private void installMetadata(MetadataRegistration reg) {
reg.register(new MethodReference(DateTimeZoneProvider.class, "getResource", ResourceMap.class),
new TimeZoneGenerator());
reg.register(new MethodReference(DateTimeZoneProvider.class, "getResource", ResourceMap.class),
new TimeZoneGenerator());
reg.register(new MethodReference(CurrencyHelper.class, "getCurrencies", ResourceArray.class),
new CurrenciesGenerator());
reg.register(new MethodReference(CurrencyHelper.class, "getCountryToCurrencyMap", ResourceMap.class),
new CountriesGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getLikelySubtagsMap", ResourceMap.class),
new LikelySubtagsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getErasMap", ResourceMap.class),
new DateSymbolsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getAmPmMap", ResourceMap.class),
new DateSymbolsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getMonthMap", ResourceMap.class),
new DateSymbolsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getShortMonthMap", ResourceMap.class),
new DateSymbolsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getWeekdayMap", ResourceMap.class),
new DateSymbolsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getShortWeekdayMap", ResourceMap.class),
new DateSymbolsMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getTimeZoneLocalizationMap", ResourceMap.class),
new TimeZoneLocalizationGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getLanguagesMap", ResourceMap.class),
new LanguageMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getCountriesMap", ResourceMap.class),
new CountryMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getDefaultLocale", StringResource.class),
new DefaultLocaleMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getAvailableLocales", ResourceArray.class),
new AvailableLocalesMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getMinimalDaysInFirstWeek", ResourceMap.class),
new MinimalDaysInFirstWeekMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getFirstDayOfWeek", ResourceMap.class),
new FirstDayOfWeekMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getDateFormatMap", ResourceMap.class),
new DateFormatMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getTimeFormatMap", ResourceMap.class),
new DateFormatMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getDateTimeFormatMap", ResourceMap.class),
new DateFormatMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getNumberFormatMap", ResourceMap.class),
new NumberFormatMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getPercentFormatMap", ResourceMap.class),
new NumberFormatMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getCurrencyFormatMap", ResourceMap.class),
new NumberFormatMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getDecimalDataMap", ResourceMap.class),
new DecimalMetadataGenerator());
reg.register(new MethodReference(CLDRHelper.class, "getCurrencyMap", ResourceMap.class),
new CurrencyLocalizationMetadataGenerator());
reg.register(new MethodReference(Character.class, "obtainDigitMapping", StringResource.class),
new CharacterMetadataGenerator());
reg.register(new MethodReference(Character.class, "obtainClasses", StringResource.class),
new CharacterMetadataGenerator());
reg.register(new MethodReference(Class.class, "getDeclaringClass", PlatformClass.class, ClassResource.class),
new DeclaringClassMetadataGenerator());
}
@PlatformMarker

View File

@ -15,7 +15,6 @@
*/
package org.teavm.classlib.impl.currency;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource;
@ -24,9 +23,7 @@ public final class CurrencyHelper {
private CurrencyHelper() {
}
@MetadataProvider(CurrenciesGenerator.class)
public static native ResourceArray<CurrencyResource> getCurrencies();
@MetadataProvider(CountriesGenerator.class)
public static native ResourceMap<StringResource> getCountryToCurrencyMap();
}

View File

@ -28,7 +28,6 @@ import org.teavm.classlib.impl.Base46;
import org.teavm.classlib.impl.CharFlow;
import org.teavm.interop.Import;
import org.teavm.jso.JSBody;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.ResourceMap;
public final class DateTimeZoneProvider {
@ -193,6 +192,5 @@ public final class DateTimeZoneProvider {
@Import(module = "teavm", name = "getNativeOffset")
private static native int getNativeOffset(double instant);
@MetadataProvider(TimeZoneGenerator.class)
private static native ResourceMap<ResourceMap<TimeZoneResource>> getResource();
}

View File

@ -26,6 +26,6 @@ public class DateTimeZoneProviderGenerator implements Generator {
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
boolean autodetect = Boolean.parseBoolean(
context.getProperties().getProperty("java.util.TimeZone.autodetect", "false"));
writer.append("return " + Boolean.toString(autodetect) + ";");
writer.append("return " + autodetect + ";");
}
}

View File

@ -15,9 +15,10 @@
*/
package org.teavm.classlib.impl.unicode;
import org.teavm.classlib.impl.FirstDayOfWeekMetadataGenerator;
import org.teavm.classlib.impl.MinimalDaysInFirstWeekMetadataGenerator;
import org.teavm.platform.metadata.*;
import org.teavm.platform.metadata.IntResource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource;
public final class CLDRHelper {
private CLDRHelper() {
@ -41,49 +42,42 @@ public final class CLDRHelper {
return country;
}
@MetadataProvider(LikelySubtagsMetadataGenerator.class)
private static native ResourceMap<StringResource> getLikelySubtagsMap();
public static String[] resolveEras(String language, String country) {
return resolveDateFormatSymbols(getErasMap(), language, country);
}
@MetadataProvider(DateSymbolsMetadataGenerator.class)
private static native ResourceMap<ResourceArray<StringResource>> getErasMap();
public static String[] resolveAmPm(String language, String country) {
return resolveDateFormatSymbols(getAmPmMap(), language, country);
}
@MetadataProvider(DateSymbolsMetadataGenerator.class)
private static native ResourceMap<ResourceArray<StringResource>> getAmPmMap();
public static String[] resolveMonths(String language, String country) {
return resolveDateFormatSymbols(getMonthMap(), language, country);
}
@MetadataProvider(DateSymbolsMetadataGenerator.class)
private static native ResourceMap<ResourceArray<StringResource>> getMonthMap();
public static String[] resolveShortMonths(String language, String country) {
return resolveDateFormatSymbols(getShortMonthMap(), language, country);
}
@MetadataProvider(DateSymbolsMetadataGenerator.class)
private static native ResourceMap<ResourceArray<StringResource>> getShortMonthMap();
public static String[] resolveWeekdays(String language, String country) {
return resolveDateFormatSymbols(getWeekdayMap(), language, country);
}
@MetadataProvider(DateSymbolsMetadataGenerator.class)
private static native ResourceMap<ResourceArray<StringResource>> getWeekdayMap();
public static String[] resolveShortWeekdays(String language, String country) {
return resolveDateFormatSymbols(getShortWeekdayMap(), language, country);
}
@MetadataProvider(DateSymbolsMetadataGenerator.class)
private static native ResourceMap<ResourceArray<StringResource>> getShortWeekdayMap();
private static String[] resolveDateFormatSymbols(ResourceMap<ResourceArray<StringResource>> map, String language,
@ -127,67 +121,54 @@ public final class CLDRHelper {
return timeZones.get(territory).getValue();
}
@MetadataProvider(TimeZoneLocalizationGenerator.class)
public static native ResourceMap<TimeZoneLocalization> getTimeZoneLocalizationMap();
@MetadataProvider(LanguageMetadataGenerator.class)
public static native ResourceMap<ResourceMap<StringResource>> getLanguagesMap();
@MetadataProvider(CountryMetadataGenerator.class)
public static native ResourceMap<ResourceMap<StringResource>> getCountriesMap();
@MetadataProvider(DefaultLocaleMetadataGenerator.class)
public static native StringResource getDefaultLocale();
@MetadataProvider(AvailableLocalesMetadataGenerator.class)
public static native ResourceArray<StringResource> getAvailableLocales();
@MetadataProvider(MinimalDaysInFirstWeekMetadataGenerator.class)
public static native ResourceMap<IntResource> getMinimalDaysInFirstWeek();
@MetadataProvider(FirstDayOfWeekMetadataGenerator.class)
public static native ResourceMap<IntResource> getFirstDayOfWeek();
public static DateFormatCollection resolveDateFormats(String language, String country) {
return resolveDateFormats(getDateFormatMap(), language, country);
}
@MetadataProvider(DateFormatMetadataGenerator.class)
private static native ResourceMap<DateFormatCollection> getDateFormatMap();
public static DateFormatCollection resolveTimeFormats(String language, String country) {
return resolveDateFormats(getTimeFormatMap(), language, country);
}
@MetadataProvider(DateFormatMetadataGenerator.class)
private static native ResourceMap<DateFormatCollection> getTimeFormatMap();
public static DateFormatCollection resolveDateTimeFormats(String language, String country) {
return resolveDateFormats(getDateTimeFormatMap(), language, country);
}
@MetadataProvider(DateFormatMetadataGenerator.class)
private static native ResourceMap<DateFormatCollection> getDateTimeFormatMap();
public static String resolveNumberFormat(String language, String country) {
return resolveFormatSymbols(getNumberFormatMap(), language, country);
}
@MetadataProvider(NumberFormatMetadataGenerator.class)
private static native ResourceMap<StringResource> getNumberFormatMap();
public static String resolvePercentFormat(String language, String country) {
return resolveFormatSymbols(getPercentFormatMap(), language, country);
}
@MetadataProvider(NumberFormatMetadataGenerator.class)
private static native ResourceMap<StringResource> getPercentFormatMap();
public static String resolveCurrencyFormat(String language, String country) {
return resolveFormatSymbols(getCurrencyFormatMap(), language, country);
}
@MetadataProvider(NumberFormatMetadataGenerator.class)
private static native ResourceMap<StringResource> getCurrencyFormatMap();
private static DateFormatCollection resolveDateFormats(ResourceMap<DateFormatCollection> map,
@ -210,7 +191,6 @@ public final class CLDRHelper {
: map.get("root");
}
@MetadataProvider(DecimalMetadataGenerator.class)
private static native ResourceMap<DecimalData> getDecimalDataMap();
public static CurrencyLocalization resolveCurrency(String language, String country, String currency) {
@ -231,6 +211,5 @@ public final class CLDRHelper {
return null;
}
@MetadataProvider(CurrencyLocalizationMetadataGenerator.class)
private static native ResourceMap<ResourceMap<CurrencyLocalization>> getCurrencyMap();
}

View File

@ -19,7 +19,6 @@ import org.teavm.classlib.impl.unicode.UnicodeHelper;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.Import;
import org.teavm.platform.Platform;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.StringResource;
public class TCharacter extends TObject implements TComparable<TCharacter> {
@ -317,7 +316,6 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
return digitMapping;
}
@MetadataProvider(CharacterMetadataGenerator.class)
private static native StringResource obtainDigitMapping();
private static UnicodeHelper.Range[] getClasses() {
@ -327,7 +325,6 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
return classMapping;
}
@MetadataProvider(CharacterMetadataGenerator.class)
private static native StringResource obtainClasses();
public static int toChars(int codePoint, char[] dst, int dstIndex) {

View File

@ -28,7 +28,6 @@ import java.util.Set;
import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.classlib.PlatformDetector;
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
import org.teavm.classlib.impl.reflection.Flags;
import org.teavm.classlib.impl.reflection.JSClass;
import org.teavm.classlib.impl.reflection.JSField;
@ -48,7 +47,6 @@ import org.teavm.platform.Platform;
import org.teavm.platform.PlatformClass;
import org.teavm.platform.PlatformSequence;
import org.teavm.platform.metadata.ClassResource;
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
import org.teavm.runtime.RuntimeClass;
import org.teavm.runtime.RuntimeObject;
@ -601,7 +599,6 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
return res != null ? getClass(Platform.classFromResource(res)) : null;
}
@ClassScopedMetadataProvider(DeclaringClassMetadataGenerator.class)
private static native ClassResource getDeclaringClass(PlatformClass cls);
@SuppressWarnings("unchecked")

View File

@ -248,4 +248,8 @@ public class TThread extends TObject implements TRunnable {
public TStackTraceElement[] getStackTrace() {
return new TStackTraceElement[0];
}
public TClassLoader getContextClassLoader() {
return TClassLoader.getSystemClassLoader();
}
}

View File

@ -16,6 +16,7 @@
package org.teavm.vm.spi;
import java.util.Properties;
import org.teavm.common.ServiceRepository;
import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.DependencyPlugin;
@ -30,7 +31,7 @@ import org.teavm.vm.TeaVMBuilder;
*
* @author Alexey Andreev
*/
public interface TeaVMHost {
public interface TeaVMHost extends ServiceRepository {
void add(DependencyListener dependencyListener);
void add(ClassHolderTransformer classTransformer);

View File

@ -1,34 +0,0 @@
/*
* Copyright 2015 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.platform.metadata;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>Binds a {@link ClassScopedMetadataGenerator} to a native method.</p>
*
* @see MetadataProvider
*
* @author Alexey Andreev
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ClassScopedMetadataProvider {
Class<? extends ClassScopedMetadataGenerator> value();
}

View File

@ -16,68 +16,24 @@
package org.teavm.platform.plugin;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.RenderingUtil;
import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.AnnotationReader;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.ClassScopedMetadataGenerator;
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
import org.teavm.platform.metadata.Resource;
public class ClassScopedMetadataProviderNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
// Validate method
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
MethodReader method = cls.getMethod(methodRef.getDescriptor());
AnnotationReader providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
if (providerAnnot == null) {
return;
}
if (!method.hasModifier(ElementModifier.NATIVE)) {
context.getDiagnostics().error(new CallLocation(methodRef), "Method {{m0}} is marked with "
+ "{{c1}} annotation, but it is not native", methodRef,
ClassScopedMetadataProvider.class.getName());
return;
class ClassScopedMetadataProviderNativeGenerator implements Generator {
private ClassScopedMetadataGenerator generator;
ClassScopedMetadataProviderNativeGenerator(ClassScopedMetadataGenerator generator) {
this.generator = generator;
}
// Find and instantiate metadata generator
ValueType generatorType = providerAnnot.getValue("value").getJavaClass();
String generatorClassName = ((ValueType.Object) generatorType).getClassName();
Class<?> generatorClass;
try {
generatorClass = Class.forName(generatorClassName, true, context.getClassLoader());
} catch (ClassNotFoundException e) {
context.getDiagnostics().error(new CallLocation(methodRef), "Can't find metadata provider class {{c0}}",
generatorClassName);
return;
}
Constructor<?> cons;
try {
cons = generatorClass.getConstructor();
} catch (NoSuchMethodException e) {
context.getDiagnostics().error(new CallLocation(methodRef), "Metadata generator {{c0}} does not have "
+ "a public no-arg constructor", generatorClassName);
return;
}
ClassScopedMetadataGenerator generator;
try {
generator = (ClassScopedMetadataGenerator) cons.newInstance();
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
context.getDiagnostics().error(new CallLocation(methodRef), "Error instantiating metadata "
+ "generator {{c0}}", generatorClassName);
return;
}
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
context.getClassLoader(), context.getProperties(), context);

View File

@ -23,43 +23,38 @@ import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicContext;
import org.teavm.common.ServiceRepository;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
public class MetadataCIntrinsic implements Intrinsic {
private ClassReaderSource classSource;
private ClassLoader classLoader;
class MetadataCIntrinsic implements Intrinsic {
private Set<String> writtenStructures = new HashSet<>();
private Set<MethodReference> writtenInitializers = new HashSet<>();
private CodeWriter structuresWriter;
private CodeWriter staticFieldInitWriter;
private DefaultMetadataGeneratorContext metadataContext;
private MethodReference constructorMethod;
private MethodReference targetMethod;
private MetadataGenerator generator;
public MetadataCIntrinsic(ClassReaderSource classSource, ClassLoader classLoader,
MetadataCIntrinsic(ClassReaderSource classSource, ClassLoader classLoader,
ServiceRepository services, Properties properties, CodeWriter structuresWriter,
CodeWriter staticFieldInitWriter) {
this.classSource = classSource;
this.classLoader = classLoader;
CodeWriter staticFieldInitWriter, MethodReference constructorMethod, MethodReference targetMethod,
MetadataGenerator generator) {
this.structuresWriter = structuresWriter;
this.staticFieldInitWriter = staticFieldInitWriter;
metadataContext = new DefaultMetadataGeneratorContext(classSource, classLoader, properties, services);
this.constructorMethod = constructorMethod;
this.targetMethod = targetMethod;
this.generator = generator;
}
@Override
public boolean canHandle(MethodReference methodReference) {
MethodReader method = classSource.resolve(methodReference);
if (method == null) {
return false;
}
return method.getAnnotations().get(MetadataProvider.class.getName()) != null;
return constructorMethod.equals(methodReference);
}
@Override
@ -74,17 +69,13 @@ public class MetadataCIntrinsic implements Intrinsic {
return;
}
MethodReader method = classSource.resolve(methodReference);
MetadataGenerator generator = MetadataUtils.createMetadataGenerator(classLoader, method,
new CallLocation(invocation.getMethod()), context.getDiagnotics());
String variableName = context.names().forMethod(methodReference);
staticFieldInitWriter.print("static ").printType(method.getResultType()).print(" ")
staticFieldInitWriter.print("static ").printType(methodReference.getReturnType()).print(" ")
.print(variableName).print(" = ");
if (generator == null) {
staticFieldInitWriter.print("NULL");
} else {
Resource resource = generator.generateMetadata(metadataContext, invocation.getMethod());
Resource resource = generator.generateMetadata(metadataContext, targetMethod);
writeValue(context, resource);
}
staticFieldInitWriter.println(";");

View File

@ -32,53 +32,45 @@ import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.common.ServiceRepository;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
public class MetadataIntrinsic implements WasmIntrinsic {
class MetadataIntrinsic implements WasmIntrinsic {
private ClassReaderSource classSource;
private ClassLoader classLoader;
private ServiceRepository services;
private Properties properties;
private Map<ResourceTypeDescriptor, DataStructure> resourceTypeCache = new HashMap<>();
private MethodReference constructor;
private MethodReference targetMethod;
private MetadataGenerator generator;
public MetadataIntrinsic(ClassReaderSource classSource, ClassLoader classLoader,
ServiceRepository services, Properties properties) {
MetadataIntrinsic(ClassReaderSource classSource, ClassLoader classLoader,
ServiceRepository services, Properties properties, MethodReference constructor,
MethodReference targetMethod, MetadataGenerator generator) {
this.classSource = classSource;
this.classLoader = classLoader;
this.services = services;
this.properties = properties;
this.constructor = constructor;
this.targetMethod = targetMethod;
this.generator = generator;
}
@Override
public boolean isApplicable(MethodReference methodReference) {
MethodReader method = classSource.resolve(methodReference);
if (method == null) {
return false;
}
return method.getAnnotations().get(MetadataProvider.class.getName()) != null;
return methodReference.equals(constructor);
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
MethodReader method = classSource.resolve(invocation.getMethod());
MetadataGenerator generator = MetadataUtils.createMetadataGenerator(classLoader, method,
new CallLocation(invocation.getMethod()), manager.getDiagnostics());
if (generator == null) {
return new WasmInt32Constant(0);
}
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(classSource,
classLoader, properties, services);
Resource resource = generator.generateMetadata(metadataContext, invocation.getMethod());
Resource resource = generator.generateMetadata(metadataContext, targetMethod);
int address = writeValue(manager.getBinaryWriter(), manager.getStringPool(), resource);
return new WasmInt32Constant(address);

View File

@ -19,34 +19,26 @@ import java.io.IOException;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.AnnotationReader;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.Resource;
public class MetadataProviderNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
MethodReader method = cls.getMethod(methodRef.getDescriptor());
class MetadataProviderNativeGenerator implements Generator {
private MetadataGenerator generator;
private MethodReference forMethod;
AnnotationReader refAnnot = method.getAnnotations().get(MetadataProviderRef.class.getName());
methodRef = MethodReference.parse(refAnnot.getValue("value").getString());
MetadataGenerator generator = MetadataUtils.createMetadataGenerator(context.getClassLoader(),
method, new CallLocation(methodRef), context.getDiagnostics());
if (generator == null) {
return;
MetadataProviderNativeGenerator(MetadataGenerator generator, MethodReference forMethod) {
this.generator = generator;
this.forMethod = forMethod;
}
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
context.getClassLoader(), context.getProperties(), context);
// Generate resource loader
Resource resource = generator.generateMetadata(metadataContext, methodRef);
Resource resource = generator.generateMetadata(metadataContext, forMethod);
writer.append("return ");
ResourceWriterHelper.write(writer, resource);
writer.append(';').softNewLine();

View File

@ -15,13 +15,12 @@
*/
package org.teavm.platform.plugin;
import java.util.HashSet;
import java.util.Set;
import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.AccessLevel;
import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
@ -29,46 +28,29 @@ import org.teavm.model.ClassHolderTransformerContext;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldHolder;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.util.ModelUtils;
import org.teavm.platform.PlatformClass;
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
import org.teavm.platform.metadata.MetadataProvider;
class MetadataProviderTransformer implements ClassHolderTransformer {
private Set<MethodReference> metadataMethods = new HashSet<>();
void addMetadataMethod(MethodReference method) {
metadataMethods.add(method);
}
@Override
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
int index = 0;
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
if (providerAnnot != null) {
transformMetadataMethod(cls, method, context.getDiagnostics(), context.getHierarchy(), index++);
}
providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
if (providerAnnot != null) {
ValueType[] params = method.getParameterTypes();
if (params.length != 1 && params[0].isObject(PlatformClass.class.getName())) {
context.getDiagnostics().error(new CallLocation(method.getReference()),
"Method {{m0}} marked with {{c1}} must take exactly one parameter of type {{c2}}",
method.getReference(), ClassScopedMetadataProvider.class.getName(),
PlatformClass.class.getName());
}
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
ClassScopedMetadataProviderNativeGenerator.class.getName())));
method.getAnnotations().add(genAnnot);
if (metadataMethods.contains(method.getReference())) {
transformMetadataMethod(cls, method, context.getHierarchy(), index++);
}
}
}
private void transformMetadataMethod(ClassHolder cls, MethodHolder method, Diagnostics diagnostics,
ClassHierarchy hierarchy, int suffix) {
if (!validate(method, diagnostics)) {
return;
}
private void transformMetadataMethod(ClassHolder cls, MethodHolder method, ClassHierarchy hierarchy, int suffix) {
FieldHolder field = new FieldHolder("$$metadata$$" + suffix);
field.setType(method.getResultType());
field.setLevel(AccessLevel.PRIVATE);
@ -98,18 +80,4 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
pe.getField(field.getReference(), field.getType())
.returnValue();
}
private boolean validate(MethodHolder method, Diagnostics diagnostics) {
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
if (providerAnnot == null) {
return false;
}
if (!method.hasModifier(ElementModifier.NATIVE)) {
diagnostics.error(new CallLocation(method.getReference()), "Method {{m0}} is marked with "
+ "{{c1}} annotation, but it is not native", method.getReference(),
MetadataProvider.class.getName());
return false;
}
return true;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2014 Alexey Andreev.
* Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,20 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.platform.metadata;
package org.teavm.platform.plugin;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.ClassScopedMetadataGenerator;
import org.teavm.platform.metadata.MetadataGenerator;
/**
* <p>Binds a {@link MetadataGenerator} to a native method.</p>
*
* @author Alexey Andreev
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MetadataProvider {
Class<? extends MetadataGenerator> value();
public interface MetadataRegistration {
void register(MethodReference method, MetadataGenerator generator);
void register(MethodReference method, ClassScopedMetadataGenerator generator);
}

View File

@ -1,64 +0,0 @@
/*
* 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.platform.plugin;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.AnnotationReader;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReader;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataProvider;
public final class MetadataUtils {
private MetadataUtils() {
}
public static MetadataGenerator createMetadataGenerator(ClassLoader classLoader, MethodReader method,
CallLocation callLocation, Diagnostics diagnostics) {
AnnotationReader annot = method.getAnnotations().get(MetadataProvider.class.getName());
ValueType generatorType = annot.getValue("value").getJavaClass();
String generatorClassName = ((ValueType.Object) generatorType).getClassName();
Class<?> generatorClass;
try {
generatorClass = Class.forName(generatorClassName, true, classLoader);
} catch (ClassNotFoundException e) {
diagnostics.error(callLocation, "Can't find metadata provider class {{c0}}",
generatorClassName);
return null;
}
Constructor<?> cons;
try {
cons = generatorClass.getConstructor();
} catch (NoSuchMethodException e) {
diagnostics.error(callLocation, "Metadata generator {{c0}} does not have "
+ "a public no-arg constructor", generatorClassName);
return null;
}
MetadataGenerator generator;
try {
generator = (MetadataGenerator) cons.newInstance();
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
diagnostics.error(callLocation, "Error instantiating metadata "
+ "generator {{c0}}", generatorClassName);
return null;
}
return generator;
}
}

View File

@ -15,6 +15,9 @@
*/
package org.teavm.platform.plugin;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.TeaVMCHost;
import org.teavm.backend.c.intrinsic.Intrinsic;
@ -31,15 +34,22 @@ import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformQueue;
import org.teavm.platform.metadata.ClassScopedMetadataGenerator;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.vm.TeaVMPluginUtil;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;
public class PlatformPlugin implements TeaVMPlugin {
public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
private MetadataProviderTransformer metadataTransformer = new MetadataProviderTransformer();
private List<MetadataGeneratorConsumer> metadataGeneratorConsumers = new ArrayList<>();
private List<BiConsumer<MethodReference, ClassScopedMetadataGenerator>> scopedMetadataGeneratorConsumers
= new ArrayList<>();
@Override
public void install(TeaVMHost host) {
if (host.getExtension(TeaVMJavaScriptHost.class) != null) {
host.add(new MetadataProviderTransformer());
host.add(metadataTransformer);
host.add(new ResourceTransformer());
host.add(new ResourceAccessorTransformer(host));
host.add(new ResourceAccessorDependencyListener());
@ -58,6 +68,11 @@ public class PlatformPlugin implements TeaVMPlugin {
});
host.add(new AsyncDependencyListener());
jsHost.addVirtualMethods(new AsyncMethodGenerator());
metadataGeneratorConsumers.add((method, constructor, generator) -> jsHost.add(method,
new MetadataProviderNativeGenerator(generator, constructor)));
scopedMetadataGeneratorConsumers.add((method, generator) -> jsHost.add(method,
new ClassScopedMetadataProviderNativeGenerator(generator)));
} else if (!isBootstrap()) {
host.add(new StringAmplifierTransformer());
}
@ -65,8 +80,10 @@ public class PlatformPlugin implements TeaVMPlugin {
if (!isBootstrap()) {
TeaVMWasmHost wasmHost = host.getExtension(TeaVMWasmHost.class);
if (wasmHost != null) {
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(), ctx.getServices(),
ctx.getProperties()));
metadataGeneratorConsumers.add((constructor, method, generator) -> {
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties(), constructor, method, generator));
});
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource(), ctx.getClassLoader()));
wasmHost.add(ctx -> new WasmIntrinsic() {
@ -84,9 +101,11 @@ public class PlatformPlugin implements TeaVMPlugin {
TeaVMCHost cHost = host.getExtension(TeaVMCHost.class);
if (cHost != null) {
metadataGeneratorConsumers.add((constructor, method, generator) -> {
cHost.addIntrinsic(ctx -> new MetadataCIntrinsic(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties(), ctx.getStructureCodeWriter(),
ctx.getStaticFieldsInitWriter()));
ctx.getStaticFieldsInitWriter(), constructor, method, generator));
});
cHost.addIntrinsic(ctx -> new ResourceReadCIntrinsic(ctx.getClassSource()));
cHost.addIntrinsic(ctx -> new Intrinsic() {
@Override
@ -114,6 +133,29 @@ public class PlatformPlugin implements TeaVMPlugin {
TeaVMPluginUtil.handleNatives(host, Platform.class);
TeaVMPluginUtil.handleNatives(host, PlatformQueue.class);
host.registerService(MetadataRegistration.class, this);
}
@Override
public void register(MethodReference method, MetadataGenerator generator) {
MethodReference constructor = new MethodReference(method.getClassName(), method.getName() + "$$create",
method.getSignature());
for (MetadataGeneratorConsumer consumer : metadataGeneratorConsumers) {
consumer.consume(constructor, method, generator);
}
metadataTransformer.addMetadataMethod(method);
}
@Override
public void register(MethodReference method, ClassScopedMetadataGenerator generator) {
for (BiConsumer<MethodReference, ClassScopedMetadataGenerator> consumer : scopedMetadataGeneratorConsumers) {
consumer.accept(method, generator);
}
}
interface MetadataGeneratorConsumer {
void consume(MethodReference constructor, MethodReference target, MetadataGenerator generator);
}
@PlatformMarker

View File

@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.junit.SkipJVM;
@ -26,8 +27,8 @@ import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class)
@SkipJVM
@Ignore
public class MetadataGeneratorTest {
@MetadataProvider(TestResourceGenerator.class)
private native TestResource getNull();
@Test
@ -35,7 +36,6 @@ public class MetadataGeneratorTest {
assertNull(getNull());
}
@MetadataProvider(TestResourceGenerator.class)
private native IntResource getInt();
@Test
@ -43,7 +43,6 @@ public class MetadataGeneratorTest {
assertEquals(23, getInt().getValue());
}
@MetadataProvider(TestResourceGenerator.class)
private native TestResource getResource();
@Test
@ -66,7 +65,6 @@ public class MetadataGeneratorTest {
assertNull(res.getArrayC());
}
@MetadataProvider(TestResourceGenerator.class)
private native TestResource getEmptyResource();
@Test