mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-03 05:44:10 -08:00
Simple metaprogramming test passes
This commit is contained in:
parent
4819eee3ef
commit
3e562aa08a
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="DEFAULT_COMPILER" value="Eclipse" />
|
||||
<option name="DEFAULT_COMPILER" value="Javac" />
|
||||
<excludeFromCompile>
|
||||
<directory url="file://$PROJECT_DIR$/tools/maven/webapp/src/main/resources/archetype-resources" includeSubdirectories="true" />
|
||||
</excludeFromCompile>
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.dependency;
|
|||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -55,10 +54,6 @@ import org.teavm.model.util.ProgramUtils;
|
|||
import org.teavm.optimization.UnreachableBasicBlockEliminator;
|
||||
import org.teavm.parsing.Parser;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DependencyChecker implements DependencyInfo {
|
||||
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
||||
private int classNameSuffix;
|
||||
|
@ -73,14 +68,13 @@ public class DependencyChecker implements DependencyInfo {
|
|||
private ServiceRepository services;
|
||||
private Queue<Runnable> tasks = new ArrayDeque<>();
|
||||
List<DependencyType> types = new ArrayList<>();
|
||||
Map<String, DependencyType> typeMap = new HashMap<>();
|
||||
private Map<String, DependencyType> typeMap = new HashMap<>();
|
||||
private DependencyCheckerInterruptor interruptor;
|
||||
private boolean interrupted;
|
||||
private Diagnostics diagnostics;
|
||||
DefaultCallGraph callGraph = new DefaultCallGraph();
|
||||
private DependencyAgent agent;
|
||||
List<DependencyNode> nodes = new ArrayList<>();
|
||||
List<BitSet> typeBitSets = new ArrayList<>();
|
||||
Map<MethodReference, BootstrapMethodSubstitutor> bootstrapMethodSubstitutors = new HashMap<>();
|
||||
private boolean completing;
|
||||
|
||||
|
@ -133,14 +127,13 @@ public class DependencyChecker implements DependencyInfo {
|
|||
if (type == null) {
|
||||
type = new DependencyType(this, name, types.size());
|
||||
types.add(type);
|
||||
typeBitSets.add(new BitSet(nodes.size()));
|
||||
typeMap.put(name, type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public DependencyNode createNode() {
|
||||
DependencyNode node = new DependencyNode(this, nodes.size());
|
||||
DependencyNode node = new DependencyNode(this);
|
||||
nodes.add(node);
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,6 @@ package org.teavm.dependency;
|
|||
import java.util.*;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DependencyNode implements ValueDependencyInfo {
|
||||
private DependencyChecker dependencyChecker;
|
||||
private List<DependencyConsumer> followers;
|
||||
|
@ -32,17 +28,15 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
private DependencyNode arrayItemNode;
|
||||
private DependencyNode classValueNode;
|
||||
private int degree;
|
||||
int index;
|
||||
boolean locked;
|
||||
MethodReference method;
|
||||
|
||||
DependencyNode(DependencyChecker dependencyChecker, int index) {
|
||||
this(dependencyChecker, index, 0);
|
||||
DependencyNode(DependencyChecker dependencyChecker) {
|
||||
this(dependencyChecker, 0);
|
||||
}
|
||||
|
||||
DependencyNode(DependencyChecker dependencyChecker, int index, int degree) {
|
||||
private DependencyNode(DependencyChecker dependencyChecker, int degree) {
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
this.index = index;
|
||||
this.degree = degree;
|
||||
}
|
||||
|
||||
|
@ -192,7 +186,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
@Override
|
||||
public DependencyNode getArrayItem() {
|
||||
if (arrayItemNode == null) {
|
||||
arrayItemNode = new DependencyNode(dependencyChecker, dependencyChecker.nodes.size(), degree + 1);
|
||||
arrayItemNode = new DependencyNode(dependencyChecker, degree + 1);
|
||||
dependencyChecker.nodes.add(arrayItemNode);
|
||||
if (DependencyChecker.shouldLog) {
|
||||
arrayItemNode.tag = tag + "[";
|
||||
|
@ -204,7 +198,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
|
||||
public DependencyNode getClassValueNode() {
|
||||
if (classValueNode == null) {
|
||||
classValueNode = new DependencyNode(dependencyChecker, dependencyChecker.nodes.size(), degree);
|
||||
classValueNode = new DependencyNode(dependencyChecker, degree);
|
||||
dependencyChecker.nodes.add(classValueNode);
|
||||
if (DependencyChecker.shouldLog) {
|
||||
classValueNode.tag = tag + "@";
|
||||
|
|
|
@ -15,12 +15,8 @@
|
|||
*/
|
||||
package org.teavm.dependency;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class DependencyNodeToNodeTransition implements DependencyConsumer {
|
||||
DependencyNode source;
|
||||
private DependencyNode source;
|
||||
DependencyNode destination;
|
||||
private DependencyTypeFilter filter;
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import org.teavm.model.CallLocation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AccumulationDiagnostics implements Diagnostics, ProblemProvider {
|
||||
private List<Problem> problems = new ArrayList<>();
|
||||
private List<Problem> readonlyProblems = Collections.unmodifiableList(problems);
|
||||
|
|
|
@ -17,10 +17,6 @@ package org.teavm.diagnostics;
|
|||
|
||||
import org.teavm.model.CallLocation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface Diagnostics {
|
||||
void error(CallLocation location, String error, Object... params);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ 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.metaprogramming.impl.reflect.ReflectContext;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
@ -40,6 +41,11 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene
|
|||
public void started(DependencyAgent agent) {
|
||||
proxyClassLoader = new MetaprogrammingClassLoader(agent.getClassLoader());
|
||||
describer = new MethodDescriber(agent.getDiagnostics(), agent.getClassSource());
|
||||
|
||||
MetaprogrammingImpl.classLoader = proxyClassLoader;
|
||||
MetaprogrammingImpl.classSource = agent.getClassSource();
|
||||
MetaprogrammingImpl.agent = agent;
|
||||
MetaprogrammingImpl.reflectContext = new ReflectContext(agent.getClassSource(), proxyClassLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,8 +62,9 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene
|
|||
ProgramEmitter pe = ProgramEmitter.create(model.getMethod().getDescriptor(), agent.getClassSource());
|
||||
|
||||
ValueEmitter[] paramVars = new ValueEmitter[model.getMetaParameterCount()];
|
||||
int offset = model.isStatic() ? 1 : 0;
|
||||
for (int i = 0; i < paramVars.length; ++i) {
|
||||
paramVars[i] = pe.var(i, model.getMetaParameterType(i));
|
||||
paramVars[i] = pe.var(i + offset, model.getMetaParameterType(i));
|
||||
}
|
||||
|
||||
if (model.getUsages().size() == 1) {
|
||||
|
@ -91,7 +98,7 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene
|
|||
ValueEmitter[] paramVars) {
|
||||
MethodDependencyInfo methodDep = agent.getMethod(model.getMethod());
|
||||
ValueEmitter paramVar = paramVars[model.getMetaClassParameterIndex()];
|
||||
ValueEmitter tag = paramVar.invokeVirtual("getClass", Class.class).invokeVirtual("getName", String.class);
|
||||
ValueEmitter tag = paramVar.invokeVirtual("getName", String.class);
|
||||
|
||||
StringChooseEmitter choice = pe.stringChoice(tag);
|
||||
for (Map.Entry<ValueType, MethodReference> usageEntry : model.getUsages().entrySet()) {
|
||||
|
|
|
@ -53,6 +53,7 @@ public final class MetaprogrammingImpl {
|
|||
private MetaprogrammingImpl() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static <T> Value<T> emit(Computation<T> computation) {
|
||||
if (computation instanceof ValueImpl<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -90,7 +91,8 @@ public final class MetaprogrammingImpl {
|
|||
return new LazyValueImpl<>(varContext, computation, type, generator.forcedLocation);
|
||||
}
|
||||
|
||||
public static void exit(Value<?> value) {
|
||||
@SuppressWarnings({"WeakerAccess", "SameParameterValue"})
|
||||
public static void exit(Computation<?> value) {
|
||||
if (value == null) {
|
||||
returnValue(null);
|
||||
return;
|
||||
|
@ -103,19 +105,12 @@ public final class MetaprogrammingImpl {
|
|||
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) {
|
||||
private static Variable unbox(Variable var) {
|
||||
if (returnType instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) returnType).getKind()) {
|
||||
case BOOLEAN:
|
||||
|
@ -147,7 +142,7 @@ public final class MetaprogrammingImpl {
|
|||
return var;
|
||||
}
|
||||
|
||||
static Variable unbox(Variable var, Class<?> boxed, Class<?> primitive) {
|
||||
private static Variable unbox(Variable var, Class<?> boxed, Class<?> primitive) {
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setInstance(var);
|
||||
insn.setType(InvocationType.VIRTUAL);
|
||||
|
@ -170,10 +165,12 @@ public final class MetaprogrammingImpl {
|
|||
unsupported();
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static ReflectClass<?> findClass(String name) {
|
||||
return reflectContext.findClass(name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static <T> ReflectClass<T> findClass(Class<T> cls) {
|
||||
return reflectContext.findClass(cls);
|
||||
}
|
||||
|
@ -200,6 +197,7 @@ public final class MetaprogrammingImpl {
|
|||
return proxy(findClass(type), handler);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static <T> Value<T> proxy(ReflectClass<T> type, InvocationHandler<T> handler) {
|
||||
unsupported();
|
||||
return null;
|
||||
|
|
|
@ -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.diagnostics.Diagnostics;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.Variable;
|
||||
|
||||
class TopLevelVariableContext extends VariableContext {
|
||||
private Diagnostics diagnostics;
|
||||
|
||||
TopLevelVariableContext(Diagnostics diagnostics) {
|
||||
super(null);
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitVariable(ValueImpl<?> value, CallLocation location) {
|
||||
if (value.context != this) {
|
||||
diagnostics.error(location, "Can't get variable from another context");
|
||||
}
|
||||
return value.innerValue;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ 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;
|
||||
|
@ -41,16 +40,17 @@ import org.teavm.model.Variable;
|
|||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
|
||||
public class UsageGenerator {
|
||||
class UsageGenerator {
|
||||
private static Map<DependencyAgent, Integer> suffixGenerator = new WeakHashMap<>();
|
||||
DependencyAgent agent;
|
||||
MethodModel model;
|
||||
MethodDependency methodDep;
|
||||
CallLocation location;
|
||||
Diagnostics diagnostics;
|
||||
Method proxyMethod;
|
||||
private DependencyAgent agent;
|
||||
private MethodModel model;
|
||||
private MethodDependency methodDep;
|
||||
private CallLocation location;
|
||||
private Diagnostics diagnostics;
|
||||
private Method proxyMethod;
|
||||
private MetaprogrammingClassLoader classLoader;
|
||||
private boolean annotationErrorReported;
|
||||
private MethodDependency nameDependency;
|
||||
|
||||
UsageGenerator(DependencyAgent agent, MethodModel model, MethodDependency methodDep, CallLocation location,
|
||||
MetaprogrammingClassLoader classLoader) {
|
||||
|
@ -65,10 +65,6 @@ public class UsageGenerator {
|
|||
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);
|
||||
|
@ -80,20 +76,20 @@ public class UsageGenerator {
|
|||
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);
|
||||
}
|
||||
nameDependency = installAdditionalDependencies();
|
||||
|
||||
installAdditionalDependencies(getClassDep);
|
||||
if (model.getClassParameterIndex() >= 0) {
|
||||
int index = 1 + model.getClassParameterIndex();
|
||||
methodDep.getVariable(index).getClassValueNode().addConsumer(
|
||||
type -> emitPermutation(findClass(type.getName())));
|
||||
} else {
|
||||
emitPermutation(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void installAdditionalDependencies(MethodDependency getClassDep) {
|
||||
private MethodDependency installAdditionalDependencies() {
|
||||
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();
|
||||
|
||||
|
@ -109,13 +105,11 @@ public class UsageGenerator {
|
|||
nameDep.getResult().connect(hashCodeDep.getVariable(0));
|
||||
hashCodeDep.getThrown().connect(methodDep.getThrown());
|
||||
hashCodeDep.use();
|
||||
|
||||
return nameDep;
|
||||
}
|
||||
|
||||
private void consumeType(DependencyType type, MethodDependency getClassDep) {
|
||||
emitPermutation(findClass(type.getName()), getClassDep);
|
||||
}
|
||||
|
||||
private void emitPermutation(ValueType type, MethodDependency getClassDep) {
|
||||
private void emitPermutation(ValueType type) {
|
||||
if (!classLoader.isCompileTimeClass(model.getMetaMethod().getClassName()) && !annotationErrorReported) {
|
||||
annotationErrorReported = true;
|
||||
diagnostics.error(location, "Metaprogramming method should be within class marked with "
|
||||
|
@ -128,28 +122,31 @@ public class UsageGenerator {
|
|||
return;
|
||||
}
|
||||
|
||||
implRef = buildMethodReference(type);
|
||||
implRef = buildMethodReference();
|
||||
model.getUsages().put(type, implRef);
|
||||
//emitter = new EmitterImpl<>(emitterContext, model.getProxyMethod(), model.getMethod().getReturnType());
|
||||
MetaprogrammingImpl.templateMethod = model.getMetaMethod();
|
||||
VariableContext varContext = new TopLevelVariableContext(diagnostics);
|
||||
MetaprogrammingImpl.generator = new CompositeMethodGenerator(varContext);
|
||||
MetaprogrammingImpl.varContext = varContext;
|
||||
MetaprogrammingImpl.returnType = model.getMethod().getReturnType();
|
||||
|
||||
/*for (int i = 0; i <= model.getParameters().size(); ++i) {
|
||||
emitter.generator.getProgram().createVariable();
|
||||
for (int i = 0; i <= model.getMetaParameterCount(); ++i) {
|
||||
MetaprogrammingImpl.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));
|
||||
proxyArgs[i] = new ValueImpl<>(getParameterVar(i), MetaprogrammingImpl.varContext,
|
||||
model.getMetaParameterType(i));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
proxyMethod.invoke(null, proxyArgs);
|
||||
//emitter.close();
|
||||
Program program = null; //emitter.generator.getProgram();
|
||||
Program program = MetaprogrammingImpl.generator.getProgram();
|
||||
//new BoxingEliminator().optimize(program);
|
||||
|
||||
ClassHolder cls = new ClassHolder(implRef.getClassName());
|
||||
|
@ -176,7 +173,8 @@ public class UsageGenerator {
|
|||
}
|
||||
|
||||
if (model.getClassParameterIndex() >= 0) {
|
||||
implMethod.getVariable(model.getClassParameterIndex() + 1).connect(getClassDep.getVariable(0));
|
||||
implMethod.getVariable(model.getClassParameterIndex() + 1).getClassValueNode()
|
||||
.connect(nameDependency.getVariable(0));
|
||||
}
|
||||
|
||||
if (implMethod.getResult() != null) {
|
||||
|
@ -211,15 +209,15 @@ public class UsageGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private MethodReference buildMethodReference(ValueType type) {
|
||||
private MethodReference buildMethodReference() {
|
||||
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) {
|
||||
int i;
|
||||
ValueType[] signature = new ValueType[model.getMetaParameterCount() + 1];
|
||||
for (i = 0; i < signature.length - 1; ++i) {
|
||||
signature[i] = model.getMetaParameterType(i);
|
||||
}
|
||||
signature[i] = model.getMethod().getReturnType();
|
||||
|
@ -275,9 +273,43 @@ public class UsageGenerator {
|
|||
throw new AssertionError("Don't know how to map type: " + type);
|
||||
}
|
||||
|
||||
private Variable getParameterVar(int index) {
|
||||
Program program = MetaprogrammingImpl.generator.getProgram();
|
||||
Variable var = program.variableAt(index + 1);
|
||||
ValueType type = model.getMethod().parameterType(index);
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
var = box(var, Boolean.class, boolean.class);
|
||||
break;
|
||||
case BYTE:
|
||||
var = box(var, Byte.class, byte.class);
|
||||
break;
|
||||
case SHORT:
|
||||
var = box(var, Short.class, short.class);
|
||||
break;
|
||||
case CHARACTER:
|
||||
var = box(var, Character.class, char.class);
|
||||
break;
|
||||
case INTEGER:
|
||||
var = box(var, Integer.class, int.class);
|
||||
break;
|
||||
case LONG:
|
||||
var = box(var, Long.class, long.class);
|
||||
break;
|
||||
case FLOAT:
|
||||
var = box(var, Float.class, float.class);
|
||||
break;
|
||||
case DOUBLE:
|
||||
var = box(var, Double.class, double.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
private Variable box(Variable var, Class<?> boxed, Class<?> primitive) {
|
||||
Program program = null; //emitter.generator.getProgram();
|
||||
Program program = MetaprogrammingImpl.generator.getProgram();
|
||||
BasicBlock block = program.basicBlockAt(0);
|
||||
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
|
|
|
@ -72,17 +72,18 @@ public class MethodDescriber {
|
|||
|
||||
private MethodModel findMetaMethod(MethodReader method) {
|
||||
ClassReader cls = classSource.get(method.getOwnerName());
|
||||
boolean isStatic = method.hasModifier(ElementModifier.STATIC);
|
||||
int expectedParameterCount = (isStatic ? 0 : 1) + method.parameterCount();
|
||||
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) {
|
||||
|| meta.parameterCount() != expectedParameterCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int paramOffset = 0;
|
||||
boolean isStatic = method.hasModifier(ElementModifier.STATIC);
|
||||
if (!isStatic) {
|
||||
if (meta.parameterCount() == 0 || meta.parameterType(0).isObject(Value.class)) {
|
||||
return null;
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.teavm.javascript.spi.GeneratedBy;
|
|||
import org.teavm.javascript.spi.Generator;
|
||||
import org.teavm.javascript.spi.InjectedBy;
|
||||
import org.teavm.javascript.spi.Injector;
|
||||
import org.teavm.metaprogramming.impl.MetaprogrammingDependencyListener;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.*;
|
||||
import org.teavm.model.util.*;
|
||||
|
@ -354,6 +355,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
dependencyChecker.addDependencyListener(new MetaprogrammingDependencyListener());
|
||||
|
||||
AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider();
|
||||
dependencyChecker.setInterruptor(() -> progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE);
|
||||
dependencyChecker.linkMethod(new MethodReference(Class.class.getName(), "getClass",
|
||||
|
@ -473,6 +477,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public ListableClassHolderSource link(DependencyInfo dependency) {
|
||||
reportPhase(TeaVMPhase.LINKING, dependency.getReachableClasses().size());
|
||||
Linker linker = new Linker();
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package org.teavm.metaprogramming;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface Computation<T> {
|
||||
T compute();
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public final class Metaprogramming {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static void exit(Value<?> returnValue) {
|
||||
public static void exit(Computation<?> returnValue) {
|
||||
unsupported();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,16 +24,18 @@ import org.junit.runner.RunWith;
|
|||
import org.teavm.classlib.support.Support_MapTest2;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
|
||||
@SuppressWarnings({"UnnecessaryUnboxing", "ClassInitializerMayBeStatic", "UnnecessaryTemporaryOnConversionToString",
|
||||
"MismatchedQueryAndUpdateOfCollection", "StringEquality"})
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
public class LinkedHashMapTest {
|
||||
|
||||
LinkedHashMap<Object, Object> hm;
|
||||
private LinkedHashMap<Object, Object> hm;
|
||||
|
||||
final static int hmSize = 1000;
|
||||
private final static int hmSize = 1000;
|
||||
|
||||
static Object[] objArray;
|
||||
private static Object[] objArray;
|
||||
|
||||
static Object[] objArray2;
|
||||
private static Object[] objArray2;
|
||||
{
|
||||
objArray = new Object[hmSize];
|
||||
objArray2 = new Object[hmSize];
|
||||
|
@ -47,14 +49,14 @@ public class LinkedHashMapTest {
|
|||
hm = new LinkedHashMap<>();
|
||||
for (int i = 0; i < objArray.length; i++)
|
||||
hm.put(objArray2[i], objArray[i]);
|
||||
hm.put("test", null);
|
||||
hm.put(null, "test");
|
||||
hm.put("org/teavm/metaprogramming/test", null);
|
||||
hm.put(null, "org/teavm/metaprogramming/test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Constructor() {
|
||||
// Test for method java.util.LinkedHashMap()
|
||||
new Support_MapTest2(new LinkedHashMap<String, String>()).runTest();
|
||||
new Support_MapTest2(new LinkedHashMap<>()).runTest();
|
||||
|
||||
LinkedHashMap<Object, Object> hm2 = new LinkedHashMap<>();
|
||||
assertEquals("Created incorrect LinkedHashMap", 0, hm2.size());
|
||||
|
@ -69,6 +71,7 @@ public class LinkedHashMapTest {
|
|||
new LinkedHashMap<>(-1);
|
||||
fail("Failed to throw IllegalArgumentException for initial capacity < 0");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
LinkedHashMap<Object, Object> empty = new LinkedHashMap<>(0);
|
||||
|
@ -86,6 +89,7 @@ public class LinkedHashMapTest {
|
|||
new LinkedHashMap<>(0, 0);
|
||||
fail("Failed to throw IllegalArgumentException for initial load factor <= 0");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// as expected
|
||||
}
|
||||
LinkedHashMap<String, String> empty = new LinkedHashMap<>(0, 0.75f);
|
||||
assertNull("Empty hashtable access", empty.get("nothing"));
|
||||
|
@ -114,8 +118,8 @@ public class LinkedHashMapTest {
|
|||
assertEquals("Get returned incorecct value for existing key", "HELLO", hm.get("T"));
|
||||
|
||||
LinkedHashMap<Object, String> m = new LinkedHashMap<>();
|
||||
m.put(null, "test");
|
||||
assertEquals("Failed with null key", "test", m.get(null));
|
||||
m.put(null, "org/teavm/metaprogramming/test");
|
||||
assertEquals("Failed with null key", "org/teavm/metaprogramming/test", m.get(null));
|
||||
assertNull("Failed with missing key matching null hash", m.get(new Integer(0)));
|
||||
}
|
||||
|
||||
|
@ -128,7 +132,7 @@ public class LinkedHashMapTest {
|
|||
|
||||
LinkedHashMap<Number, String> m = new LinkedHashMap<>();
|
||||
m.put(new Short((short) 0), "short");
|
||||
m.put(null, "test");
|
||||
m.put(null, "org/teavm/metaprogramming/test");
|
||||
m.put(new Integer(0), "int");
|
||||
assertEquals("Failed adding to bucket containing null", "short", m.get(new Short((short) 0)));
|
||||
assertEquals("Failed adding to bucket containing null2", "int", m.get(new Integer(0)));
|
||||
|
@ -159,7 +163,7 @@ public class LinkedHashMapTest {
|
|||
assertTrue("Returned set does not contain all keys", s.contains(objArray[i].toString()));
|
||||
|
||||
LinkedHashMap<Object, String> m = new LinkedHashMap<>();
|
||||
m.put(null, "test");
|
||||
m.put(null, "org/teavm/metaprogramming/test");
|
||||
assertTrue("Failed with null key", m.keySet().contains(null));
|
||||
assertNull("Failed with null key", m.keySet().iterator().next());
|
||||
|
||||
|
@ -228,9 +232,9 @@ public class LinkedHashMapTest {
|
|||
assertNull("Remove of non-existent key returned non-null", hm.remove("LCLCLC"));
|
||||
|
||||
LinkedHashMap<Object, String> m = new LinkedHashMap<>();
|
||||
m.put(null, "test");
|
||||
m.put(null, "org/teavm/metaprogramming/test");
|
||||
assertNull("Failed with same hash as null", m.remove(new Integer(0)));
|
||||
assertEquals("Failed with null key", "test", m.remove(null));
|
||||
assertEquals("Failed with null key", "org/teavm/metaprogramming/test", m.remove(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -313,7 +317,7 @@ public class LinkedHashMapTest {
|
|||
assertTrue("Returned true for invalid key", !hm.containsKey("KKDKDKD"));
|
||||
|
||||
LinkedHashMap<Object, String> m = new LinkedHashMap<>();
|
||||
m.put(null, "test");
|
||||
m.put(null, "org/teavm/metaprogramming/test");
|
||||
assertTrue("Failed with null key", m.containsKey(null));
|
||||
assertTrue("Failed with missing key matching null hash", !m.containsKey(new Integer(0)));
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
|
||||
@SuppressWarnings({"RedundantStringConstructorCall", "RedundantCast"})
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
public class StringTokenizerTest {
|
||||
@Test
|
||||
|
@ -79,7 +80,7 @@ public class StringTokenizerTest {
|
|||
st.nextElement();
|
||||
fail("nextElement failed to throw a NoSuchElementException when it should have been out of elements");
|
||||
} catch (NoSuchElementException e) {
|
||||
return;
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +96,7 @@ public class StringTokenizerTest {
|
|||
st.nextToken();
|
||||
fail("nextToken failed to throw a NoSuchElementException when it should have been out of elements");
|
||||
} catch (NoSuchElementException e) {
|
||||
return;
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
|
||||
@SuppressWarnings({"UnnecessaryTemporaryOnConversionToString", "SuspiciousMethodCalls"})
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
public class TreeMapTest {
|
||||
|
||||
|
@ -64,14 +65,13 @@ public class TreeMapTest {
|
|||
if (null == o1 || null == o2) {
|
||||
return -1;
|
||||
}
|
||||
T c1 = o1;
|
||||
T c2 = o2;
|
||||
return c1.compareTo(c2);
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
}
|
||||
|
||||
// Regression for Harmony-1161
|
||||
class MockComparatorNullTolerable implements Comparator<String> {
|
||||
@SuppressWarnings("StringEquality")
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
if (o1 == o2) {
|
||||
|
@ -87,9 +87,9 @@ public class TreeMapTest {
|
|||
}
|
||||
}
|
||||
|
||||
TreeMap<Object, Object> tm;
|
||||
private TreeMap<Object, Object> tm;
|
||||
|
||||
Object objArray[] = new Object[1000];
|
||||
private Object[] objArray = new Object[1000];
|
||||
|
||||
public TreeMapTest() {
|
||||
tm = new TreeMap<>();
|
||||
|
@ -255,7 +255,7 @@ public class TreeMapTest {
|
|||
&& head.containsKey("10"));
|
||||
|
||||
// Regression for Harmony-1026
|
||||
TreeMap<Integer, Double> map = new TreeMap<>(new MockComparator<Integer>());
|
||||
TreeMap<Integer, Double> map = new TreeMap<>(new MockComparator<>());
|
||||
map.put(1, 2.1);
|
||||
map.put(2, 3.1);
|
||||
map.put(3, 4.5);
|
||||
|
@ -308,12 +308,14 @@ public class TreeMapTest {
|
|||
sub.firstKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
try{
|
||||
sub.lastKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
size = 256;
|
||||
|
@ -328,12 +330,14 @@ public class TreeMapTest {
|
|||
sub.firstKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
try{
|
||||
sub.lastKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -441,7 +445,7 @@ public class TreeMapTest {
|
|||
|
||||
assertEquals(3, map.size());
|
||||
|
||||
Map<String, String> subMap = map.subMap("", "test");
|
||||
Map<String, String> subMap = map.subMap("", "org/teavm/metaprogramming/test");
|
||||
assertEquals(3, subMap.size());
|
||||
|
||||
int size = 0;
|
||||
|
@ -487,12 +491,14 @@ public class TreeMapTest {
|
|||
sub.firstKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
try{
|
||||
sub.lastKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
size = 256;
|
||||
|
@ -507,12 +513,14 @@ public class TreeMapTest {
|
|||
sub.firstKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
try{
|
||||
sub.lastKey();
|
||||
fail("java.util.NoSuchElementException should be thrown");
|
||||
} catch(java.util.NoSuchElementException e) {
|
||||
// as expected
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,14 +18,19 @@ package org.teavm.metaprogramming.test;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.teavm.metaprogramming.Metaprogramming.exit;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
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)
|
||||
public class MetaprogrammingTest {
|
||||
@Test
|
||||
@SkipJVM
|
||||
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));
|
|
@ -19,11 +19,8 @@ import static org.hamcrest.CoreMatchers.*;
|
|||
import static org.junit.Assert.*;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.junit.SkipJVM;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.vm.TeaVM;
|
||||
|
@ -98,7 +95,7 @@ public class JSOTest {
|
|||
private List<Problem> build(String methodName) {
|
||||
TeaVM vm = new TeaVMBuilder().build();
|
||||
vm.installPlugins();
|
||||
vm.entryPoint("test", new MethodReference(JSOTest.class, methodName, void.class));
|
||||
vm.entryPoint("org/teavm/metaprogramming/test", new MethodReference(JSOTest.class, methodName, void.class));
|
||||
vm.build(new StringBuilder(), null);
|
||||
return vm.getProblemProvider().getSevereProblems();
|
||||
}
|
||||
|
|
|
@ -73,7 +73,6 @@ public class TeaVMTestRunner extends Runner {
|
|||
private Class<?> testClass;
|
||||
private ClassHolder classHolder;
|
||||
private ClassLoader classLoader;
|
||||
private ClassHolderSource classSource;
|
||||
private Description suiteDescription;
|
||||
private static Map<ClassLoader, ClassHolderSource> classSources = new WeakHashMap<>();
|
||||
private File outputDir;
|
||||
|
@ -88,9 +87,11 @@ public class TeaVMTestRunner extends Runner {
|
|||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
synchronized (TeaVMTestRunner.class) {
|
||||
cleanupFuture = null;
|
||||
runner.stop();
|
||||
runner.waitForCompletion();
|
||||
if (runner != null) {
|
||||
cleanupFuture = null;
|
||||
runner.stop();
|
||||
runner.waitForCompletion();
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -98,7 +99,7 @@ public class TeaVMTestRunner extends Runner {
|
|||
public TeaVMTestRunner(Class<?> testClass) throws InitializationError {
|
||||
this.testClass = testClass;
|
||||
classLoader = TeaVMTestRunner.class.getClassLoader();
|
||||
classSource = getClassSource(classLoader);
|
||||
ClassHolderSource classSource = getClassSource(classLoader);
|
||||
classHolder = classSource.get(testClass.getName());
|
||||
String outputPath = System.getProperty(PATH_PARAM);
|
||||
if (outputPath != null) {
|
||||
|
@ -157,7 +158,7 @@ public class TeaVMTestRunner extends Runner {
|
|||
notifier.fireTestFinished(getDescription());
|
||||
}
|
||||
|
||||
protected List<Method> getChildren() {
|
||||
private List<Method> getChildren() {
|
||||
List<Method> children = new ArrayList<>();
|
||||
for (Method method : testClass.getDeclaredMethods()) {
|
||||
MethodHolder methodHolder = classHolder.getMethod(getDescriptor(method));
|
||||
|
@ -168,12 +169,12 @@ public class TeaVMTestRunner extends Runner {
|
|||
return children;
|
||||
}
|
||||
|
||||
protected Description describeChild(Method child) {
|
||||
private Description describeChild(Method child) {
|
||||
return descriptions.computeIfAbsent(child, method -> Description.createTestDescription(testClass,
|
||||
method.getName()));
|
||||
}
|
||||
|
||||
protected void runChild(Method child, RunNotifier notifier) {
|
||||
private void runChild(Method child, RunNotifier notifier) {
|
||||
notifier.fireTestStarted(describeChild(child));
|
||||
|
||||
boolean run = false;
|
||||
|
@ -261,6 +262,8 @@ public class TeaVMTestRunner extends Runner {
|
|||
if (!compileResult.success) {
|
||||
notifier.fireTestFailure(new Failure(description,
|
||||
new AssertionError(compileResult.errorMessage)));
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user