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
92dbed2593
commit
5e7311d8cc
|
@ -45,6 +45,7 @@
|
||||||
<file type="gwt" url="file://$PROJECT_DIR$/samples/benchmark" />
|
<file type="gwt" url="file://$PROJECT_DIR$/samples/benchmark" />
|
||||||
<file type="Osmorc" url="file://$PROJECT_DIR$/classlib" />
|
<file type="Osmorc" url="file://$PROJECT_DIR$/classlib" />
|
||||||
<file type="Osmorc" url="file://$PROJECT_DIR$/core" />
|
<file type="Osmorc" url="file://$PROJECT_DIR$/core" />
|
||||||
|
<file type="Osmorc" url="file://$PROJECT_DIR$/metaprogramming-api" />
|
||||||
<file type="Osmorc" url="file://$PROJECT_DIR$/platform" />
|
<file type="Osmorc" url="file://$PROJECT_DIR$/platform" />
|
||||||
<file type="Osmorc" url="file://$PROJECT_DIR$/tools/chrome-rdp" />
|
<file type="Osmorc" url="file://$PROJECT_DIR$/tools/chrome-rdp" />
|
||||||
<file type="Osmorc" url="file://$PROJECT_DIR$/tools/core" />
|
<file type="Osmorc" url="file://$PROJECT_DIR$/tools/core" />
|
||||||
|
|
|
@ -0,0 +1,308 @@
|
||||||
|
/*
|
||||||
|
* 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.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.teavm.common.DisjointSet;
|
||||||
|
import org.teavm.model.BasicBlockReader;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodHandle;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.PhiReader;
|
||||||
|
import org.teavm.model.ProgramReader;
|
||||||
|
import org.teavm.model.RuntimeConstant;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.VariableReader;
|
||||||
|
import org.teavm.model.instructions.ArrayElementType;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingCondition;
|
||||||
|
import org.teavm.model.instructions.BinaryOperation;
|
||||||
|
import org.teavm.model.instructions.BranchingCondition;
|
||||||
|
import org.teavm.model.instructions.CastIntegerDirection;
|
||||||
|
import org.teavm.model.instructions.InstructionReader;
|
||||||
|
import org.teavm.model.instructions.IntegerSubtype;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.NumericOperandType;
|
||||||
|
import org.teavm.model.instructions.SwitchTableEntryReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class AliasFinder {
|
||||||
|
int[] aliases;
|
||||||
|
Object[] constants;
|
||||||
|
ArrayElement[] arrayElements;
|
||||||
|
|
||||||
|
public void findAliases(ProgramReader program) {
|
||||||
|
DisjointSet set = new DisjointSet();
|
||||||
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
|
set.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
AliasReader reader = new AliasReader(set, program.variableCount());
|
||||||
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
|
block.readAllInstructions(reader);
|
||||||
|
for (PhiReader phi : block.readPhis()) {
|
||||||
|
Set<Integer> inputs = phi.readIncomings().stream()
|
||||||
|
.map(incoming -> incoming.getValue().getIndex())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (inputs.size() == 1) {
|
||||||
|
set.union(inputs.iterator().next(), phi.getReceiver().getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] map = new int[set.size()];
|
||||||
|
Arrays.fill(map, -1);
|
||||||
|
int[] variables = new int[program.variableCount()];
|
||||||
|
for (int i = 0; i < variables.length; ++i) {
|
||||||
|
int v = set.find(i);
|
||||||
|
int master = map[v];
|
||||||
|
if (master == -1) {
|
||||||
|
master = i;
|
||||||
|
map[v] = master;
|
||||||
|
}
|
||||||
|
variables[i] = master;
|
||||||
|
}
|
||||||
|
|
||||||
|
aliases = variables;
|
||||||
|
constants = reader.constants;
|
||||||
|
arrayElements = reader.arrayElements;
|
||||||
|
|
||||||
|
for (int i = 0; i < arrayElements.length; ++i) {
|
||||||
|
ArrayElement elem = arrayElements[i];
|
||||||
|
if (elem == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
elem.index = aliases[elem.index];
|
||||||
|
if (constants[elem.index] instanceof Integer) {
|
||||||
|
elem.index = (Integer) constants[elem.index];
|
||||||
|
} else {
|
||||||
|
arrayElements[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArrayElement {
|
||||||
|
public int array;
|
||||||
|
public int index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getAliases() {
|
||||||
|
return aliases.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getConstants() {
|
||||||
|
return constants.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayElement[] getArrayElements() {
|
||||||
|
return arrayElements.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AliasReader implements InstructionReader {
|
||||||
|
DisjointSet disjointSet;
|
||||||
|
Object[] constants;
|
||||||
|
ArrayElement[] arrayElements;
|
||||||
|
|
||||||
|
AliasReader(DisjointSet disjointSet, int variableCount) {
|
||||||
|
this.disjointSet = disjointSet;
|
||||||
|
this.constants = new Object[variableCount];
|
||||||
|
this.arrayElements = new ArrayElement[variableCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void location(InstructionLocation location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
|
constants[receiver.getIndex()] = cst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullConstant(VariableReader receiver) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void integerConstant(VariableReader receiver, int cst) {
|
||||||
|
constants[receiver.getIndex()] = cst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void longConstant(VariableReader receiver, long cst) {
|
||||||
|
constants[receiver.getIndex()] = cst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void floatConstant(VariableReader receiver, float cst) {
|
||||||
|
constants[receiver.getIndex()] = cst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doubleConstant(VariableReader receiver, double cst) {
|
||||||
|
constants[receiver.getIndex()] = cst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
|
constants[receiver.getIndex()] = cst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||||
|
NumericOperandType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||||
|
disjointSet.union(receiver.getIndex(), assignee.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||||
|
NumericOperandType targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||||
|
CastIntegerDirection targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||||
|
BasicBlockReader alternative) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||||
|
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jump(BasicBlockReader target) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||||
|
BasicBlockReader defaultTarget) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exit(VariableReader valueToReturn) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void raise(VariableReader exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType,
|
||||||
|
List<? extends VariableReader> dimensions) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(VariableReader receiver, String type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||||
|
ValueType fieldType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||||
|
disjointSet.union(receiver.getIndex(), array.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||||
|
ArrayElement elem = new ArrayElement();
|
||||||
|
elem.array = array.getIndex();
|
||||||
|
elem.index = index.getIndex();
|
||||||
|
arrayElements[receiver.getIndex()] = elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
|
List<? extends VariableReader> arguments, InvocationType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
|
||||||
|
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
|
||||||
|
List<RuntimeConstant> bootstrapArguments) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initClass(String className) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullCheck(VariableReader receiver, VariableReader value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void monitorEnter(VariableReader objectRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void monitorExit(VariableReader objectRef) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.LazyComputation;
|
||||||
|
import org.teavm.metaprogramming.Value;
|
||||||
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class LazyValueImpl<T> implements Value<T> {
|
||||||
|
boolean evaluated;
|
||||||
|
VariableContext context;
|
||||||
|
LazyComputation<T> computation;
|
||||||
|
ValueType type;
|
||||||
|
InstructionLocation forcedLocation;
|
||||||
|
|
||||||
|
public LazyValueImpl(VariableContext context, LazyComputation<T> computation, ValueType type,
|
||||||
|
InstructionLocation forcedLocation) {
|
||||||
|
this.context = context;
|
||||||
|
this.computation = computation;
|
||||||
|
this.type = type;
|
||||||
|
this.forcedLocation = forcedLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get() {
|
||||||
|
throw new IllegalStateException("Can only read this value in emitter domain");
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,46 +15,151 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.metaprogramming.impl;
|
package org.teavm.metaprogramming.impl;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.teavm.metaprogramming.Diagnostics;
|
||||||
import org.teavm.metaprogramming.InvocationHandler;
|
import org.teavm.metaprogramming.InvocationHandler;
|
||||||
import org.teavm.metaprogramming.LazyComputation;
|
import org.teavm.metaprogramming.LazyComputation;
|
||||||
import org.teavm.metaprogramming.ReflectClass;
|
import org.teavm.metaprogramming.ReflectClass;
|
||||||
import org.teavm.metaprogramming.Scope;
|
import org.teavm.metaprogramming.SourceLocation;
|
||||||
import org.teavm.metaprogramming.Value;
|
import org.teavm.metaprogramming.Value;
|
||||||
import org.teavm.metaprogramming.impl.reflect.ReflectClassImpl;
|
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.ReflectMethodImpl;
|
||||||
|
import org.teavm.model.CallLocation;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.MethodReader;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
|
||||||
public final class MetaprogrammingImpl {
|
public final class MetaprogrammingImpl {
|
||||||
static ClassLoader classLoader;
|
static ClassLoader classLoader;
|
||||||
|
static ClassReaderSource classSource;
|
||||||
static ReflectContext reflectContext;
|
static ReflectContext reflectContext;
|
||||||
|
static DependencyAgent agent;
|
||||||
|
static VariableContext varContext;
|
||||||
|
static MethodReference templateMethod;
|
||||||
|
static CompositeMethodGenerator generator;
|
||||||
|
static ValueType returnType;
|
||||||
|
|
||||||
private MetaprogrammingImpl() {
|
private MetaprogrammingImpl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Value<T> emit(Computation<T> computation) {
|
public static <T> Value<T> emit(Computation<T> computation) {
|
||||||
unsupported();
|
if (computation instanceof ValueImpl<?>) {
|
||||||
return null;
|
@SuppressWarnings("unchecked")
|
||||||
|
ValueImpl<T> valueImpl = (ValueImpl<T>) computation;
|
||||||
|
Variable var = varContext.emitVariable(valueImpl, new CallLocation(templateMethod, generator.location));
|
||||||
|
return new ValueImpl<>(var, varContext, valueImpl.type);
|
||||||
|
} else if (computation instanceof LazyValueImpl<?>) {
|
||||||
|
LazyValueImpl<?> valueImpl = (LazyValueImpl<?>) computation;
|
||||||
|
Variable var = generator.lazy(valueImpl);
|
||||||
|
return var != null ? new ValueImpl<>(var, varContext, valueImpl.type) : null;
|
||||||
|
} else {
|
||||||
|
Fragment fragment = (Fragment) computation;
|
||||||
|
MethodReader method = classSource.resolve(fragment.method);
|
||||||
|
generator.addProgram(method.getProgram(), fragment.capturedValues);
|
||||||
|
return new ValueImpl<>(generator.getResultVar(), varContext, fragment.method.getReturnType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void emit(Action action) {
|
public static void emit(Action action) {
|
||||||
unsupported();
|
Fragment fragment = (Fragment) action;
|
||||||
|
MethodReader method = classSource.resolve(fragment.method);
|
||||||
|
generator.addProgram(method.getProgram(), fragment.capturedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Value<T> lazyFragment(LazyComputation<T> computation) {
|
public static <T> Value<T> lazyFragment(LazyComputation<T> computation) {
|
||||||
unsupported();
|
return lazyFragment(ValueType.object("java.lang.Object"), computation);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Value<T> lazy(Computation<T> computation) {
|
public static <T> Value<T> lazy(Computation<T> computation) {
|
||||||
unsupported();
|
Fragment fragment = (Fragment) computation;
|
||||||
return null;
|
return lazyFragment(fragment.method.getReturnType(), () -> emit(computation));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scope currentScope() {
|
private static <T> Value<T> lazyFragment(ValueType type, LazyComputation<T> computation) {
|
||||||
unsupported();
|
return new LazyValueImpl<>(varContext, computation, type, generator.forcedLocation);
|
||||||
return null;
|
}
|
||||||
|
|
||||||
|
public static void exit(Value<?> value) {
|
||||||
|
if (value == null) {
|
||||||
|
returnValue(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof Fragment) {
|
||||||
|
Fragment fragment = (Fragment) value;
|
||||||
|
MethodReader method = classSource.resolve(fragment.method);
|
||||||
|
generator.addProgram(method.getProgram(), fragment.capturedValues);
|
||||||
|
generator.blockIndex = generator.returnBlockIndex;
|
||||||
|
|
||||||
|
returnValue(unbox(generator.getResultVar()));
|
||||||
|
} else if (value instanceof ValueImpl) {
|
||||||
|
ValueImpl<?> valueImpl = (ValueImpl<?>) value;
|
||||||
|
returnValue(unbox(varContext.emitVariable(valueImpl, new CallLocation(templateMethod,
|
||||||
|
generator.location))));
|
||||||
|
} else if (value instanceof LazyValueImpl) {
|
||||||
|
Variable var = generator.lazy((LazyValueImpl<?>) value);
|
||||||
|
returnValue(unbox(var));
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unexpected computation type: " + value.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Variable unbox(Variable var) {
|
||||||
|
if (returnType instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) returnType).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
var = unbox(var, Boolean.class, boolean.class);
|
||||||
|
break;
|
||||||
|
case BYTE:
|
||||||
|
var = unbox(var, Byte.class, byte.class);
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
var = unbox(var, Short.class, short.class);
|
||||||
|
break;
|
||||||
|
case CHARACTER:
|
||||||
|
var = unbox(var, Character.class, char.class);
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
var = unbox(var, Integer.class, int.class);
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
var = unbox(var, Long.class, long.class);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
var = unbox(var, Float.class, float.class);
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
var = unbox(var, Double.class, double.class);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Variable unbox(Variable var, Class<?> boxed, Class<?> primitive) {
|
||||||
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
|
insn.setInstance(var);
|
||||||
|
insn.setType(InvocationType.VIRTUAL);
|
||||||
|
insn.setMethod(new MethodReference(boxed, primitive.getName() + "Value", primitive));
|
||||||
|
var = generator.program.createVariable();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
generator.add(insn);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void exit() {
|
||||||
|
exit(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void location(String fileName, int lineNumber) {
|
public static void location(String fileName, int lineNumber) {
|
||||||
|
@ -88,8 +193,7 @@ public final class MetaprogrammingImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReflectClass<?> createClass(byte[] bytecode) {
|
public static ReflectClass<?> createClass(byte[] bytecode) {
|
||||||
unsupported();
|
return findClass(agent.submitClassFile(bytecode).replace('/', '.'));
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Value<T> proxy(Class<T> type, InvocationHandler<T> handler) {
|
public static <T> Value<T> proxy(Class<T> type, InvocationHandler<T> handler) {
|
||||||
|
@ -101,8 +205,58 @@ public final class MetaprogrammingImpl {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void returnValue(Variable var) {
|
||||||
|
ExitInstruction insn = new ExitInstruction();
|
||||||
|
insn.setValueToReturn(var);
|
||||||
|
generator.add(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Diagnostics getDiagnostics() {
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void submitClass(ClassHolder cls) {
|
||||||
|
agent.submitClass(cls);
|
||||||
|
}
|
||||||
|
|
||||||
private static void unsupported() {
|
private static void unsupported() {
|
||||||
throw new UnsupportedOperationException("This operation is only supported from TeaVM compile-time "
|
throw new UnsupportedOperationException("This operation is only supported from TeaVM compile-time "
|
||||||
+ "environment");
|
+ "environment");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Diagnostics diagnostics = new Diagnostics() {
|
||||||
|
@Override
|
||||||
|
public void error(SourceLocation location, String error, Object... params) {
|
||||||
|
convertParams(params);
|
||||||
|
agent.getDiagnostics().error(convertLocation(location), error, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warning(SourceLocation location, String error, Object... params) {
|
||||||
|
convertParams(params);
|
||||||
|
agent.getDiagnostics().warning(convertLocation(location), error, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertParams(Object[] params) {
|
||||||
|
for (int i = 0; i < params.length; ++i) {
|
||||||
|
if (params[i] instanceof ReflectMethodImpl) {
|
||||||
|
params[i] = ((ReflectMethodImpl) params[i]).method.getReference();
|
||||||
|
} else if (params[i] instanceof ReflectClassImpl) {
|
||||||
|
params[i] = ((ReflectClassImpl<?>) params[i]).type;
|
||||||
|
} else if (params[i] instanceof ReflectFieldImpl) {
|
||||||
|
params[i] = ((ReflectFieldImpl) params[i]).field.getReference();
|
||||||
|
} else if (params[i] instanceof Class<?>) {
|
||||||
|
params[i] = ValueType.parse((Class<?>) params[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallLocation convertLocation(SourceLocation location) {
|
||||||
|
MethodReader method = ((ReflectMethodImpl) location.getMethod()).method;
|
||||||
|
return location.getFileName() != null
|
||||||
|
? new CallLocation(method.getReference(),
|
||||||
|
new InstructionLocation(location.getFileName(), location.getLineNumber()))
|
||||||
|
: new CallLocation(method.getReference());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,19 @@
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>teavm-metaprogramming-api</artifactId>
|
<artifactId>teavm-metaprogramming-api</artifactId>
|
||||||
|
|
||||||
|
<packaging>bundle</packaging>
|
||||||
|
|
||||||
<name>TeaVM metaprogramming API</name>
|
<name>TeaVM metaprogramming API</name>
|
||||||
<description>Declaration of interfaces and annotations for TeaVM metaprogramming</description>
|
<description>Declaration of interfaces and annotations for TeaVM metaprogramming</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -47,6 +57,17 @@
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>test-jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.felix</groupId>
|
<groupId>org.apache.felix</groupId>
|
||||||
<artifactId>maven-bundle-plugin</artifactId>
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
|
|
@ -39,9 +39,12 @@ public final class Metaprogramming {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scope currentScope() {
|
public static void exit(Value<?> returnValue) {
|
||||||
|
unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void exit() {
|
||||||
unsupported();
|
unsupported();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void location(String fileName, int lineNumber) {
|
public static void location(String fileName, int lineNumber) {
|
||||||
|
@ -86,6 +89,11 @@ public final class Metaprogramming {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Diagnostics getDiagnostics() {
|
||||||
|
unsupported();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static void unsupported() {
|
private static void unsupported() {
|
||||||
throw new UnsupportedOperationException("This operation is only supported from TeaVM compile-time "
|
throw new UnsupportedOperationException("This operation is only supported from TeaVM compile-time "
|
||||||
+ "environment");
|
+ "environment");
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
public interface Scope {
|
|
||||||
void exit(Object returnValue);
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.teavm.metaprogramming.Metaprogramming.exit;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.teavm.metaprogramming.CompileTime;
|
||||||
|
import org.teavm.metaprogramming.Meta;
|
||||||
|
import org.teavm.metaprogramming.ReflectClass;
|
||||||
|
import org.teavm.metaprogramming.Value;
|
||||||
|
|
||||||
|
@CompileTime
|
||||||
|
public class MetaprogrammingTest {
|
||||||
|
@Test
|
||||||
|
public void works() {
|
||||||
|
assertEquals("java.lang.Object".length() + 2, classNameLength(Object.class, 2));
|
||||||
|
assertEquals("java.lang.Integer".length() + 3, classNameLength(Integer.valueOf(5).getClass(), 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Meta
|
||||||
|
static native int classNameLength(Class<?> cls, int add);
|
||||||
|
static void classNameLength(ReflectClass<Object> cls, Value<Integer> add) {
|
||||||
|
int length = cls.getName().length();
|
||||||
|
exit(() -> length + add.get());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,28 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="Osmorc" name="OSGi">
|
||||||
|
<configuration manifestGenerationMode="OsmorcControlled" manifestLocation="" jarfileLocation="teavm-metaprogramming-api-1.0.0-SNAPSHOT.jar" outputPathType="CompilerOutputPath" bndFileLocation="" bundlorFileLocation="" bundleActivator="" bundleSymbolicName="teavm-metaprogramming-api" bundleVersion="1.0.0.SNAPSHOT" ignoreFilePattern="" useProjectDefaultManifestFileLocation="true" alwaysRebuildBundleJAR="false" doNotSynchronizeWithMaven="false">
|
||||||
|
<additionalProperties>
|
||||||
|
<property key="Bundle-Description" value="Declaration of interfaces and annotations for TeaVM metaprogramming" />
|
||||||
|
<property key="Export-Package" value="org.teavm.metaprogramming.*" />
|
||||||
|
<property key="Bundle-Name" value="TeaVM metaprogramming API" />
|
||||||
|
</additionalProperties>
|
||||||
|
<additionalJARContents />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
|
||||||
<output url="file://$MODULE_DIR$/target/classes" />
|
<output url="file://$MODULE_DIR$/target/classes" />
|
||||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</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: junit:junit:4.11" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
|
@ -55,6 +55,13 @@
|
||||||
<classifier>tests</classifier>
|
<classifier>tests</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.teavm</groupId>
|
||||||
|
<artifactId>teavm-metaprogramming-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
<orderEntry type="module" module-name="teavm-platform" />
|
<orderEntry type="module" module-name="teavm-platform" />
|
||||||
<orderEntry type="module" module-name="teavm-jso-apis" />
|
<orderEntry type="module" module-name="teavm-jso-apis" />
|
||||||
<orderEntry type="module" module-name="teavm-jso-apis" production-on-test="" />
|
<orderEntry type="module" module-name="teavm-jso-apis" production-on-test="" />
|
||||||
|
<orderEntry type="module" module-name="teavm-metaprogramming-api" production-on-test="" />
|
||||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" />
|
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||||
<orderEntry type="module" module-name="teavm-tooling" scope="TEST" />
|
<orderEntry type="module" module-name="teavm-tooling" scope="TEST" />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user