Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.strobel.assembler.ir.StackMappingVisitor Maven / Gradle / Ivy
/*
* StackMappingVisitor.java
*
* Copyright (c) 2013 Mike Strobel
*
* This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
* and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.assembler.ir;
import com.strobel.assembler.ir.attributes.SourceAttribute;
import com.strobel.assembler.metadata.*;
import com.strobel.assembler.metadata.annotations.CustomAnnotation;
import com.strobel.core.StringUtilities;
import com.strobel.core.VerifyArgument;
import com.strobel.decompiler.InstructionHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class StackMappingVisitor implements MethodVisitor {
private final MethodVisitor _innerVisitor;
private int _maxLocals;
// private int _maxStack;
private List _stack = new ArrayList<>();
private List _locals = new ArrayList<>();
private Map _initializations = new IdentityHashMap<>();
public StackMappingVisitor() {
_innerVisitor = null;
}
public StackMappingVisitor(final MethodVisitor innerVisitor) {
_innerVisitor = innerVisitor;
}
public final Frame buildFrame() {
return new Frame(
FrameType.New,
_locals.toArray(new FrameValue[_locals.size()]),
_stack.toArray(new FrameValue[_stack.size()])
);
}
public final int getStackSize() {
return _stack == null ? 0 : _stack.size();
}
public final int getLocalCount() {
return _locals == null ? 0 : _locals.size();
}
public final FrameValue getStackValue(final int offset) {
VerifyArgument.inRange(0, getStackSize(), offset, "offset");
return _stack.get(_stack.size() - offset - 1);
}
public final FrameValue getLocalValue(final int slot) {
VerifyArgument.inRange(0, getLocalCount(), slot, "slot");
return _locals.get(slot);
}
public final Map getInitializations() {
return Collections.unmodifiableMap(_initializations);
}
public final FrameValue[] getStackSnapshot() {
if (_stack == null || _stack.isEmpty()) {
return FrameValue.EMPTY_VALUES;
}
return _stack.toArray(new FrameValue[_stack.size()]);
}
public final FrameValue[] getLocalsSnapshot() {
if (_locals == null || _locals.isEmpty()) {
return FrameValue.EMPTY_VALUES;
}
return _locals.toArray(new FrameValue[_locals.size()]);
}
@Override
public boolean canVisitBody() {
return true;
}
@Override
public InstructionVisitor visitBody(final MethodBody body) {
if (_innerVisitor != null && _innerVisitor.canVisitBody()) {
return new InstructionAnalyzer(body, _innerVisitor.visitBody(body));
}
else {
return new InstructionAnalyzer(body);
}
}
@Override
public void visitEnd() {
if (_innerVisitor != null) {
_innerVisitor.visitEnd();
}
}
@Override
public void visitFrame(final Frame frame) {
VerifyArgument.notNull(frame, "frame");
if (frame.getFrameType() != FrameType.New) {
throw Error.stackMapperCalledWithUnexpandedFrame(frame.getFrameType());
}
if (_innerVisitor != null) {
_innerVisitor.visitFrame(frame);
}
if (_locals != null) {
_locals.clear();
_stack.clear();
// _initializations.clear();
}
else {
_locals = new ArrayList<>();
_stack = new ArrayList<>();
_initializations = new IdentityHashMap<>();
}
for (final FrameValue frameValue : frame.getLocalValues()) {
_locals.add(frameValue);
}
for (final FrameValue frameValue : frame.getStackValues()) {
_stack.add(frameValue);
}
}
@Override
public void visitLineNumber(final Instruction instruction, final int lineNumber) {
if (_innerVisitor != null) {
_innerVisitor.visitLineNumber(instruction, lineNumber);
}
}
@Override
public void visitAttribute(final SourceAttribute attribute) {
if (_innerVisitor != null) {
_innerVisitor.visitAttribute(attribute);
}
}
@Override
public void visitAnnotation(final CustomAnnotation annotation, final boolean visible) {
if (_innerVisitor != null) {
_innerVisitor.visitAnnotation(annotation, visible);
}
}
@Override
public void visitParameterAnnotation(final int parameter, final CustomAnnotation annotation, final boolean visible) {
if (_innerVisitor != null) {
_innerVisitor.visitParameterAnnotation(parameter, annotation, visible);
}
}
protected final FrameValue get(final int local) {
_maxLocals = Math.max(_maxLocals, local);
return local < _locals.size() ? _locals.get(local) : FrameValue.TOP;
}
protected final void set(final int local, final FrameValue value) {
_maxLocals = Math.max(_maxLocals, local);
if (_locals == null) {
_locals = new ArrayList<>();
_stack = new ArrayList<>();
_initializations = new IdentityHashMap<>();
}
while (local >= _locals.size()) {
_locals.add(FrameValue.TOP);
}
_locals.set(local, value);
if (value.getType().isDoubleWord()) {
_locals.set(local + 1, FrameValue.TOP);
}
}
protected final void set(final int local, final TypeReference type) {
_maxLocals = Math.max(_maxLocals, local);
if (_locals == null) {
_locals = new ArrayList<>();
_stack = new ArrayList<>();
_initializations = new IdentityHashMap<>();
}
while (local >= _locals.size()) {
_locals.add(FrameValue.TOP);
}
if (type == null) {
_locals.set(local, FrameValue.TOP);
return;
}
switch (type.getSimpleType()) {
case Boolean:
case Byte:
case Character:
case Short:
case Integer:
_locals.set(local, FrameValue.INTEGER);
break;
case Long:
_locals.set(local, FrameValue.LONG);
if (local + 1 >= _locals.size()) {
_locals.add(FrameValue.TOP);
}
else {
_locals.set(local + 1, FrameValue.TOP);
}
break;
case Float:
_locals.set(local, FrameValue.FLOAT);
break;
case Double:
_locals.set(local, FrameValue.DOUBLE);
if (local + 1 >= _locals.size()) {
_locals.add(FrameValue.TOP);
}
else {
_locals.set(local + 1, FrameValue.TOP);
}
break;
case Object:
case Array:
case TypeVariable:
case Wildcard:
_locals.set(local, FrameValue.makeReference(type));
break;
case Void:
throw new IllegalArgumentException("Cannot set local to type void.");
}
}
protected final FrameValue pop() {
return _stack.remove(_stack.size() - 1);
}
protected final FrameValue peek() {
return _stack.get(_stack.size() - 1);
}
protected final void pop(final int count) {
final int size = _stack.size();
final int end = size - count;
for (int i = size - 1; i >= end; i--) {
_stack.remove(i);
}
}
protected final void push(final TypeReference type) {
if (_stack == null) {
_locals = new ArrayList<>();
_stack = new ArrayList<>();
_initializations = new IdentityHashMap<>();
}
switch (type.getSimpleType()) {
case Boolean:
case Byte:
case Character:
case Short:
case Integer:
_stack.add(FrameValue.INTEGER);
break;
case Long:
_stack.add(FrameValue.LONG);
_stack.add(FrameValue.TOP);
break;
case Float:
_stack.add(FrameValue.FLOAT);
break;
case Double:
_stack.add(FrameValue.DOUBLE);
_stack.add(FrameValue.TOP);
break;
case Object:
case Array:
case TypeVariable:
case Wildcard:
_stack.add(FrameValue.makeReference(type));
break;
case Void:
break;
}
}
protected final void push(final FrameValue value) {
if (_stack == null) {
_locals = new ArrayList<>();
_stack = new ArrayList<>();
_initializations = new IdentityHashMap<>();
}
_stack.add(value);
}
protected void initialize(final FrameValue value, final TypeReference type) {
VerifyArgument.notNull(type, "type");
final Object parameter = value.getParameter();
final FrameValue initializedValue = FrameValue.makeReference(type);
if (parameter instanceof Instruction) {
_initializations.put((Instruction) parameter, type);
}
for (int i = 0; i < _stack.size(); i++) {
if (_stack.get(i) == value) {
_stack.set(i, initializedValue);
}
}
for (int i = 0; i < _locals.size(); i++) {
if (_locals.get(i) == value) {
_locals.set(i, initializedValue);
}
}
}
public void pruneLocals() {
while (!_locals.isEmpty() && _locals.get(_locals.size() - 1) == FrameValue.OUT_OF_SCOPE) {
_locals.remove(_locals.size() - 1);
}
for (int i = 0; i < _locals.size(); i++) {
if (_locals.get(i) == FrameValue.OUT_OF_SCOPE) {
_locals.set(i, FrameValue.TOP);
}
}
}
private final class InstructionAnalyzer implements InstructionVisitor {
private final InstructionVisitor _innerVisitor;
private final MethodBody _body;
private final CoreMetadataFactory _factory;
private boolean _afterExecute;
private InstructionAnalyzer(final MethodBody body) {
this(body, null);
}
private InstructionAnalyzer(final MethodBody body, final InstructionVisitor innerVisitor) {
_body = VerifyArgument.notNull(body, "body");
_innerVisitor = innerVisitor;
if (body.getMethod().isConstructor()) {
set(0, FrameValue.UNINITIALIZED_THIS);
}
_factory = CoreMetadataFactory.make(_body.getMethod().getDeclaringType(), _body.getMethod());
}
@Override
public void visit(final Instruction instruction) {
if (_innerVisitor != null) {
_innerVisitor.visit(instruction);
}
instruction.accept(this);
execute(instruction);
_afterExecute = true;
try {
instruction.accept(this);
}
finally {
_afterExecute = false;
}
}
@Override
public void visit(final OpCode code) {
if (_afterExecute) {
if (code.isStore()) {
final FrameValue value = _temp.isEmpty() ? pop() : _temp.pop();
if (code.getStackChange() == -2) {
final FrameValue doubleOrLong = _temp.isEmpty() ? pop() : _temp.pop();
set(OpCodeHelpers.getLoadStoreMacroArgumentIndex(code), doubleOrLong);
set(OpCodeHelpers.getLoadStoreMacroArgumentIndex(code) + 1, value);
}
else {
set(OpCodeHelpers.getLoadStoreMacroArgumentIndex(code), value);
}
}
}
else if (code.isLoad()) {
final FrameValue value = get(OpCodeHelpers.getLoadStoreMacroArgumentIndex(code));
push(value);
if (value.getType().isDoubleWord()) {
push(get(OpCodeHelpers.getLoadStoreMacroArgumentIndex(code) + 1));
}
}
}
@Override
public void visitConstant(final OpCode code, final TypeReference value) {
}
@Override
public void visitConstant(final OpCode code, final int value) {
}
@Override
public void visitConstant(final OpCode code, final long value) {
}
@Override
public void visitConstant(final OpCode code, final float value) {
}
@Override
public void visitConstant(final OpCode code, final double value) {
}
@Override
public void visitConstant(final OpCode code, final String value) {
}
@Override
public void visitBranch(final OpCode code, final Instruction target) {
}
@Override
public void visitVariable(final OpCode code, final VariableReference variable) {
if (_afterExecute) {
if (code.isStore()) {
final FrameValue value = _temp.isEmpty() ? pop() : _temp.pop();
if (code.getStackChange() == -2) {
final FrameValue doubleOrLong = _temp.isEmpty() ? pop() : _temp.pop();
set(variable.getSlot(), doubleOrLong);
set(variable.getSlot() + 1, value);
}
else {
set(variable.getSlot(), value);
}
}
}
else if (code.isLoad()) {
final FrameValue value = get(variable.getSlot());
push(value);
if (code.getStackChange() == 2) {
push(get(variable.getSlot() + 1));
}
}
}
@Override
public void visitVariable(final OpCode code, final VariableReference variable, final int operand) {
}
@Override
public void visitType(final OpCode code, final TypeReference type) {
}
@Override
public void visitMethod(final OpCode code, final MethodReference method) {
}
@Override
public void visitDynamicCallSite(final OpCode opCode, final DynamicCallSite callSite) {
}
@Override
public void visitField(final OpCode code, final FieldReference field) {
}
@Override
public void visitLabel(final Label label) {
}
@Override
public void visitSwitch(final OpCode code, final SwitchInfo switchInfo) {
}
@Override
public void visitEnd() {
}
private final Stack _temp = new Stack<>();
@SuppressWarnings("ConstantConditions")
private void execute(final Instruction instruction) {
final OpCode code = instruction.getOpCode();
_temp.clear();
if (code.isLoad() || code.isStore()) {
return;
}
switch (code.getStackBehaviorPop()) {
case Pop0:
break;
case Pop1:
_temp.push(pop());
break;
case Pop2:
case Pop1_Pop1:
_temp.push(pop());
_temp.push(pop());
break;
case Pop1_Pop2:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case Pop1_PopA:
_temp.push(pop());
_temp.push(pop());
break;
case Pop2_Pop1:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case Pop2_Pop2:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopI4:
_temp.push(pop());
break;
case PopI8:
_temp.push(pop());
_temp.push(pop());
break;
case PopR4:
_temp.push(pop());
break;
case PopR8:
_temp.push(pop());
_temp.push(pop());
break;
case PopA:
_temp.push(pop());
break;
case PopI4_PopI4:
_temp.push(pop());
_temp.push(pop());
break;
case PopI4_PopI8:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopI8_PopI8:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopR4_PopR4:
_temp.push(pop());
_temp.push(pop());
break;
case PopR8_PopR8:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopI4_PopA:
_temp.push(pop());
_temp.push(pop());
break;
case PopI4_PopI4_PopA:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopI8_PopI4_PopA:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopR4_PopI4_PopA:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopR8_PopI4_PopA:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopA_PopI4_PopA:
_temp.push(pop());
_temp.push(pop());
_temp.push(pop());
break;
case PopA_PopA:
_temp.push(pop());
_temp.push(pop());
break;
case VarPop: {
switch (code) {
case INVOKEVIRTUAL:
case INVOKESPECIAL:
case INVOKESTATIC:
case INVOKEINTERFACE:
case INVOKEDYNAMIC: {
final IMethodSignature method;
if (code == OpCode.INVOKEDYNAMIC) {
method = instruction.getOperand(0).getMethodType();
}
else {
method = instruction.getOperand(0);
}
final List parameters = method.getParameters();
if (code == OpCode.INVOKESPECIAL &&
((MethodReference) method).isConstructor()) {
final FrameValue firstParameter = getStackValue(computeSize(parameters));
final FrameValueType firstParameterType = firstParameter.getType();
if (firstParameterType == FrameValueType.UninitializedThis ||
firstParameterType == FrameValueType.Uninitialized) {
TypeReference initializedType;
if (firstParameterType == FrameValueType.UninitializedThis) {
initializedType = _body.getMethod().getDeclaringType();
}
else {
initializedType = ((MethodReference) method).getDeclaringType();
}
if (initializedType.isGenericDefinition()) {
final Instruction next = instruction.getNext();
if (next != null && next.getOpCode().isStore()) {
final int slot = InstructionHelper.getLoadOrStoreSlot(next);
final VariableDefinition variable = _body.getVariables().tryFind(slot, next.getEndOffset());
if (variable != null &&
variable.isFromMetadata() &&
variable.getVariableType() instanceof IGenericInstance &&
StringUtilities.equals(initializedType.getInternalName(), variable.getVariableType().getInternalName())) {
initializedType = variable.getVariableType();
}
}
}
initialize(firstParameter, initializedType);
}
}
for (final ParameterDefinition parameter : parameters) {
final TypeReference parameterType = parameter.getParameterType();
switch (parameterType.getSimpleType()) {
case Long:
case Double:
_temp.push(pop());
_temp.push(pop());
break;
default:
_temp.push(pop());
break;
}
}
/*if (code == OpCode.INVOKEDYNAMIC) {
final MethodDefinition resolved = method instanceof MethodReference ? ((MethodReference) method).resolve()
: null;
if (resolved != null) {
if (!resolved.isStatic() && !resolved.isConstructor()) {
_temp.push(pop());
}
}
else {
final DynamicCallSite callSite = instruction.getOperand(0);
final MethodReference bootstrapMethod = callSite.getBootstrapMethod();
if ("java/lang/invoke/LambdaMetafactory".equals(bootstrapMethod.getDeclaringType().getInternalName()) &&
StringUtilities.equals("metaFactory", bootstrapMethod.getName(), StringComparison.OrdinalIgnoreCase) &&
callSite.getBootstrapArguments().size() == 3 &&
callSite.getBootstrapArguments().get(1) instanceof MethodHandle) {
final MethodHandle targetMethodHandle = (MethodHandle) callSite.getBootstrapArguments().get(1);
switch (targetMethodHandle.getHandleType()) {
case GetField:
case PutField:
case InvokeVirtual:
case InvokeInterface:
case InvokeSpecial:
_temp.push(pop());
break;
}
}
}
}
else*/ if (code != OpCode.INVOKESTATIC && code != OpCode.INVOKEDYNAMIC) {
_temp.push(pop());
}
break;
}
case ATHROW: {
_temp.push(pop());
while (!_stack.isEmpty()) {
pop();
}
break;
}
case MULTIANEWARRAY: {
final int dimensions = ((Number) instruction.getOperand(1)).intValue();
for (int i = 0; i < dimensions; i++) {
_temp.push(pop());
}
break;
}
}
break;
}
}
if (code.isArrayLoad()) {
final FrameValue frameValue = _temp.pop();
final Object parameter = frameValue.getParameter();
switch (code) {
case BALOAD:
case CALOAD:
case SALOAD:
case IALOAD:
push(FrameValue.INTEGER);
break;
case LALOAD:
push(FrameValue.LONG);
push(FrameValue.TOP);
break;
case FALOAD:
push(FrameValue.FLOAT);
break;
case DALOAD:
push(FrameValue.DOUBLE);
push(FrameValue.TOP);
break;
case AALOAD:
if (parameter instanceof TypeReference) {
push(((TypeReference) parameter).getElementType());
}
else if (frameValue.getType() == FrameValueType.Null) {
push(FrameValue.NULL);
}
else {
push(FrameValue.TOP);
}
break;
}
return;
}
else if (code == OpCode.JSR || code == OpCode.JSR) {
set(0, FrameValue.makeAddress(instruction.getNext()));
}
switch (code.getStackBehaviorPush()) {
case Push0:
break;
case Push1: {
switch (code) {
case LDC:
case LDC_W: {
final Object op = instruction.getOperand(0);
if (op instanceof String) {
push(_factory.makeNamedType("java.lang.String"));
}
else if (op instanceof TypeReference) {
push(_factory.makeNamedType("java.lang.Class"));
}
else {
if (op instanceof Long) {
push(FrameValue.LONG);
push(FrameValue.TOP);
}
else if (op instanceof Float) {
push(FrameValue.FLOAT);
}
else if (op instanceof Double) {
push(FrameValue.DOUBLE);
push(FrameValue.TOP);
}
else if (op instanceof Integer) {
push(FrameValue.INTEGER);
}
}
break;
}
case GETFIELD:
case GETSTATIC: {
final FieldReference field = instruction.getOperand(0);
push(field.getFieldType());
break;
}
}
break;
}
case Push1_Push1: {
switch (code) {
case DUP: {
final FrameValue value = _temp.pop();
push(value);
push(value);
break;
}
case SWAP: {
final FrameValue t2 = _temp.pop();
final FrameValue t1 = _temp.pop();
push(t2);
push(t1);
break;
}
}
break;
}
case Push1_Push1_Push1: {
final FrameValue t2 = _temp.pop();
final FrameValue t1 = _temp.pop();
push(t1);
push(t2);
push(t1);
break;
}
case Push1_Push2_Push1: {
final FrameValue t3 = _temp.pop();
final FrameValue t2 = _temp.pop();
final FrameValue t1 = _temp.pop();
push(t1);
push(t3);
push(t2);
push(t1);
break;
}
case Push2: {
final Number constant = instruction.getOperand(0);
if (constant instanceof Double) {
push(FrameValue.DOUBLE);
push(FrameValue.TOP);
}
else {
push(FrameValue.LONG);
push(FrameValue.TOP);
}
break;
}
case Push2_Push2: {
final FrameValue t2 = _temp.pop();
final FrameValue t1 = _temp.pop();
push(t2);
push(t1);
push(t2);
push(t1);
break;
}
case Push2_Push1_Push2: {
final FrameValue t3 = _temp.pop();
final FrameValue t2 = _temp.pop();
final FrameValue t1 = _temp.pop();
push(t2);
push(t1);
push(t3);
push(t2);
push(t1);
break;
}
case Push2_Push2_Push2: {
final FrameValue t4 = _temp.pop();
final FrameValue t3 = _temp.pop();
final FrameValue t2 = _temp.pop();
final FrameValue t1 = _temp.pop();
push(t2);
push(t1);
push(t4);
push(t3);
push(t2);
push(t1);
break;
}
case PushI4: {
push(FrameValue.INTEGER);
break;
}
case PushI8: {
push(FrameValue.LONG);
push(FrameValue.TOP);
break;
}
case PushR4: {
push(FrameValue.FLOAT);
break;
}
case PushR8: {
push(FrameValue.DOUBLE);
push(FrameValue.TOP);
break;
}
case PushA: {
switch (code) {
case NEW:
push(FrameValue.makeUninitializedReference(instruction));
break;
case NEWARRAY:
case ANEWARRAY:
push(instruction.getOperand(0).makeArrayType());
break;
case CHECKCAST:
case MULTIANEWARRAY:
push(instruction.getOperand(0));
break;
case ACONST_NULL:
push(FrameValue.NULL);
break;
default:
push(pop());
break;
}
break;
}
case PushAddress: {
push(FrameValue.makeAddress(instruction.getNext()));
break;
}
case VarPush: {
final IMethodSignature signature;
if (code == OpCode.INVOKEDYNAMIC) {
signature = instruction.getOperand(0).getMethodType();
}
else {
signature = instruction.getOperand(0);
}
TypeReference returnType = signature.getReturnType();
if (returnType.getSimpleType() != JvmType.Void) {
if (code != OpCode.INVOKESTATIC &&
code != OpCode.INVOKEDYNAMIC) {
final TypeReference typeReference;
if (code == OpCode.INVOKESPECIAL) {
typeReference = ((MethodReference) signature).getDeclaringType();
}
else {
final Object parameter = _temp.peek().getParameter();
typeReference = parameter instanceof Instruction ? _initializations.get(parameter)
: (TypeReference) parameter;
}
final TypeReference targetType = substituteTypeArguments(
typeReference,
(MemberReference) signature
);
returnType = substituteTypeArguments(
substituteTypeArguments(
signature.getReturnType(),
(MemberReference) signature
),
targetType
);
}
else if (instruction.getNext() != null &&
instruction.getNext().getOpCode().isStore()) {
final Instruction next = instruction.getNext();
final int slot = InstructionHelper.getLoadOrStoreSlot(next);
final VariableDefinition variable = _body.getVariables().tryFind(slot, next.getEndOffset());
if (variable != null && variable.isFromMetadata()) {
returnType = substituteTypeArguments(
variable.getVariableType(),
signature.getReturnType()
);
}
}
}
if (returnType.isWildcardType()) {
returnType = returnType.hasSuperBound() ? returnType.getSuperBound()
: returnType.getExtendsBound();
}
switch (returnType.getSimpleType()) {
case Boolean:
case Byte:
case Character:
case Short:
case Integer:
push(FrameValue.INTEGER);
break;
case Long:
push(FrameValue.LONG);
push(FrameValue.TOP);
break;
case Float:
push(FrameValue.FLOAT);
break;
case Double:
push(FrameValue.DOUBLE);
push(FrameValue.TOP);
break;
case Object:
case Array:
case TypeVariable:
case Wildcard:
push(FrameValue.makeReference(returnType));
break;
case Void:
break;
}
break;
}
}
}
private int computeSize(final List parameters) {
int size = 0;
for (final ParameterDefinition parameter : parameters) {
size += parameter.getSize();
}
return size;
}
private TypeReference substituteTypeArguments(final TypeReference type, final MemberReference member) {
if (type instanceof ArrayType) {
final ArrayType arrayType = (ArrayType) type;
final TypeReference elementType = substituteTypeArguments(
arrayType.getElementType(),
member
);
if (!MetadataResolver.areEquivalent(elementType, arrayType.getElementType())) {
return elementType.makeArrayType();
}
return type;
}
if (type instanceof IGenericInstance) {
final IGenericInstance genericInstance = (IGenericInstance) type;
final List newTypeArguments = new ArrayList<>();
boolean isChanged = false;
for (final TypeReference typeArgument : genericInstance.getTypeArguments()) {
final TypeReference newTypeArgument = substituteTypeArguments(typeArgument, member);
newTypeArguments.add(newTypeArgument);
isChanged |= newTypeArgument != typeArgument;
}
return isChanged ? type.makeGenericType(newTypeArguments)
: type;
}
if (type instanceof GenericParameter) {
final GenericParameter genericParameter = (GenericParameter) type;
final IGenericParameterProvider owner = genericParameter.getOwner();
if (member.getDeclaringType() instanceof ArrayType) {
return member.getDeclaringType().getElementType();
}
else if (owner instanceof MethodReference && member instanceof MethodReference) {
final MethodReference method = (MethodReference) member;
final MethodReference ownerMethod = (MethodReference) owner;
if (method.isGenericMethod() &&
MetadataResolver.areEquivalent(ownerMethod.getDeclaringType(), method.getDeclaringType()) &&
StringUtilities.equals(ownerMethod.getName(), method.getName()) &&
StringUtilities.equals(ownerMethod.getErasedSignature(), method.getErasedSignature())) {
if (method instanceof IGenericInstance) {
final List typeArguments = ((IGenericInstance) member).getTypeArguments();
return typeArguments.get(genericParameter.getPosition());
}
else {
return method.getGenericParameters().get(genericParameter.getPosition());
}
}
}
else if (owner instanceof TypeReference) {
TypeReference declaringType;
if (member instanceof TypeReference) {
declaringType = (TypeReference) member;
}
else {
declaringType = member.getDeclaringType();
}
if (MetadataResolver.areEquivalent((TypeReference) owner, declaringType)) {
if (declaringType instanceof IGenericInstance) {
final List typeArguments = ((IGenericInstance) declaringType).getTypeArguments();
return typeArguments.get(genericParameter.getPosition());
}
if (!declaringType.isGenericDefinition()) {
declaringType = declaringType.resolve();
}
if (declaringType != null && declaringType.isGenericDefinition()) {
return declaringType.getGenericParameters().get(genericParameter.getPosition());
}
}
}
}
return type;
}
}
}