rename Shrike*Wrapper to just Shrike*

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@552 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
sjfink 2007-01-10 20:51:00 +00:00
parent 979451f05c
commit 429403c321
3 changed files with 2014 additions and 0 deletions

View File

@ -0,0 +1,925 @@
/*******************************************************************************
* 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 java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.ibm.wala.shrikeBT.ArrayLoadInstruction;
import com.ibm.wala.shrikeBT.ArrayStoreInstruction;
import com.ibm.wala.shrikeBT.BytecodeConstants;
import com.ibm.wala.shrikeBT.CheckCastInstruction;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.Decoder;
import com.ibm.wala.shrikeBT.ExceptionHandler;
import com.ibm.wala.shrikeBT.GetInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeBT.Instruction;
import com.ibm.wala.shrikeBT.InvokeInstruction;
import com.ibm.wala.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrikeBT.NewInstruction;
import com.ibm.wala.shrikeBT.PutInstruction;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.Atom;
import com.ibm.wala.util.Exceptions;
import com.ibm.wala.util.ImmutableByteArray;
import com.ibm.wala.util.ShrikeUtil;
import com.ibm.wala.util.bytecode.BytecodeStream;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Assertions;
/**
*
* A wrapper around a Shrike object that represents a method
*
* @author sfink
*/
public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
/**
* Some verbose progress output?
*/
private final static boolean verbose = false;
private static int methodsParsed = 0;
/**
* A wrapper around the declaring class.
*/
protected final IClass declaringClass;
/**
* Canonical reference for this method
*/
private MethodReference methodReference;
// break these out to save some space; they're computed lazily.
protected static class BytecodeInfo {
Decoder decoder;
CallSiteReference[] callSites;
FieldReference[] fieldsWritten;
FieldReference[] fieldsRead;
NewSiteReference[] newSites;
TypeReference[] arraysRead;
TypeReference[] arraysWritten;
TypeReference[] implicitExceptions;
TypeReference[] castTypes;
boolean hasMonitorOp;
/**
* Mapping from instruction index to program counter.
*/
private int[] pcMap;
/**
* Cached map representing line number information in ShrikeCT format TODO:
* do more careful caching than just soft references
*/
protected int[] lineNumberMap;
/**
* an array mapping bytecode offsets to arrays representing the local
* variable maps for each offset; a local variable map is represented as an
* array of localVars*2 elements, containing a pair (nameIndex, typeIndex)
* for each local variable; a pair (0,0) indicates there is no information
* for that local variable at that offset
*/
protected int[][] localVariableMap;
/**
* Exception types this method might throw. Computed on demand.
*/
private TypeReference[] exceptionTypes;
}
/**
* Cache the information about the method statements.
*/
protected BytecodeInfo bcInfo;
public ShrikeBTMethod(IClass klass) {
this.declaringClass = klass;
}
/**
* Return the program counter (bytecode index) for a particular Shrike
* instruction index.
*
* @throws InvalidClassFileException
*/
public int getBytecodeIndex(int instructionIndex) throws InvalidClassFileException {
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return bcInfo.pcMap[instructionIndex];
}
/**
* @return an Iterator of CallSiteReferences from this method.
* @throws InvalidClassFileException
*/
Iterator<CallSiteReference> getCallSites() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
Iterator<CallSiteReference> empty = EmptyIterator.instance();
return (bcInfo.callSites == null) ? empty : Arrays.asList(bcInfo.callSites).iterator();
}
/**
* @return an Iterator of NewlSiteReferences from this method.
* @throws InvalidClassFileException
*/
Iterator<NewSiteReference> getNewSites() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
Iterator<NewSiteReference> empty = EmptyIterator.instance();
return (bcInfo.newSites == null) ? empty : Arrays.asList(bcInfo.newSites).iterator();
}
/**
* @return Set <TypeReference>, the exceptions that statements in this method
* may throw,
* @throws InvalidClassFileException
*/
public Collection getImplicitExceptionTypes() throws InvalidClassFileException {
if (isNative()) {
return Collections.EMPTY_SET;
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return (bcInfo.implicitExceptions == null) ? Arrays.asList(new TypeReference[0]) : Arrays.asList(bcInfo.implicitExceptions);
}
/**
* Method processBytecodes. Do a cheap pass over the bytecodes to collect some
* mapping information. Some methods require this as a pre-req to accessing
* ShrikeCT information.
*
* @throws InvalidClassFileException
*/
public void processBytecodes() throws InvalidClassFileException {
if (bcInfo != null) {
// already done.
return;
}
bcInfo = new BytecodeInfo();
bcInfo.exceptionTypes = computeDeclaredExceptions();
if (isNative()) {
return;
}
if (verbose) {
methodsParsed += 1;
if (methodsParsed % 100 == 0) {
System.out.println(methodsParsed + " methods processed...");
}
}
processBytecodesWithShrikeBT();
}
/**
* @return true iff this method has a monitorenter or monitorexit
* @throws InvalidClassFileException
*/
public boolean hasMonitorOp() throws InvalidClassFileException {
if (isNative()) {
return false;
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return bcInfo.hasMonitorOp;
}
/**
* @return Set of FieldReference
* @throws InvalidClassFileException
*/
public Iterator<FieldReference> getFieldsWritten() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
if (bcInfo.fieldsWritten == null) {
return EmptyIterator.instance();
} else {
List<FieldReference> l = Arrays.asList(bcInfo.fieldsWritten);
return l.iterator();
}
}
/**
* @return Iterator of FieldReference
* @throws InvalidClassFileException
*/
public Iterator<FieldReference> getFieldsRead() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
if (bcInfo.fieldsRead == null) {
return EmptyIterator.instance();
} else {
List<FieldReference> l = Arrays.asList(bcInfo.fieldsRead);
return l.iterator();
}
}
/**
* @return Iterator of TypeReference
* @throws InvalidClassFileException
*/
public Iterator getArraysRead() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return (bcInfo.arraysRead == null) ? EmptyIterator.instance() : Arrays.asList(bcInfo.arraysRead).iterator();
}
/**
* @return Iterator of TypeReference
* @throws InvalidClassFileException
*/
public Iterator getArraysWritten() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return (bcInfo.arraysWritten == null) ? EmptyIterator.instance() : Arrays.asList(bcInfo.arraysWritten).iterator();
}
/**
* @return Iterator of TypeReference
* @throws InvalidClassFileException
*/
public Iterator getCastTypes() throws InvalidClassFileException {
if (isNative()) {
return EmptyIterator.instance();
}
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return (bcInfo.castTypes == null) ? EmptyIterator.instance() : Arrays.asList(bcInfo.castTypes).iterator();
}
protected abstract byte[] getBytecodes();
/**
* Method getBytecodeStream.
*
* @return the bytecode stream for this method, or null if no bytecodes.
*/
public BytecodeStream getBytecodeStream() {
byte[] bytecodes = getBytecodes();
if (bytecodes == null) {
return null;
} else {
return new BytecodeStream(this, bytecodes);
}
}
protected abstract String getMethodName() throws InvalidClassFileException;
protected abstract String getMethodSignature() throws InvalidClassFileException;
private MethodReference computeMethodReference() {
try {
Atom name = Atom.findOrCreateUnicodeAtom(getMethodName());
ImmutableByteArray desc = ImmutableByteArray.make(getMethodSignature());
Descriptor D = Descriptor.findOrCreate(desc);
return
MethodReference.findOrCreate(declaringClass.getReference(), name, D);
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
return null;
}
}
public MethodReference getReference() {
if (methodReference == null) {
methodReference = computeMethodReference();
}
return methodReference;
}
public boolean isClinit() {
return getReference().getSelector().equals(MethodReference.clinitSelector);
}
public boolean isInit() {
return getReference().getName().equals(MethodReference.initAtom);
}
protected abstract int getModifiers();
public boolean isNative() {
return ((getModifiers() & Constants.ACC_NATIVE) != 0);
}
public boolean isAbstract() {
return ((getModifiers() & Constants.ACC_ABSTRACT) != 0);
}
public boolean isPrivate() {
return ((getModifiers() & Constants.ACC_PRIVATE) != 0);
}
public boolean isProtected() {
return ((getModifiers() & Constants.ACC_PROTECTED) != 0);
}
public boolean isPublic() {
return ((getModifiers() & Constants.ACC_PUBLIC) != 0);
}
public boolean isFinal() {
return ((getModifiers() & Constants.ACC_FINAL) != 0);
}
public boolean isSynchronized() {
return ((getModifiers() & Constants.ACC_SYNCHRONIZED) != 0);
}
public boolean isStatic() {
return ((getModifiers() & Constants.ACC_STATIC) != 0);
}
public boolean isSynthetic() {
return false;
}
public IClass getDeclaringClass() {
return declaringClass;
}
/**
* Find the decoder object for this method, or create one if necessary.
*
* @return null if the method has no code.
*/
protected abstract Decoder makeDecoder();
/**
* Walk through the bytecodes and collect trivial information.
*
* @throws InvalidClassFileException
*/
protected abstract void processDebugInfo(BytecodeInfo bcInfo) throws InvalidClassFileException;
private void processBytecodesWithShrikeBT() throws InvalidClassFileException {
bcInfo.decoder = makeDecoder();
if (Assertions.verifyAssertions) {
if (!isAbstract() && bcInfo.decoder == null) {
Assertions.UNREACHABLE("bad method " + getReference());
}
}
if (bcInfo.decoder == null) {
return;
}
bcInfo.pcMap = bcInfo.decoder.getInstructionsToBytecodes();
processDebugInfo(bcInfo);
SimpleVisitor simpleVisitor = new SimpleVisitor();
Instruction[] instructions = bcInfo.decoder.getInstructions();
for (int i = 0; i < instructions.length; i++) {
simpleVisitor.setInstructionIndex(i);
instructions[i].visit(simpleVisitor);
if (Exceptions.isPEI(instructions[i])) {
Collection<TypeReference> t = Exceptions.getIndependentExceptionTypes(instructions[i]);
simpleVisitor.implicitExceptions.addAll(t);
}
}
// copy the Set results into arrays; will use less
// storage
copyVisitorSetsToArrays(simpleVisitor);
}
private void copyVisitorSetsToArrays(SimpleVisitor simpleVisitor) {
bcInfo.newSites = new NewSiteReference[simpleVisitor.newSites.size()];
int i = 0;
for (Iterator<NewSiteReference> it = simpleVisitor.newSites.iterator(); it.hasNext();) {
bcInfo.newSites[i++] = it.next();
}
bcInfo.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()];
i = 0;
for (Iterator<FieldReference> it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) {
bcInfo.fieldsRead[i++] = it.next();
}
bcInfo.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()];
i = 0;
for (Iterator<FieldReference> it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) {
bcInfo.fieldsRead[i++] = it.next();
}
bcInfo.fieldsWritten = new FieldReference[simpleVisitor.fieldsWritten.size()];
i = 0;
for (Iterator<FieldReference> it = simpleVisitor.fieldsWritten.iterator(); it.hasNext();) {
bcInfo.fieldsWritten[i++] = it.next();
}
bcInfo.callSites = new CallSiteReference[simpleVisitor.callSites.size()];
i = 0;
for (Iterator<CallSiteReference> it = simpleVisitor.callSites.iterator(); it.hasNext();) {
bcInfo.callSites[i++] = it.next();
}
bcInfo.arraysRead = new TypeReference[simpleVisitor.arraysRead.size()];
i = 0;
for (Iterator<TypeReference> it = simpleVisitor.arraysRead.iterator(); it.hasNext();) {
bcInfo.arraysRead[i++] = it.next();
}
bcInfo.arraysWritten = new TypeReference[simpleVisitor.arraysWritten.size()];
i = 0;
for (Iterator<TypeReference> it = simpleVisitor.arraysWritten.iterator(); it.hasNext();) {
bcInfo.arraysWritten[i++] = it.next();
}
bcInfo.implicitExceptions = new TypeReference[simpleVisitor.implicitExceptions.size()];
i = 0;
for (Iterator it = simpleVisitor.implicitExceptions.iterator(); it.hasNext();) {
bcInfo.implicitExceptions[i++] = (TypeReference) it.next();
}
bcInfo.castTypes = new TypeReference[simpleVisitor.castTypes.size()];
i = 0;
for (Iterator<TypeReference> it = simpleVisitor.castTypes.iterator(); it.hasNext();) {
bcInfo.castTypes[i++] = it.next();
}
bcInfo.hasMonitorOp = simpleVisitor.hasMonitorOp;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return getReference().toString();
}
/**
* @see java.lang.Object#equals(Object)
*/
public boolean equals(Object obj) {
// instanceof is OK because this class is final.
// if (this.getClass().equals(obj.getClass())) {
if (obj instanceof ShrikeBTMethod) {
ShrikeBTMethod that = (ShrikeBTMethod) obj;
return (getDeclaringClass().equals(that.getDeclaringClass()) && getReference().equals(that.getReference()));
} else {
return false;
}
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 9661 * getReference().hashCode();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#getMaxLocals()
*/
public abstract int getMaxLocals();
// TODO: ShrikeBT should have a getMaxStack method on Decoder, I think.
public abstract int getMaxStackHeight();
public Atom getName() {
return getReference().getName();
}
public Descriptor getDescriptor() {
return getReference().getDescriptor();
}
private class SimpleVisitor extends Instruction.Visitor {
// TODO: make a better Set implementation for these.
Set<CallSiteReference> callSites = HashSetFactory.make(5);
Set<FieldReference> fieldsWritten = HashSetFactory.make(5);
Set<FieldReference> fieldsRead = HashSetFactory.make(5);
Set<NewSiteReference> newSites = HashSetFactory.make(5);
Set<TypeReference> arraysRead = HashSetFactory.make(5);
Set<TypeReference> arraysWritten = HashSetFactory.make(5);
Set<TypeReference> implicitExceptions = HashSetFactory.make(5);
Set<TypeReference> castTypes = HashSetFactory.make(5);
boolean hasMonitorOp;
private int instructionIndex;
public void setInstructionIndex(int i) {
instructionIndex = i;
}
public int getProgramCounter() throws InvalidClassFileException {
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return bcInfo.pcMap[instructionIndex];
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitMonitor(com.ibm.wala.shrikeBT.MonitorInstruction)
*/
public void visitMonitor(MonitorInstruction instruction) {
hasMonitorOp = true;
}
public void visitNew(NewInstruction instruction) {
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
try {
newSites.add(NewSiteReference.make(getProgramCounter(), t));
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
public void visitGet(GetInstruction instruction) {
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
FieldReference f = ShrikeUtil.makeFieldReference(loader, instruction.getClassType(), instruction.getFieldName(), instruction
.getFieldType());
fieldsRead.add(f);
}
public void visitPut(PutInstruction instruction) {
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
FieldReference f = ShrikeUtil.makeFieldReference(loader, instruction.getClassType(), instruction.getFieldName(), instruction
.getFieldType());
fieldsWritten.add(f);
}
public void visitInvoke(InvokeInstruction instruction) {
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
MethodReference m = ShrikeUtil.makeMethodReference(loader, instruction.getClassType(), instruction.getMethodName(),
instruction.getMethodSignature());
int programCounter = 0;
try {
programCounter = getProgramCounter();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
CallSiteReference site = null;
int nParams = m.getNumberOfParameters();
switch (instruction.getInvocationMode()) {
case Constants.OP_invokestatic:
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.STATIC);
break;
case Constants.OP_invokeinterface:
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.INTERFACE);
nParams++;
break;
case Constants.OP_invokespecial:
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.SPECIAL);
nParams++;
break;
case Constants.OP_invokevirtual:
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.VIRTUAL);
nParams++;
break;
default:
Assertions.UNREACHABLE();
}
callSites.add(site);
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(com.ibm.wala.shrikeBT.ArrayLoadInstruction)
*/
public void visitArrayLoad(ArrayLoadInstruction instruction) {
arraysRead.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(com.ibm.wala.shrikeBT.ArrayStoreInstruction)
*/
public void visitArrayStore(ArrayStoreInstruction instruction) {
arraysWritten.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
}
public void visitCheckCast(CheckCastInstruction instruction) {
castTypes.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
}
}
/**
* Method getInstructions.
*
* @return Instruction[]
* @throws InvalidClassFileException
*/
public Instruction[] getInstructions() throws InvalidClassFileException {
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
if (bcInfo.decoder == null) {
return null;
} else {
return bcInfo.decoder.getInstructions();
}
}
/**
* Method getHandlers.
*
* @return ExceptionHandler[][]
* @throws InvalidClassFileException
*/
public ExceptionHandler[][] getHandlers() throws InvalidClassFileException {
if (bcInfo == null) {
processBytecodes();
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
if (bcInfo.decoder == null) {
return null;
} else {
return bcInfo.decoder.getHandlers();
}
}
/**
* Method getParameterType. By convention, for a non-static method,
* getParameterType(0) is the this pointer
*
* @param i
* @return TypeReference
*/
public TypeReference getParameterType(int i) {
if (!isStatic()) {
if (i == 0)
return declaringClass.getReference();
else
return getReference().getParameterType(i - 1);
} else {
return getReference().getParameterType(i);
}
}
/**
* Method getNumberOfParameters. This result includes the "this" pointer if
* applicable
*
* @return int
*/
public int getNumberOfParameters() {
if (isStatic() || isClinit()) {
return getReference().getNumberOfParameters();
} else {
return getReference().getNumberOfParameters() + 1;
}
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#hasExceptionHandler()
*/
public abstract boolean hasExceptionHandler();
/**
* Clients should not modify the returned array. TODO: clone to avoid the
* problem?
*
* @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions()
*/
public TypeReference[] getDeclaredExceptions() {
if (bcInfo == null) {
try {
processBytecodes();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return (bcInfo.exceptionTypes == null) ? new TypeReference[0] : bcInfo.exceptionTypes;
}
protected abstract String[] getDeclaredExceptionTypeNames() throws InvalidClassFileException;
/**
*
* @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions()
*/
private TypeReference[] computeDeclaredExceptions() {
try {
String[] strings = getDeclaredExceptionTypeNames();
if (strings == null) return null;
ClassLoaderReference loader = getDeclaringClass().getClassLoader().getReference();
TypeReference[] result = new TypeReference[strings.length];
for (int i = 0; i < result.length; i++) {
result[i] = TypeReference.findOrCreate(loader, TypeName.findOrCreate(ImmutableByteArray.make("L" + strings[i])));
}
return result;
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
return null;
}
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#getLineNumber(int)
*/
public int getLineNumber(int bcIndex) {
if (bcInfo == null) {
try {
processBytecodes();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
if (Assertions.verifyAssertions) {
Assertions._assert(bcInfo != null);
}
return (bcInfo.lineNumberMap == null) ? -1 : bcInfo.lineNumberMap[bcIndex];
}
/**
* @return Set <TypeReference>
* @throws InvalidClassFileException
*/
public Set<TypeReference> getCaughtExceptionTypes() throws InvalidClassFileException {
ExceptionHandler[][] handlers = getHandlers();
if (handlers == null) {
return Collections.emptySet();
}
HashSet<TypeReference> result = HashSetFactory.make(10);
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
for (int i = 0; i < handlers.length; i++) {
for (int j = 0; j < handlers[i].length; j++) {
TypeReference t = ShrikeUtil.makeTypeReference(loader, handlers[i][j].getCatchClass());
if (t == null) {
t = TypeReference.JavaLangThrowable;
}
result.add(t);
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#getSignature()
*/
public String getSignature() {
return getReference().getSignature();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#getSelector()
*/
public Selector getSelector() {
return getReference().getSelector();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int)
*/
public abstract String getLocalVariableName(int bcIndex, int localNumber);
/*
* TODO: cache for efficiency? (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable()
*/
public abstract boolean hasLocalVariableTable();
/**
* Clear all optional cached data associated with this class
*/
public void clearCaches() {
bcInfo = null;
}
}

View File

@ -0,0 +1,249 @@
/*******************************************************************************
* 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.ipa.cha.ClassHierarchy;
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 ShrikeCTMethod extends ShrikeBTMethod {
/**
* 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;
private final ClassHierarchy cha;
public ShrikeCTMethod(IClass klass, int index) {
super(klass);
this.shrikeMethodIndex = index;
this.cha = klass.getClassHierarchy();
}
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 ((ShrikeClass)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();
}
public ClassHierarchy getClassHierarchy() {
return cha;
}
}

View File

@ -0,0 +1,840 @@
/*******************************************************************************
* 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.ClassHierarchyWarning;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeCT.ClassConstants;
import com.ibm.wala.shrikeCT.ClassReader;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.Atom;
import com.ibm.wala.util.ImmutableByteArray;
import com.ibm.wala.util.ShrikeClassReaderHandle;
import com.ibm.wala.util.collections.BimodalMap;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.SmallMap;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.Trace;
import com.ibm.wala.util.warnings.Warning;
import com.ibm.wala.util.warnings.WarningSet;
/**
* A class read from Shrike
*
* @author sfink
*/
public final class ShrikeClass implements IClass {
static final boolean DEBUG = false;
/**
* The Shrike object that knows how to read the class file
*/
private final ShrikeClassReaderHandle reader;
/**
* The object that loaded this class.
*/
private final IClassLoader loader;
/**
* Governing class hierarchy for this class
*/
private final ClassHierarchy cha;
/**
* A mapping from Selector to IMethod
*
* TODO: get rid of this for classes (though keep it for interfaces) instead
* ... use a VMT.
*/
private Map<Selector, IMethod> methodMap;
/**
* A mapping from Selector to IMethod used to cache method lookups from
* superclasses
*/
private Map<Selector, IMethod> inheritCache;
/**
* Canonical type representation
*/
private TypeReference typeReference;
/**
* An object to track warnings
*/
private final WarningSet warnings;
/**
* superclass
*/
private IClass superClass;
/**
* Compute the superclass lazily.
*/
private boolean superclassComputed = false;
/**
* An Atom which holds the name of the super class. We cache this for
* efficiency reasons.
*/
private ImmutableByteArray superName;
/**
* The names of interfaces for this class. We cache this for efficiency
* reasons.
*/
private ImmutableByteArray[] interfaceNames;
/**
* The IClasses that represent all interfaces this class implements (if it's a
* class) or extends (it it's an interface)
*/
private Collection<IClass> allInterfaces = null;
/**
* The instance fields declared in this class.
*/
private IField[] instanceFields;
/**
* The static fields declared in this class.
*/
private IField[] staticFields;
/**
* JVM-level modifiers; cached here for efficiency
*/
private int modifiers;
/**
* hash code; cached here for efficiency
*/
private final int hashCode;
/**
* @param reader
* @param loader
* @param cha
* @param warnings
* @throws InvalidClassFileException
*/
public ShrikeClass(ShrikeClassReaderHandle reader, IClassLoader loader, ClassHierarchy cha, WarningSet warnings)
throws InvalidClassFileException {
if (reader == null)
throw new NullPointerException();
this.reader = reader;
this.loader = loader;
this.cha = cha;
this.warnings = warnings;
computeTypeReference();
this.hashCode = 2161 * getReference().hashCode();
// as long as the reader is around, pull more data out
// of it before the soft reference to it disappears
computeSuperName();
computeModifiers();
computeInterfaceNames();
computeFields();
}
/**
* Compute the fields declared by this class
*
* @throws InvalidClassFileException
* iff Shrike fails to read the class file correctly
*/
private void computeFields() throws InvalidClassFileException {
ClassReader cr = reader.get();
int fieldCount = cr.getFieldCount();
List<FieldImpl> instanceList = new ArrayList<FieldImpl>(fieldCount);
List<FieldImpl> staticList = new ArrayList<FieldImpl>(fieldCount);
try {
for (int i = 0; i < fieldCount; i++) {
int accessFlags = cr.getFieldAccessFlags(i);
Atom name = Atom.findOrCreateUnicodeAtom(cr.getFieldName(i));
ImmutableByteArray b = ImmutableByteArray.make(cr.getFieldType(i));
if ((accessFlags & ClassConstants.ACC_STATIC) == 0) {
addFieldToList(instanceList, name, b, accessFlags);
} else {
addFieldToList(staticList, name, b, accessFlags);
}
}
instanceFields = new IField[instanceList.size()];
populateFieldArrayFromList(instanceList, instanceFields);
staticFields = new IField[staticList.size()];
populateFieldArrayFromList(staticList, staticFields);
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
private void populateFieldArrayFromList(List<FieldImpl> L, IField[] A) {
Iterator<FieldImpl> it = L.iterator();
for (int i = 0; i < A.length; i++) {
A[i] = it.next();
}
}
private void addFieldToList(List<FieldImpl> L, Atom name, ImmutableByteArray fieldType, int accessFlags) {
TypeName T = null;
if (fieldType.get(fieldType.length() - 1) == ';') {
T = TypeName.findOrCreate(fieldType, 0, fieldType.length() - 1);
} else {
T = TypeName.findOrCreate(fieldType);
}
TypeReference type = TypeReference.findOrCreate(getClassLoader().getReference(), T);
FieldReference fr = FieldReference.findOrCreate(getReference(), name, type);
FieldImpl f = new FieldImpl(this, fr, accessFlags);
L.add(f);
}
public IClassLoader getClassLoader() {
return loader;
}
public boolean isInterface() {
boolean result = ((modifiers & Constants.ACC_INTERFACE) != 0);
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#isAbstract()
*/
public boolean isAbstract() {
boolean result = ((modifiers & Constants.ACC_ABSTRACT) != 0);
return result;
}
/**
* @throws InvalidClassFileException
*/
private void computeModifiers() throws InvalidClassFileException {
modifiers = reader.get().getAccessFlags();
}
public int getModifiers() {
return modifiers;
}
/**
* Note that this is called from the constructor, at which point this class is
* not yet ready to actually load the superclass. Instead, we pull out the
* name of the superclass and cache it here, to avoid hitting the reader
* later.
*/
private void computeSuperName() {
try {
String s = reader.get().getSuperName();
if (s != null) {
superName = ImmutableByteArray.make("L" + s);
}
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
}
}
private void computeSuperclass() {
superclassComputed = true;
if (superName == null) {
if (!getReference().equals(TypeReference.JavaLangObject)) {
superClass = loader.lookupClass(TypeReference.JavaLangObject.getName(), getClassHierarchy());
}
return;
}
superClass = loader.lookupClass(TypeName.findOrCreate(superName), getClassHierarchy());
if (DEBUG) {
Trace.println("got superclass " + superClass + " for " + this);
}
}
public IClass getSuperclass() throws ClassHierarchyException {
if (!superclassComputed) {
computeSuperclass();
}
if (superClass == null && !getReference().equals(TypeReference.JavaLangObject)) {
try {
throw new ClassHierarchyException("No superclass " + reader.get().getSuperName() + " found for " + this);
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
}
}
return superClass;
}
/**
* Note that this is called from the constructor, at which point this class is
* not yet ready to actually load the interfaces. Instead, we pull out the
* name of the interfaces and cache it here, to avoid hitting the reader
* later.
*/
private void computeInterfaceNames() {
try {
String[] s = reader.get().getInterfaceNames();
interfaceNames = new ImmutableByteArray[s.length];
for (int i = 0; i < interfaceNames.length; i++) {
interfaceNames[i] = ImmutableByteArray.make("L" + s[i]);
}
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
}
}
/**
* Method getAllInterfacesAsCollection.
*
* @return Collection of IClasses, representing the interfaces this class
* implements.
*/
private Collection<IClass> computeAllInterfacesAsCollection() throws ClassHierarchyException {
Collection<IClass> c = getDirectInterfaces();
Set<IClass> result = HashSetFactory.make();
for (Iterator<IClass> it = c.iterator(); it.hasNext();) {
IClass klass = it.next();
if (klass.isInterface()) {
result.add(klass);
} else {
warnings.add(ClassHierarchyWarning.create("expected an interface " + klass));
}
}
for (Iterator<IClass> it = c.iterator(); it.hasNext();) {
ShrikeClass I = (ShrikeClass) it.next();
if (I.isInterface()) {
result.addAll(I.computeAllInterfacesAsCollection());
} else {
warnings.add(ClassHierarchyWarning.create("expected an interface " + I));
}
}
// now add any interfaces from the super class
ShrikeClass sup = null;
try {
sup = (ShrikeClass) getSuperclass();
} catch (ClassHierarchyException e1) {
Assertions.UNREACHABLE();
}
if (sup != null) {
result.addAll(sup.computeAllInterfacesAsCollection());
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getDirectInterfaces()
*/
public Collection<IClass> getDirectInterfaces() {
return array2IClassSet(interfaceNames);
}
/**
* Method array2Set.
*
* @param interfaces
* a set of class names
* @return Set of all IClasses that can be loaded corresponding to the class
* names in the interfaces array; raise warnings if classes can not be
* loaded
*/
private Collection<IClass> array2IClassSet(ImmutableByteArray[] interfaces) {
ArrayList<IClass> result = new ArrayList<IClass>(interfaces.length);
for (int i = 0; i < interfaces.length; i++) {
ImmutableByteArray name = interfaces[i];
IClass klass = null;
klass = loader.lookupClass(TypeName.findOrCreate(name), getClassHierarchy());
if (klass == null) {
warnings.add(ClassNotFoundWarning.create(name));
} else {
result.add(klass);
}
}
return result;
}
/**
* @author sfink
*
* A warning for when we get a class not found exception
*/
private static class ClassNotFoundWarning extends Warning {
final ImmutableByteArray className;
ClassNotFoundWarning(ImmutableByteArray className) {
super(Warning.SEVERE);
this.className = className;
}
public String getMsg() {
return getClass().toString() + " : " + className;
}
public static ClassNotFoundWarning create(ImmutableByteArray className) {
return new ClassNotFoundWarning(className);
}
}
/**
* set up the methodMap mapping
*/
private void computeMethodMap() throws InvalidClassFileException {
if (methodMap == null) {
ShrikeCTMethod[] methods = computeDeclaredMethods();
if (methods.length > 5) {
methodMap = HashMapFactory.make(methods.length);
} else {
methodMap = new SmallMap<Selector, IMethod>();
}
for (int i = 0; i < methods.length; i++) {
ShrikeCTMethod m = methods[i];
methodMap.put(m.getReference().getSelector(), m);
}
}
}
/**
* initialize the declared methods array
*
* @throws InvalidClassFileException
*/
private ShrikeCTMethod[] computeDeclaredMethods() throws InvalidClassFileException {
int methodCount = reader.get().getMethodCount();
ShrikeCTMethod[] result = new ShrikeCTMethod[methodCount];
for (int i = 0; i < methodCount; i++) {
ShrikeCTMethod m = new ShrikeCTMethod(this, i);
if (DEBUG) {
Trace.println("Register method " + m + " for class " + this);
}
result[i] = m;
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.types.Selector)
*/
public IMethod getMethod(Selector selector) {
if (DEBUG) {
Trace.println("getMethod " + selector + " in " + this);
}
if (methodMap == null) {
try {
computeMethodMap();
} catch (InvalidClassFileException e1) {
e1.printStackTrace();
Assertions.UNREACHABLE();
}
}
// my methods + cached parent stuff
IMethod result = (IMethod) methodMap.get(selector);
if (result != null) {
return result;
}
if (inheritCache != null) {
result = inheritCache.get(selector);
if (result != null) {
return result;
}
}
// check parent, caching if found
try {
if (!selector.equals(MethodReference.clinitSelector) && !selector.equals(MethodReference.initSelector)) {
ShrikeClass superclass = (ShrikeClass) getSuperclass();
if (superclass != null) {
IMethod inherit = superclass.getMethod(selector);
if (inherit != null) {
if (inheritCache == null) {
inheritCache = new BimodalMap<Selector, IMethod>(5);
}
inheritCache.put(selector, inherit);
return inherit;
}
}
}
} catch (ClassHierarchyException e) {
Assertions.UNREACHABLE();
}
// didn't find it yet. special logic for interfaces
try {
if (isInterface()) {
// try each superinterface
for (Iterator it = getAllAncestorInterfaces().iterator(); it.hasNext();) {
IClass k = (IClass) it.next();
result = k.getMethod(selector);
if (result != null) {
return result;
}
}
}
} catch (ClassHierarchyException e) {
e.printStackTrace();
Assertions.UNREACHABLE("Bad method lookup in " + this);
}
return null;
}
private final HashMap<Atom, IField> fieldMap = new HashMap<Atom, IField>(5);
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getField(com.ibm.wala.util.Atom)
*/
public IField getField(Atom name) {
if (fieldMap.containsKey(name)) {
return fieldMap.get(name);
} else {
IField f = findDeclaredField(name);
if (f != null) {
fieldMap.put(name, f);
return f;
} else if (superClass != null) {
f = superClass.getField(name);
if (f != null) {
fieldMap.put(name, f);
return f;
}
}
}
return null;
}
private IField findDeclaredField(Atom name) {
for (int i = 0; i < instanceFields.length; i++) {
if (instanceFields[i].getName() == name) {
return instanceFields[i];
}
}
for (int i = 0; i < staticFields.length; i++) {
if (staticFields[i].getName() == name) {
return staticFields[i];
}
}
return null;
}
/**
* initialize the TypeReference field for this instance
*
* @throws InvalidClassFileException
* iff Shrike can't read this class
*/
private void computeTypeReference() throws InvalidClassFileException {
String className = "L" + reader.get().getName();
ImmutableByteArray name = ImmutableByteArray.make(className);
typeReference = TypeReference.findOrCreate(getClassLoader().getReference(), TypeName.findOrCreate(name));
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getReference()
*/
public TypeReference getReference() {
return typeReference;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getSourceFileName()
*/
public String getSourceFileName() {
return loader.getSourceFileName(this);
}
public Collection<IClass> getAllImplementedInterfaces() throws ClassHierarchyException {
if (Assertions.verifyAssertions) {
if (isInterface()) {
Assertions.UNREACHABLE("shouldn't ask for implemented interfaces of " + this);
}
}
if (allInterfaces != null) {
return allInterfaces;
} else {
Collection<IClass> C = computeAllInterfacesAsCollection();
allInterfaces = Collections.unmodifiableCollection(C);
return allInterfaces;
}
}
public Collection<IClass> getAllAncestorInterfaces() throws ClassHierarchyException {
if (Assertions.verifyAssertions) {
if (!isInterface()) {
Assertions.UNREACHABLE();
}
}
if (allInterfaces != null) {
return allInterfaces;
} else {
Collection<IClass> C = computeAllInterfacesAsCollection();
allInterfaces = Collections.unmodifiableCollection(C);
return allInterfaces;
}
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return getReference().toString();
}
/**
* @see java.lang.Object#equals(Object)
*/
public boolean equals(Object obj) {
// it's ok to use instanceof since this class is final
// if (this.getClass().equals(obj.getClass())) {
if (obj instanceof ShrikeClass) {
return getReference().equals(((ShrikeClass) obj).getReference());
} else {
return false;
}
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return hashCode;
}
/**
* Method getReader.
*/
public ClassReader getReader() {
try {
return reader.get();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
return null;
}
}
/**
* @see com.ibm.wala.classLoader.IClass#getClassInitializer()
*/
public IMethod getClassInitializer() {
if (methodMap == null) {
try {
computeMethodMap();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
return (IMethod) methodMap.get(MethodReference.clinitSelector);
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getDeclaredMethods()
*/
public Collection<IMethod> getDeclaredMethods() {
if (methodMap == null) {
try {
computeMethodMap();
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
}
return Collections.unmodifiableCollection(methodMap.values());
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#isArrayClass()
*/
public boolean isArrayClass() {
return false;
}
public ClassHierarchy getClassHierarchy() {
return cha;
}
public WarningSet getWarnings() {
return warnings;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getDeclaredFields()
*/
public Collection<IField> getDeclaredInstanceFields() {
return Collections.unmodifiableList(Arrays.asList(instanceFields));
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getDeclaredFields()
*/
public Collection<IField> getDeclaredStaticFields() {
return Collections.unmodifiableList(Arrays.asList(staticFields));
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getName()
*/
public TypeName getName() {
return getReference().getName();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#isReferenceType()
*/
public boolean isReferenceType() {
return getReference().isReferenceType();
}
/**
* Clear all optional cached data associated with this class
*/
public void clearSoftCaches() {
// toss optional information from each method.
if (methodMap != null) {
for (Iterator it = getDeclaredMethods().iterator(); it.hasNext();) {
ShrikeCTMethod m = (ShrikeCTMethod) it.next();
m.clearCaches();
}
}
// clear the methodMap cache
// SJF: don't do this!!! makes it hard to clear caches on methods.
// methodMap = null;
inheritCache = null;
// clear the cached interfaces
allInterfaces = null;
// toss away the Shrike reader
reader.clear();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getAllInstanceFields()
*/
public Collection<IField> getAllInstanceFields() throws ClassHierarchyException {
Collection<IField> result = new LinkedList<IField>(getDeclaredInstanceFields());
IClass s = getSuperclass();
while (s != null) {
result.addAll(s.getDeclaredInstanceFields());
s = s.getSuperclass();
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getAllStaticFields()
*/
public Collection<IField> getAllStaticFields() throws ClassHierarchyException {
Collection<IField> result = new LinkedList<IField>(getDeclaredStaticFields());
IClass s = getSuperclass();
while (s != null) {
result.addAll(s.getDeclaredStaticFields());
s = s.getSuperclass();
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getAllMethods()
*/
public Collection<IMethod> getAllMethods() throws ClassHierarchyException {
Collection<IMethod> result = new LinkedList<IMethod>();
Iterator<IMethod> declaredMethods = getDeclaredMethods().iterator();
while (declaredMethods.hasNext()) {
result.add(declaredMethods.next());
}
IClass s = getSuperclass();
while (s != null) {
Iterator<IMethod> superDeclaredMethods = s.getDeclaredMethods().iterator();
while (superDeclaredMethods.hasNext()) {
result.add(superDeclaredMethods.next());
}
s = s.getSuperclass();
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.classLoader.IClass#getAllFields()
*/
public Collection<IField> getAllFields() throws ClassHierarchyException {
Collection<IField> result = new LinkedList<IField>();
result.addAll(getAllInstanceFields());
result.addAll(getAllStaticFields());
return result;
}
public boolean isPublic() {
boolean result = ((modifiers & Constants.ACC_PUBLIC) != 0);
return result;
}
}