mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Most of TClass now uses Platform instead of code generation
This commit is contained in:
parent
d93fa6cf41
commit
2ae7b587d1
|
@ -15,18 +15,26 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl;
|
package org.teavm.classlib.impl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.platform.metadata.MetadataGenerator;
|
import org.teavm.platform.metadata.*;
|
||||||
import org.teavm.platform.metadata.MetadataGeneratorContext;
|
|
||||||
import org.teavm.platform.metadata.Resource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class DeclaringClassMetadataGenerator implements MetadataGenerator {
|
public class DeclaringClassMetadataGenerator implements ClassScopedMetadataGenerator {
|
||||||
@Override
|
@Override
|
||||||
public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) {
|
public Map<String, Resource> generateMetadata(MetadataGeneratorContext context, MethodReference method) {
|
||||||
return null;
|
Map<String, Resource> result = new HashMap<>();
|
||||||
|
for (String clsName : context.getClassSource().getClassNames()) {
|
||||||
|
ClassReader cls = context.getClassSource().get(clsName);
|
||||||
|
if (cls.getOwnerName() != null) {
|
||||||
|
result.put(clsName, context.createClassResource(cls.getOwnerName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.teavm.classlib.impl;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import org.teavm.classlib.impl.unicode.CLDRReader;
|
import org.teavm.classlib.impl.unicode.CLDRReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.platform.PlatformClass;
|
||||||
import org.teavm.vm.spi.TeaVMHost;
|
import org.teavm.vm.spi.TeaVMHost;
|
||||||
import org.teavm.vm.spi.TeaVMPlugin;
|
import org.teavm.vm.spi.TeaVMPlugin;
|
||||||
|
|
||||||
|
@ -30,12 +31,11 @@ public class JCLPlugin implements TeaVMPlugin {
|
||||||
public void install(TeaVMHost host) {
|
public void install(TeaVMHost host) {
|
||||||
host.add(new EnumDependencySupport());
|
host.add(new EnumDependencySupport());
|
||||||
host.add(new EnumTransformer());
|
host.add(new EnumTransformer());
|
||||||
host.add(new ClassLookupDependencySupport());
|
|
||||||
host.add(new ObjectEnrichRenderer());
|
host.add(new ObjectEnrichRenderer());
|
||||||
ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader());
|
ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader());
|
||||||
host.add(serviceLoaderSupp);
|
host.add(serviceLoaderSupp);
|
||||||
MethodReference loadServicesMethod = new MethodReference(ServiceLoader.class, "loadServices",
|
MethodReference loadServicesMethod = new MethodReference(ServiceLoader.class, "loadServices",
|
||||||
Class.class, Object[].class);
|
PlatformClass.class, Object[].class);
|
||||||
host.add(loadServicesMethod, serviceLoaderSupp);
|
host.add(loadServicesMethod, serviceLoaderSupp);
|
||||||
JavacSupport javacSupport = new JavacSupport();
|
JavacSupport javacSupport = new JavacSupport();
|
||||||
host.add(javacSupport);
|
host.add(javacSupport);
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
||||||
}
|
}
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
String param = context.getParameterName(1);
|
String param = context.getParameterName(1);
|
||||||
writer.append("var cls = " + param + ".$data;").softNewLine();
|
writer.append("var cls = " + param + ";").softNewLine();
|
||||||
writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine();
|
writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine();
|
||||||
writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine();
|
writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
|
|
|
@ -16,12 +16,6 @@
|
||||||
package org.teavm.classlib.java.lang;
|
package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.teavm.codegen.SourceWriter;
|
|
||||||
import org.teavm.dependency.DependencyAgent;
|
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
|
||||||
import org.teavm.dependency.MethodDependency;
|
|
||||||
import org.teavm.javascript.spi.Generator;
|
|
||||||
import org.teavm.javascript.spi.GeneratorContext;
|
|
||||||
import org.teavm.javascript.spi.Injector;
|
import org.teavm.javascript.spi.Injector;
|
||||||
import org.teavm.javascript.spi.InjectorContext;
|
import org.teavm.javascript.spi.InjectorContext;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
|
@ -30,70 +24,13 @@ import org.teavm.model.*;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ClassNativeGenerator implements Generator, Injector, DependencyPlugin {
|
public class ClassNativeGenerator implements Injector {
|
||||||
@Override
|
|
||||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
|
|
||||||
throws IOException {
|
|
||||||
switch (methodRef.getName()) {
|
|
||||||
case "forNameImpl":
|
|
||||||
generateForName(context, writer);
|
|
||||||
break;
|
|
||||||
case "getDeclaringClass":
|
|
||||||
generateGetDeclaringClass(context, writer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||||
switch (methodRef.getName()) {
|
switch (methodRef.getName()) {
|
||||||
case "getEnumConstantsImpl":
|
case "getEnumConstantsImpl":
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
context.getWriter().append(".$data.values()");
|
context.getWriter().append(".values()");
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateForName(GeneratorContext context, SourceWriter writer) throws IOException {
|
|
||||||
String param = context.getParameterName(1);
|
|
||||||
writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent();
|
|
||||||
for (String name : context.getClassSource().getClassNames()) {
|
|
||||||
writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ")
|
|
||||||
.append("return $rt_cls(").appendClass(name).append(");").softNewLine();
|
|
||||||
}
|
|
||||||
writer.append("default: return null;").softNewLine();
|
|
||||||
writer.outdent().append("}").softNewLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateGetDeclaringClass(GeneratorContext context, SourceWriter writer) throws IOException {
|
|
||||||
String self = context.getParameterName(0);
|
|
||||||
writer.append("if (!").appendClass("java.lang.Class").append(".$$owners$$) {").indent().softNewLine();
|
|
||||||
writer.appendClass("java.lang.Class").append(".$$owners$$ = true;").softNewLine();
|
|
||||||
for (String clsName : context.getClassSource().getClassNames()) {
|
|
||||||
ClassReader cls = context.getClassSource().get(clsName);
|
|
||||||
writer.appendClass(clsName).append(".$$owner$$ = ");
|
|
||||||
if (cls.getOwnerName() != null) {
|
|
||||||
writer.appendClass(cls.getOwnerName());
|
|
||||||
} else {
|
|
||||||
writer.append("null");
|
|
||||||
}
|
|
||||||
writer.append(";").softNewLine();
|
|
||||||
}
|
|
||||||
writer.outdent().append("}").softNewLine();
|
|
||||||
writer.append("var cls = " + self + ".$data;").softNewLine();
|
|
||||||
writer.append("return cls.$$owner$$ != null ? $rt_cls(cls.$$owner$$) : null;").softNewLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void methodAchieved(DependencyAgent agent, MethodDependency graph, CallLocation location) {
|
|
||||||
switch (graph.getReference().getName()) {
|
|
||||||
case "forNameImpl":
|
|
||||||
case "getDeclaringClass":
|
|
||||||
graph.getResult().propagate(agent.getType("java.lang.Class"));
|
|
||||||
break;
|
|
||||||
case "newInstance":
|
|
||||||
agent.linkMethod(new MethodReference(InstantiationException.class, "<init>", void.class),
|
|
||||||
location).use();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
|
||||||
import org.teavm.javascript.spi.InjectedBy;
|
import org.teavm.javascript.spi.InjectedBy;
|
||||||
import org.teavm.platform.Platform;
|
import org.teavm.platform.Platform;
|
||||||
import org.teavm.platform.PlatformClass;
|
import org.teavm.platform.PlatformClass;
|
||||||
import org.teavm.platform.metadata.MetadataProvider;
|
import org.teavm.platform.metadata.ClassResource;
|
||||||
|
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -36,7 +37,7 @@ public class TClass<T> extends TObject {
|
||||||
platformClass.setJavaClass(Platform.getPlatformObject(this));
|
platformClass.setJavaClass(Platform.getPlatformObject(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
static TClass<?> getClass(PlatformClass cls) {
|
public static TClass<?> getClass(PlatformClass cls) {
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ public class TClass<T> extends TObject {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformClass getPlatformClass() {
|
public PlatformClass getPlatformClass() {
|
||||||
return platformClass;
|
return platformClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ public class TClass<T> extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isArray() {
|
public boolean isArray() {
|
||||||
return platformClass.getMetadata().isArray();
|
return platformClass.getMetadata().getArrayItem() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnum() {
|
public boolean isEnum() {
|
||||||
|
@ -141,12 +142,13 @@ public class TClass<T> extends TObject {
|
||||||
return (TClass<? super T>)getClass(platformClass.getMetadata().getSuperclass());
|
return (TClass<? super T>)getClass(platformClass.getMetadata().getSuperclass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public T[] getEnumConstants() {
|
public T[] getEnumConstants() {
|
||||||
return isEnum() ? getEnumConstantsImpl() : null;
|
return isEnum() ? (T[])getEnumConstantsImpl(platformClass) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectedBy(ClassNativeGenerator.class)
|
@InjectedBy(ClassNativeGenerator.class)
|
||||||
public native T[] getEnumConstantsImpl();
|
private static native Object[] getEnumConstantsImpl(PlatformClass cls);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T cast(TObject obj) {
|
public T cast(TObject obj) {
|
||||||
|
@ -175,12 +177,22 @@ public class TClass<T> extends TObject {
|
||||||
return forName(name);
|
return forName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public T newInstance() throws TInstantiationException, TIllegalAccessException {
|
public T newInstance() throws TInstantiationException, TIllegalAccessException {
|
||||||
return Platform.newInstance(platformClass);
|
Object instance = Platform.newInstance(platformClass);
|
||||||
|
if (instance == null) {
|
||||||
|
throw new TInstantiationException();
|
||||||
|
}
|
||||||
|
return (T)instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MetadataProvider(DeclaringClassMetadataGenerator.class)
|
public TClass<?> getDeclaringClass() {
|
||||||
public native TClass<?> getDeclaringClass();
|
ClassResource res = getDeclaringClass(platformClass);
|
||||||
|
return res != null ? getClass(Platform.classFromResource(res)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ClassScopedMetadataProvider(DeclaringClassMetadataGenerator.class)
|
||||||
|
private static native ClassResource getDeclaringClass(PlatformClass cls);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <U> TClass<? extends U> asSubclass(TClass<U> clazz) {
|
public <U> TClass<? extends U> asSubclass(TClass<U> clazz) {
|
||||||
|
|
|
@ -93,15 +93,14 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
|
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||||
String type = context.getParameterName(1);
|
String type = context.getParameterName(1);
|
||||||
String length = context.getParameterName(2);
|
String length = context.getParameterName(2);
|
||||||
writer.append("var cls = " + type + ".$data;").softNewLine();
|
writer.append("if (").append(type).append(".$meta.primitive) {").softNewLine().indent();
|
||||||
writer.append("if (cls.primitive) {").softNewLine().indent();
|
|
||||||
for (String primitive : primitives) {
|
for (String primitive : primitives) {
|
||||||
writer.append("if (cls == $rt_" + primitive.toLowerCase() + "cls()) {").indent().softNewLine();
|
writer.append("if (" + type + " == $rt_" + primitive.toLowerCase() + "cls()) {").indent().softNewLine();
|
||||||
writer.append("return $rt_create" + primitive + "Array(" + length + ");").softNewLine();
|
writer.append("return $rt_create" + primitive + "Array(" + length + ");").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
}
|
}
|
||||||
writer.outdent().append("} else {").indent().softNewLine();
|
writer.outdent().append("} else {").indent().softNewLine();
|
||||||
writer.append("return $rt_createArray(cls, " + length + ")").softNewLine();
|
writer.append("return $rt_createArray(" + type + ", " + length + ")").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.teavm.classlib.java.lang.reflect;
|
||||||
import org.teavm.classlib.java.lang.*;
|
import org.teavm.classlib.java.lang.*;
|
||||||
import org.teavm.dependency.PluggableDependency;
|
import org.teavm.dependency.PluggableDependency;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
|
import org.teavm.platform.PlatformClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -38,12 +39,12 @@ public final class TArray extends TObject {
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
throw new TNegativeArraySizeException();
|
throw new TNegativeArraySizeException();
|
||||||
}
|
}
|
||||||
return newInstanceImpl(componentType, length);
|
return newInstanceImpl(componentType.getPlatformClass(), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(ArrayNativeGenerator.class)
|
@GeneratedBy(ArrayNativeGenerator.class)
|
||||||
@PluggableDependency(ArrayNativeGenerator.class)
|
@PluggableDependency(ArrayNativeGenerator.class)
|
||||||
private static native TObject newInstanceImpl(TClass<?> componentType, int length);
|
private static native TObject newInstanceImpl(PlatformClass componentType, int length);
|
||||||
|
|
||||||
public static TObject get(TObject array, int index) throws TIllegalArgumentException,
|
public static TObject get(TObject array, int index) throws TIllegalArgumentException,
|
||||||
TArrayIndexOutOfBoundsException {
|
TArrayIndexOutOfBoundsException {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.classlib.java.util;
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
import org.teavm.classlib.java.lang.*;
|
import org.teavm.classlib.java.lang.*;
|
||||||
|
import org.teavm.platform.PlatformClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -48,7 +49,7 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <S> TServiceLoader<S> load(TClass<S> service) {
|
public static <S> TServiceLoader<S> load(TClass<S> service) {
|
||||||
return new TServiceLoader<>(loadServices(service));
|
return new TServiceLoader<>(loadServices(service.getPlatformClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <S> TServiceLoader<S> load(TClass<S> service, @SuppressWarnings("unused") TClassLoader loader) {
|
public static <S> TServiceLoader<S> load(TClass<S> service, @SuppressWarnings("unused") TClassLoader loader) {
|
||||||
|
@ -59,7 +60,7 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
|
||||||
return load(service);
|
return load(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native <T> T[] loadServices(TClass<T> serviceType);
|
private static native <T> T[] loadServices(PlatformClass cls);
|
||||||
|
|
||||||
public void reload() {
|
public void reload() {
|
||||||
// Do nothing, services are bound at build time
|
// Do nothing, services are bound at build time
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.teavm.common.ServiceRepository;
|
||||||
import org.teavm.debugging.information.DebugInformationEmitter;
|
import org.teavm.debugging.information.DebugInformationEmitter;
|
||||||
import org.teavm.debugging.information.DeferredCallSite;
|
import org.teavm.debugging.information.DeferredCallSite;
|
||||||
import org.teavm.debugging.information.DummyDebugInformationEmitter;
|
import org.teavm.debugging.information.DummyDebugInformationEmitter;
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.javascript.ast.*;
|
import org.teavm.javascript.ast.*;
|
||||||
import org.teavm.javascript.spi.GeneratorContext;
|
import org.teavm.javascript.spi.GeneratorContext;
|
||||||
import org.teavm.javascript.spi.InjectedBy;
|
import org.teavm.javascript.spi.InjectedBy;
|
||||||
|
@ -54,6 +55,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
private DeferredCallSite lastCallSite;
|
private DeferredCallSite lastCallSite;
|
||||||
private DeferredCallSite prevCallSite;
|
private DeferredCallSite prevCallSite;
|
||||||
private Set<MethodReference> asyncMethods;
|
private Set<MethodReference> asyncMethods;
|
||||||
|
private Diagnostics diagnostics;
|
||||||
private boolean async;
|
private boolean async;
|
||||||
|
|
||||||
private static class InjectorHolder {
|
private static class InjectorHolder {
|
||||||
|
@ -77,13 +79,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
|
|
||||||
public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader,
|
public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader,
|
||||||
ServiceRepository services, Set<MethodReference> asyncMethods) {
|
ServiceRepository services, Set<MethodReference> asyncMethods, Diagnostics diagnostics) {
|
||||||
this.naming = writer.getNaming();
|
this.naming = writer.getNaming();
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.services = services;
|
this.services = services;
|
||||||
this.asyncMethods = new HashSet<>(asyncMethods);
|
this.asyncMethods = new HashSet<>(asyncMethods);
|
||||||
|
this.diagnostics = diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -167,43 +170,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRuntimeCls() throws IOException {
|
private void renderRuntimeCls() throws IOException {
|
||||||
writer.append("function $rt_cls").ws().append("(clsProto)").ws().append("{")
|
writer.append("function $rt_cls(cls)").ws().append("{").softNewLine().indent();
|
||||||
.indent().softNewLine();
|
writer.append("return ").appendMethodBody("java.lang.Class", "getClass",
|
||||||
String classClass = "java.lang.Class";
|
ValueType.object("org.teavm.platform.PlatformClass"),
|
||||||
writer.append("var cls").ws().append("=").ws().append("clsProto.classObject;").softNewLine();
|
ValueType.object("java.lang.Class")).append("(cls);")
|
||||||
writer.append("if").ws().append("(typeof cls").ws().append("===").ws().append("'undefined')").ws()
|
.softNewLine();
|
||||||
.append("{").softNewLine().indent();
|
|
||||||
MethodReference createMethodRef = new MethodReference(classClass, "createNew", ValueType.object(classClass));
|
|
||||||
writer.append("cls").ws().append("=").ws().appendMethodBody(createMethodRef).append("();").softNewLine();
|
|
||||||
writer.append("cls.$data = clsProto;").softNewLine();
|
|
||||||
if (classSource.get(classClass).getField("name") != null) {
|
|
||||||
writer.append("cls.").appendField(new FieldReference(classClass, "name")).ws().append("=").ws()
|
|
||||||
.append("clsProto.$meta.name").ws().append("!==").ws().append("undefined").ws().append("?").ws()
|
|
||||||
.append("$rt_str(clsProto.$meta.name)").ws().append(":").ws().append("null;").softNewLine();
|
|
||||||
}
|
|
||||||
if (classSource.get(classClass).getField("name") != null) {
|
|
||||||
writer.append("cls.").appendField(new FieldReference(classClass, "binaryName")).ws().append("=").ws()
|
|
||||||
.append("clsProto.$meta.binaryName").ws().append("!==").ws().append("undefined").ws()
|
|
||||||
.append("?").ws()
|
|
||||||
.append("$rt_str(clsProto.$meta.binaryName)").ws().append(":").ws().append("null;").softNewLine();
|
|
||||||
}
|
|
||||||
if (classSource.get(classClass).getField("primitive") != null) {
|
|
||||||
writer.append("cls.").appendField(new FieldReference(classClass, "primitive"))
|
|
||||||
.append(" = clsProto.$meta.primitive ? 1 : 0;").newLine();
|
|
||||||
}
|
|
||||||
if (classSource.get(classClass).getField("array") != null) {
|
|
||||||
writer.append("cls.").appendField(new FieldReference(classClass, "array")).ws()
|
|
||||||
.append("=").ws().append("clsProto.$meta.item").ws().append("?").ws()
|
|
||||||
.append("1").ws().append(":").ws().append("0;").softNewLine();
|
|
||||||
}
|
|
||||||
if (classSource.get(classClass).getField("isEnum") != null) {
|
|
||||||
writer.append("cls.").appendField(new FieldReference(classClass, "isEnum")).ws()
|
|
||||||
.append("=").ws().append("clsProto.$meta.enum").ws().append("?").ws()
|
|
||||||
.append("1").ws().append(":").ws().append("0;").softNewLine();
|
|
||||||
}
|
|
||||||
writer.append("clsProto.classObject").ws().append("=").ws().append("cls;").softNewLine();
|
|
||||||
writer.outdent().append("}").softNewLine();
|
|
||||||
writer.append("return cls;").softNewLine();
|
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,6 +677,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
public String getCompleteContinuation() {
|
public String getCompleteContinuation() {
|
||||||
return "$return";
|
return "$return";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Diagnostics getDiagnostics() {
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pushLocation(NodeLocation location) {
|
private void pushLocation(NodeLocation location) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.javascript.spi;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import org.teavm.common.ServiceRepository;
|
import org.teavm.common.ServiceRepository;
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.model.ListableClassReaderSource;
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
@ -38,4 +39,6 @@ public interface GeneratorContext extends ServiceRepository {
|
||||||
String getCompleteContinuation();
|
String getCompleteContinuation();
|
||||||
|
|
||||||
boolean isAsync(MethodReference method);
|
boolean isAsync(MethodReference method);
|
||||||
|
|
||||||
|
Diagnostics getDiagnostics();
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,7 +334,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE;
|
return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class), null).use();
|
dependencyChecker.linkMethod(new MethodReference(Class.class.getName(), "getClass",
|
||||||
|
ValueType.object("org.teavm.platform.PlatformClass"), ValueType.parse(Class.class)), null).use();
|
||||||
dependencyChecker.linkMethod(new MethodReference(String.class, "<init>", char[].class, void.class),
|
dependencyChecker.linkMethod(new MethodReference(String.class, "<init>", char[].class, void.class),
|
||||||
null).use();
|
null).use();
|
||||||
dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class,
|
dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class,
|
||||||
|
@ -396,7 +397,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
||||||
builder.setMinified(minifying);
|
builder.setMinified(minifying);
|
||||||
SourceWriter sourceWriter = builder.build(writer);
|
SourceWriter sourceWriter = builder.build(writer);
|
||||||
Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods);
|
Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods, diagnostics);
|
||||||
renderer.setProperties(properties);
|
renderer.setProperties(properties);
|
||||||
if (debugEmitter != null) {
|
if (debugEmitter != null) {
|
||||||
int classIndex = 0;
|
int classIndex = 0;
|
||||||
|
|
|
@ -130,15 +130,18 @@ function $rt_arraycls(cls) {
|
||||||
}
|
}
|
||||||
var name = "[" + cls.$meta.binaryName;
|
var name = "[" + cls.$meta.binaryName;
|
||||||
arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls(),
|
arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls(),
|
||||||
name : name, binaryName : name };
|
name : name, binaryName : name, enum : false };
|
||||||
|
arraycls.classObject = null;
|
||||||
cls.$array = arraycls;
|
cls.$array = arraycls;
|
||||||
}
|
}
|
||||||
return cls.$array;
|
return cls.$array;
|
||||||
}
|
}
|
||||||
function $rt_createcls() {
|
function $rt_createcls() {
|
||||||
return {
|
return {
|
||||||
|
classObject : null,
|
||||||
$meta : {
|
$meta : {
|
||||||
supertypes : []
|
supertypes : [],
|
||||||
|
superclass : null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -147,6 +150,8 @@ function $rt_createPrimitiveCls(name, binaryName) {
|
||||||
cls.$meta.primitive = true;
|
cls.$meta.primitive = true;
|
||||||
cls.$meta.name = name;
|
cls.$meta.name = name;
|
||||||
cls.$meta.binaryName = binaryName;
|
cls.$meta.binaryName = binaryName;
|
||||||
|
cls.$meta.enum = false;
|
||||||
|
cls.$meta.item = null;
|
||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
var $rt_booleanclsCache = null;
|
var $rt_booleanclsCache = null;
|
||||||
|
@ -365,18 +370,21 @@ function $rt_putStderr(ch) {
|
||||||
}
|
}
|
||||||
function $rt_declClass(cls, data) {
|
function $rt_declClass(cls, data) {
|
||||||
cls.$meta = {};
|
cls.$meta = {};
|
||||||
cls.$meta.superclass = data.superclass;
|
var m = cls.$meta
|
||||||
cls.$meta.supertypes = data.interfaces ? data.interfaces.slice() : [];
|
m.superclass = typeof(data.superclass) !== 'undefined' ? data.superclass : null;
|
||||||
|
m.supertypes = data.interfaces ? data.interfaces.slice() : [];
|
||||||
if (data.superclass) {
|
if (data.superclass) {
|
||||||
cls.$meta.supertypes.push(data.superclass);
|
m.supertypes.push(data.superclass);
|
||||||
cls.prototype = new data.superclass();
|
cls.prototype = new data.superclass();
|
||||||
} else {
|
} else {
|
||||||
cls.prototype = new Object();
|
cls.prototype = new Object();
|
||||||
}
|
}
|
||||||
cls.$meta.name = data.name;
|
m.name = data.name;
|
||||||
cls.$meta.binaryName = "L" + data.name + ";";
|
m.binaryName = "L" + data.name + ";";
|
||||||
cls.$meta.enum = data.enum;
|
m.enum = data.enum;
|
||||||
|
m.item = null;
|
||||||
cls.prototype.constructor = cls;
|
cls.prototype.constructor = cls;
|
||||||
|
cls.classObject = null;
|
||||||
cls.$clinit = data.clinit ? data.clinit : function() {};
|
cls.$clinit = data.clinit ? data.clinit : function() {};
|
||||||
}
|
}
|
||||||
function $rt_virtualMethods(cls) {
|
function $rt_virtualMethods(cls) {
|
||||||
|
|
|
@ -370,11 +370,11 @@ var JUnitClient = {};
|
||||||
JUnitClient.run = function() {
|
JUnitClient.run = function() {
|
||||||
var handler = window.addEventListener("message", function() {
|
var handler = window.addEventListener("message", function() {
|
||||||
window.removeEventListener("message", handler);
|
window.removeEventListener("message", handler);
|
||||||
|
var message = {};
|
||||||
try {
|
try {
|
||||||
var instance = new TestClass();
|
var instance = new TestClass();
|
||||||
initInstance(instance);
|
initInstance(instance);
|
||||||
runTest(instance, function(restore) {
|
runTest(instance, function(restore) {
|
||||||
var message = {};
|
|
||||||
try {
|
try {
|
||||||
var result = restore();
|
var result = restore();
|
||||||
message.status = "ok";
|
message.status = "ok";
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class JSNativeGenerator implements Injector, DependencyPlugin {
|
||||||
}
|
}
|
||||||
writer.append("))");
|
writer.append("))");
|
||||||
break;
|
break;
|
||||||
case "pass":
|
case "marshall":
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
break;
|
break;
|
||||||
case "wrap":
|
case "wrap":
|
||||||
|
|
|
@ -72,7 +72,7 @@ public final class Platform {
|
||||||
@PluggableDependency(PlatformGenerator.class)
|
@PluggableDependency(PlatformGenerator.class)
|
||||||
public static native void initClass(PlatformClass cls);
|
public static native void initClass(PlatformClass cls);
|
||||||
|
|
||||||
@GeneratedBy(PlatformGenerator.class)
|
@InjectedBy(PlatformGenerator.class)
|
||||||
@PluggableDependency(PlatformGenerator.class)
|
@PluggableDependency(PlatformGenerator.class)
|
||||||
public static native PlatformClass classFromResource(ClassResource resource);
|
public static native PlatformClass classFromResource(ClassResource resource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,12 @@ package org.teavm.platform;
|
||||||
|
|
||||||
import org.teavm.jso.JSObject;
|
import org.teavm.jso.JSObject;
|
||||||
import org.teavm.jso.JSProperty;
|
import org.teavm.jso.JSProperty;
|
||||||
import org.teavm.platform.metadata.Resource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface PlatformClass extends JSObject, Resource {
|
public interface PlatformClass extends JSObject {
|
||||||
@JSProperty("$meta")
|
@JSProperty("$meta")
|
||||||
PlatformClassMetadata getMetadata();
|
PlatformClassMetadata getMetadata();
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,6 @@ public interface PlatformClassMetadata extends JSObject {
|
||||||
@JSProperty
|
@JSProperty
|
||||||
boolean isPrimitive();
|
boolean isPrimitive();
|
||||||
|
|
||||||
@JSProperty
|
|
||||||
boolean isArray();
|
|
||||||
|
|
||||||
@JSProperty
|
@JSProperty
|
||||||
boolean isEnum();
|
boolean isEnum();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,38 +15,38 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.platform;
|
package org.teavm.platform;
|
||||||
|
|
||||||
|
import org.teavm.jso.JSMethod;
|
||||||
import org.teavm.jso.JSObject;
|
import org.teavm.jso.JSObject;
|
||||||
import org.teavm.jso.JSProperty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface PlatformPrimitives extends JSObject {
|
public interface PlatformPrimitives extends JSObject {
|
||||||
@JSProperty("$rt_voidcls")
|
@JSMethod("$rt_voidcls")
|
||||||
PlatformClass getVoidClass();
|
PlatformClass getVoidClass();
|
||||||
|
|
||||||
@JSProperty("$rt_booleancls")
|
@JSMethod("$rt_booleancls")
|
||||||
PlatformClass getBooleanClass();
|
PlatformClass getBooleanClass();
|
||||||
|
|
||||||
@JSProperty("$rt_bytecls")
|
@JSMethod("$rt_bytecls")
|
||||||
PlatformClass getByteClass();
|
PlatformClass getByteClass();
|
||||||
|
|
||||||
@JSProperty("$rt_shortcls")
|
@JSMethod("$rt_shortcls")
|
||||||
PlatformClass getShortClass();
|
PlatformClass getShortClass();
|
||||||
|
|
||||||
@JSProperty("$rt_charcls")
|
@JSMethod("$rt_charcls")
|
||||||
PlatformClass getCharClass();
|
PlatformClass getCharClass();
|
||||||
|
|
||||||
@JSProperty("$rt_intcls")
|
@JSMethod("$rt_intcls")
|
||||||
PlatformClass getIntClass();
|
PlatformClass getIntClass();
|
||||||
|
|
||||||
@JSProperty("$rt_longcls")
|
@JSMethod("$rt_longcls")
|
||||||
PlatformClass getLongClass();
|
PlatformClass getLongClass();
|
||||||
|
|
||||||
@JSProperty("$rt_floatcls")
|
@JSMethod("$rt_floatcls")
|
||||||
PlatformClass getFloatClass();
|
PlatformClass getFloatClass();
|
||||||
|
|
||||||
@JSProperty("$rt_doublecls")
|
@JSMethod("$rt_doublecls")
|
||||||
PlatformClass getDoubleClass();
|
PlatformClass getDoubleClass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import org.teavm.jso.JSProperty;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface PlatformSequence<T> extends JSObject {
|
public interface PlatformSequence<T extends JSObject> extends JSObject {
|
||||||
@JSProperty
|
@JSProperty
|
||||||
int getLength();
|
int getLength();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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.util.Map;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.platform.PlatformClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Behaviour of this class is similar to {@link MetadataGenerator}. The difference is that method, marked with
|
||||||
|
* {@link ClassScopedMetadataProvider} must take one argument of type {@link PlatformClass}. It will
|
||||||
|
* return different resource for each given class, corresponding to map entries, produced by
|
||||||
|
* {@link #generateMetadata(MetadataGeneratorContext, MethodReference)}.
|
||||||
|
*
|
||||||
|
* @see ClassScopedMetadataProvider
|
||||||
|
* @see MetadataGenerator
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
public interface ClassScopedMetadataGenerator {
|
||||||
|
Map<String, Resource> generateMetadata(MetadataGeneratorContext context, MethodReference method);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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 <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface ClassScopedMetadataProvider {
|
||||||
|
Class<? extends ClassScopedMetadataGenerator> value();
|
||||||
|
}
|
|
@ -50,6 +50,8 @@ import org.teavm.model.MethodReference;
|
||||||
*
|
*
|
||||||
* <p>All other types are not considered to be resources and therefore are not accepted.</p>
|
* <p>All other types are not considered to be resources and therefore are not accepted.</p>
|
||||||
*
|
*
|
||||||
|
* @see ClassScopedMetadataGenerator
|
||||||
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface MetadataGenerator {
|
public interface MetadataGenerator {
|
||||||
|
|
|
@ -102,8 +102,8 @@ class BuildTimeResourceProxyBuilder {
|
||||||
|
|
||||||
private void scanIface(Class<?> iface) {
|
private void scanIface(Class<?> iface) {
|
||||||
if (!Resource.class.isAssignableFrom(iface)) {
|
if (!Resource.class.isAssignableFrom(iface)) {
|
||||||
throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() +
|
throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() + "." +
|
||||||
". This type does not implement the " + Resource.class.getName() + " interface");
|
" This type does not implement the " + Resource.class.getName() + " interface");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan methods
|
// Scan methods
|
||||||
|
|
|
@ -36,7 +36,7 @@ class BuildTimeResourceWriterMethod implements BuildTimeResourceMethod {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
writer.append(',').ws();
|
writer.append(',').ws();
|
||||||
}
|
}
|
||||||
ResourceWriterHelper.writeString(writer, propertyNames[i]);
|
ResourceWriterHelper.writeIdentifier(writer, propertyNames[i]);
|
||||||
writer.ws().append(':').ws();
|
writer.ws().append(':').ws();
|
||||||
ResourceWriterHelper.write(writer, proxy.data[i]);
|
ResourceWriterHelper.write(writer, proxy.data[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,11 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl;
|
package org.teavm.platform.plugin;
|
||||||
|
|
||||||
import org.teavm.dependency.*;
|
import org.teavm.dependency.*;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.platform.Platform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -38,14 +39,14 @@ public class ClassLookupDependencySupport implements DependencyListener {
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) {
|
public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) {
|
||||||
MethodReference ref = method.getReference();
|
MethodReference ref = method.getReference();
|
||||||
if (ref.getClassName().equals("java.lang.Class") && ref.getName().equals("forNameImpl")) {
|
if (ref.getClassName().equals(Platform.class.getName()) && ref.getName().equals("lookupClass")) {
|
||||||
allClasses.addConsumer(new DependencyConsumer() {
|
allClasses.addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(DependencyAgentType type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
ClassReader cls = agent.getClassSource().get(type.getName());
|
ClassReader cls = agent.getClassSource().get(type.getName());
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodReader initMethod = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID));
|
MethodReader initMethod = cls.getMethod(new MethodDescriptor("<clinit>", void.class));
|
||||||
if (initMethod != null) {
|
if (initMethod != null) {
|
||||||
agent.linkMethod(initMethod.getReference(), location).use();
|
agent.linkMethod(initMethod.getReference(), location).use();
|
||||||
}
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* 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.plugin;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.teavm.codegen.SourceWriter;
|
||||||
|
import org.teavm.javascript.Renderer;
|
||||||
|
import org.teavm.javascript.spi.Generator;
|
||||||
|
import org.teavm.javascript.spi.GeneratorContext;
|
||||||
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.platform.metadata.ClassScopedMetadataGenerator;
|
||||||
|
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||||
|
import org.teavm.platform.metadata.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
|
||||||
|
context.getClassLoader(), context.getProperties(), context);
|
||||||
|
|
||||||
|
Map<String, Resource> resourceMap = generator.generateMetadata(metadataContext, methodRef);
|
||||||
|
writer.append("var p").ws().append("=").ws().append("\"" + Renderer.escapeString("$$res_" +
|
||||||
|
writer.getNaming().getNameFor(methodRef)) + "\"").append(";").softNewLine();
|
||||||
|
for (Map.Entry<String, Resource> entry : resourceMap.entrySet()) {
|
||||||
|
writer.appendClass(entry.getKey()).append("[p]").ws().append("=").ws();
|
||||||
|
ResourceWriterHelper.write(writer, entry.getValue());
|
||||||
|
writer.append(";").softNewLine();
|
||||||
|
}
|
||||||
|
writer.appendMethodBody(methodRef).ws().append('=').ws().append("function(cls)").ws().append("{")
|
||||||
|
.softNewLine().indent();
|
||||||
|
writer.append("return cls.hasOwnProperty(p)").ws().append("?").ws().append("cls[p]").ws().append(":")
|
||||||
|
.ws().append("null;").softNewLine();
|
||||||
|
writer.outdent().append("}").softNewLine();
|
||||||
|
writer.append("return ").appendMethodBody(methodRef).append("(").append(context.getParameterName(1))
|
||||||
|
.append(");").softNewLine();
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,8 +41,9 @@ public class MetadataProviderNativeGenerator implements Generator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!method.hasModifier(ElementModifier.NATIVE)) {
|
if (!method.hasModifier(ElementModifier.NATIVE)) {
|
||||||
throw new IllegalStateException("Method " + method.getReference() + " was marked with " +
|
context.getDiagnostics().error(new CallLocation(methodRef), "Method {{m0}} is marked with " +
|
||||||
MetadataProvider.class.getName() + " but it is not native");
|
"{{c1}} annotation, but it is not native", methodRef, MetadataProvider.class.getName());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and instantiate metadata generator
|
// Find and instantiate metadata generator
|
||||||
|
@ -52,23 +53,25 @@ public class MetadataProviderNativeGenerator implements Generator {
|
||||||
try {
|
try {
|
||||||
generatorClass = Class.forName(generatorClassName, true, context.getClassLoader());
|
generatorClass = Class.forName(generatorClassName, true, context.getClassLoader());
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new RuntimeException("Can't find metadata generator class: " + generatorClassName, e);
|
context.getDiagnostics().error(new CallLocation(methodRef), "Can't find metadata provider class {{c0}}",
|
||||||
|
generatorClassName);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Constructor<?> cons;
|
Constructor<?> cons;
|
||||||
try {
|
try {
|
||||||
cons = generatorClass.getConstructor();
|
cons = generatorClass.getConstructor();
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new RuntimeException("Metadata generator " + generatorClassName + " does not have a public " +
|
context.getDiagnostics().error(new CallLocation(methodRef), "Metadata generator {{c0}} does not have " +
|
||||||
"no-arg constructor", e);
|
"a public no-arg constructor", generatorClassName);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
MetadataGenerator generator;
|
MetadataGenerator generator;
|
||||||
try {
|
try {
|
||||||
generator = (MetadataGenerator)cons.newInstance();
|
generator = (MetadataGenerator)cons.newInstance();
|
||||||
} catch (IllegalAccessException | InstantiationException e) {
|
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||||
throw new RuntimeException("Error instantiating metadata generator " + generatorClassName, e);
|
context.getDiagnostics().error(new CallLocation(methodRef), "Error instantiating metadata " +
|
||||||
} catch (InvocationTargetException e) {
|
"generator {{c0}}", generatorClassName);
|
||||||
throw new RuntimeException("Error instantiating metadata generator " + generatorClassName,
|
return;
|
||||||
e.getTargetException());
|
|
||||||
}
|
}
|
||||||
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
|
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
|
||||||
context.getClassLoader(), context.getProperties(), context);
|
context.getClassLoader(), context.getProperties(), context);
|
||||||
|
|
|
@ -18,6 +18,8 @@ package org.teavm.platform.plugin;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.platform.PlatformClass;
|
||||||
|
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||||
import org.teavm.platform.metadata.MetadataProvider;
|
import org.teavm.platform.metadata.MetadataProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,13 +31,26 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
|
||||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||||
if (providerAnnot == null) {
|
if (providerAnnot != null) {
|
||||||
continue;
|
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
||||||
|
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
|
||||||
|
MetadataProviderNativeGenerator.class.getName())));
|
||||||
|
method.getAnnotations().add(genAnnot);
|
||||||
|
}
|
||||||
|
providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
|
||||||
|
if (providerAnnot != null) {
|
||||||
|
ValueType[] params = method.getParameterTypes();
|
||||||
|
if (params.length != 1 && params[0].isObject(PlatformClass.class.getName())) {
|
||||||
|
diagnostics.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);
|
||||||
}
|
}
|
||||||
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
|
||||||
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
|
|
||||||
MetadataProviderNativeGenerator.class.getName())));
|
|
||||||
method.getAnnotations().add(genAnnot);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.teavm.javascript.spi.GeneratorContext;
|
||||||
import org.teavm.javascript.spi.Injector;
|
import org.teavm.javascript.spi.Injector;
|
||||||
import org.teavm.javascript.spi.InjectorContext;
|
import org.teavm.javascript.spi.InjectorContext;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
import org.teavm.platform.Platform;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -45,6 +44,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
||||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||||
switch (methodRef.getName()) {
|
switch (methodRef.getName()) {
|
||||||
case "asJavaClass":
|
case "asJavaClass":
|
||||||
|
case "classFromResource":
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -54,34 +54,45 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
||||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||||
switch (methodRef.getName()) {
|
switch (methodRef.getName()) {
|
||||||
case "newInstance":
|
case "newInstance":
|
||||||
generateNewInstance(context, writer);
|
generateNewInstance(context, writer, methodRef);
|
||||||
|
break;
|
||||||
|
case "lookupClass":
|
||||||
|
generateLookup(context, writer);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
|
private void generateNewInstance(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
|
||||||
String self = context.getParameterName(0);
|
throws IOException {
|
||||||
writer.append("if").ws().append("(!").appendClass(Platform.class).append(".$$constructors$$)").ws()
|
writer.append("var c").ws().append("=").ws().append("'$$constructor$$';").softNewLine();
|
||||||
.append("{").indent().softNewLine();
|
|
||||||
writer.appendClass(Platform.class).append(".$$constructors$$").ws().append("=").append("true;").softNewLine();
|
|
||||||
for (String clsName : context.getClassSource().getClassNames()) {
|
for (String clsName : context.getClassSource().getClassNames()) {
|
||||||
ClassReader cls = context.getClassSource().get(clsName);
|
ClassReader cls = context.getClassSource().get(clsName);
|
||||||
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", void.class));
|
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", void.class));
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
writer.appendClass(clsName).append(".$$constructor$$").ws().append("=").ws()
|
writer.appendClass(clsName).append("[c]").ws().append("=").ws()
|
||||||
.appendMethodBody(method.getReference()).append(";").softNewLine();
|
.append(writer.getNaming().getNameForInit(method.getReference()))
|
||||||
|
.append(";").softNewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
writer.appendMethodBody(methodRef).ws().append("=").ws().append("function(cls)").ws().append("{")
|
||||||
|
.softNewLine().indent();
|
||||||
|
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
||||||
|
writer.append("return null;").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.append("var cls = " + self + ".$data;").softNewLine();
|
writer.append("return cls[c]();").softNewLine();
|
||||||
writer.append("var ctor = cls.$$constructor$$;").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.append("if (!ctor) {").indent().softNewLine();
|
writer.append("return ").appendMethodBody(methodRef).append("(")
|
||||||
writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine();
|
.append(context.getParameterName(1)).append(");").softNewLine();
|
||||||
writer.appendMethodBody(new MethodReference(InstantiationException.class, "<init>", void.class))
|
}
|
||||||
.append("(ex);").softNewLine();
|
|
||||||
writer.append("$rt_throw(ex);").softNewLine();
|
private void generateLookup(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||||
|
String param = context.getParameterName(1);
|
||||||
|
writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent();
|
||||||
|
for (String name : context.getClassSource().getClassNames()) {
|
||||||
|
writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ")
|
||||||
|
.append("return ").appendClass(name).append(";").softNewLine();
|
||||||
|
}
|
||||||
|
writer.append("default: return null;").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.append("var instance = new cls();").softNewLine();
|
|
||||||
writer.append("ctor(instance);").softNewLine();
|
|
||||||
writer.append("return instance;").softNewLine();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,6 @@ public class PlatformPlugin implements TeaVMPlugin {
|
||||||
host.add(new ResourceAccessorDependencyListener());
|
host.add(new ResourceAccessorDependencyListener());
|
||||||
host.add(new AsyncMethodProcessor());
|
host.add(new AsyncMethodProcessor());
|
||||||
host.add(new NewInstanceDependencySupport());
|
host.add(new NewInstanceDependencySupport());
|
||||||
|
host.add(new ClassLookupDependencySupport());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,34 @@ final class ResourceWriterHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void writeIdentifier(SourceWriter writer, String id) throws IOException {
|
||||||
|
if (id.isEmpty() || !isIdentifierStart(id.charAt(0))) {
|
||||||
|
writeString(writer, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 1; i < id.length(); ++i) {
|
||||||
|
if (isIdentifierPart(id.charAt(i))) {
|
||||||
|
writeString(writer, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.append(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIdentifierStart(char c) {
|
||||||
|
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return c == '$' || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIdentifierPart(char c) {
|
||||||
|
if (isIdentifierStart(c)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
public static void writeString(SourceWriter writer, String s) throws IOException {
|
public static void writeString(SourceWriter writer, String s) throws IOException {
|
||||||
writer.append('"');
|
writer.append('"');
|
||||||
for (int i = 0; i < s.length(); ++i) {
|
for (int i = 0; i < s.length(); ++i) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user