mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Fix https://github.com/konsoletyper/teavm/issues/133
This commit is contained in:
parent
d5da4964c4
commit
6ab53cbf6a
|
@ -17,7 +17,6 @@ package org.teavm.classlib.impl;
|
|||
|
||||
import java.util.ServiceLoader;
|
||||
import org.teavm.classlib.impl.unicode.CLDRReader;
|
||||
import org.teavm.classlib.java.lang.reflect.AnnotationClassTransformer;
|
||||
import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
|
@ -42,6 +41,5 @@ public class JCLPlugin implements TeaVMPlugin {
|
|||
host.registerService(CLDRReader.class, new CLDRReader(host.getProperties(), host.getClassLoader()));
|
||||
|
||||
host.add(new AnnotationDependencyListener());
|
||||
host.add(new AnnotationClassTransformer());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,141 +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.classlib.java.lang.reflect;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.AccessLevel;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
import org.teavm.model.AnnotationValue;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.emit.ProgramEmitter;
|
||||
import org.teavm.model.emit.ValueEmitter;
|
||||
import org.teavm.model.instructions.ArrayElementType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AnnotationClassTransformer implements ClassHolderTransformer {
|
||||
@Override
|
||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||
MethodHolder readerMethod = new MethodHolder("$$__readAnnotations__$$", ValueType.parse(Annotation[].class));
|
||||
readerMethod.setLevel(AccessLevel.PUBLIC);
|
||||
readerMethod.getModifiers().add(ElementModifier.STATIC);
|
||||
ProgramEmitter pe = ProgramEmitter.create(readerMethod);
|
||||
|
||||
List<AnnotationReader> annotations = new ArrayList<>();
|
||||
for (AnnotationReader annot : cls.getAnnotations().all()) {
|
||||
ClassReader annotType = innerSource.get(annot.getType());
|
||||
if (annotType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AnnotationReader retention = annotType.getAnnotations().get(Retention.class.getName());
|
||||
String retentionPolicy = retention.getValue("value").getEnumValue().getFieldName();
|
||||
if (retentionPolicy.equals("RUNTIME")) {
|
||||
annotations.add(annot);
|
||||
}
|
||||
}
|
||||
|
||||
ValueEmitter array = pe.constructArray(Annotation.class, annotations.size());
|
||||
for (int i = 0; i < annotations.size(); ++i) {
|
||||
array.unwrapArray(ArrayElementType.OBJECT).setElement(i,
|
||||
generateAnnotationInstance(innerSource, pe, annotations.get(i)));
|
||||
}
|
||||
|
||||
array.returnValue();
|
||||
|
||||
cls.addMethod(readerMethod);
|
||||
}
|
||||
|
||||
private ValueEmitter generateAnnotationInstance(ClassReaderSource classSource, ProgramEmitter pe,
|
||||
AnnotationReader annotation) {
|
||||
ClassReader annotationClass = classSource.get(annotation.getType());
|
||||
if (annotationClass == null) {
|
||||
return pe.constantNull();
|
||||
}
|
||||
|
||||
String className = annotation.getType() + "$$_impl";
|
||||
List<ValueType> ctorSignature = new ArrayList<>();
|
||||
List<ValueEmitter> params = new ArrayList<>();
|
||||
for (MethodReader methodDecl : annotationClass.getMethods()) {
|
||||
ctorSignature.add(methodDecl.getResultType());
|
||||
AnnotationValue value = annotation.getValue(methodDecl.getName());
|
||||
if (value == null) {
|
||||
value = methodDecl.getAnnotationDefault();
|
||||
}
|
||||
params.add(generateAnnotationValue(classSource, pe, methodDecl.getResultType(), value));
|
||||
}
|
||||
ctorSignature.add(ValueType.VOID);
|
||||
|
||||
MethodReference ctor = new MethodReference(className, "<init>", ctorSignature.toArray(
|
||||
new ValueType[ctorSignature.size()]));
|
||||
return pe.construct(ctor, params.toArray(new ValueEmitter[params.size()]));
|
||||
}
|
||||
|
||||
private ValueEmitter generateAnnotationValue(ClassReaderSource classSource, ProgramEmitter pe, ValueType type,
|
||||
AnnotationValue value) {
|
||||
switch (value.getType()) {
|
||||
case AnnotationValue.BOOLEAN:
|
||||
return pe.constant(value.getBoolean() ? 1 : 0);
|
||||
case AnnotationValue.BYTE:
|
||||
return pe.constant(value.getByte());
|
||||
case AnnotationValue.SHORT:
|
||||
return pe.constant(value.getShort());
|
||||
case AnnotationValue.INT:
|
||||
return pe.constant(value.getInt());
|
||||
case AnnotationValue.LONG:
|
||||
return pe.constant(value.getLong());
|
||||
case AnnotationValue.FLOAT:
|
||||
return pe.constant(value.getFloat());
|
||||
case AnnotationValue.DOUBLE:
|
||||
return pe.constant(value.getDouble());
|
||||
case AnnotationValue.STRING:
|
||||
return pe.constant(value.getString());
|
||||
case AnnotationValue.LIST: {
|
||||
List<AnnotationValue> list = value.getList();
|
||||
ValueType itemType = ((ValueType.Array)type).getItemType();
|
||||
ValueEmitter array = pe.constructArray(itemType, list.size());
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
array.unwrapArray(ArrayElementType.OBJECT).setElement(i,
|
||||
generateAnnotationValue(classSource, pe, itemType, list.get(i)));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
case AnnotationValue.ENUM:
|
||||
pe.initClass(value.getEnumValue().getClassName());
|
||||
return pe.getField(value.getEnumValue(), type);
|
||||
case AnnotationValue.CLASS:
|
||||
return pe.constant(value.getJavaClass());
|
||||
case AnnotationValue.ANNOTATION:
|
||||
return generateAnnotationInstance(classSource, pe, value.getAnnotation());
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown annotation value type: " + value.getType());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang.reflect;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.dependency.AbstractDependencyListener;
|
||||
|
@ -22,6 +24,7 @@ import org.teavm.dependency.DependencyAgent;
|
|||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.model.AccessLevel;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
import org.teavm.model.AnnotationValue;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReader;
|
||||
|
@ -35,6 +38,8 @@ import org.teavm.model.MethodReference;
|
|||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.emit.ProgramEmitter;
|
||||
import org.teavm.model.emit.ValueEmitter;
|
||||
import org.teavm.model.instructions.ArrayElementType;
|
||||
import org.teavm.platform.PlatformAnnotationProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -48,12 +53,11 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cls.hasModifier(ElementModifier.ANNOTATION)) {
|
||||
getAnnotationImplementor(agent, className);
|
||||
}
|
||||
for (AnnotationReader annotation : cls.getAnnotations().all()) {
|
||||
agent.linkClass(annotation.getType(), location);
|
||||
}
|
||||
|
||||
createAnnotationClass(agent, className);
|
||||
}
|
||||
|
||||
private String getAnnotationImplementor(DependencyAgent agent, String annotationType) {
|
||||
|
@ -150,4 +154,128 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createAnnotationClass(DependencyAgent agent, String className) {
|
||||
String readerClassName = className + "$$__annotations__$$";
|
||||
if (agent.getClassSource().get(readerClassName) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassHolder cls = new ClassHolder(className + "$$__annotations__$$");
|
||||
cls.setLevel(AccessLevel.PUBLIC);
|
||||
cls.setOwnerName("java.lang.Object");
|
||||
cls.getInterfaces().add(PlatformAnnotationProvider.class.getName());
|
||||
|
||||
MethodHolder ctor = new MethodHolder("<init>", ValueType.VOID);
|
||||
ctor.setLevel(AccessLevel.PUBLIC);
|
||||
ProgramEmitter pe = ProgramEmitter.create(ctor);
|
||||
ValueEmitter thisVar = pe.newVar();
|
||||
|
||||
thisVar.invokeSpecial(new MethodReference(Object.class, "<init>", void.class));
|
||||
pe.exit();
|
||||
|
||||
ClassReader annotatedClass = agent.getClassSource().get(className);
|
||||
cls.addMethod(ctor);
|
||||
cls.addMethod(addReader(agent, annotatedClass));
|
||||
|
||||
agent.submitClass(cls);
|
||||
}
|
||||
|
||||
private MethodHolder addReader(DependencyAgent agent, ClassReader cls) {
|
||||
MethodHolder readerMethod = new MethodHolder("getAnnotations", ValueType.parse(Annotation[].class));
|
||||
readerMethod.setLevel(AccessLevel.PUBLIC);
|
||||
ProgramEmitter pe = ProgramEmitter.create(readerMethod);
|
||||
|
||||
List<AnnotationReader> annotations = new ArrayList<>();
|
||||
for (AnnotationReader annot : cls.getAnnotations().all()) {
|
||||
ClassReader annotType = agent.getClassSource().get(annot.getType());
|
||||
if (annotType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AnnotationReader retention = annotType.getAnnotations().get(Retention.class.getName());
|
||||
if (retention != null) {
|
||||
String retentionPolicy = retention.getValue("value").getEnumValue().getFieldName();
|
||||
if (retentionPolicy.equals("RUNTIME")) {
|
||||
annotations.add(annot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ValueEmitter array = pe.constructArray(Annotation.class, annotations.size());
|
||||
for (int i = 0; i < annotations.size(); ++i) {
|
||||
array.unwrapArray(ArrayElementType.OBJECT).setElement(i,
|
||||
generateAnnotationInstance(agent, pe, annotations.get(i)));
|
||||
}
|
||||
|
||||
array.returnValue();
|
||||
|
||||
return readerMethod;
|
||||
}
|
||||
|
||||
private ValueEmitter generateAnnotationInstance(DependencyAgent agent, ProgramEmitter pe,
|
||||
AnnotationReader annotation) {
|
||||
ClassReader annotationClass = agent.getClassSource().get(annotation.getType());
|
||||
if (annotationClass == null) {
|
||||
return pe.constantNull();
|
||||
}
|
||||
|
||||
String className = getAnnotationImplementor(agent, annotation.getType());
|
||||
List<ValueType> ctorSignature = new ArrayList<>();
|
||||
List<ValueEmitter> params = new ArrayList<>();
|
||||
for (MethodReader methodDecl : annotationClass.getMethods()) {
|
||||
ctorSignature.add(methodDecl.getResultType());
|
||||
AnnotationValue value = annotation.getValue(methodDecl.getName());
|
||||
if (value == null) {
|
||||
value = methodDecl.getAnnotationDefault();
|
||||
}
|
||||
params.add(generateAnnotationValue(agent, pe, methodDecl.getResultType(), value));
|
||||
}
|
||||
ctorSignature.add(ValueType.VOID);
|
||||
|
||||
MethodReference ctor = new MethodReference(className, "<init>", ctorSignature.toArray(
|
||||
new ValueType[ctorSignature.size()]));
|
||||
return pe.construct(ctor, params.toArray(new ValueEmitter[params.size()]));
|
||||
}
|
||||
|
||||
private ValueEmitter generateAnnotationValue(DependencyAgent agent, ProgramEmitter pe, ValueType type,
|
||||
AnnotationValue value) {
|
||||
switch (value.getType()) {
|
||||
case AnnotationValue.BOOLEAN:
|
||||
return pe.constant(value.getBoolean() ? 1 : 0);
|
||||
case AnnotationValue.BYTE:
|
||||
return pe.constant(value.getByte());
|
||||
case AnnotationValue.SHORT:
|
||||
return pe.constant(value.getShort());
|
||||
case AnnotationValue.INT:
|
||||
return pe.constant(value.getInt());
|
||||
case AnnotationValue.LONG:
|
||||
return pe.constant(value.getLong());
|
||||
case AnnotationValue.FLOAT:
|
||||
return pe.constant(value.getFloat());
|
||||
case AnnotationValue.DOUBLE:
|
||||
return pe.constant(value.getDouble());
|
||||
case AnnotationValue.STRING:
|
||||
return pe.constant(value.getString());
|
||||
case AnnotationValue.LIST: {
|
||||
List<AnnotationValue> list = value.getList();
|
||||
ValueType itemType = ((ValueType.Array)type).getItemType();
|
||||
ValueEmitter array = pe.constructArray(itemType, list.size());
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
array.unwrapArray(ArrayElementType.OBJECT).setElement(i,
|
||||
generateAnnotationValue(agent, pe, itemType, list.get(i)));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
case AnnotationValue.ENUM:
|
||||
pe.initClass(value.getEnumValue().getClassName());
|
||||
return pe.getField(value.getEnumValue(), type);
|
||||
case AnnotationValue.CLASS:
|
||||
return pe.constant(value.getJavaClass());
|
||||
case AnnotationValue.ANNOTATION:
|
||||
return generateAnnotationInstance(agent, pe, value.getAnnotation());
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown annotation value type: " + value.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface PlatformAnnotationProvider {
|
||||
Annotation[] getAnnotations();
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.teavm.model.CallLocation;
|
|||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.platform.Platform;
|
||||
import org.teavm.platform.PlatformAnnotationProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -50,10 +51,19 @@ public class AnnotationDependencySupport extends AbstractDependencyListener {
|
|||
if (method.getReference().getClassName().equals(Platform.class.getName()) &&
|
||||
method.getReference().getName().equals("getAnnotations")) {
|
||||
method.getResult().propagate(agent.getType("[" + Annotation.class.getName()));
|
||||
agent.linkMethod(new MethodReference(PlatformAnnotationProvider.class, "getAnnotations",
|
||||
Annotation[].class), location);
|
||||
allClasses.addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(DependencyType type) {
|
||||
MethodDependency readMethod = agent.linkMethod(new MethodReference(type.getName(),
|
||||
"$$__readAnnotations__$$", ValueType.parse(Annotation[].class)), location);
|
||||
if (type.getName().endsWith("$$__annotations__$$")) {
|
||||
return;
|
||||
}
|
||||
String className = type.getName() + "$$__annotations__$$";
|
||||
agent.linkMethod(new MethodReference(className, "<init>", ValueType.VOID), location)
|
||||
.propagate(0, className)
|
||||
.use();
|
||||
MethodDependency readMethod = agent.linkMethod(new MethodReference(className,
|
||||
"getAnnotations", ValueType.parse(Annotation[].class)), location);
|
||||
readMethod.getResult().getArrayItem().connect(method.getResult().getArrayItem());
|
||||
readMethod.use();
|
||||
}
|
||||
|
|
|
@ -209,13 +209,12 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
|||
private void generateAnnotations(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
writer.append("var c").ws().append("=").ws().append("'$$annotations$$';").softNewLine();
|
||||
for (String clsName : context.getClassSource().getClassNames()) {
|
||||
ClassReader cls = context.getClassSource().get(clsName);
|
||||
MethodReader method = cls.getMethod(new MethodDescriptor("$$__readAnnotations__$$",
|
||||
ValueType.parse(Annotation[].class)));
|
||||
if (method != null) {
|
||||
ClassReader annotCls = context.getClassSource().get(clsName + "$$__annotations__$$");
|
||||
if (annotCls != null) {
|
||||
writer.appendClass(clsName).append("[c]").ws().append("=").ws();
|
||||
writer.appendMethodBody(method.getReference());
|
||||
writer.append(";").softNewLine();
|
||||
MethodReference ctor = new MethodReference(annotCls.getName(), "<init>", ValueType.VOID);
|
||||
writer.append(writer.getNaming().getNameForInit(ctor));
|
||||
writer.append("();").softNewLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +224,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
|||
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
||||
writer.append("return null;").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("return cls[c]();").softNewLine();
|
||||
writer.append("return cls[c].").appendMethod("getAnnotations", Annotation[].class).append("();").softNewLine();
|
||||
writer.outdent().append("};").softNewLine();
|
||||
|
||||
writer.append("return ").append(selfName).append("(").append(context.getParameterName(1))
|
||||
|
|
Loading…
Reference in New Issue
Block a user