mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Make bytecode parser to cache method references to reduce memory consumption
This commit is contained in:
parent
a3f60996e2
commit
6b6c968aea
|
@ -48,6 +48,7 @@ import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.ReferenceCache;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.util.ModelUtils;
|
import org.teavm.model.util.ModelUtils;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
@ -156,7 +157,7 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
ClassNode node = new ClassNode();
|
ClassNode node = new ClassNode();
|
||||||
org.objectweb.asm.ClassReader reader = new org.objectweb.asm.ClassReader(data);
|
org.objectweb.asm.ClassReader reader = new org.objectweb.asm.ClassReader(data);
|
||||||
reader.accept(node, 0);
|
reader.accept(node, 0);
|
||||||
submitClass(Parser.parseClass(node));
|
submitClass(new Parser(new ReferenceCache()).parseClass(node));
|
||||||
return node.name;
|
return node.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -364,8 +364,7 @@ class DependencyGraphBuilder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodReference methodRef = new MethodReference(className, methodDesc);
|
MethodReference methodRef = new MethodReference(className, methodDesc);
|
||||||
final MethodDependency methodDep = checker.linkMethod(methodRef,
|
MethodDependency methodDep = checker.linkMethod(methodRef, new CallLocation(caller.getMethod(), location));
|
||||||
new CallLocation(caller.getMethod(), location));
|
|
||||||
if (!methodDep.isMissing() && knownMethods.add(methodRef)) {
|
if (!methodDep.isMissing() && knownMethods.add(methodRef)) {
|
||||||
methodDep.use();
|
methodDep.use();
|
||||||
DependencyNode[] targetParams = methodDep.getVariables();
|
DependencyNode[] targetParams = methodDep.getVariables();
|
||||||
|
|
|
@ -29,10 +29,6 @@ import org.teavm.model.instructions.InitClassInstruction;
|
||||||
import org.teavm.model.instructions.InvokeInstruction;
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
import org.teavm.model.instructions.PutFieldInstruction;
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class Linker {
|
public class Linker {
|
||||||
public void link(DependencyInfo dependency, ClassHolder cls) {
|
public void link(DependencyInfo dependency, ClassHolder cls) {
|
||||||
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
||||||
|
|
|
@ -17,10 +17,6 @@ package org.teavm.model;
|
||||||
|
|
||||||
import org.teavm.model.instructions.InstructionVisitor;
|
import org.teavm.model.instructions.InstructionVisitor;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public abstract class Instruction {
|
public abstract class Instruction {
|
||||||
private BasicBlock basicBlock;
|
private BasicBlock basicBlock;
|
||||||
private InstructionLocation location;
|
private InstructionLocation location;
|
||||||
|
|
|
@ -17,10 +17,6 @@ package org.teavm.model;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class MethodDescriptor {
|
public class MethodDescriptor {
|
||||||
private String name;
|
private String name;
|
||||||
private ValueType[] signature;
|
private ValueType[] signature;
|
||||||
|
|
146
core/src/main/java/org/teavm/model/ReferenceCache.java
Normal file
146
core/src/main/java/org/teavm/model/ReferenceCache.java
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ReferenceCache {
|
||||||
|
private Map<MethodReference, MethodReference> referenceCache = new HashMap<>();
|
||||||
|
private Map<FieldReference, FieldReference> fieldRefenceCache = new HashMap<>();
|
||||||
|
private Map<MethodDescriptor, MethodDescriptor> descriptorCache = new HashMap<>();
|
||||||
|
private Map<ValueType, ValueType> valueTypeCache = new HashMap<>();
|
||||||
|
private Map<String, String> classCache = new HashMap<>();
|
||||||
|
private Map<String, MethodReference> referenceParseCache = new HashMap<>();
|
||||||
|
private Map<String, MethodDescriptor> descriptorParseCache = new HashMap<>();
|
||||||
|
private Map<String, ValueType> valueTypeParseCache = new HashMap<>();
|
||||||
|
|
||||||
|
public MethodReference getCached(MethodReference reference) {
|
||||||
|
MethodReference result = referenceCache.get(reference);
|
||||||
|
if (result == null) {
|
||||||
|
MethodDescriptor descriptor = getCached(reference.getDescriptor());
|
||||||
|
String className = getCached(reference.getClassName());
|
||||||
|
if (descriptor != reference.getDescriptor() || className != reference.getClassName()) {
|
||||||
|
result = new MethodReference(className, descriptor);
|
||||||
|
} else {
|
||||||
|
result = reference;
|
||||||
|
}
|
||||||
|
referenceCache.put(result, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDescriptor getCached(MethodDescriptor descriptor) {
|
||||||
|
MethodDescriptor result = descriptorCache.get(descriptor);
|
||||||
|
if (result == null) {
|
||||||
|
result = descriptor;
|
||||||
|
ValueType[] signature = descriptor.getSignature();
|
||||||
|
boolean signatureChanged = false;
|
||||||
|
for (int i = 0; i < signature.length; ++i) {
|
||||||
|
ValueType type = signature[i];
|
||||||
|
if (type == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ValueType cachedType = getCached(type);
|
||||||
|
if (type != cachedType) {
|
||||||
|
signatureChanged = true;
|
||||||
|
signature[i] = cachedType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (signatureChanged) {
|
||||||
|
result = new MethodDescriptor(descriptor.getName(), signature);
|
||||||
|
}
|
||||||
|
descriptorCache.put(result, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReference getCached(FieldReference reference) {
|
||||||
|
FieldReference result = fieldRefenceCache.get(reference);
|
||||||
|
if (result == null) {
|
||||||
|
result = reference;
|
||||||
|
String classNameCached = getCached(reference.getClassName());
|
||||||
|
String fieldNameCached = getCached(reference.getFieldName());
|
||||||
|
if (classNameCached != reference.getClassName() || fieldNameCached != reference.getFieldName()) {
|
||||||
|
result = new FieldReference(classNameCached, fieldNameCached);
|
||||||
|
}
|
||||||
|
fieldRefenceCache.put(result, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueType getCached(ValueType valueType) {
|
||||||
|
if (valueType instanceof ValueType.Primitive) {
|
||||||
|
return valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType result = valueTypeCache.get(valueType);
|
||||||
|
if (result == null) {
|
||||||
|
result = valueType;
|
||||||
|
if (result instanceof ValueType.Object) {
|
||||||
|
String className = ((ValueType.Object) result).getClassName();
|
||||||
|
String cachedClassName = getCached(className);
|
||||||
|
if (cachedClassName != className) {
|
||||||
|
result = ValueType.object(cachedClassName);
|
||||||
|
}
|
||||||
|
} else if (result instanceof ValueType.Array) {
|
||||||
|
ValueType item = ((ValueType.Array) result).getItemType();
|
||||||
|
ValueType cachedItem = getCached(item);
|
||||||
|
if (item != cachedItem) {
|
||||||
|
result = ValueType.arrayOf(cachedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valueTypeCache.put(result, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCached(String className) {
|
||||||
|
String result = classCache.get(className);
|
||||||
|
if (result == null) {
|
||||||
|
result = className;
|
||||||
|
classCache.put(result, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference parseReferenceCached(String value) {
|
||||||
|
MethodReference result = referenceParseCache.get(value);
|
||||||
|
if (result == null) {
|
||||||
|
result = getCached(MethodReference.parse(value));
|
||||||
|
referenceParseCache.put(value, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDescriptor parseDescriptorCached(String value) {
|
||||||
|
MethodDescriptor result = descriptorParseCache.get(value);
|
||||||
|
if (result == null) {
|
||||||
|
result = getCached(MethodDescriptor.parse(value));
|
||||||
|
descriptorParseCache.put(value, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueType parseValueTypeCached(String value) {
|
||||||
|
ValueType result = valueTypeParseCache.get(value);
|
||||||
|
if (result == null) {
|
||||||
|
result = getCached(ValueType.parse(value));
|
||||||
|
valueTypeParseCache.put(value, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,11 +35,14 @@ import org.teavm.model.util.PhiUpdater;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
import org.teavm.optimization.UnreachableBasicBlockEliminator;
|
import org.teavm.optimization.UnreachableBasicBlockEliminator;
|
||||||
|
|
||||||
public final class Parser {
|
public class Parser {
|
||||||
private Parser() {
|
private ReferenceCache referenceCache;
|
||||||
|
|
||||||
|
public Parser(ReferenceCache referenceCache) {
|
||||||
|
this.referenceCache = referenceCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodHolder parseMethod(MethodNode node, String className, String fileName) {
|
public MethodHolder parseMethod(MethodNode node, String className, String fileName) {
|
||||||
MethodNode nodeWithoutJsr = new MethodNode(Opcodes.ASM5, node.access, node.name, node.desc, node.signature,
|
MethodNode nodeWithoutJsr = new MethodNode(Opcodes.ASM5, node.access, node.name, node.desc, node.signature,
|
||||||
node.exceptions.toArray(new String[0]));
|
node.exceptions.toArray(new String[0]));
|
||||||
JSRInlinerAdapter adapter = new JSRInlinerAdapter(nodeWithoutJsr, node.access, node.name, node.desc,
|
JSRInlinerAdapter adapter = new JSRInlinerAdapter(nodeWithoutJsr, node.access, node.name, node.desc,
|
||||||
|
@ -50,7 +53,7 @@ public final class Parser {
|
||||||
MethodHolder method = new MethodHolder(node.name, signature);
|
MethodHolder method = new MethodHolder(node.name, signature);
|
||||||
parseModifiers(node.access, method);
|
parseModifiers(node.access, method);
|
||||||
|
|
||||||
ProgramParser programParser = new ProgramParser();
|
ProgramParser programParser = new ProgramParser(referenceCache);
|
||||||
programParser.setFileName(fileName);
|
programParser.setFileName(fileName);
|
||||||
Program program = programParser.parse(node, className);
|
Program program = programParser.parse(node, className);
|
||||||
new UnreachableBasicBlockEliminator().optimize(program);
|
new UnreachableBasicBlockEliminator().optimize(program);
|
||||||
|
@ -75,7 +78,7 @@ public final class Parser {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyDebugNames(Program program, PhiUpdater phiUpdater, ProgramParser parser,
|
private void applyDebugNames(Program program, PhiUpdater phiUpdater, ProgramParser parser,
|
||||||
Variable[] argumentMapping) {
|
Variable[] argumentMapping) {
|
||||||
if (program.basicBlockCount() == 0) {
|
if (program.basicBlockCount() == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -110,7 +113,7 @@ public final class Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntIntMap[] getBlockEntryVariableMappings(Program program, PhiUpdater phiUpdater,
|
private IntIntMap[] getBlockEntryVariableMappings(Program program, PhiUpdater phiUpdater,
|
||||||
Variable[] argumentMapping) {
|
Variable[] argumentMapping) {
|
||||||
class Step {
|
class Step {
|
||||||
int node;
|
int node;
|
||||||
|
@ -179,7 +182,7 @@ public final class Parser {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Variable[] applySignature(Program program, ValueType[] arguments) {
|
private Variable[] applySignature(Program program, ValueType[] arguments) {
|
||||||
if (program.variableCount() == 0) {
|
if (program.variableCount() == 0) {
|
||||||
return new Variable[0];
|
return new Variable[0];
|
||||||
}
|
}
|
||||||
|
@ -204,7 +207,7 @@ public final class Parser {
|
||||||
return Arrays.copyOf(variableMap, index);
|
return Arrays.copyOf(variableMap, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassHolder parseClass(ClassNode node) {
|
public ClassHolder parseClass(ClassNode node) {
|
||||||
ClassHolder cls = new ClassHolder(node.name.replace('/', '.'));
|
ClassHolder cls = new ClassHolder(node.name.replace('/', '.'));
|
||||||
parseModifiers(node.access, cls);
|
parseModifiers(node.access, cls);
|
||||||
if (node.superName != null) {
|
if (node.superName != null) {
|
||||||
|
@ -238,7 +241,7 @@ public final class Parser {
|
||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldHolder parseField(FieldNode node) {
|
public FieldHolder parseField(FieldNode node) {
|
||||||
FieldHolder field = new FieldHolder(node.name);
|
FieldHolder field = new FieldHolder(node.name);
|
||||||
field.setType(ValueType.parse(node.desc));
|
field.setType(ValueType.parse(node.desc));
|
||||||
field.setInitialValue(node.value);
|
field.setInitialValue(node.value);
|
||||||
|
@ -247,7 +250,7 @@ public final class Parser {
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void parseModifiers(int access, ElementHolder member) {
|
public void parseModifiers(int access, ElementHolder member) {
|
||||||
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||||
member.setLevel(AccessLevel.PRIVATE);
|
member.setLevel(AccessLevel.PRIVATE);
|
||||||
} else if ((access & Opcodes.ACC_PROTECTED) != 0) {
|
} else if ((access & Opcodes.ACC_PROTECTED) != 0) {
|
||||||
|
@ -306,7 +309,7 @@ public final class Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseAnnotations(AnnotationContainer annotations, List<AnnotationNode> visibleAnnotations,
|
private void parseAnnotations(AnnotationContainer annotations, List<AnnotationNode> visibleAnnotations,
|
||||||
List<AnnotationNode> invisibleAnnotations) {
|
List<AnnotationNode> invisibleAnnotations) {
|
||||||
List<Object> annotNodes = new ArrayList<>();
|
List<Object> annotNodes = new ArrayList<>();
|
||||||
if (visibleAnnotations != null) {
|
if (visibleAnnotations != null) {
|
||||||
|
@ -328,7 +331,7 @@ public final class Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseAnnotationValues(AnnotationHolder annot, List<Object> values) {
|
private void parseAnnotationValues(AnnotationHolder annot, List<Object> values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +342,7 @@ public final class Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AnnotationValue parseAnnotationValue(Object value) {
|
private AnnotationValue parseAnnotationValue(Object value) {
|
||||||
if (value instanceof String[]) {
|
if (value instanceof String[]) {
|
||||||
String[] enumInfo = (String[]) value;
|
String[] enumInfo = (String[]) value;
|
||||||
ValueType.Object object = (ValueType.Object) ValueType.parse(enumInfo[0]);
|
ValueType.Object object = (ValueType.Object) ValueType.parse(enumInfo[0]);
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.model.util.InstructionTransitionExtractor;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
|
||||||
public class ProgramParser {
|
public class ProgramParser {
|
||||||
|
private ReferenceCache referenceCache;
|
||||||
private static final byte ROOT = 0;
|
private static final byte ROOT = 0;
|
||||||
private static final byte SINGLE = 1;
|
private static final byte SINGLE = 1;
|
||||||
private static final byte DOUBLE_FIRST_HALF = 2;
|
private static final byte DOUBLE_FIRST_HALF = 2;
|
||||||
|
@ -45,6 +46,10 @@ public class ProgramParser {
|
||||||
private Map<Integer, List<LocalVariableNode>> localVariableMap = new HashMap<>();
|
private Map<Integer, List<LocalVariableNode>> localVariableMap = new HashMap<>();
|
||||||
private Map<Instruction, Map<Integer, String>> variableDebugNames = new HashMap<>();
|
private Map<Instruction, Map<Integer, String>> variableDebugNames = new HashMap<>();
|
||||||
|
|
||||||
|
public ProgramParser(ReferenceCache methodReferenceCache) {
|
||||||
|
this.referenceCache = methodReferenceCache;
|
||||||
|
}
|
||||||
|
|
||||||
private static class Step {
|
private static class Step {
|
||||||
public final int source;
|
public final int source;
|
||||||
public final int target;
|
public final int target;
|
||||||
|
@ -389,9 +394,9 @@ public class ProgramParser {
|
||||||
|
|
||||||
private ValueType parseType(String type) {
|
private ValueType parseType(String type) {
|
||||||
if (type.startsWith("[")) {
|
if (type.startsWith("[")) {
|
||||||
return ValueType.parse(type);
|
return referenceCache.parseValueTypeCached(type);
|
||||||
} else {
|
} else {
|
||||||
return ValueType.object(type.replace('/', '.'));
|
return referenceCache.getCached(ValueType.object(type.replace('/', '.')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,7 +512,8 @@ public class ProgramParser {
|
||||||
insn.setReceiver(getVariable(returnType.getSize() == 2 ? pushDouble() : pushSingle()));
|
insn.setReceiver(getVariable(returnType.getSize() == 2 ? pushDouble() : pushSingle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
insn.setMethod(new MethodDescriptor(name, MethodDescriptor.parseSignature(desc)));
|
insn.setMethod(referenceCache.getCached(
|
||||||
|
new MethodDescriptor(name, MethodDescriptor.parseSignature(desc))));
|
||||||
for (Object bsmArg : bsmArgs) {
|
for (Object bsmArg : bsmArgs) {
|
||||||
insn.getBootstrapArguments().add(convertConstant(bsmArg));
|
insn.getBootstrapArguments().add(convertConstant(bsmArg));
|
||||||
}
|
}
|
||||||
|
@ -531,7 +537,7 @@ public class ProgramParser {
|
||||||
if (type.getSort() == Type.METHOD) {
|
if (type.getSort() == Type.METHOD) {
|
||||||
return new RuntimeConstant(MethodDescriptor.parseSignature(type.getDescriptor()));
|
return new RuntimeConstant(MethodDescriptor.parseSignature(type.getDescriptor()));
|
||||||
} else {
|
} else {
|
||||||
return new RuntimeConstant(ValueType.parse(type.getDescriptor()));
|
return new RuntimeConstant(referenceCache.parseValueTypeCached(type.getDescriptor()));
|
||||||
}
|
}
|
||||||
} else if (value instanceof Handle) {
|
} else if (value instanceof Handle) {
|
||||||
return new RuntimeConstant(parseHandle((Handle) value));
|
return new RuntimeConstant(parseHandle((Handle) value));
|
||||||
|
@ -566,7 +572,8 @@ public class ProgramParser {
|
||||||
for (int i = types.length - 1; i >= 0; --i) {
|
for (int i = types.length - 1; i >= 0; --i) {
|
||||||
args[--j] = types[i].getSize() == 2 ? getVariable(popDouble()) : getVariable(popSingle());
|
args[--j] = types[i].getSize() == 2 ? getVariable(popDouble()) : getVariable(popSingle());
|
||||||
}
|
}
|
||||||
MethodDescriptor method = new MethodDescriptor(name, MethodDescriptor.parseSignature(desc));
|
MethodDescriptor method = referenceCache.getCached(
|
||||||
|
new MethodDescriptor(name, MethodDescriptor.parseSignature(desc)));
|
||||||
int instance = -1;
|
int instance = -1;
|
||||||
if (opcode != Opcodes.INVOKESTATIC) {
|
if (opcode != Opcodes.INVOKESTATIC) {
|
||||||
instance = popSingle();
|
instance = popSingle();
|
||||||
|
@ -579,7 +586,7 @@ public class ProgramParser {
|
||||||
if (instance == -1) {
|
if (instance == -1) {
|
||||||
InvokeInstruction insn = new InvokeInstruction();
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
insn.setType(InvocationType.SPECIAL);
|
insn.setType(InvocationType.SPECIAL);
|
||||||
insn.setMethod(new MethodReference(ownerCls, method));
|
insn.setMethod(referenceCache.getCached(new MethodReference(ownerCls, method)));
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
insn.setReceiver(getVariable(result));
|
insn.setReceiver(getVariable(result));
|
||||||
}
|
}
|
||||||
|
@ -592,7 +599,7 @@ public class ProgramParser {
|
||||||
} else {
|
} else {
|
||||||
insn.setType(InvocationType.VIRTUAL);
|
insn.setType(InvocationType.VIRTUAL);
|
||||||
}
|
}
|
||||||
insn.setMethod(new MethodReference(ownerCls, method));
|
insn.setMethod(referenceCache.getCached(new MethodReference(ownerCls, method)));
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
insn.setReceiver(getVariable(result));
|
insn.setReceiver(getVariable(result));
|
||||||
}
|
}
|
||||||
|
@ -656,7 +663,7 @@ public class ProgramParser {
|
||||||
addInstruction(insn);
|
addInstruction(insn);
|
||||||
} else if (cst instanceof Type) {
|
} else if (cst instanceof Type) {
|
||||||
ClassConstantInstruction insn = new ClassConstantInstruction();
|
ClassConstantInstruction insn = new ClassConstantInstruction();
|
||||||
insn.setConstant(ValueType.parse(((Type) cst).getDescriptor()));
|
insn.setConstant(referenceCache.getCached(ValueType.parse(((Type) cst).getDescriptor())));
|
||||||
insn.setReceiver(getVariable(pushSingle()));
|
insn.setReceiver(getVariable(pushSingle()));
|
||||||
addInstruction(insn);
|
addInstruction(insn);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1652,11 +1659,11 @@ public class ProgramParser {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case Opcodes.GETFIELD: {
|
case Opcodes.GETFIELD: {
|
||||||
int instance = popSingle();
|
int instance = popSingle();
|
||||||
ValueType type = ValueType.parse(desc);
|
ValueType type = referenceCache.parseValueTypeCached(desc);
|
||||||
int value = desc.equals("D") || desc.equals("J") ? pushDouble() : pushSingle();
|
int value = desc.equals("D") || desc.equals("J") ? pushDouble() : pushSingle();
|
||||||
GetFieldInstruction insn = new GetFieldInstruction();
|
GetFieldInstruction insn = new GetFieldInstruction();
|
||||||
insn.setInstance(getVariable(instance));
|
insn.setInstance(getVariable(instance));
|
||||||
insn.setField(new FieldReference(ownerCls, name));
|
insn.setField(referenceCache.getCached(new FieldReference(ownerCls, name)));
|
||||||
insn.setFieldType(type);
|
insn.setFieldType(type);
|
||||||
insn.setReceiver(getVariable(value));
|
insn.setReceiver(getVariable(value));
|
||||||
addInstruction(insn);
|
addInstruction(insn);
|
||||||
|
@ -1667,17 +1674,17 @@ public class ProgramParser {
|
||||||
int instance = popSingle();
|
int instance = popSingle();
|
||||||
PutFieldInstruction insn = new PutFieldInstruction();
|
PutFieldInstruction insn = new PutFieldInstruction();
|
||||||
insn.setInstance(getVariable(instance));
|
insn.setInstance(getVariable(instance));
|
||||||
insn.setField(new FieldReference(ownerCls, name));
|
insn.setField(referenceCache.getCached(new FieldReference(ownerCls, name)));
|
||||||
insn.setValue(getVariable(value));
|
insn.setValue(getVariable(value));
|
||||||
insn.setFieldType(ValueType.parse(desc));
|
insn.setFieldType(referenceCache.parseValueTypeCached(desc));
|
||||||
addInstruction(insn);
|
addInstruction(insn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Opcodes.GETSTATIC: {
|
case Opcodes.GETSTATIC: {
|
||||||
ValueType type = ValueType.parse(desc);
|
ValueType type = referenceCache.parseValueTypeCached(desc);
|
||||||
int value = desc.equals("D") || desc.equals("J") ? pushDouble() : pushSingle();
|
int value = desc.equals("D") || desc.equals("J") ? pushDouble() : pushSingle();
|
||||||
GetFieldInstruction insn = new GetFieldInstruction();
|
GetFieldInstruction insn = new GetFieldInstruction();
|
||||||
insn.setField(new FieldReference(ownerCls, name));
|
insn.setField(referenceCache.getCached(new FieldReference(ownerCls, name)));
|
||||||
insn.setFieldType(type);
|
insn.setFieldType(type);
|
||||||
insn.setReceiver(getVariable(value));
|
insn.setReceiver(getVariable(value));
|
||||||
addInstruction(insn);
|
addInstruction(insn);
|
||||||
|
@ -1691,7 +1698,7 @@ public class ProgramParser {
|
||||||
}
|
}
|
||||||
int value = desc.equals("D") || desc.equals("J") ? popDouble() : popSingle();
|
int value = desc.equals("D") || desc.equals("J") ? popDouble() : popSingle();
|
||||||
PutFieldInstruction insn = new PutFieldInstruction();
|
PutFieldInstruction insn = new PutFieldInstruction();
|
||||||
insn.setField(new FieldReference(ownerCls, name));
|
insn.setField(referenceCache.getCached(new FieldReference(ownerCls, name)));
|
||||||
insn.setValue(getVariable(value));
|
insn.setValue(getVariable(value));
|
||||||
addInstruction(insn);
|
addInstruction(insn);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,13 +21,11 @@ import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.teavm.common.Mapper;
|
import org.teavm.common.Mapper;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ReferenceCache;
|
||||||
import org.teavm.parsing.Parser;
|
import org.teavm.parsing.Parser;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class ResourceClassHolderMapper implements Mapper<String, ClassHolder> {
|
public class ResourceClassHolderMapper implements Mapper<String, ClassHolder> {
|
||||||
|
private Parser parser = new Parser(new ReferenceCache());
|
||||||
private ResourceReader resourceReader;
|
private ResourceReader resourceReader;
|
||||||
|
|
||||||
public ResourceClassHolderMapper(ResourceReader resourceReader) {
|
public ResourceClassHolderMapper(ResourceReader resourceReader) {
|
||||||
|
@ -47,6 +45,6 @@ public class ResourceClassHolderMapper implements Mapper<String, ClassHolder> {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return Parser.parseClass(clsNode);
|
return parser.parseClass(clsNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013 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.resource;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import org.objectweb.asm.ClassReader;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
import org.teavm.common.Mapper;
|
|
||||||
import org.teavm.model.ClassHolder;
|
|
||||||
import org.teavm.parsing.Parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class ResourceParser implements Mapper<String, ClassHolder> {
|
|
||||||
private ResourceReader resourceReader;
|
|
||||||
|
|
||||||
public ResourceParser(ResourceReader resourceReader) {
|
|
||||||
this.resourceReader = resourceReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClassHolder map(String name) {
|
|
||||||
ClassNode clsNode = new ClassNode();
|
|
||||||
try (InputStream input = resourceReader.openResource(name.replace('.', '/') + ".class")) {
|
|
||||||
ClassReader reader = new ClassReader(input);
|
|
||||||
reader.accept(clsNode, 0);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return Parser.parseClass(clsNode);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user