WALA/com.ibm.wala.core/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeCTMethodWrapper.java

242 lines
7.3 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.classLoader;
import com.ibm.wala.shrikeBT.Decoder;
import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder;
import com.ibm.wala.shrikeCT.ClassReader;
import com.ibm.wala.shrikeCT.CodeReader;
import com.ibm.wala.shrikeCT.ExceptionsReader;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.shrikeCT.LineNumberTableReader;
import com.ibm.wala.shrikeCT.LocalVariableTableReader;
import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.debug.Assertions;
/**
*
* A wrapper around a Shrike object that represents a method
*
* @author sfink
*/
public final class ShrikeCTMethodWrapper extends ShrikeBTMethodWrapper {
/**
* The index of this method in the declaring class's method list according to
* Shrike CT.
*/
private int shrikeMethodIndex;
/**
* JVM-level modifiers for this method a value of -1 means "uninitialized"
*/
private int modifiers = -1;
public ShrikeCTMethodWrapper(IClass klass, int index) {
super(klass);
this.shrikeMethodIndex = index;
}
public byte[] getBytecodes() {
CodeReader code = getCodeReader();
if (code == null) {
return null;
} else {
return code.getBytecode();
}
}
protected String getMethodName() throws InvalidClassFileException {
ClassReader reader = getClassReader();
return reader.getMethodName(shrikeMethodIndex);
}
protected String getMethodSignature() throws InvalidClassFileException {
ClassReader reader = getClassReader();
return reader.getMethodType(shrikeMethodIndex);
}
protected int getModifiers() {
if (modifiers == -1) {
modifiers = getClassReader().getMethodAccessFlags(shrikeMethodIndex);
}
return modifiers;
}
protected Decoder makeDecoder() {
CodeReader reader = getCodeReader();
if (reader == null) {
return null;
}
final Decoder d = new CTDecoder(reader);
try {
d.decode();
} catch (Decoder.InvalidBytecodeException ex) {
Assertions.UNREACHABLE();
}
return d;
}
public int getMaxLocals() {
CodeReader reader = getCodeReader();
return reader.getMaxLocals();
}
public int getMaxStackHeight() {
CodeReader reader = getCodeReader();
// note that Shrike returns the maximum index in the zero-indexed stack
// array.
// Instead, we want the max number of entries on the stack.
// So we add 1.
// Additionally, ShrikeBT may add additional stack entries with
// Constant instructions. We add an additional 1 to account for this,
// which seems to handle all ShrikeBT code generation patterns.
// TODO: ShrikeBT should have a getMaxStack method on Decoder, I think.
return reader.getMaxStack() + 2;
}
public boolean hasExceptionHandler() {
CodeReader reader = getCodeReader();
if (reader == null)
return false;
int[] handlers = reader.getRawHandlers();
return handlers != null && handlers.length > 0;
}
protected String[] getDeclaredExceptionTypeNames() throws InvalidClassFileException {
ExceptionsReader reader = getExceptionReader();
if (reader == null) {
return null;
} else {
return reader.getClasses();
}
}
protected void processDebugInfo(BytecodeInfo bcInfo) throws InvalidClassFileException {
CodeReader cr = getCodeReader();
bcInfo.lineNumberMap = LineNumberTableReader.makeBytecodeToSourceMap(cr);
bcInfo.localVariableMap = LocalVariableTableReader.makeVarMap(cr);
}
public String getLocalVariableName(int bcIndex, int localNumber) {
if (bcInfo == null) {
try {
processBytecodes();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
int[][] map = bcInfo.localVariableMap;
if (localNumber > getMaxLocals()) {
throw new IllegalArgumentException("illegal local number: " + localNumber + ", method " + getName() + " uses at most "
+ getMaxLocals());
}
if (map == null) {
return null;
} else {
int[] localPairs = map[bcIndex];
int localIndex = localNumber * 2;
if (localPairs == null || localIndex >= localPairs.length) {
// no information about the specified local at this program point
return null;
}
int nameIndex = localPairs[localIndex];
if (nameIndex == 0) {
return null;
} else {
try {
return getClassReader().getCP().getCPUtf8(nameIndex);
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
return null;
}
}
}
}
/*
* TODO: cache for efficiency? (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable()
*/
public boolean hasLocalVariableTable() {
try {
ClassReader.AttrIterator iter = new ClassReader.AttrIterator();
getCodeReader().initAttributeIterator(iter);
for (; iter.isValid(); iter.advance()) {
if (iter.getName().equals("LocalVariableTable")) {
return true;
}
}
return false;
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
return false;
}
}
private ClassReader getClassReader() {
return ((ShrikeCTClassWrapper)getDeclaringClass()).getReader();
}
private CodeReader getCodeReader() {
ClassReader.AttrIterator iter = new AttrIterator();
getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter);
// search for the code attribute
CodeReader code = null;
try {
for (; iter.isValid(); iter.advance()) {
if (iter.getName().toString().equals("Code")) {
code = new CodeReader(iter);
break;
}
}
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
}
return code;
}
private ExceptionsReader getExceptionReader() {
ClassReader.AttrIterator iter = new AttrIterator();
getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter);
// search for the desired attribute
ExceptionsReader result = null;
try {
for (; iter.isValid(); iter.advance()) {
if (iter.getName().toString().equals("Exceptions")) {
result = new ExceptionsReader(iter);
break;
}
}
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
}
return result;
}
public TypeReference getReturnType() {
return getReference().getReturnType();
}
}