Start porting metaprogramming API implementation

This commit is contained in:
Alexey Andreev 2016-02-22 23:59:54 +03:00
parent 1826e04951
commit 92dbed2593
42 changed files with 2317 additions and 2 deletions

View File

@ -35,6 +35,7 @@
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="module" module-name="teavm-platform" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso" />

View File

@ -32,6 +32,11 @@
<artifactId>junit</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-metaprogramming-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>

View File

@ -0,0 +1,35 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.util.List;
import org.teavm.metaprogramming.Action;
import org.teavm.model.MethodReference;
public class ActionImpl extends Fragment implements Action {
public ActionImpl(List<CapturedValue> capturedValues, MethodReference method) {
super(capturedValues, method);
}
@Override
public void run() {
throw new IllegalStateException("Don't call this method directly");
}
public static ActionImpl create(List<CapturedValue> capturedValues, MethodReference method) {
return new ActionImpl(capturedValues, method);
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 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.metaprogramming.impl;
public class CapturedValue {
public Object obj;
public boolean primitive;
public CapturedValue(Object obj, boolean primitive) {
this.obj = obj;
this.primitive = primitive;
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.util.List;
import org.teavm.metaprogramming.Computation;
import org.teavm.model.MethodReference;
public class ComputationImpl<T> extends Fragment implements Computation<T> {
public ComputationImpl(List<CapturedValue> capturedValues, MethodReference method) {
super(capturedValues, method);
}
@Override
public T compute() {
throw new IllegalStateException("Don't call this method directly");
}
public static <S> ComputationImpl<S> create(List<CapturedValue> capturedValues, MethodReference method) {
return new ComputationImpl<>(capturedValues, method);
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.util.List;
import org.teavm.model.MethodReference;
public class Fragment {
List<CapturedValue> capturedValues;
MethodReference method;
public Fragment(List<CapturedValue> capturedValues, MethodReference method) {
this.capturedValues = capturedValues;
this.method = method;
}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.teavm.metaprogramming.CompileTime;
public class MetaprogrammingClassLoader extends ClassLoader {
private MetaprogrammingInstrumentation instrumentation = new MetaprogrammingInstrumentation();
private Map<String, Boolean> compileTimeClasses = new HashMap<>();
private Map<String, Boolean> compileTimePackages = new HashMap<>();
public MetaprogrammingClassLoader(ClassLoader parent) {
super(parent);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (!isCompileTimeClass(name)) {
return super.loadClass(name, resolve);
} else {
try (InputStream input = getResourceAsStream(name.replace('.', '/') + ".class")) {
byte[] array = instrumentation.instrument(IOUtils.toByteArray(input));
return defineClass(name, array, 0, array.length);
} catch (IOException e) {
throw new ClassNotFoundException("Error reading bytecode of class " + name, e);
}
}
}
public boolean isCompileTimeClass(String name) {
return compileTimeClasses.computeIfAbsent(name, n -> checkIfCompileTime(n));
}
private boolean checkIfCompileTime(String name) {
String packageName = name;
while (true) {
int index = packageName.lastIndexOf('.');
if (index < 0) {
break;
}
packageName = packageName.substring(0, index);
if (isCompileTimePackage(packageName)) {
return true;
}
}
String outerName = name;
while (true) {
int index = outerName.lastIndexOf('$');
if (index < 0) {
break;
}
outerName = outerName.substring(0, index);
if (isCompileTimeClass(outerName)) {
return true;
}
}
CompileTimeClassVisitor visitor = new CompileTimeClassVisitor();
try (InputStream input = getResourceAsStream(name.replace('.', '/') + ".class")) {
if (input == null) {
return false;
}
new ClassReader(input).accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);
} catch (IOException e) {
return false;
}
if (visitor.compileTime) {
return true;
}
if (visitor.parent != null && !visitor.parent.equals(name)) {
return isCompileTimeClass(visitor.parent);
}
return false;
}
private boolean isCompileTimePackage(String name) {
return compileTimePackages.computeIfAbsent(name, n -> checkIfCompileTimePackage(n));
}
private boolean checkIfCompileTimePackage(String name) {
CompileTimeClassVisitor visitor = new CompileTimeClassVisitor();
try (InputStream input = getResourceAsStream(name.replace('.', '/') + "/package-info.class")) {
if (input == null) {
return false;
}
new ClassReader(input).accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);
} catch (IOException e) {
return false;
}
return visitor.compileTime;
}
static class CompileTimeClassVisitor extends ClassVisitor {
String parent;
boolean compileTime;
CompileTimeClassVisitor() {
super(Opcodes.ASM5, null);
}
@Override
public void visit(int version, int access, String name, String signature, String superName,
String[] interfaces) {
this.parent = superName != null ? superName.replace('/', '.') : null;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (desc.equals(Type.getDescriptor(CompileTime.class))) {
compileTime = true;
}
return null;
}
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.teavm.dependency.AbstractDependencyListener;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.MethodDependency;
import org.teavm.dependency.MethodDependencyInfo;
import org.teavm.metaprogramming.impl.model.MethodDescriber;
import org.teavm.metaprogramming.impl.model.MethodModel;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.StringChooseEmitter;
import org.teavm.model.emit.ValueEmitter;
public class MetaprogrammingDependencyListener extends AbstractDependencyListener {
private MethodDescriber describer;
private Set<MethodModel> installedProxies = new HashSet<>();
private MetaprogrammingClassLoader proxyClassLoader;
@Override
public void started(DependencyAgent agent) {
proxyClassLoader = new MetaprogrammingClassLoader(agent.getClassLoader());
describer = new MethodDescriber(agent.getDiagnostics(), agent.getClassSource());
}
@Override
public void methodReached(DependencyAgent agent, MethodDependency methodDep, CallLocation location) {
MethodModel proxy = describer.getMethod(methodDep.getReference());
if (proxy != null && installedProxies.add(proxy)) {
new UsageGenerator(agent, proxy, methodDep, location, proxyClassLoader).installProxyEmitter();
}
}
@Override
public void completing(DependencyAgent agent) {
for (MethodModel model : describer.getKnownMethods()) {
ProgramEmitter pe = ProgramEmitter.create(model.getMethod().getDescriptor(), agent.getClassSource());
ValueEmitter[] paramVars = new ValueEmitter[model.getMetaParameterCount()];
for (int i = 0; i < paramVars.length; ++i) {
paramVars[i] = pe.var(i, model.getMetaParameterType(i));
}
if (model.getUsages().size() == 1) {
emitSingleUsage(model, pe, agent, paramVars);
} else if (model.getUsages().isEmpty()) {
if (model.getMethod().getReturnType() == ValueType.VOID) {
pe.exit();
} else {
pe.constantNull(Object.class).returnValue();
}
} else {
emitMultipleUsage(model, pe, agent, paramVars);
}
}
}
private void emitSingleUsage(MethodModel model, ProgramEmitter pe, DependencyAgent agent,
ValueEmitter[] paramVars) {
MethodReference usage = model.getUsages().values().stream().findFirst().get();
ValueEmitter result = pe.invoke(usage, paramVars);
if (usage.getReturnType() == ValueType.VOID) {
pe.exit();
} else {
assert result != null : "Expected non-null result at " + model.getMethod();
result.returnValue();
}
agent.submitMethod(model.getMethod(), pe.getProgram());
}
private void emitMultipleUsage(MethodModel model, ProgramEmitter pe, DependencyAgent agent,
ValueEmitter[] paramVars) {
MethodDependencyInfo methodDep = agent.getMethod(model.getMethod());
ValueEmitter paramVar = paramVars[model.getMetaClassParameterIndex()];
ValueEmitter tag = paramVar.invokeVirtual("getClass", Class.class).invokeVirtual("getName", String.class);
StringChooseEmitter choice = pe.stringChoice(tag);
for (Map.Entry<ValueType, MethodReference> usageEntry : model.getUsages().entrySet()) {
ValueType type = usageEntry.getKey();
String typeName = type instanceof ValueType.Object
? ((ValueType.Object) type).getClassName()
: type.toString();
choice.option(typeName, () -> {
MethodReference implMethod = usageEntry.getValue();
ValueEmitter[] castParamVars = new ValueEmitter[paramVars.length];
for (int i = 0; i < castParamVars.length; ++i) {
castParamVars[i] = paramVars[i].cast(implMethod.parameterType(i));
}
ValueEmitter result = pe.invoke(implMethod, castParamVars);
if (implMethod.getReturnType() == ValueType.VOID) {
pe.exit();
} else {
assert result != null : "Expected non-null result at " + model.getMethod();
result.returnValue();
}
});
}
choice.otherwise(() -> {
if (methodDep.getReference().getReturnType() == ValueType.VOID) {
pe.exit();
} else {
pe.constantNull(Object.class).returnValue();
}
});
agent.submitMethod(model.getMethod(), pe.getProgram());
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import org.teavm.metaprogramming.Action;
import org.teavm.metaprogramming.Computation;
import org.teavm.metaprogramming.InvocationHandler;
import org.teavm.metaprogramming.LazyComputation;
import org.teavm.metaprogramming.ReflectClass;
import org.teavm.metaprogramming.Scope;
import org.teavm.metaprogramming.Value;
import org.teavm.metaprogramming.impl.reflect.ReflectClassImpl;
import org.teavm.metaprogramming.impl.reflect.ReflectContext;
import org.teavm.model.ValueType;
public final class MetaprogrammingImpl {
static ClassLoader classLoader;
static ReflectContext reflectContext;
private MetaprogrammingImpl() {
}
public static <T> Value<T> emit(Computation<T> computation) {
unsupported();
return null;
}
public static void emit(Action action) {
unsupported();
}
public static <T> Value<T> lazyFragment(LazyComputation<T> computation) {
unsupported();
return null;
}
public static <T> Value<T> lazy(Computation<T> computation) {
unsupported();
return null;
}
public static Scope currentScope() {
unsupported();
return null;
}
public static void location(String fileName, int lineNumber) {
unsupported();
}
public static void defaultLocation() {
unsupported();
}
public static ReflectClass<?> findClass(String name) {
return reflectContext.findClass(name);
}
public static <T> ReflectClass<T> findClass(Class<T> cls) {
return reflectContext.findClass(cls);
}
static ReflectClass<?> findClass(ValueType type) {
return reflectContext.getClass(type);
}
public static ClassLoader getClassLoader() {
return classLoader;
}
@SuppressWarnings("unchecked")
public static <T> ReflectClass<T[]> arrayClass(ReflectClass<T> componentType) {
ReflectClassImpl<T> componentTypeImpl = (ReflectClassImpl<T>) componentType;
return (ReflectClassImpl<T[]>) reflectContext.getClass(ValueType.arrayOf(componentTypeImpl.type));
}
public static ReflectClass<?> createClass(byte[] bytecode) {
unsupported();
return null;
}
public static <T> Value<T> proxy(Class<T> type, InvocationHandler<T> handler) {
return proxy(findClass(type), handler);
}
public static <T> Value<T> proxy(ReflectClass<T> type, InvocationHandler<T> handler) {
unsupported();
return null;
}
private static void unsupported() {
throw new UnsupportedOperationException("This operation is only supported from TeaVM compile-time "
+ "environment");
}
}

View File

@ -0,0 +1,222 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.lang.invoke.LambdaMetafactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.teavm.metaprogramming.Action;
import org.teavm.metaprogramming.Computation;
import org.teavm.metaprogramming.Metaprogramming;
import org.teavm.model.MethodReference;
public class MetaprogrammingInstrumentation {
private static String lambdaMetafactory = LambdaMetafactory.class.getName().replace('.', '/');
private static String proxyHelperType = Type.getInternalName(RuntimeHelper.class);
private static String listDesc = Type.getDescriptor(List.class);
public byte[] instrument(byte[] bytecode) {
ClassReader reader = new ClassReader(bytecode);
ClassWriter writer = new ClassWriter(0);
ClassTransformer transformer = new ClassTransformer(writer);
reader.accept(transformer, 0);
return writer.toByteArray();
}
class ClassTransformer extends ClassVisitor {
ClassTransformer(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor innerVisitor = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodTransformer(innerVisitor);
}
}
class MethodTransformer extends MethodVisitor {
private boolean instrumented;
MethodTransformer(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
if (!bsm.getOwner().equals(lambdaMetafactory) || bsm.getName().equals("metafactory")) {
Type returnType = Type.getReturnType(desc);
if (returnType.getSort() == Type.OBJECT) {
if (returnType.getClassName().equals(Action.class.getName())) {
instrumented = true;
transformAction(desc, bsmArgs);
return;
} else if (returnType.getClassName().equals(Computation.class.getName())) {
instrumented = true;
transformComputation(desc, bsmArgs);
return;
}
}
}
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
private void transformAction(String desc, Object[] bsmArgs) {
transformArguments(desc);
transformMethod((Handle) bsmArgs[1]);
super.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(ActionImpl.class), "create",
"(" + Type.getDescriptor(List.class) + Type.getDescriptor(MethodReference.class) + ")"
+ Type.getDescriptor(ActionImpl.class), false);
}
private void transformComputation(String desc, Object[] bsmArgs) {
transformArguments(desc);
transformMethod((Handle) bsmArgs[1]);
super.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(ComputationImpl.class), "create",
"(" + Type.getDescriptor(List.class) + Type.getDescriptor(MethodReference.class) + ")"
+ Type.getDescriptor(ComputationImpl.class), false);
}
private void transformArguments(String desc) {
Type[] argTypes = Type.getArgumentTypes(desc);
String arrayListType = Type.getInternalName(ArrayList.class);
super.visitTypeInsn(Opcodes.NEW, arrayListType);
super.visitInsn(Opcodes.DUP);
super.visitIntInsn(Opcodes.SIPUSH, argTypes.length);
super.visitMethodInsn(Opcodes.INVOKESPECIAL, arrayListType, "<init>", "(I)V", false);
for (int i = argTypes.length - 1; i >= 0; --i) {
transformArgument(argTypes[i]);
}
super.visitInsn(Opcodes.DUP);
super.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Collections.class), "reverse",
"(" + listDesc + ")V", false);
}
private void transformArgument(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.SHORT:
case Type.CHAR:
case Type.INT:
transformArgument("I");
break;
case Type.LONG:
transformArgument("L");
break;
case Type.FLOAT:
transformArgument("F");
break;
case Type.DOUBLE:
transformArgument("D");
break;
default:
transformArgument("Ljava/lang/Object;");
break;
}
}
private void transformArgument(String desc) {
super.visitMethodInsn(Opcodes.INVOKESTATIC, proxyHelperType, "add",
"(" + desc + listDesc + ")" + listDesc, false);
}
private void transformMethod(Handle handle) {
super.visitTypeInsn(Opcodes.NEW, Type.getInternalName(MethodReference.class));
super.visitInsn(Opcodes.DUP);
Type ownerType = Type.getType("L" + handle.getOwner() + ";");
super.visitLdcInsn(ownerType);
super.visitLdcInsn(handle.getName());
Type[] argTypes = Type.getArgumentTypes(handle.getDesc());
Type resultType = Type.getReturnType(handle.getDesc());
super.visitIntInsn(Opcodes.SIPUSH, argTypes.length + 1);
super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
for (int i = 0; i < argTypes.length; ++i) {
super.visitInsn(Opcodes.DUP);
super.visitIntInsn(Opcodes.SIPUSH, i);
emitClassLiteral(argTypes[i]);
super.visitInsn(Opcodes.AASTORE);
}
super.visitInsn(Opcodes.DUP);
super.visitIntInsn(Opcodes.SIPUSH, argTypes.length);
emitClassLiteral(resultType);
super.visitInsn(Opcodes.AASTORE);
super.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(MethodReference.class),
"<init>", "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)V", false);
}
private void emitClassLiteral(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
break;
case Type.BYTE:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
break;
case Type.SHORT:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
break;
case Type.CHAR:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
break;
case Type.INT:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
break;
case Type.LONG:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
break;
case Type.FLOAT:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
break;
case Type.DOUBLE:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
break;
case Type.VOID:
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;");
break;
default:
super.visitLdcInsn(type);
}
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (opcode == Opcodes.INVOKESTATIC && owner.equals(Type.getInternalName(Metaprogramming.class))) {
owner = Type.getInternalName(MetaprogrammingImpl.class);
}
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(instrumented ? maxStack + 9 : maxStack, maxLocals);
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.util.List;
public class RuntimeHelper {
private RuntimeHelper() {
}
public static List<CapturedValue> add(int value, List<CapturedValue> args) {
args.add(new CapturedValue(value, true));
return args;
}
public static List<CapturedValue> add(long value, List<CapturedValue> args) {
args.add(new CapturedValue(value, true));
return args;
}
public static List<CapturedValue> add(float value, List<CapturedValue> args) {
args.add(new CapturedValue(value, true));
return args;
}
public static List<CapturedValue> add(double value, List<CapturedValue> args) {
args.add(new CapturedValue(value, true));
return args;
}
public static List<CapturedValue> add(Object value, List<CapturedValue> args) {
args.add(new CapturedValue(value, false));
return args;
}
}

View File

@ -0,0 +1,293 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.WeakHashMap;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyType;
import org.teavm.dependency.MethodDependency;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.metaprogramming.CompileTime;
import org.teavm.metaprogramming.impl.model.MethodModel;
import org.teavm.model.AccessLevel;
import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
public class UsageGenerator {
private static Map<DependencyAgent, Integer> suffixGenerator = new WeakHashMap<>();
DependencyAgent agent;
MethodModel model;
MethodDependency methodDep;
CallLocation location;
Diagnostics diagnostics;
Method proxyMethod;
private MetaprogrammingClassLoader classLoader;
private boolean annotationErrorReported;
UsageGenerator(DependencyAgent agent, MethodModel model, MethodDependency methodDep, CallLocation location,
MetaprogrammingClassLoader classLoader) {
this.agent = agent;
this.diagnostics = agent.getDiagnostics();
this.model = model;
this.methodDep = methodDep;
this.location = location;
this.classLoader = classLoader;
}
public void installProxyEmitter() {
Diagnostics diagnostics = agent.getDiagnostics();
MethodDependency getClassDep = agent.linkMethod(new MethodReference(Object.class, "getClass", Class.class),
location);
getClassDep.getThrown().connect(methodDep.getThrown());
try {
proxyMethod = getJavaMethod(classLoader, model.getMetaMethod());
proxyMethod.setAccessible(true);
} catch (ReflectiveOperationException e) {
StringWriter stackTraceWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stackTraceWriter));
diagnostics.error(location, "Error accessing proxy method {{m0}}: " + stackTraceWriter.getBuffer(),
model.getMetaMethod());
return;
}
if (model.getClassParameterIndex() >= 0) {
int index = (model.isStatic() ? 0 : 1) + model.getClassParameterIndex();
methodDep.getVariable(index).addConsumer(type -> consumeType(type, getClassDep));
} else {
emitPermutation(null, getClassDep);
}
installAdditionalDependencies(getClassDep);
}
private void installAdditionalDependencies(MethodDependency getClassDep) {
MethodDependency nameDep = agent.linkMethod(new MethodReference(Class.class, "getName", String.class),
location);
getClassDep.getResult().connect(nameDep.getVariable(0));
nameDep.getThrown().connect(methodDep.getThrown());
nameDep.use();
MethodDependency equalsDep = agent.linkMethod(new MethodReference(String.class, "equals", Object.class,
boolean.class), location);
nameDep.getResult().connect(equalsDep.getVariable(0));
equalsDep.getVariable(1).propagate(agent.getType("java.lang.String"));
equalsDep.getThrown().connect(methodDep.getThrown());
equalsDep.use();
MethodDependency hashCodeDep = agent.linkMethod(new MethodReference(String.class, "hashCode", int.class),
location);
nameDep.getResult().connect(hashCodeDep.getVariable(0));
hashCodeDep.getThrown().connect(methodDep.getThrown());
hashCodeDep.use();
}
private void consumeType(DependencyType type, MethodDependency getClassDep) {
emitPermutation(findClass(type.getName()), getClassDep);
}
private void emitPermutation(ValueType type, MethodDependency getClassDep) {
if (!classLoader.isCompileTimeClass(model.getMetaMethod().getClassName()) && !annotationErrorReported) {
annotationErrorReported = true;
diagnostics.error(location, "Metaprogramming method should be within class marked with "
+ "{{c0}} annotation", CompileTime.class.getName());
return;
}
MethodReference implRef = model.getUsages().get(type);
if (implRef != null) {
return;
}
implRef = buildMethodReference(type);
model.getUsages().put(type, implRef);
//emitter = new EmitterImpl<>(emitterContext, model.getProxyMethod(), model.getMethod().getReturnType());
/*for (int i = 0; i <= model.getParameters().size(); ++i) {
emitter.generator.getProgram().createVariable();
}
*/
Object[] proxyArgs = new Object[model.getMetaParameterCount()];
for (int i = 0; i < proxyArgs.length; ++i) {
if (i == model.getMetaClassParameterIndex()) {
proxyArgs[i] = MetaprogrammingImpl.findClass(type);
} else {
proxyArgs[i] = new ValueImpl<>(null, null, model.getMetaParameterType(i));
}
}
try {
proxyMethod.invoke(null, proxyArgs);
//emitter.close();
Program program = null; //emitter.generator.getProgram();
//new BoxingEliminator().optimize(program);
ClassHolder cls = new ClassHolder(implRef.getClassName());
cls.setLevel(AccessLevel.PUBLIC);
cls.setParent("java.lang.Object");
MethodHolder method = new MethodHolder(implRef.getDescriptor());
method.setLevel(AccessLevel.PUBLIC);
method.getModifiers().add(ElementModifier.STATIC);
method.setProgram(program);
cls.addMethod(method);
agent.submitClass(cls);
} catch (IllegalAccessException | InvocationTargetException e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
diagnostics.error(location, "Error calling proxy method {{m0}}: " + writer.toString(),
model.getMetaMethod());
}
MethodDependency implMethod = agent.linkMethod(implRef, location);
for (int i = 0; i < implRef.parameterCount(); ++i) {
methodDep.getVariable(i + 1).connect(implMethod.getVariable(i + 1));
}
if (model.getClassParameterIndex() >= 0) {
implMethod.getVariable(model.getClassParameterIndex() + 1).connect(getClassDep.getVariable(0));
}
if (implMethod.getResult() != null) {
implMethod.getResult().connect(methodDep.getResult());
}
implMethod.getThrown().connect(methodDep.getThrown());
implMethod.use();
agent.linkClass(implRef.getClassName(), location);
}
private ValueType findClass(String name) {
// TODO: dirty hack due to bugs somewhere in TeaVM
if (name.startsWith("[")) {
ValueType type = ValueType.parseIfPossible(name);
if (type != null) {
return type;
}
int degree = 0;
while (name.charAt(degree) == '[') {
++degree;
}
type = ValueType.object(name.substring(degree));
while (degree-- > 0) {
type = ValueType.arrayOf(type);
}
return type;
} else {
return ValueType.object(name);
}
}
private MethodReference buildMethodReference(ValueType type) {
if (model.getClassParameterIndex() < 0) {
return new MethodReference(model.getMethod().getClassName() + "$PROXY$" + getSuffix(),
model.getMethod().getDescriptor());
}
int i = 0;
ValueType[] signature = new ValueType[model.getMetaParameterCount()];
for (i = 0; i < signature.length; ++i) {
signature[i] = model.getMetaParameterType(i);
}
signature[i] = model.getMethod().getReturnType();
return new MethodReference(model.getMethod().getClassName() + "$PROXY$" + getSuffix(),
model.getMethod().getName(), signature);
}
private int getSuffix() {
int suffix = suffixGenerator.getOrDefault(agent, 0);
suffixGenerator.put(agent, suffix + 1);
return suffix;
}
private Method getJavaMethod(ClassLoader classLoader, MethodReference ref) throws ReflectiveOperationException {
Class<?> cls = Class.forName(ref.getClassName(), true, classLoader);
Class<?>[] parameterTypes = new Class<?>[ref.parameterCount()];
for (int i = 0; i < parameterTypes.length; ++i) {
parameterTypes[i] = getJavaType(classLoader, ref.parameterType(i));
}
return cls.getDeclaredMethod(ref.getName(), parameterTypes);
}
private Class<?> getJavaType(ClassLoader classLoader, ValueType type) throws ReflectiveOperationException {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
return boolean.class;
case BYTE:
return byte.class;
case SHORT:
return short.class;
case CHARACTER:
return char.class;
case INTEGER:
return int.class;
case LONG:
return long.class;
case FLOAT:
return float.class;
case DOUBLE:
return double.class;
}
} else if (type instanceof ValueType.Array) {
Class<?> componentType = getJavaType(classLoader, ((ValueType.Array) type).getItemType());
return Array.newInstance(componentType, 0).getClass();
} else if (type instanceof ValueType.Object) {
String className = ((ValueType.Object) type).getClassName();
return Class.forName(className, true, classLoader);
} else if (type instanceof ValueType.Void) {
return void.class;
}
throw new AssertionError("Don't know how to map type: " + type);
}
private Variable box(Variable var, Class<?> boxed, Class<?> primitive) {
Program program = null; //emitter.generator.getProgram();
BasicBlock block = program.basicBlockAt(0);
InvokeInstruction insn = new InvokeInstruction();
insn.setType(InvocationType.SPECIAL);
insn.setMethod(new MethodReference(boxed, "valueOf", primitive, boxed));
insn.getArguments().add(var);
var = program.createVariable();
insn.setReceiver(var);
block.getInstructions().add(insn);
return var;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import org.teavm.metaprogramming.Value;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
public class ValueImpl<T> implements Value<T> {
Variable innerValue;
VariableContext context;
ValueType type;
public ValueImpl(Variable innerValue, VariableContext context, ValueType type) {
this.innerValue = innerValue;
this.context = context;
this.type = type;
}
@Override
public T get() {
throw new IllegalStateException("Can only read this value in emitter domain");
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2016 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.metaprogramming.impl;
import org.teavm.model.CallLocation;
import org.teavm.model.Variable;
public abstract class VariableContext {
private VariableContext parent;
public VariableContext(VariableContext parent) {
this.parent = parent;
}
public VariableContext getParent() {
return parent;
}
public abstract Variable emitVariable(ValueImpl<?> value, CallLocation location);
}

View File

@ -0,0 +1,112 @@
/*
* Copyright 2016 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.metaprogramming.impl.model;
import java.util.HashMap;
import java.util.Map;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.metaprogramming.Meta;
import org.teavm.metaprogramming.ReflectClass;
import org.teavm.metaprogramming.Value;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class MethodDescriber {
private Diagnostics diagnostics;
private ClassReaderSource classSource;
private Map<MethodReference, MethodModel> cache = new HashMap<>();
public MethodDescriber(Diagnostics diagnostics, ClassReaderSource classSource) {
this.diagnostics = diagnostics;
this.classSource = classSource;
}
public MethodModel getMethod(MethodReference method) {
return cache.computeIfAbsent(method, this::describeMethod);
}
public MethodModel getKnownMethod(MethodReference method) {
return cache.get(method);
}
public Iterable<MethodModel> getKnownMethods() {
return cache.values();
}
private MethodModel describeMethod(MethodReference methodRef) {
MethodReader method = classSource.resolve(methodRef);
if (method == null) {
return null;
}
if (method.getAnnotations().get(Meta.class.getName()) == null) {
return null;
}
CallLocation location = new CallLocation(methodRef);
MethodModel proxyMethod = findMetaMethod(method);
if (proxyMethod == null) {
diagnostics.error(location, "Corresponding meta method was not found");
return null;
}
return proxyMethod;
}
private MethodModel findMetaMethod(MethodReader method) {
ClassReader cls = classSource.get(method.getOwnerName());
for (MethodReader meta : cls.getMethods()) {
if (meta == method
|| !meta.hasModifier(ElementModifier.STATIC)
|| !meta.getName().equals(method.getName())
|| meta.getResultType() != ValueType.VOID
|| meta.parameterCount() != method.parameterCount() + 1) {
continue;
}
int paramOffset = 0;
boolean isStatic = method.hasModifier(ElementModifier.STATIC);
if (!isStatic) {
if (meta.parameterCount() == 0 || meta.parameterType(0).isObject(Value.class)) {
return null;
}
paramOffset++;
}
int classParamIndex = -1;
for (int i = 0; i < method.parameterCount(); ++i) {
ValueType proxyParam = meta.parameterType(i + paramOffset);
ValueType param = method.parameterType(i);
if (proxyParam.isObject(ReflectClass.class)) {
if (classParamIndex == -1) {
classParamIndex = i;
} else {
return null;
}
} else if (!proxyParam.isObject(Value.class)) {
return null;
}
}
return new MethodModel(method.getReference(), meta.getReference(), classParamIndex, isStatic);
}
return null;
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright 2016 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.metaprogramming.impl.model;
import java.util.HashMap;
import java.util.Map;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class MethodModel {
private MethodReference method;
private MethodReference metaMethod;
private int classParameterIndex;
private boolean isStatic;
private Map<ValueType, MethodReference> usages = new HashMap<>();
MethodModel(MethodReference method, MethodReference metaMethod, int classParameterIndex, boolean isStatic) {
this.method = method;
this.metaMethod = metaMethod;
this.classParameterIndex = classParameterIndex;
this.isStatic = isStatic;
}
public MethodReference getMethod() {
return method;
}
public MethodReference getMetaMethod() {
return metaMethod;
}
public boolean isStatic() {
return isStatic;
}
public int getClassParameterIndex() {
return classParameterIndex;
}
public Map<ValueType, MethodReference> getUsages() {
return usages;
}
public int getMetaParameterCount() {
return (isStatic ? 0 : 1) + method.parameterCount();
}
public ValueType getMetaParameterType(int index) {
if (!isStatic) {
if (index == 0) {
return ValueType.object(method.getClassName());
} else {
--index;
}
}
return method.parameterType(index);
}
public int getMetaClassParameterIndex() {
return classParameterIndex >= 0 ? mapParameterIndex(classParameterIndex) : -1;
}
public int mapParameterIndex(int index) {
return isStatic ? index : index + 1;
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright 2016 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.metaprogramming.impl.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.ValueType;
class AnnotationProxy implements InvocationHandler {
private ClassLoader classLoader;
private ClassReaderSource classSource;
private AnnotationReader reader;
private Class<?> annotationType;
private Map<String, Object> cache = new HashMap<>();
AnnotationProxy(ClassLoader classLoader, ClassReaderSource classSource, AnnotationReader reader,
Class<?> annotationType) {
this.classLoader = classLoader;
this.classSource = classSource;
this.reader = reader;
this.annotationType = annotationType;
}
AnnotationProxy(AnnotationReader reader) {
this.reader = reader;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("annotationType")) {
return annotationType;
} else {
ClassReader cls = classSource.get(reader.getType());
return cache.computeIfAbsent(method.getName(), name -> {
MethodDescriptor desc = new MethodDescriptor(name, ValueType.parse(method.getReturnType()));
MethodReader methodReader = cls.getMethod(desc);
AnnotationValue value = reader.getValue(name);
if (value == null) {
value = methodReader.getAnnotationDefault();
}
try {
return convertValue(value, desc.getResultType());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}
private Object convertValue(AnnotationValue value, ValueType type) throws Exception {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
return value.getBoolean();
case BYTE:
return value.getByte();
case SHORT:
return value.getShort();
case INTEGER:
return value.getInt();
case LONG:
return value.getLong();
case FLOAT:
return value.getFloat();
case DOUBLE:
return value.getDouble();
case CHARACTER:
break;
}
} else if (type.isObject(String.class)) {
return value.getString();
} else if (type instanceof ValueType.Array) {
List<AnnotationValue> array = value.getList();
ValueType itemType = ((ValueType.Array) type).getItemType();
Class<?> componentType = convertClass(itemType);
Object result = Array.newInstance(componentType, array.size());
for (int i = 0; i < array.size(); ++i) {
Array.set(result, i, convertValue(array.get(i), itemType));
}
return result;
} else if (type.isObject(Class.class)) {
return convertClass(value.getJavaClass());
} else if (classSource.isSuperType(ValueType.parse(Enum.class), type).orElse(false)) {
FieldReference fieldRef = value.getEnumValue();
Class<?> enumClass = Class.forName(fieldRef.getClassName(), true, classLoader);
return enumClass.getField(fieldRef.getFieldName()).get(null);
} else if (classSource.isSuperType(ValueType.parse(Annotation.class), type).orElse(false)) {
Class<?> annotType = convertClass(type);
AnnotationProxy handler = new AnnotationProxy(classLoader, classSource, value.getAnnotation(), annotType);
return Proxy.newProxyInstance(classLoader, new Class<?>[] { annotType }, handler);
}
throw new AssertionError("Unsupported type: " + type);
}
private Class<?> convertClass(ValueType type) throws Exception {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
return boolean.class;
case BYTE:
return byte.class;
case SHORT:
return short.class;
case CHARACTER:
return char.class;
case INTEGER:
return int.class;
case LONG:
return long.class;
case FLOAT:
return float.class;
case DOUBLE:
return double.class;
}
} else if (type instanceof ValueType.Array) {
Class<?> componentType = convertClass(((ValueType.Array) type).getItemType());
return Array.newInstance(componentType, 0).getClass();
} else if (type == ValueType.VOID) {
return void.class;
} else if (type instanceof ValueType.Object) {
String name = ((ValueType.Object) type).getClassName();
return Class.forName(name, true, classLoader);
}
throw new AssertionError("Unsupported type: " + type);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2016 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.metaprogramming.impl.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import org.teavm.metaprogramming.reflect.ReflectAnnotatedElement;
import org.teavm.model.AnnotationContainerReader;
import org.teavm.model.AnnotationReader;
public class ReflectAnnotatedElementImpl implements ReflectAnnotatedElement {
private ReflectContext context;
private AnnotationContainerReader annotationContainer;
private Map<Class<?>, Annotation> annotations = new HashMap<>();
public ReflectAnnotatedElementImpl(ReflectContext context, AnnotationContainerReader annotationContainer) {
this.context = context;
this.annotationContainer = annotationContainer;
}
@Override
public <S extends Annotation> S getAnnotation(Class<S> type) {
@SuppressWarnings("unchecked")
S result = (S) annotations.computeIfAbsent(type, t -> {
if (annotationContainer == null) {
return null;
}
AnnotationReader annot = annotationContainer.get(t.getName());
if (annot == null) {
return null;
}
AnnotationProxy handler = new AnnotationProxy(context.getClassLoader(), context.getClassSource(),
annot, t);
return (Annotation) Proxy.newProxyInstance(context.getClassLoader(), new Class<?>[] { t }, handler);
});
return result;
}
}

View File

@ -0,0 +1,395 @@
/*
* Copyright 2016 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.metaprogramming.impl.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.teavm.metaprogramming.ReflectClass;
import org.teavm.metaprogramming.reflect.ReflectField;
import org.teavm.metaprogramming.reflect.ReflectMethod;
import org.teavm.model.AccessLevel;
import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReader;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.ValueType;
public class ReflectClassImpl<T> implements ReflectClass<T> {
public final ValueType type;
private ReflectContext context;
private ClassReader classReader;
private boolean resolved;
private Class<?> cls;
private Map<String, ReflectFieldImpl> declaredFields = new HashMap<>();
private ReflectField[] fieldsCache;
private Map<MethodDescriptor, ReflectMethodImpl> methods = new HashMap<>();
private Map<String, ReflectMethodImpl> declaredMethods = new HashMap<>();
private ReflectMethod[] methodsCache;
private ReflectAnnotatedElementImpl annotations;
ReflectClassImpl(ValueType type, ReflectContext context) {
this.type = type;
this.context = context;
}
public ReflectContext getReflectContext() {
return context;
}
@Override
public boolean isPrimitive() {
return type instanceof ValueType.Primitive;
}
@Override
public boolean isInterface() {
resolve();
return classReader != null && classReader.readModifiers().contains(ElementModifier.INTERFACE);
}
@Override
public boolean isArray() {
return type instanceof ValueType.Array;
}
@Override
public boolean isAnnotation() {
resolve();
return classReader != null && classReader.readModifiers().contains(ElementModifier.ANNOTATION);
}
@Override
public boolean isEnum() {
resolve();
return classReader != null && classReader.readModifiers().contains(ElementModifier.ENUM);
}
@SuppressWarnings("unchecked")
@Override
public T[] getEnumConstants() {
resolve();
if (classReader == null) {
return null;
}
if (cls == null) {
try {
cls = Class.forName(classReader.getName(), true, context.getClassLoader());
} catch (ClassNotFoundException e) {
return null;
}
}
return (T[]) cls.getEnumConstants();
}
@Override
public int getModifiers() {
resolve();
if (classReader == null) {
return 0;
}
return ReflectContext.getModifiers(classReader);
}
@Override
public ReflectClass<?> getComponentType() {
if (!(type instanceof ValueType.Array)) {
return null;
}
ValueType componentType = ((ValueType.Array) type).getItemType();
return context.getClass(componentType);
}
@Override
public String getName() {
if (type instanceof ValueType.Object) {
return ((ValueType.Object) type).getClassName();
} else if (type instanceof ValueType.Void) {
return "void";
} else if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
return "boolean";
case BYTE:
return "byte";
case SHORT:
return "short";
case CHARACTER:
return "char";
case INTEGER:
return "int";
case LONG:
return "long";
case FLOAT:
return "float";
case DOUBLE:
return "double";
default:
return "";
}
} else if (type instanceof ValueType.Array) {
return type.toString().replace('/', '.');
} else {
return "";
}
}
@SuppressWarnings("unchecked")
@Override
public ReflectClass<? super T> getSuperclass() {
resolve();
if (classReader == null || classReader.getParent() == null
|| classReader.getName().equals(classReader.getParent())) {
return null;
}
return (ReflectClass<? super T>) context.getClass(new ValueType.Object(classReader.getParent()));
}
@SuppressWarnings("unchecked")
@Override
public ReflectClass<? super T>[] getInterfaces() {
resolve();
if (classReader == null) {
return (ReflectClass<? super T>[]) Array.newInstance(ReflectClassImpl.class, 0);
}
return classReader.getInterfaces().stream()
.map(iface -> context.getClass(new ValueType.Object(iface)))
.toArray(sz -> (ReflectClass<? super T>[]) Array.newInstance(ReflectClassImpl.class, sz));
}
@Override
public boolean isInstance(Object obj) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public T cast(Object obj) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@SuppressWarnings("unchecked")
@Override
public <U> ReflectClass<U> asSubclass(Class<U> cls) {
ReflectClass<U> reflectClass = context.findClass(cls);
if (!reflectClass.isAssignableFrom(this)) {
throw new IllegalArgumentException(cls.getName() + " is not subclass of " + getName());
}
return (ReflectClass<U>) this;
}
@Override
public ReflectMethod[] getDeclaredMethods() {
resolve();
if (classReader == null) {
return new ReflectMethod[0];
}
return classReader.getMethods().stream()
.filter(method -> !method.getName().equals("<clinit>"))
.map(method -> getDeclaredMethod(method.getDescriptor()))
.toArray(ReflectMethod[]::new);
}
@Override
public ReflectMethod[] getMethods() {
resolve();
if (classReader == null) {
return new ReflectMethod[0];
}
if (methodsCache == null) {
Set<String> visited = new HashSet<>();
methodsCache = context.getClassSource().getAncestors(classReader.getName())
.flatMap(cls -> cls.getMethods().stream())
.filter(method -> !method.getName().equals("<clinit>"))
.filter(method -> visited.add(method.getDescriptor().toString()))
.map(method -> context.getClass(ValueType.object(method.getOwnerName()))
.getDeclaredMethod(method.getDescriptor()))
.filter(Objects::nonNull)
.toArray(ReflectMethod[]::new);
}
return methodsCache.clone();
}
@Override
public ReflectMethod getDeclaredMethod(String name, ReflectClass<?>... parameterTypes) {
resolve();
if (classReader == null) {
return null;
}
ValueType[] internalParameterTypes = Arrays.stream(parameterTypes)
.map(type -> ((ReflectClassImpl<?>) type).type)
.toArray(ValueType[]::new);
String key = name + "(" + ValueType.manyToString(internalParameterTypes) + ")";
return declaredMethods.computeIfAbsent(key, k -> {
MethodReader candidate = null;
for (MethodReader method : classReader.getMethods()) {
if (!method.getName().equals(name)) {
continue;
}
if (!Arrays.equals(method.getParameterTypes(), internalParameterTypes)) {
continue;
}
if (candidate == null) {
candidate = method;
} else {
boolean moreSpecial = context.getClassSource()
.isSuperType(candidate.getResultType(), method.getResultType())
.orElse(false);
if (moreSpecial) {
candidate = method;
}
}
}
return candidate != null ? getDeclaredMethod(candidate.getDescriptor()) : null;
});
}
public ReflectMethodImpl getDeclaredMethod(MethodDescriptor method) {
resolve();
return methods.computeIfAbsent(method, m -> {
MethodReader methodReader = classReader.getMethod(m);
return methodReader != null ? new ReflectMethodImpl(this, methodReader) : null;
});
}
@Override
public ReflectMethod getMethod(String name, ReflectClass<?>... parameterTypes) {
resolve();
if (classReader == null) {
return null;
}
Iterable<ClassReader> ancestors = () -> context.getClassSource().getAncestors(classReader.getName())
.iterator();
for (ClassReader cls : ancestors) {
ReflectClassImpl<?> reflectClass = context.getClass(ValueType.object(cls.getName()));
ReflectMethod method = reflectClass.getDeclaredMethod(name, parameterTypes);
if (method != null && Modifier.isPublic(method.getModifiers())) {
return method;
}
}
return null;
}
@Override
public ReflectField[] getDeclaredFields() {
resolve();
if (classReader == null) {
return new ReflectField[0];
}
return classReader.getFields().stream()
.map(fld -> getDeclaredField(fld.getName()))
.toArray(ReflectField[]::new);
}
@Override
public ReflectField[] getFields() {
if (fieldsCache == null) {
Set<String> visited = new HashSet<>();
fieldsCache = context.getClassSource()
.getAncestors(classReader.getName())
.flatMap(cls -> cls.getFields().stream().filter(fld -> fld.getLevel() == AccessLevel.PUBLIC))
.filter(fld -> visited.add(fld.getName()))
.map(fld -> context.getClass(ValueType.object(fld.getOwnerName()))
.getDeclaredField(fld.getName()))
.toArray(ReflectField[]::new);
}
return fieldsCache.clone();
}
@Override
public ReflectField getDeclaredField(String name) {
resolve();
return declaredFields.computeIfAbsent(name, n -> {
FieldReader fld = classReader.getField(n);
return fld != null ? new ReflectFieldImpl(this, fld) : null;
});
}
@Override
public ReflectField getField(String name) {
resolve();
if (classReader == null) {
return null;
}
FieldReader fieldReader = classReader.getField(name);
return fieldReader != null && fieldReader.getLevel() == AccessLevel.PUBLIC
? getDeclaredField(name)
: null;
}
@Override
public <S extends Annotation> S getAnnotation(Class<S> type) {
resolve();
if (classReader == null) {
return null;
}
if (annotations == null) {
annotations = new ReflectAnnotatedElementImpl(context, classReader.getAnnotations());
}
return annotations.getAnnotation(type);
}
private void resolve() {
if (resolved) {
return;
}
resolved = true;
if (!(type instanceof ValueType.Object)) {
return;
}
String className = ((ValueType.Object) type).getClassName();
classReader = context.getClassSource().get(className);
}
@Override
public String toString() {
if (isArray()) {
return getComponentType().toString() + "[]";
} else {
return getName();
}
}
@Override
public T[] createArray(int size) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public T getArrayElement(Object array, int index) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public int getArrayLength(Object array) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public Class<T> asJavaClass() {
throw new IllegalStateException("Don't call this method from compile domain");
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2016 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.metaprogramming.impl.reflect;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.ElementReader;
import org.teavm.model.ValueType;
/**
*
* @author Alexey Andreev
*/
public class ReflectContext {
private ClassReaderSource classSource;
private Map<ValueType, ReflectClassImpl<?>> classes = new HashMap<>();
private ClassLoader classLoader;
public ReflectContext(ClassReaderSource classSource, ClassLoader classLoader) {
this.classSource = classSource;
this.classLoader = classLoader;
}
public ClassLoader getClassLoader() {
return classLoader;
}
public ClassReaderSource getClassSource() {
return classSource;
}
public ReflectClassImpl<?> getClass(ValueType type) {
return classes.computeIfAbsent(type, t -> new ReflectClassImpl<>(type, this));
}
@SuppressWarnings("unchecked")
public <T> ReflectClassImpl<T> findClass(Class<T> cls) {
return (ReflectClassImpl<T>) getClass(ValueType.parse(cls));
}
public ReflectClassImpl<?> findClass(String name) {
if (classSource.get(name) == null) {
return null;
}
return getClass(ValueType.object(name));
}
public static int getModifiers(ElementReader element) {
int modifiers = 0;
switch (element.getLevel()) {
case PUBLIC:
modifiers |= Modifier.PUBLIC;
break;
case PROTECTED:
modifiers |= Modifier.PROTECTED;
break;
case PRIVATE:
modifiers |= Modifier.PRIVATE;
break;
case PACKAGE_PRIVATE:
break;
}
Set<ElementModifier> modifierSet = element.readModifiers();
if (modifierSet.contains(ElementModifier.ABSTRACT)) {
modifiers |= Modifier.ABSTRACT;
}
if (modifierSet.contains(ElementModifier.FINAL)) {
modifiers |= Modifier.FINAL;
}
if (modifierSet.contains(ElementModifier.INTERFACE)) {
modifiers |= Modifier.INTERFACE;
}
if (modifierSet.contains(ElementModifier.NATIVE)) {
modifiers |= Modifier.NATIVE;
}
if (modifierSet.contains(ElementModifier.STATIC)) {
modifiers |= Modifier.STATIC;
}
if (modifierSet.contains(ElementModifier.STRICT)) {
modifiers |= Modifier.STRICT;
}
if (modifierSet.contains(ElementModifier.SYNCHRONIZED)) {
modifiers |= Modifier.SYNCHRONIZED;
}
if (modifierSet.contains(ElementModifier.TRANSIENT)) {
modifiers |= Modifier.TRANSIENT;
}
if (modifierSet.contains(ElementModifier.VOLATILE)) {
modifiers |= Modifier.VOLATILE;
}
return modifiers;
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright 2016 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.metaprogramming.impl.reflect;
import java.lang.annotation.Annotation;
import org.teavm.metaprogramming.ReflectClass;
import org.teavm.metaprogramming.reflect.ReflectField;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReader;
/**
*
* @author Alexey Andreev
*/
public class ReflectFieldImpl implements ReflectField {
private ReflectContext context;
private ReflectClassImpl<?> declaringClass;
public final FieldReader field;
private ReflectClassImpl<?> type;
private ReflectAnnotatedElementImpl annotations;
public ReflectFieldImpl(ReflectClassImpl<?> declaringClass, FieldReader field) {
context = declaringClass.getReflectContext();
this.declaringClass = declaringClass;
this.field = field;
}
@Override
public ReflectClass<?> getDeclaringClass() {
return declaringClass;
}
@Override
public String getName() {
return field.getName();
}
@Override
public int getModifiers() {
return ReflectContext.getModifiers(field);
}
@Override
public boolean isEnumConstant() {
return field.readModifiers().contains(ElementModifier.ENUM);
}
@Override
public ReflectClass<?> getType() {
if (type == null) {
type = context.getClass(field.getType());
}
return type;
}
@Override
public Object get(Object target) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public void set(Object target, Object value) {
throw new IllegalStateException("Don't call this method from compile domain");
}
public FieldReader getBackingField() {
return field;
}
@Override
public <S extends Annotation> S getAnnotation(Class<S> type) {
if (annotations == null) {
annotations = new ReflectAnnotatedElementImpl(context, field.getAnnotations());
}
return annotations.getAnnotation(type);
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright 2016 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.metaprogramming.impl.reflect;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import org.teavm.metaprogramming.ReflectClass;
import org.teavm.metaprogramming.reflect.ReflectAnnotatedElement;
import org.teavm.metaprogramming.reflect.ReflectMethod;
import org.teavm.model.MethodReader;
/**
*
* @author Alexey Andreev
*/
public class ReflectMethodImpl implements ReflectMethod {
private ReflectContext context;
private ReflectClassImpl<?> declaringClass;
public final MethodReader method;
private ReflectClassImpl<?> returnType;
private ReflectClass<?>[] parameterTypes;
private ReflectAnnotatedElementImpl annotations;
private ReflectAnnotatedElementImpl[] parameterAnnotations;
public ReflectMethodImpl(ReflectClassImpl<?> declaringClass, MethodReader method) {
this.declaringClass = declaringClass;
this.method = method;
context = declaringClass.getReflectContext();
}
@Override
public ReflectClass<?> getDeclaringClass() {
return declaringClass;
}
@Override
public String getName() {
return method.getName();
}
@Override
public int getModifiers() {
return ReflectContext.getModifiers(method);
}
@Override
public boolean isConstructor() {
return method.getName().equals("<init>");
}
@Override
public ReflectClass<?> getReturnType() {
if (returnType == null) {
returnType = context.getClass(method.getResultType());
}
return returnType;
}
@Override
public ReflectClass<?>[] getParameterTypes() {
ensureParameterTypes();
return parameterTypes.clone();
}
@Override
public ReflectClass<?> getParameterType(int index) {
ensureParameterTypes();
return parameterTypes[index];
}
@Override
public int getParameterCount() {
ensureParameterTypes();
return parameterTypes.length;
}
private void ensureParameterTypes() {
if (parameterTypes == null) {
parameterTypes = Arrays.stream(method.getParameterTypes())
.map(type -> context.getClass(type))
.toArray(sz -> new ReflectClass<?>[sz]);
}
}
@Override
public <S extends Annotation> S getAnnotation(Class<S> type) {
if (annotations == null) {
annotations = new ReflectAnnotatedElementImpl(context, method.getAnnotations());
}
return annotations.getAnnotation(type);
}
@Override
public Object invoke(Object obj, Object... args) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public Object construct(Object... args) {
throw new IllegalStateException("Don't call this method from compile domain");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getReturnType()).append(' ').append(getName()).append('(');
ReflectClass<?>[] parameterTypes = getParameterTypes();
sb.append(Arrays.stream(parameterTypes).map(Objects::toString).collect(Collectors.joining(", ")));
sb.append(')');
return sb.toString();
}
@Override
public ReflectAnnotatedElement getParameterAnnotations(int index) {
if (parameterAnnotations == null) {
parameterAnnotations = Arrays.stream(method.getParameterAnnotations())
.map(annot -> new ReflectAnnotatedElementImpl(context, annot))
.toArray(sz -> new ReflectAnnotatedElementImpl[sz]);
}
return parameterAnnotations[index];
}
}

View File

@ -27,6 +27,7 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="Maven: junit:junit:4.11" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -11,6 +11,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -20,6 +20,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -12,6 +12,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 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.metaprogramming;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Meta {
}

View File

@ -16,10 +16,11 @@
package org.teavm.metaprogramming;
import java.util.Arrays;
import org.teavm.metaprogramming.reflect.ReflectAnnotatedElement;
import org.teavm.metaprogramming.reflect.ReflectField;
import org.teavm.metaprogramming.reflect.ReflectMethod;
public interface ReflectClass<T> {
public interface ReflectClass<T> extends ReflectAnnotatedElement {
boolean isPrimitive();
boolean isInterface();

View File

@ -17,7 +17,7 @@ package org.teavm.metaprogramming.reflect;
import org.teavm.metaprogramming.ReflectClass;
public interface ReflectMember {
public interface ReflectMember extends ReflectAnnotatedElement {
ReflectClass<?> getDeclaringClass();
String getName();

View File

@ -24,6 +24,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -25,6 +25,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso" scope="PROVIDED" />

View File

@ -35,6 +35,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso" scope="PROVIDED" />

View File

@ -25,6 +25,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso-apis" scope="PROVIDED" />

View File

@ -29,6 +29,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso" scope="PROVIDED" />

View File

@ -25,6 +25,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso-apis" scope="PROVIDED" />

View File

@ -25,6 +25,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso" scope="PROVIDED" />

View File

@ -25,6 +25,7 @@
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" scope="PROVIDED" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="module" module-name="teavm-jso" scope="PROVIDED" />

View File

@ -11,6 +11,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -45,6 +45,7 @@
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.2.1.v20140609" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.2.1.v20140609" level="project" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -11,6 +11,7 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-tooling" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -24,6 +24,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />

View File

@ -42,6 +42,7 @@
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.maven:maven-artifact:3.3.3" level="project" />
<orderEntry type="module" module-name="teavm-tooling" />
<orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />