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