mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
InvokeDynamic support
This commit is contained in:
parent
50b42ab092
commit
d5f5e2633b
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2015 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.dependency;
|
||||
|
||||
import org.teavm.model.emit.ProgramEmitter;
|
||||
import org.teavm.model.emit.ValueEmitter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BootstrapMethodSubstitutor {
|
||||
ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter pe);
|
||||
}
|
|
@ -307,6 +307,13 @@ public class DataFlowGraphBuilder implements InstructionReader {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
|
||||
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
|
||||
List<RuntimeConstant> bootstrapArguments) {
|
||||
// Should be eliminated by bootstrap method substitutor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||
}
|
||||
|
|
|
@ -15,7 +15,16 @@
|
|||
*/
|
||||
package org.teavm.dependency;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.callgraph.DefaultCallGraph;
|
||||
import org.teavm.callgraph.DefaultCallGraphNode;
|
||||
|
@ -29,10 +38,12 @@ import org.teavm.model.ClassHolder;
|
|||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.FieldHolder;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.InstructionLocation;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
@ -47,8 +58,8 @@ public class DependencyChecker implements DependencyInfo {
|
|||
private int classNameSuffix;
|
||||
private DependencyClassSource classSource;
|
||||
private ClassLoader classLoader;
|
||||
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
||||
private Mapper<FieldReference, FieldReader> fieldReaderCache;
|
||||
private Mapper<MethodReference, MethodHolder> methodReaderCache;
|
||||
private Mapper<FieldReference, FieldHolder> fieldReaderCache;
|
||||
private CachedMapper<MethodReference, MethodDependency> methodCache;
|
||||
private CachedMapper<FieldReference, FieldDependency> fieldCache;
|
||||
private CachedMapper<String, ClassDependency> classCache;
|
||||
|
@ -64,6 +75,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
private DependencyAgent agent;
|
||||
List<DependencyNode> nodes = new ArrayList<>();
|
||||
List<BitSet> typeBitSets = new ArrayList<>();
|
||||
Map<MethodReference, BootstrapMethodSubstitutor> bootstrapMethodSubstitutors = new HashMap<>();
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
|
||||
Diagnostics diagnostics) {
|
||||
|
@ -71,10 +83,10 @@ public class DependencyChecker implements DependencyInfo {
|
|||
this.classSource = new DependencyClassSource(classSource, diagnostics);
|
||||
this.classLoader = classLoader;
|
||||
this.services = services;
|
||||
methodReaderCache = new CachedMapper<>(preimage -> findMethodReader(preimage));
|
||||
fieldReaderCache = new CachedMapper<>(preimage -> findFieldReader(preimage));
|
||||
methodReaderCache = new CachedMapper<>(preimage -> this.classSource.resolveMutable(preimage));
|
||||
fieldReaderCache = new CachedMapper<>(preimage -> this.classSource.resolveMutable(preimage));
|
||||
methodCache = new CachedMapper<>(preimage -> {
|
||||
MethodReader method = methodReaderCache.map(preimage);
|
||||
MethodHolder method = methodReaderCache.map(preimage);
|
||||
if (method != null && !method.getReference().equals(preimage)) {
|
||||
return methodCache.map(method.getReference());
|
||||
}
|
||||
|
@ -268,53 +280,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
}
|
||||
}
|
||||
|
||||
private MethodReader findMethodReader(MethodReference methodRef) {
|
||||
String clsName = methodRef.getClassName();
|
||||
MethodDescriptor desc = methodRef.getDescriptor();
|
||||
ClassReader cls = classSource.get(clsName);
|
||||
if (cls == null) {
|
||||
return null;
|
||||
}
|
||||
MethodReader reader = cls.getMethod(desc);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
if (cls.getParent() != null && cls.getParent().equals(cls.getParent())) {
|
||||
reader = methodReaderCache.map(new MethodReference(cls.getParent(), desc));
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
for (String ifaceName : cls.getInterfaces()) {
|
||||
reader = methodReaderCache.map(new MethodReference(ifaceName, desc));
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private FieldReader findFieldReader(FieldReference fieldRef) {
|
||||
String clsName = fieldRef.getClassName();
|
||||
String name = fieldRef.getFieldName();
|
||||
while (clsName != null) {
|
||||
ClassReader cls = classSource.get(clsName);
|
||||
if (cls == null) {
|
||||
return null;
|
||||
}
|
||||
FieldReader field = cls.getField(name);
|
||||
if (field != null) {
|
||||
return field;
|
||||
}
|
||||
if (clsName.equals(cls.getParent())) {
|
||||
break;
|
||||
}
|
||||
clsName = cls.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method) {
|
||||
private MethodDependency createMethodDep(MethodReference methodRef, MethodHolder method) {
|
||||
ValueType[] arguments = methodRef.getParameterTypes();
|
||||
int paramCount = arguments.length + 1;
|
||||
DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1];
|
||||
|
@ -482,4 +448,8 @@ public class DependencyChecker implements DependencyInfo {
|
|||
public CallGraph getCallGraph() {
|
||||
return callGraph;
|
||||
}
|
||||
|
||||
public void addBootstrapMethodSubstitutor(MethodReference method, BootstrapMethodSubstitutor substitutor) {
|
||||
bootstrapMethodSubstitutors.put(method, substitutor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.common.CachedMapper;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderSource;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
|
@ -32,12 +32,12 @@ import org.teavm.model.util.ModelUtils;
|
|||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class DependencyClassSource implements ClassReaderSource {
|
||||
class DependencyClassSource implements ClassHolderSource {
|
||||
private ClassReaderSource innerSource;
|
||||
private Diagnostics diagnostics;
|
||||
private Map<String, ClassHolder> generatedClasses = new HashMap<>();
|
||||
private List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||
private CachedMapper<String, ClassReader> cache = new CachedMapper<>(preimage -> findAndTransformClass(preimage));
|
||||
private Map<String, ClassHolder> cache = new HashMap<>();
|
||||
|
||||
public DependencyClassSource(ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||
this.innerSource = innerSource;
|
||||
|
@ -45,8 +45,8 @@ class DependencyClassSource implements ClassReaderSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ClassReader get(String name) {
|
||||
return cache.map(name);
|
||||
public ClassHolder get(String name) {
|
||||
return cache.computeIfAbsent(name, n -> findAndTransformClass(n));
|
||||
}
|
||||
|
||||
public void submit(ClassHolder cls) {
|
||||
|
@ -54,10 +54,10 @@ class DependencyClassSource implements ClassReaderSource {
|
|||
throw new IllegalArgumentException("Class " + cls.getName() + " is already defined");
|
||||
}
|
||||
generatedClasses.put(cls.getName(), cls);
|
||||
cache.invalidate(cls.getName());
|
||||
cache.remove(cls.getName());
|
||||
}
|
||||
|
||||
private ClassReader findAndTransformClass(String name) {
|
||||
private ClassHolder findAndTransformClass(String name) {
|
||||
ClassHolder cls = findClass(name);
|
||||
if (cls != null && !transformers.isEmpty()) {
|
||||
for (ClassHolderTransformer transformer : transformers) {
|
||||
|
|
|
@ -20,9 +20,45 @@ import java.util.Arrays;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.callgraph.DefaultCallGraphNode;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.*;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.BasicBlockReader;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.IncomingReader;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.InstructionLocation;
|
||||
import org.teavm.model.InvokeDynamicInstruction;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHandle;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.PhiReader;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.RuntimeConstant;
|
||||
import org.teavm.model.TryCatchBlockReader;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.VariableReader;
|
||||
import org.teavm.model.emit.ProgramEmitter;
|
||||
import org.teavm.model.emit.ValueEmitter;
|
||||
import org.teavm.model.instructions.ArrayElementType;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.BinaryBranchingCondition;
|
||||
import org.teavm.model.instructions.BinaryOperation;
|
||||
import org.teavm.model.instructions.BranchingCondition;
|
||||
import org.teavm.model.instructions.CastIntegerDirection;
|
||||
import org.teavm.model.instructions.InstructionReader;
|
||||
import org.teavm.model.instructions.IntegerSubtype;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.NullConstantInstruction;
|
||||
import org.teavm.model.instructions.NumericOperandType;
|
||||
import org.teavm.model.instructions.SwitchTableEntryReader;
|
||||
import org.teavm.model.util.ListingBuilder;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +69,7 @@ class DependencyGraphBuilder {
|
|||
private DependencyChecker dependencyChecker;
|
||||
private DependencyNode[] nodes;
|
||||
private DependencyNode resultNode;
|
||||
private ProgramReader program;
|
||||
private Program program;
|
||||
private DefaultCallGraphNode caller;
|
||||
private InstructionLocation currentLocation;
|
||||
private ExceptionConsumer currentExceptionConsumer;
|
||||
|
@ -44,13 +80,15 @@ class DependencyGraphBuilder {
|
|||
|
||||
public void buildGraph(MethodDependency dep) {
|
||||
caller = dependencyChecker.callGraph.getNode(dep.getReference());
|
||||
MethodReader method = dep.getMethod();
|
||||
MethodHolder method = dep.method;
|
||||
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
||||
return;
|
||||
}
|
||||
program = method.getProgram();
|
||||
resultNode = dep.getResult();
|
||||
|
||||
processInvokeDynamic();
|
||||
|
||||
DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder();
|
||||
boolean[] significantParams = new boolean[dep.getParameterCount()];
|
||||
significantParams[0] = true;
|
||||
|
@ -146,6 +184,77 @@ class DependencyGraphBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private void processInvokeDynamic() {
|
||||
if (program == null) {
|
||||
return;
|
||||
}
|
||||
System.out.println(new ListingBuilder().buildListing(program, ""));
|
||||
ProgramEmitter pe = ProgramEmitter.create(program);
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (int j = 0; j < block.getInstructions().size(); ++j) {
|
||||
Instruction insn = block.getInstructions().get(j);
|
||||
if (!(insn instanceof InvokeDynamicInstruction)) {
|
||||
continue;
|
||||
}
|
||||
InvokeDynamicInstruction indy = (InvokeDynamicInstruction) insn;
|
||||
MethodReference bootstrapMethod = new MethodReference(indy.getBootstrapMethod().getClassName(),
|
||||
indy.getBootstrapMethod().getName(), indy.getBootstrapMethod().signature());
|
||||
BootstrapMethodSubstitutor substitutor = dependencyChecker.bootstrapMethodSubstitutors
|
||||
.get(bootstrapMethod);
|
||||
if (substitutor == null) {
|
||||
NullConstantInstruction nullInsn = new NullConstantInstruction();
|
||||
nullInsn.setReceiver(indy.getReceiver());
|
||||
nullInsn.setLocation(indy.getLocation());
|
||||
block.getInstructions().set(j, nullInsn);
|
||||
CallLocation location = new CallLocation(bootstrapMethod, indy.getLocation());
|
||||
dependencyChecker.getDiagnostics().error(location, "Substitutor for this dependency method "
|
||||
+ "was not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicBlock splitBlock = program.createBasicBlock();
|
||||
List<Instruction> splitInstructions = block.getInstructions().subList(j + 1,
|
||||
block.getInstructions().size());
|
||||
splitBlock.getInstructions().addAll(splitInstructions);
|
||||
splitInstructions.clear();
|
||||
|
||||
for (int k = 0; k < program.basicBlockCount() - 1; ++k) {
|
||||
BasicBlock replaceBlock = program.basicBlockAt(k);
|
||||
for (Phi phi : replaceBlock.getPhis()) {
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
if (incoming.getSource() == block) {
|
||||
incoming.setSource(splitBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pe.setBlock(block);
|
||||
pe.setCurrentLocation(indy.getLocation());
|
||||
block.getInstructions().remove(j);
|
||||
|
||||
DynamicCallSite callSite = new DynamicCallSite(
|
||||
indy.getMethod(),
|
||||
indy.getInstance() != null ? pe.var(indy.getInstance()) : null,
|
||||
indy.getArguments().stream().map(arg -> pe.var(arg)).collect(Collectors.toList()),
|
||||
indy.getBootstrapMethod(),
|
||||
indy.getBootstrapArguments(),
|
||||
dependencyChecker.getAgent(),
|
||||
indy.getInstance() != null ? nodes[indy.getInstance().getIndex()] : null,
|
||||
indy.getArguments().stream().map(arg -> nodes[arg.getIndex()]).collect(Collectors.toList()));
|
||||
ValueEmitter result = substitutor.substitute(callSite, pe);
|
||||
if (result.getVariable() != null && result.getVariable() != indy.getReceiver()) {
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setAssignee(result.getVariable());
|
||||
assign.setReceiver(indy.getReceiver());
|
||||
pe.addInstruction(insn);
|
||||
}
|
||||
pe.jump(splitBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ExceptionConsumer createExceptionConsumer(MethodDependency methodDep, BasicBlockReader block) {
|
||||
List<? extends TryCatchBlockReader> tryCatchBlocks = block.readTryCatchBlocks();
|
||||
ClassReader[] exceptions = new ClassReader[tryCatchBlocks.size()];
|
||||
|
@ -613,6 +722,13 @@ class DependencyGraphBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
|
||||
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
|
||||
List<RuntimeConstant> bootstrapArguments) {
|
||||
// Should be eliminated by processInvokeDynamic method
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initClass(final String className) {
|
||||
CallLocation callLocation = new CallLocation(caller.getMethod(), currentLocation);
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2015 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.dependency;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHandle;
|
||||
import org.teavm.model.RuntimeConstant;
|
||||
import org.teavm.model.emit.ValueEmitter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DynamicCallSite {
|
||||
private MethodDescriptor calledMethod;
|
||||
private ValueEmitter instance;
|
||||
private List<ValueEmitter> arguments;
|
||||
private MethodHandle bootstrapMethod;
|
||||
private List<RuntimeConstant> bootstrapArguments;
|
||||
private DependencyAgent agent;
|
||||
private DependencyNode instanceNode;
|
||||
private List<DependencyNode> argumentNodes = new ArrayList<>();
|
||||
|
||||
DynamicCallSite(MethodDescriptor calledMethod, ValueEmitter instance, List<ValueEmitter> arguments,
|
||||
MethodHandle bootstrapMethod, List<RuntimeConstant> bootstrapArguments, DependencyAgent agent,
|
||||
DependencyNode instanceNode, List<DependencyNode> argumentNodes) {
|
||||
this.calledMethod = calledMethod;
|
||||
this.instance = instance;
|
||||
this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments));
|
||||
this.bootstrapMethod = bootstrapMethod;
|
||||
this.bootstrapArguments = Collections.unmodifiableList(new ArrayList<>(bootstrapArguments));
|
||||
this.agent = agent;
|
||||
this.instanceNode = instanceNode;
|
||||
this.argumentNodes = Collections.unmodifiableList(new ArrayList<>(argumentNodes));
|
||||
}
|
||||
|
||||
public MethodDescriptor getCalledMethod() {
|
||||
return calledMethod;
|
||||
}
|
||||
|
||||
public MethodHandle getBootstrapMethod() {
|
||||
return bootstrapMethod;
|
||||
}
|
||||
|
||||
public List<ValueEmitter> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public List<RuntimeConstant> getBootstrapArguments() {
|
||||
return bootstrapArguments;
|
||||
}
|
||||
|
||||
public DependencyAgent getAgent() {
|
||||
return agent;
|
||||
}
|
||||
|
||||
public ValueEmitter getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public DependencyNode getInstanceNode() {
|
||||
return instanceNode;
|
||||
}
|
||||
|
||||
public List<DependencyNode> getArgumentNodes() {
|
||||
return argumentNodes;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.dependency;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
|
@ -29,14 +30,14 @@ public class MethodDependency implements MethodDependencyInfo {
|
|||
private int parameterCount;
|
||||
private DependencyNode resultNode;
|
||||
private DependencyNode thrown;
|
||||
private MethodReader method;
|
||||
MethodHolder method;
|
||||
private MethodReference reference;
|
||||
private boolean used;
|
||||
DependencyPlugin dependencyPlugin;
|
||||
boolean dependencyPluginAttached;
|
||||
|
||||
MethodDependency(DependencyChecker dependencyChecker, DependencyNode[] variableNodes, int parameterCount,
|
||||
DependencyNode resultNode, DependencyNode thrown, MethodReader method, MethodReference reference) {
|
||||
DependencyNode resultNode, DependencyNode thrown, MethodHolder method, MethodReference reference) {
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
|
||||
this.parameterCount = parameterCount;
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
*/
|
||||
package org.teavm.model;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
|
@ -52,6 +56,7 @@ public interface ClassReaderSource {
|
|||
private Deque<Deque<ClassReader>> state = new ArrayDeque<>();
|
||||
private Set<ClassReader> visited = new HashSet<>();
|
||||
{
|
||||
state.push(new ArrayDeque<>());
|
||||
add(name);
|
||||
}
|
||||
@Override public ClassReader next() {
|
||||
|
@ -89,14 +94,14 @@ public interface ClassReaderSource {
|
|||
}
|
||||
|
||||
default MethodReader resolve(MethodReference method) {
|
||||
return getAncestorClasses(method.getClassName())
|
||||
return getAncestors(method.getClassName())
|
||||
.map(cls -> cls.getMethod(method.getDescriptor()))
|
||||
.filter(candidate -> candidate != null)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
default FieldReader resolve(FieldReference field) {
|
||||
return getAncestorClasses(field.getClassName())
|
||||
return getAncestors(field.getClassName())
|
||||
.map(cls -> cls.getField(field.getFieldName()))
|
||||
.filter(candidate -> candidate != null)
|
||||
.findFirst().orElse(null);
|
||||
|
|
|
@ -117,8 +117,8 @@ public class MethodHandle {
|
|||
}
|
||||
|
||||
public static MethodHandle staticCaller(String className, String name, ValueType... arguments) {
|
||||
ValueType valueType = arguments[0];
|
||||
arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
|
||||
ValueType valueType = arguments[arguments.length - 1];
|
||||
arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
|
||||
return new MethodHandle(MethodHandleType.INVOKE_STATIC, className, name, valueType, arguments);
|
||||
}
|
||||
|
||||
|
@ -131,8 +131,8 @@ public class MethodHandle {
|
|||
}
|
||||
|
||||
public static MethodHandle specialCaller(String className, String name, ValueType... arguments) {
|
||||
ValueType valueType = arguments[0];
|
||||
arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
|
||||
ValueType valueType = arguments[arguments.length - 1];
|
||||
arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
|
||||
return new MethodHandle(MethodHandleType.INVOKE_SPECIAL, className, name, valueType, arguments);
|
||||
}
|
||||
|
||||
|
@ -145,8 +145,8 @@ public class MethodHandle {
|
|||
}
|
||||
|
||||
public static MethodHandle constructorCaller(String className, String name, ValueType... arguments) {
|
||||
ValueType valueType = arguments[0];
|
||||
arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
|
||||
ValueType valueType = arguments[arguments.length - 1];
|
||||
arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
|
||||
return new MethodHandle(MethodHandleType.INVOKE_CONSTRUCTOR, className, name, valueType, arguments);
|
||||
}
|
||||
|
||||
|
@ -159,8 +159,8 @@ public class MethodHandle {
|
|||
}
|
||||
|
||||
public static MethodHandle interfaceCaller(String className, String name, ValueType... arguments) {
|
||||
ValueType valueType = arguments[0];
|
||||
arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
|
||||
ValueType valueType = arguments[arguments.length - 1];
|
||||
arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
|
||||
return new MethodHandle(MethodHandleType.INVOKE_INTERFACE, className, name, valueType, arguments);
|
||||
}
|
||||
|
||||
|
|
|
@ -258,4 +258,8 @@ public final class ProgramEmitter {
|
|||
|
||||
return new ProgramEmitter(program, block);
|
||||
}
|
||||
|
||||
public static ProgramEmitter create(Program program) {
|
||||
return new ProgramEmitter(program, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -346,8 +346,10 @@ public class InstructionStringifier implements InstructionReader {
|
|||
if (receiver != null) {
|
||||
sb.append("@").append(receiver.getIndex()).append(" := ");
|
||||
}
|
||||
sb.append("@").append(instance.getIndex());
|
||||
sb.append(".").append(method.getName()).append("(");
|
||||
if (instance != null) {
|
||||
sb.append("@").append(instance.getIndex()).append(".");
|
||||
}
|
||||
sb.append(method.getName()).append("(");
|
||||
sb.append(arguments.stream().map(arg -> "@" + arg.getIndex()).collect(Collectors.joining(", ")));
|
||||
sb.append(") ");
|
||||
sb.append("[").append(convert(bootstrapMethod)).append('(');
|
||||
|
|
|
@ -480,7 +480,9 @@ public final class ProgramUtils {
|
|||
insnCopy.setMethod(method);
|
||||
insnCopy.setBootstrapMethod(bootstrapMethod);
|
||||
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
|
||||
insnCopy.setInstance(copyVar(instance));
|
||||
if (instance != null) {
|
||||
insnCopy.setInstance(copyVar(instance));
|
||||
}
|
||||
insnCopy.getArguments().addAll(arguments.stream().map(v -> copyVar(v)).collect(Collectors.toList()));
|
||||
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
|
||||
copy = insnCopy;
|
||||
|
|
|
@ -487,8 +487,18 @@ public class ProgramParser implements VariableDebugInformation {
|
|||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
|
||||
InvokeDynamicInstruction insn = new InvokeDynamicInstruction();
|
||||
insn.setBootstrapMethod(parseHandle(bsm));
|
||||
|
||||
insn.setInstance(getVariable(popSingle()));
|
||||
switch (insn.getBootstrapMethod().getKind()) {
|
||||
case GET_STATIC_FIELD:
|
||||
case PUT_STATIC_FIELD:
|
||||
case INVOKE_STATIC:
|
||||
case INVOKE_CONSTRUCTOR:
|
||||
break;
|
||||
default:
|
||||
insn.setInstance(getVariable(popSingle()));
|
||||
break;
|
||||
}
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
Variable[] args = new Variable[types.length];
|
||||
int j = args.length;
|
||||
|
@ -503,7 +513,6 @@ public class ProgramParser implements VariableDebugInformation {
|
|||
}
|
||||
|
||||
insn.setMethod(new MethodDescriptor(name, MethodDescriptor.parseSignature(desc)));
|
||||
insn.setBootstrapMethod(parseHandle(bsm));
|
||||
for (int i = 0; i < bsmArgs.length; ++i) {
|
||||
insn.getBootstrapArguments().add(convertConstant(bsmArgs[i]));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import java.lang.reflect.Array;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class LambdaTest {
|
||||
@Test
|
||||
public void lambdaWorks() {
|
||||
Integer[] src = { 1, 2, 3 };
|
||||
Integer[] array = map(src, (Integer n) -> n * 2 + src[0]);
|
||||
assertArrayEquals(new Integer[] { 3, 5, 7 }, array);
|
||||
}
|
||||
|
||||
static <T> T[] map(T[] array, Function<T> f) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T[] result = (T[])Array.newInstance(array.getClass().getComponentType(), array.length);
|
||||
for (int i = 0; i < result.length; ++i) {
|
||||
result[i] = f.apply(array[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
interface Function<T> {
|
||||
T apply(T value);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user