mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Implement metaprogramming proxies
This commit is contained in:
parent
b0e9f6f7a5
commit
84d9899b3e
|
@ -14,7 +14,7 @@
|
||||||
<property key="Bundle-Description" value="TeaVM Java class library emulation" />
|
<property key="Bundle-Description" value="TeaVM Java class library emulation" />
|
||||||
<property key="Export-Package" value="org.teavm.classlib.*" />
|
<property key="Export-Package" value="org.teavm.classlib.*" />
|
||||||
<property key="Bundle-Name" value="TeaVM Java class library" />
|
<property key="Bundle-Name" value="TeaVM Java class library" />
|
||||||
<property key="Include-Resource" value="html/jcl.html=$MODULE_DIR$/src/main/resources/html/jcl.html,html/annotation_obj.png=$MODULE_DIR$/src/main/resources/html/annotation_obj.png,html/enum_obj.png=$MODULE_DIR$/src/main/resources/html/enum_obj.png,html/jcl.css=$MODULE_DIR$/src/main/resources/html/jcl.css,html/package_obj.png=$MODULE_DIR$/src/main/resources/html/package_obj.png,html/field_public_obj.png=$MODULE_DIR$/src/main/resources/html/field_public_obj.png,html/class_obj.png=$MODULE_DIR$/src/main/resources/html/class_obj.png,html/int_obj.png=$MODULE_DIR$/src/main/resources/html/int_obj.png,html/jcl-class.html=$MODULE_DIR$/src/main/resources/html/jcl-class.html,html/methpro_obj.png=$MODULE_DIR$/src/main/resources/html/methpro_obj.png,html/methpub_obj.png=$MODULE_DIR$/src/main/resources/html/methpub_obj.png,html/field_protected_obj.png=$MODULE_DIR$/src/main/resources/html/field_protected_obj.png,META-INF/teavm.properties=$MODULE_DIR$/src/main/resources/META-INF/teavm.properties,META-INF/services/org.teavm.vm.spi.TeaVMPlugin=$MODULE_DIR$/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin,org/teavm/classlib/impl/tz/tzdata2015d.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/tz/tzdata2015d.zip,org/teavm/classlib/impl/currency/iso4217.xml=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso4217.xml,org/teavm/classlib/impl/currency/iso3166.csv=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso3166.csv,org/teavm/classlib/impl/unicode/UnicodeData.txt=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/UnicodeData.txt,org/teavm/classlib/impl/unicode/cldr-json.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip" />
|
<property key="Include-Resource" value="META-INF/services/org.teavm.vm.spi.TeaVMPlugin=$MODULE_DIR$/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin,META-INF/teavm.properties=$MODULE_DIR$/src/main/resources/META-INF/teavm.properties,html/field_public_obj.png=$MODULE_DIR$/src/main/resources/html/field_public_obj.png,html/methpro_obj.png=$MODULE_DIR$/src/main/resources/html/methpro_obj.png,html/int_obj.png=$MODULE_DIR$/src/main/resources/html/int_obj.png,html/jcl-class.html=$MODULE_DIR$/src/main/resources/html/jcl-class.html,html/enum_obj.png=$MODULE_DIR$/src/main/resources/html/enum_obj.png,html/jcl.css=$MODULE_DIR$/src/main/resources/html/jcl.css,html/field_protected_obj.png=$MODULE_DIR$/src/main/resources/html/field_protected_obj.png,html/class_obj.png=$MODULE_DIR$/src/main/resources/html/class_obj.png,html/package_obj.png=$MODULE_DIR$/src/main/resources/html/package_obj.png,html/methpub_obj.png=$MODULE_DIR$/src/main/resources/html/methpub_obj.png,html/annotation_obj.png=$MODULE_DIR$/src/main/resources/html/annotation_obj.png,html/jcl.html=$MODULE_DIR$/src/main/resources/html/jcl.html,org/teavm/classlib/impl/currency/iso4217.xml=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso4217.xml,org/teavm/classlib/impl/currency/iso3166.csv=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso3166.csv,org/teavm/classlib/impl/unicode/UnicodeData.txt=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/UnicodeData.txt,org/teavm/classlib/impl/unicode/cldr-json.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip,org/teavm/classlib/impl/tz/tzdata2015d.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/tz/tzdata2015d.zip" />
|
||||||
</additionalProperties>
|
</additionalProperties>
|
||||||
<additionalJARContents />
|
<additionalJARContents />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.metaprogramming.impl;
|
package org.teavm.metaprogramming.impl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import org.teavm.dependency.DependencyAgent;
|
import org.teavm.dependency.DependencyAgent;
|
||||||
import org.teavm.metaprogramming.Action;
|
import org.teavm.metaprogramming.Action;
|
||||||
import org.teavm.metaprogramming.Computation;
|
import org.teavm.metaprogramming.Computation;
|
||||||
|
@ -28,14 +30,19 @@ import org.teavm.metaprogramming.impl.reflect.ReflectClassImpl;
|
||||||
import org.teavm.metaprogramming.impl.reflect.ReflectContext;
|
import org.teavm.metaprogramming.impl.reflect.ReflectContext;
|
||||||
import org.teavm.metaprogramming.impl.reflect.ReflectFieldImpl;
|
import org.teavm.metaprogramming.impl.reflect.ReflectFieldImpl;
|
||||||
import org.teavm.metaprogramming.impl.reflect.ReflectMethodImpl;
|
import org.teavm.metaprogramming.impl.reflect.ReflectMethodImpl;
|
||||||
|
import org.teavm.metaprogramming.reflect.ReflectMethod;
|
||||||
|
import org.teavm.model.AccessLevel;
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.Instruction;
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.InstructionLocation;
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.Variable;
|
||||||
import org.teavm.model.instructions.DoubleConstantInstruction;
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
@ -44,11 +51,13 @@ import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
import org.teavm.model.instructions.InvocationType;
|
import org.teavm.model.instructions.InvocationType;
|
||||||
import org.teavm.model.instructions.InvokeInstruction;
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.JumpInstruction;
|
||||||
import org.teavm.model.instructions.LongConstantInstruction;
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
import org.teavm.model.instructions.NullConstantInstruction;
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
import org.teavm.model.util.InstructionTransitionExtractor;
|
import org.teavm.model.util.InstructionTransitionExtractor;
|
||||||
|
|
||||||
public final class MetaprogrammingImpl {
|
public final class MetaprogrammingImpl {
|
||||||
|
static Map<String, Integer> proxySuffixGenerators = new HashMap<>();
|
||||||
static ClassLoader classLoader;
|
static ClassLoader classLoader;
|
||||||
static ClassReaderSource classSource;
|
static ClassReaderSource classSource;
|
||||||
static ReflectContext reflectContext;
|
static ReflectContext reflectContext;
|
||||||
|
@ -207,8 +216,86 @@ public final class MetaprogrammingImpl {
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public static <T> Value<T> proxy(ReflectClass<T> type, InvocationHandler<T> handler) {
|
public static <T> Value<T> proxy(ReflectClass<T> type, InvocationHandler<T> handler) {
|
||||||
unsupported();
|
ValueType innerType = ((ReflectClassImpl<?>) type).type;
|
||||||
return null;
|
ClassHolder cls = new ClassHolder(createProxyName(type.getName()));
|
||||||
|
cls.setLevel(AccessLevel.PUBLIC);
|
||||||
|
|
||||||
|
String typeName = ((ValueType.Object) innerType).getClassName();
|
||||||
|
org.teavm.model.ClassReader typeReader = classSource.get(typeName);
|
||||||
|
if (typeReader.hasModifier(ElementModifier.INTERFACE)) {
|
||||||
|
cls.setParent("java.lang.Object");
|
||||||
|
cls.getInterfaces().add(typeName);
|
||||||
|
} else {
|
||||||
|
cls.setParent(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyVariableContext nestedVarContext = new ProxyVariableContext(varContext, cls);
|
||||||
|
for (ReflectMethod method : type.getMethods()) {
|
||||||
|
ReflectMethodImpl methodImpl = (ReflectMethodImpl) method;
|
||||||
|
if (methodImpl.method.getProgram() != null && methodImpl.method.getProgram().basicBlockCount() > 0
|
||||||
|
|| methodImpl.method.hasModifier(ElementModifier.NATIVE)
|
||||||
|
|| !methodImpl.method.hasModifier(ElementModifier.ABSTRACT)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodHolder methodHolder = new MethodHolder(methodImpl.method.getDescriptor());
|
||||||
|
methodHolder.setLevel(AccessLevel.PUBLIC);
|
||||||
|
|
||||||
|
ValueType returnTypeBackup = returnType;
|
||||||
|
VariableContext varContextBackup = varContext;
|
||||||
|
CompositeMethodGenerator generatorBackup = generator;
|
||||||
|
try {
|
||||||
|
returnType = methodHolder.getResultType();
|
||||||
|
varContext = nestedVarContext;
|
||||||
|
generator = new CompositeMethodGenerator(varContext, new Program());
|
||||||
|
|
||||||
|
Program program = generator.program;
|
||||||
|
program.createBasicBlock();
|
||||||
|
generator.blockIndex = 0;
|
||||||
|
BasicBlock startBlock = generator.currentBlock();
|
||||||
|
nestedVarContext.init(startBlock);
|
||||||
|
|
||||||
|
methodHolder.setProgram(program);
|
||||||
|
Variable thisVar = program.createVariable();
|
||||||
|
int argumentCount = methodImpl.method.parameterCount();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ValueImpl<Object>[] arguments = (ValueImpl<Object>[]) new ValueImpl<?>[argumentCount];
|
||||||
|
for (int i = 0; i < arguments.length; ++i) {
|
||||||
|
arguments[i] = new ValueImpl<>(program.createVariable(), nestedVarContext,
|
||||||
|
methodImpl.method.parameterType(i));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < arguments.length; ++i) {
|
||||||
|
ValueType argType = methodImpl.method.parameterType(i);
|
||||||
|
Variable var = generator.box(arguments[i].innerValue, argType);
|
||||||
|
arguments[i] = new ValueImpl<>(var, nestedVarContext, argType);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.invoke(new ValueImpl<>(thisVar, nestedVarContext, innerType), methodImpl, arguments);
|
||||||
|
close();
|
||||||
|
|
||||||
|
JumpInstruction jumpToStart = new JumpInstruction();
|
||||||
|
jumpToStart.setTarget(program.basicBlockAt(startBlock.getIndex() + 1));
|
||||||
|
startBlock.getInstructions().add(jumpToStart);
|
||||||
|
|
||||||
|
//new BoxingEliminator().optimize(program);
|
||||||
|
cls.addMethod(methodHolder);
|
||||||
|
} finally {
|
||||||
|
returnType = returnTypeBackup;
|
||||||
|
varContext = varContextBackup;
|
||||||
|
generator = generatorBackup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueImpl<T> result = new ValueImpl<>(nestedVarContext.createInstance(generator), varContext, innerType);
|
||||||
|
|
||||||
|
agent.submitClass(cls);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createProxyName(String className) {
|
||||||
|
int suffix = proxySuffixGenerators.getOrDefault(className, 0);
|
||||||
|
proxySuffixGenerators.put(className, suffix + 1);
|
||||||
|
return className + "$proxy" + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void returnValue(Variable var) {
|
private static void returnValue(Variable var) {
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* 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.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.teavm.model.AccessLevel;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.CallLocation;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.FieldHolder;
|
||||||
|
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.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
|
||||||
|
public class ProxyVariableContext extends VariableContext {
|
||||||
|
private Map<ValueImpl<?>, Variable> cache = new HashMap<>();
|
||||||
|
private BasicBlock startBlock;
|
||||||
|
private ClassHolder proxyClass;
|
||||||
|
private int suffixGenerator;
|
||||||
|
private Map<Variable, CapturedValue> capturedValueMap = new HashMap<>();
|
||||||
|
private List<CapturedValue> capturedValues = new ArrayList<>();
|
||||||
|
|
||||||
|
public ProxyVariableContext(VariableContext parent, ClassHolder proxyClass) {
|
||||||
|
super(parent);
|
||||||
|
this.proxyClass = proxyClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(BasicBlock startBlock) {
|
||||||
|
this.startBlock = startBlock;
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Variable emitVariable(ValueImpl<?> value, CallLocation location) {
|
||||||
|
return cache.computeIfAbsent(value, v -> createVariable(v, location));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Variable createVariable(ValueImpl<?> value, CallLocation location) {
|
||||||
|
if (value.context == this) {
|
||||||
|
return value.innerValue;
|
||||||
|
}
|
||||||
|
Variable outerVar = getParent().emitVariable(value, location);
|
||||||
|
|
||||||
|
CapturedValue capturedValue = capturedValueMap.computeIfAbsent(outerVar, v -> {
|
||||||
|
FieldHolder field = new FieldHolder("proxyCapture" + suffixGenerator++);
|
||||||
|
field.setLevel(AccessLevel.PUBLIC);
|
||||||
|
field.setType(value.type);
|
||||||
|
proxyClass.addField(field);
|
||||||
|
|
||||||
|
CapturedValue result = new CapturedValue(field, v);
|
||||||
|
capturedValues.add(result);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
Program program = startBlock.getProgram();
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
GetFieldInstruction insn = new GetFieldInstruction();
|
||||||
|
insn.setInstance(program.variableAt(0));
|
||||||
|
insn.setField(capturedValue.field.getReference());
|
||||||
|
insn.setFieldType(capturedValue.field.getType());
|
||||||
|
insn.setReceiver(var);
|
||||||
|
startBlock.getInstructions().add(insn);
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable createInstance(CompositeMethodGenerator generator) {
|
||||||
|
ValueType[] signature = new ValueType[capturedValues.size() + 1];
|
||||||
|
for (int i = 0; i < capturedValues.size(); ++i) {
|
||||||
|
signature[i] = capturedValues.get(i).field.getType();
|
||||||
|
}
|
||||||
|
signature[capturedValues.size()] = ValueType.VOID;
|
||||||
|
|
||||||
|
MethodHolder ctor = new MethodHolder("<init>", signature);
|
||||||
|
ctor.setLevel(AccessLevel.PUBLIC);
|
||||||
|
Program ctorProgram = new Program();
|
||||||
|
ctor.setProgram(ctorProgram);
|
||||||
|
BasicBlock ctorBlock = ctorProgram.createBasicBlock();
|
||||||
|
|
||||||
|
InvokeInstruction invokeSuper = new InvokeInstruction();
|
||||||
|
invokeSuper.setInstance(ctorProgram.createVariable());
|
||||||
|
invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), "<init>", ValueType.VOID));
|
||||||
|
invokeSuper.setType(InvocationType.SPECIAL);
|
||||||
|
ctorBlock.getInstructions().add(invokeSuper);
|
||||||
|
|
||||||
|
for (int i = 0; i < capturedValues.size(); ++i) {
|
||||||
|
PutFieldInstruction putInsn = new PutFieldInstruction();
|
||||||
|
putInsn.setField(capturedValues.get(i).field.getReference());
|
||||||
|
putInsn.setFieldType(capturedValues.get(i).field.getType());
|
||||||
|
putInsn.setValue(ctorProgram.createVariable());
|
||||||
|
putInsn.setInstance(ctorProgram.variableAt(0));
|
||||||
|
ctorBlock.getInstructions().add(putInsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitInstruction exit = new ExitInstruction();
|
||||||
|
ctorBlock.getInstructions().add(exit);
|
||||||
|
|
||||||
|
proxyClass.addMethod(ctor);
|
||||||
|
|
||||||
|
ConstructInstruction constructInsn = new ConstructInstruction();
|
||||||
|
constructInsn.setReceiver(generator.program.createVariable());
|
||||||
|
constructInsn.setType(proxyClass.getName());
|
||||||
|
generator.add(constructInsn);
|
||||||
|
|
||||||
|
InvokeInstruction initInsn = new InvokeInstruction();
|
||||||
|
initInsn.setInstance(constructInsn.getReceiver());
|
||||||
|
initInsn.setMethod(ctor.getReference());
|
||||||
|
initInsn.setType(InvocationType.SPECIAL);
|
||||||
|
for (int i = 0; i < capturedValues.size(); ++i) {
|
||||||
|
initInsn.getArguments().add(capturedValues.get(i).value);
|
||||||
|
}
|
||||||
|
generator.add(initInsn);
|
||||||
|
|
||||||
|
return constructInsn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
class CapturedValue {
|
||||||
|
FieldHolder field;
|
||||||
|
Variable value;
|
||||||
|
|
||||||
|
CapturedValue(FieldHolder field, Variable value) {
|
||||||
|
this.field = field;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,5 +18,5 @@ package org.teavm.metaprogramming;
|
||||||
import org.teavm.metaprogramming.reflect.ReflectMethod;
|
import org.teavm.metaprogramming.reflect.ReflectMethod;
|
||||||
|
|
||||||
public interface InvocationHandler<T> {
|
public interface InvocationHandler<T> {
|
||||||
Computation<?> invoke(Value<T> proxy, ReflectMethod method, Value<Object>[] args);
|
void invoke(Value<T> proxy, ReflectMethod method, Value<Object>[] args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* 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.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.teavm.metaprogramming.Metaprogramming.emit;
|
||||||
|
import static org.teavm.metaprogramming.Metaprogramming.exit;
|
||||||
|
import static org.teavm.metaprogramming.Metaprogramming.proxy;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.teavm.classlib.java.lang.StringBuilderTest;
|
||||||
|
import org.teavm.junit.SkipJVM;
|
||||||
|
import org.teavm.junit.TeaVMTestRunner;
|
||||||
|
import org.teavm.metaprogramming.CompileTime;
|
||||||
|
import org.teavm.metaprogramming.Meta;
|
||||||
|
import org.teavm.metaprogramming.ReflectClass;
|
||||||
|
import org.teavm.metaprogramming.Value;
|
||||||
|
|
||||||
|
@CompileTime
|
||||||
|
@RunWith(TeaVMTestRunner.class)
|
||||||
|
@SkipJVM
|
||||||
|
public class ProxyTest {
|
||||||
|
@Test
|
||||||
|
public void createsProxy() {
|
||||||
|
A proxy = createProxy(A.class, "!");
|
||||||
|
assertEquals("foo!", proxy.foo());
|
||||||
|
assertEquals("bar!", proxy.bar());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Meta
|
||||||
|
private static native <T> T createProxy(Class<T> proxyType, String add);
|
||||||
|
private static <T> void createProxy(ReflectClass<T> proxyType, Value<String> add) {
|
||||||
|
Value<T> proxy = proxy(proxyType, (instance, method, args) -> {
|
||||||
|
String name = method.getName();
|
||||||
|
exit(() -> name + add.get());
|
||||||
|
});
|
||||||
|
exit(() -> proxy.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultReturnValue() {
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
B proxy = createProxyWithDefaultReturnValue(B.class, log);
|
||||||
|
assertNull(proxy.foo());
|
||||||
|
assertEquals(0, proxy.bar());
|
||||||
|
proxy.baz();
|
||||||
|
|
||||||
|
assertEquals("foo;bar;baz;", log.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Meta
|
||||||
|
private static native <T> T createProxyWithDefaultReturnValue(Class<T> proxyType, StringBuilder sb);
|
||||||
|
private static <T> void createProxyWithDefaultReturnValue(ReflectClass<T> proxyType, Value<StringBuilder> sb) {
|
||||||
|
Value<T> proxy = proxy(proxyType, (instance, method, args) -> {
|
||||||
|
String name = method.getName();
|
||||||
|
emit(() -> sb.get().append(name + ";"));
|
||||||
|
});
|
||||||
|
exit(() -> proxy.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void boxParameters() {
|
||||||
|
C proxy = createProxyWithBoxedParameters(C.class);
|
||||||
|
assertEquals("foo(true,0,1,2,3,4,5)", proxy.foo(true, (byte) 0, '1', (short) 2, 3, 4, "5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Meta
|
||||||
|
private static native <T> T createProxyWithBoxedParameters(Class<T> proxyType);
|
||||||
|
private static <T> void createProxyWithBoxedParameters(ReflectClass<T> proxyType) {
|
||||||
|
Value<T> proxy = proxy(proxyType, (instance, method, args) -> {
|
||||||
|
Value<StringBuilder> result = emit(() -> new StringBuilder());
|
||||||
|
|
||||||
|
String name = method.getName();
|
||||||
|
emit(() -> result.get().append(name).append('('));
|
||||||
|
if (args.length > 0) {
|
||||||
|
emit(() -> result.get().append(args[0].get().toString()));
|
||||||
|
for (int i = 1; i < args.length; ++i) {
|
||||||
|
Value<Object> arg = args[i];
|
||||||
|
emit(() -> result.get().append(',').append(arg.get().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit(() -> result.get().append(')'));
|
||||||
|
|
||||||
|
exit(() -> result.get().toString());
|
||||||
|
});
|
||||||
|
exit(() -> proxy.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
String foo();
|
||||||
|
|
||||||
|
String bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B {
|
||||||
|
String foo();
|
||||||
|
|
||||||
|
int bar();
|
||||||
|
|
||||||
|
void baz();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface C {
|
||||||
|
String foo(boolean a, byte b, char c, short d, int e, long f, String g);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,14 @@
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.htmlunit:htmlunit:2.19" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.apache.httpcomponents:httpmime:4.5.1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.cssparser:cssparser:0.9.18" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-util:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-io:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.13.v20150730" level="project" />
|
||||||
<orderEntry type="module" module-name="teavm-core" />
|
<orderEntry type="module" module-name="teavm-core" />
|
||||||
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
|
<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: commons-io:commons-io:2.4" level="project" />
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<property key="Bundle-Description" value="TeaVM API that helps to create tooling" />
|
<property key="Bundle-Description" value="TeaVM API that helps to create tooling" />
|
||||||
<property key="Export-Package" value="org.teavm.*" />
|
<property key="Export-Package" value="org.teavm.*" />
|
||||||
<property key="Bundle-Name" value="TeaVM tooling core" />
|
<property key="Bundle-Name" value="TeaVM tooling core" />
|
||||||
<property key="Include-Resource" value="org/teavm/tooling/main.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/main.html,org/teavm/tooling/test/junit.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit.html,org/teavm/tooling/test/junit-client.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit-client.html,org/teavm/tooling/test/res/junit-support.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-support.js,org/teavm/tooling/test/res/control-000-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/control-000-small.png,org/teavm/tooling/test/res/package_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/package_obj.png,org/teavm/tooling/test/res/junit-client.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-client.js,org/teavm/tooling/test/res/junit.css=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit.css,org/teavm/tooling/test/res/tick-small-red.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png,org/teavm/tooling/test/res/tick-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small.png,org/teavm/tooling/test/res/class_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/class_obj.png,org/teavm/tooling/test/res/toggle-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small.png,org/teavm/tooling/test/res/toggle-small-expand.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png,org/teavm/tooling/test/res/methpub_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png" />
|
<property key="Include-Resource" value="org/teavm/tooling/test/junit.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit.html,org/teavm/tooling/test/res/junit.css=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit.css,org/teavm/tooling/test/res/tick-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small.png,org/teavm/tooling/test/res/tick-small-red.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png,org/teavm/tooling/test/res/toggle-small-expand.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png,org/teavm/tooling/test/res/control-000-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/control-000-small.png,org/teavm/tooling/test/res/junit-support.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-support.js,org/teavm/tooling/test/res/class_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/class_obj.png,org/teavm/tooling/test/res/package_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/package_obj.png,org/teavm/tooling/test/res/methpub_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png,org/teavm/tooling/test/res/junit-client.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-client.js,org/teavm/tooling/test/res/toggle-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small.png,org/teavm/tooling/test/junit-client.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit-client.html,org/teavm/tooling/main.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/main.html" />
|
||||||
</additionalProperties>
|
</additionalProperties>
|
||||||
<additionalJARContents />
|
<additionalJARContents />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -11,6 +11,14 @@
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit:2.19" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpmime:4.5.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: net.sourceforge.cssparser:cssparser:0.9.18" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.13.v20150730" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.13.v20150730" level="project" />
|
||||||
<orderEntry type="library" scope="PROVIDED" name="Maven: junit:junit:4.11" level="project" />
|
<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="library" scope="PROVIDED" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||||
<orderEntry type="module" module-name="teavm-tooling" />
|
<orderEntry type="module" module-name="teavm-tooling" />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user