mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Start porting metaprogramming API implementation
This commit is contained in:
parent
1826e04951
commit
92dbed2593
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Reference in New Issue
Block a user