WALA/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/XMLMethodSummaryReader.java

972 lines
33 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.ipa.summaries;
import static com.ibm.wala.types.TypeName.ArrayMask;
import static com.ibm.wala.types.TypeName.ElementBits;
import static com.ibm.wala.types.TypeName.PrimitiveMask;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.shrikeBT.BytecodeConstants;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
import com.ibm.wala.ssa.SSAGetInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.ssa.SSAReturnInstruction;
import com.ibm.wala.ssa.SSAThrowInstruction;
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.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.warnings.Warning;
/**
* This class reads method summaries from an XML Stream.
*/
public class XMLMethodSummaryReader implements BytecodeConstants {
static final boolean DEBUG = false;
/**
* Governing analysis scope
*/
final private AnalysisScope scope;
/**
* Method summaries collected for methods
*/
final private HashMap<MethodReference, MethodSummary> summaries = HashMapFactory.make();
/**
* Set of TypeReferences that are marked as "allocatable"
*/
final private HashSet<TypeReference> allocatable = HashSetFactory.make();
/**
* Set of Atoms that represent packages that can be ignored
*/
final private HashSet<Atom> ignoredPackages = HashSetFactory.make();
//
// Define XML element names
//
private final static int E_CLASSLOADER = 0;
private final static int E_METHOD = 1;
private final static int E_CLASS = 2;
private final static int E_PACKAGE = 3;
private final static int E_CALL = 4;
private final static int E_NEW = 5;
private final static int E_POISON = 6;
private final static int E_SUMMARY_SPEC = 7;
private final static int E_RETURN = 8;
private final static int E_PUTSTATIC = 9;
private final static int E_AASTORE = 10;
private final static int E_PUTFIELD = 11;
private final static int E_GETFIELD = 12;
private final static int E_ATHROW = 13;
private final static int E_CONSTANT = 14;
private final static int E_AALOAD = 15;
private final static Map<String, Integer> elementMap = HashMapFactory.make(14);
static {
elementMap.put("classloader", Integer.valueOf(E_CLASSLOADER));
elementMap.put("method", Integer.valueOf(E_METHOD));
elementMap.put("class", Integer.valueOf(E_CLASS));
elementMap.put("package", Integer.valueOf(E_PACKAGE));
elementMap.put("call", Integer.valueOf(E_CALL));
elementMap.put("new", Integer.valueOf(E_NEW));
elementMap.put("poison", Integer.valueOf(E_POISON));
elementMap.put("summary-spec", Integer.valueOf(E_SUMMARY_SPEC));
elementMap.put("return", Integer.valueOf(E_RETURN));
elementMap.put("putstatic", Integer.valueOf(E_PUTSTATIC));
elementMap.put("aastore", Integer.valueOf(E_AASTORE));
elementMap.put("putfield", Integer.valueOf(E_PUTFIELD));
elementMap.put("getfield", Integer.valueOf(E_GETFIELD));
elementMap.put("throw", Integer.valueOf(E_ATHROW));
elementMap.put("constant", Integer.valueOf(E_CONSTANT));
elementMap.put("aaload", Integer.valueOf(E_AALOAD));
}
//
// Define XML attribute names
//
private final static String A_NAME = "name";
private final static String A_TYPE = "type";
private final static String A_CLASS = "class";
private final static String A_SIZE = "size";
private final static String A_DESCRIPTOR = "descriptor";
private final static String A_REASON = "reason";
private final static String A_LEVEL = "level";
private final static String A_WILDCARD = "*";
private final static String A_DEF = "def";
private final static String A_STATIC = "static";
private final static String A_VALUE = "value";
private final static String A_FIELD = "field";
private final static String A_FIELD_TYPE = "fieldType";
private final static String A_ARG = "arg";
private final static String A_ALLOCATABLE = "allocatable";
private final static String A_REF = "ref";
private final static String A_INDEX = "index";
private final static String A_IGNORE = "ignore";
private final static String A_FACTORY = "factory";
private final static String A_NUM_ARGS = "numArgs";
private final static String A_PARAM_NAMES = "paramNames";
private final static String V_NULL = "null";
private final static String V_TRUE = "true";
public XMLMethodSummaryReader(InputStream xmlFile, AnalysisScope scope) {
super();
if (xmlFile == null) {
throw new IllegalArgumentException("null xmlFile");
}
if (scope == null) {
throw new IllegalArgumentException("null scope");
}
this.scope = scope;
try {
readXML(xmlFile);
} catch (Exception e) {
throw new Error("bad xml file", e);
}
}
private void readXML(InputStream xml) throws SAXException, IOException, ParserConfigurationException {
SAXHandler handler = new SAXHandler();
assert xml != null : "Null xml stream";
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(new InputSource(xml), handler);
}
/**
* @return Method summaries collected for methods. Mapping Object -&gt; MethodSummary where Object is either a
* <ul>
* <li>MethodReference
* <li>TypeReference
* <li>Atom (package name)
* </ul>
*/
public Map<MethodReference, MethodSummary> getSummaries() {
return summaries;
}
/**
* @return Set of TypeReferences marked "allocatable"
*/
public Set<TypeReference> getAllocatableClasses() {
return allocatable;
}
/**
* @return Set of Atoms representing ignorable packages
*/
public Set<Atom> getIgnoredPackages() {
return ignoredPackages;
}
/**
* @author sfink
*
* SAX parser logic for XML method summaries
*/
private class SAXHandler extends DefaultHandler {
/**
* The class loader reference for the element being processed
*/
private ClassLoaderReference governingLoader = null;
/**
* The method summary for the element being processed
*/
private MethodSummary governingMethod = null;
/**
* The declaring class for the element begin processed
*/
private TypeReference governingClass = null;
/**
* The package for the element being processed
*/
private Atom governingPackage = null;
/**
* The next available local number for the method being processed
*/
private int nextLocal = -1;
/**
* A mapping from String (variable name) -&gt; Integer (local number)
*/
private Map<String, Integer> symbolTable = null;
/*
* @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
@Override
public void startElement(String uri, String name, String qName, Attributes atts) {
Integer element = elementMap.get(qName);
if (element == null) {
Assertions.UNREACHABLE("Invalid element: " + qName);
}
switch (element.intValue()) {
case E_CLASSLOADER: {
String clName = atts.getValue(A_NAME);
governingLoader = classLoaderName2Ref(clName);
}
break;
case E_METHOD:
String mname = atts.getValue(A_NAME);
if (mname.equals(A_WILDCARD)) {
Assertions.UNREACHABLE("Wildcards not currently implemented.");
} else {
startMethod(atts);
}
break;
case E_CLASS:
String cname = atts.getValue(A_NAME);
if (cname.equals(A_WILDCARD)) {
Assertions.UNREACHABLE("Wildcards not currently implemented");
} else {
startClass(cname, atts);
}
break;
case E_PACKAGE:
governingPackage = Atom.findOrCreateUnicodeAtom(atts.getValue(A_NAME));
String ignore = atts.getValue(A_IGNORE);
if (ignore != null && ignore.equals(V_TRUE)) {
ignoredPackages.add(governingPackage);
}
break;
case E_CALL:
processCallSite(atts);
break;
case E_NEW:
processAllocation(atts);
break;
case E_PUTSTATIC:
processPutStatic(atts);
break;
case E_PUTFIELD:
processPutField(atts);
break;
case E_GETFIELD:
processGetField(atts);
break;
case E_ATHROW:
processAthrow(atts);
break;
case E_AASTORE:
processAastore(atts);
break;
case E_AALOAD:
processAaload(atts);
break;
case E_RETURN:
processReturn(atts);
break;
case E_POISON:
processPoison(atts);
break;
case E_CONSTANT:
processConstant(atts);
break;
case E_SUMMARY_SPEC:
break;
default:
Assertions.UNREACHABLE("Unexpected element: " + name);
break;
}
}
private void startClass(String cname, Attributes atts) {
String clName = governingPackage==null? "L" + cname: "L" + governingPackage + "/" + cname;
governingClass = className2Ref(clName);
String allocString = atts.getValue(A_ALLOCATABLE);
if (allocString != null) {
Assertions.productionAssertion(allocString.equals("true"));
allocatable.add(governingClass);
}
}
/*
* @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void endElement(String uri, String name, String qName) {
Integer element = elementMap.get(qName);
if (element == null) {
Assertions.UNREACHABLE("Invalid element: " + name);
}
switch (element.intValue()) {
case E_CLASSLOADER:
governingLoader = null;
break;
case E_METHOD:
if (governingMethod != null) {
checkReturnValue(governingMethod);
}
governingMethod = null;
symbolTable = null;
break;
case E_CLASS:
governingClass = null;
break;
case E_PACKAGE:
governingPackage = null;
break;
case E_CALL:
case E_GETFIELD:
case E_NEW:
case E_POISON:
case E_PUTSTATIC:
case E_PUTFIELD:
case E_AALOAD:
case E_AASTORE:
case E_ATHROW:
case E_SUMMARY_SPEC:
case E_RETURN:
case E_CONSTANT:
break;
default:
Assertions.UNREACHABLE("Unexpected element: " + name);
break;
}
}
/**
* If a method is declared to return a value, be sure the method summary includes a return statement. Throw an assertion if not.
*
* @param governingMethod
*/
private void checkReturnValue(MethodSummary governingMethod) {
Assertions.productionAssertion(governingMethod != null);
Assertions.productionAssertion(governingMethod.getReturnType() != null);
if (governingMethod.getReturnType().isReferenceType()) {
SSAInstruction[] statements = governingMethod.getStatements();
for (SSAInstruction statement : statements) {
if (statement instanceof SSAReturnInstruction) {
return;
}
}
Assertions.UNREACHABLE("Method summary " + governingMethod + " must have a return statement.");
}
}
/**
* Process an element indicating a call instruction
*
* @param atts
*/
private void processCallSite(Attributes atts) {
String typeString = atts.getValue(A_TYPE);
String nameString = atts.getValue(A_NAME);
String classString = atts.getValue(A_CLASS);
String descString = atts.getValue(A_DESCRIPTOR);
TypeReference type = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(classString));
Atom nm = Atom.findOrCreateAsciiAtom(nameString);
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
Descriptor D = Descriptor.findOrCreateUTF8(lang, descString);
MethodReference ref = MethodReference.findOrCreate(type, nm, D);
CallSiteReference site = null;
int nParams = ref.getNumberOfParameters();
if (typeString.equals("virtual")) {
site = CallSiteReference.make(governingMethod.getNextProgramCounter(), ref, IInvokeInstruction.Dispatch.VIRTUAL);
nParams++;
} else if (typeString.equals("special")) {
site = CallSiteReference.make(governingMethod.getNextProgramCounter(), ref, IInvokeInstruction.Dispatch.SPECIAL);
nParams++;
} else if (typeString.equals("interface")) {
site = CallSiteReference.make(governingMethod.getNextProgramCounter(), ref, IInvokeInstruction.Dispatch.INTERFACE);
nParams++;
} else if (typeString.equals("static")) {
site = CallSiteReference.make(governingMethod.getNextProgramCounter(), ref, IInvokeInstruction.Dispatch.STATIC);
} else {
Assertions.UNREACHABLE("Invalid call type " + typeString);
}
String paramCount = atts.getValue(A_NUM_ARGS);
if (paramCount != null) {
nParams = Integer.parseInt(paramCount);
}
int[] params = new int[nParams];
for (int i = 0; i < params.length; i++) {
String argString = atts.getValue(A_ARG + i);
Assertions.productionAssertion(argString != null, "unspecified arg in method " + governingMethod + " " + site);
Integer valueNumber = symbolTable.get(argString);
if (valueNumber == null) {
valueNumber = Integer.parseInt(argString);
}
params[i] = valueNumber.intValue();
}
// allocate local for exceptions
int exceptionValue = nextLocal++;
// register the local variable defined by this call, if appropriate
String defVar = atts.getValue(A_DEF);
if (defVar != null) {
if (symbolTable.keySet().contains(defVar)) {
Assertions.UNREACHABLE("Cannot def variable twice: " + defVar + " in " + governingMethod);
}
int defNum = nextLocal;
symbolTable.put(defVar, Integer.valueOf(nextLocal++));
governingMethod.addStatement(insts.InvokeInstruction(governingMethod.getNumberOfStatements(), defNum, params, exceptionValue, site, null));
} else {
// ignore return value, if any
governingMethod.addStatement(insts.InvokeInstruction(governingMethod.getNumberOfStatements(), params, exceptionValue, site, null));
}
}
/**
* Process an element indicating a new allocation site.
*
* @param atts
*/
private void processAllocation(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
// deduce the concrete type allocated
String classString = atts.getValue(A_CLASS);
final TypeReference type = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(classString));
// register the local variable defined by this allocation
String defVar = atts.getValue(A_DEF);
if (symbolTable.keySet().contains(defVar)) {
Assertions.UNREACHABLE("Cannot def variable twice: " + defVar + " in " + governingMethod);
}
if (defVar == null) {
// the method summary ignores the def'ed variable.
// just allocate a temporary
defVar = "L" + nextLocal;
}
int defNum = nextLocal;
symbolTable.put(defVar, Integer.valueOf(nextLocal++));
// create the allocation statement and add it to the method summary
NewSiteReference ref = NewSiteReference.make(governingMethod.getNextProgramCounter(), type);
SSANewInstruction a = null;
if (type.isArrayType()) {
String size = atts.getValue(A_SIZE);
Assertions.productionAssertion(size != null);
Integer sNumber = symbolTable.get(size);
Assertions.productionAssertion(sNumber != null);
Assertions.productionAssertion(
// array of objects
type.getDerivedMask()==ArrayMask ||
// array of primitives
type.getDerivedMask()==((ArrayMask<<ElementBits)|PrimitiveMask));
a = insts.NewInstruction(governingMethod.getNumberOfStatements(), defNum, ref, new int[] { sNumber.intValue() });
} else {
a = insts.NewInstruction(governingMethod.getNumberOfStatements(), defNum, ref);
}
governingMethod.addStatement(a);
}
/**
* Process an element indicating an Athrow
*
* @param atts
*/
private void processAthrow(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
// get the value thrown
String V = atts.getValue(A_VALUE);
if (V == null) {
Assertions.UNREACHABLE("Must specify value for putfield " + governingMethod);
}
Integer valueNumber = symbolTable.get(V);
if (valueNumber == null) {
Assertions.UNREACHABLE("Cannot lookup value: " + V);
}
SSAThrowInstruction T = insts.ThrowInstruction(governingMethod.getNumberOfStatements(), valueNumber.intValue());
governingMethod.addStatement(T);
}
/**
* Process an element indicating a putfield.
*
* @param atts
*/
private void processGetField(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
// deduce the field written
String classString = atts.getValue(A_CLASS);
TypeReference type = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(classString));
String fieldString = atts.getValue(A_FIELD);
Atom fieldName = Atom.findOrCreateAsciiAtom(fieldString);
String ftString = atts.getValue(A_FIELD_TYPE);
TypeReference fieldType = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(ftString));
FieldReference field = FieldReference.findOrCreate(type, fieldName, fieldType);
// get the value def'fed
String defVar = atts.getValue(A_DEF);
if (symbolTable.keySet().contains(defVar)) {
Assertions.UNREACHABLE("Cannot def variable twice: " + defVar + " in " + governingMethod);
}
if (defVar == null) {
Assertions.UNREACHABLE("Must specify def for getfield " + governingMethod);
}
int defNum = nextLocal;
symbolTable.put(defVar, Integer.valueOf(nextLocal++));
// get the ref read from
String R = atts.getValue(A_REF);
if (R == null) {
Assertions.UNREACHABLE("Must specify ref for getfield " + governingMethod);
}
Integer refNumber = symbolTable.get(R);
if (refNumber == null) {
Assertions.UNREACHABLE("Cannot lookup ref: " + R);
}
SSAGetInstruction G = insts.GetInstruction(governingMethod.getNumberOfStatements(), defNum, refNumber.intValue(), field);
governingMethod.addStatement(G);
}
/**
* Process an element indicating a putfield.
*
* @param atts
*/
private void processPutField(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
// deduce the field written
String classString = atts.getValue(A_CLASS);
TypeReference type = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(classString));
String fieldString = atts.getValue(A_FIELD);
Atom fieldName = Atom.findOrCreateAsciiAtom(fieldString);
String ftString = atts.getValue(A_FIELD_TYPE);
TypeReference fieldType = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(ftString));
FieldReference field = FieldReference.findOrCreate(type, fieldName, fieldType);
// get the value stored
String V = atts.getValue(A_VALUE);
if (V == null) {
Assertions.UNREACHABLE("Must specify value for putfield " + governingMethod);
}
Integer valueNumber = symbolTable.containsKey(V)? symbolTable.get(V): Integer.parseInt(V);
// get the ref stored to
String R = atts.getValue(A_REF);
if (R == null) {
Assertions.UNREACHABLE("Must specify ref for putfield " + governingMethod);
}
Integer refNumber = symbolTable.get(R);
if (refNumber == null) {
Assertions.UNREACHABLE("Cannot lookup ref: " + R);
}
SSAPutInstruction P = insts.PutInstruction(governingMethod.getNumberOfStatements(), refNumber.intValue(), valueNumber.intValue(), field);
governingMethod.addStatement(P);
}
/**
* Process an element indicating a putstatic.
*
* @param atts
*/
private void processPutStatic(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
// deduce the field written
String classString = atts.getValue(A_CLASS);
TypeReference type = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(classString));
String fieldString = atts.getValue(A_FIELD);
Atom fieldName = Atom.findOrCreateAsciiAtom(fieldString);
String ftString = atts.getValue(A_FIELD_TYPE);
TypeReference fieldType = TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(ftString));
FieldReference field = FieldReference.findOrCreate(type, fieldName, fieldType);
// get the value stored
String V = atts.getValue(A_VALUE);
if (V == null) {
Assertions.UNREACHABLE("Must specify value for putstatic " + governingMethod);
}
Integer valueNumber = symbolTable.get(V);
if (valueNumber == null) {
Assertions.UNREACHABLE("Cannot lookup value: " + V);
}
SSAPutInstruction P = insts.PutInstruction(governingMethod.getNumberOfStatements(), valueNumber.intValue(), field);
governingMethod.addStatement(P);
}
/**
* Process an element indicating an Aastore
*
* @param atts
*/
private void processAastore(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
String R = atts.getValue(A_REF);
if (R == null) {
Assertions.UNREACHABLE("Must specify ref for aastore " + governingMethod);
}
Integer refNumber = symbolTable.get(R);
if (refNumber == null) {
Assertions.UNREACHABLE("Cannot lookup value: " + R);
}
// N.B: we currently ignore the index
String I = atts.getValue(A_INDEX);
if (I == null) {
Assertions.UNREACHABLE("Must specify index for aastore " + governingMethod);
}
String V = atts.getValue(A_VALUE);
if (V == null) {
Assertions.UNREACHABLE("Must specify value for aastore " + governingMethod);
}
/** BEGIN Custom change: expect type information in array-store instructions */
String strType = atts.getValue(A_TYPE);
TypeReference type;
if (strType == null) {
type = TypeReference.JavaLangObject;
} else {
type = TypeReference.findOrCreate(governingLoader, strType);
}
/** END Custom change: get type information in array-store instructions */
Integer valueNumber = symbolTable.get(V);
if (valueNumber == null) {
Assertions.UNREACHABLE("Cannot lookup value: " + V);
}
/** BEGIN Custom change: expect type information in array-store instructions */
SSAArrayStoreInstruction S = insts.ArrayStoreInstruction(governingMethod.getNumberOfStatements(), refNumber.intValue(), 0, valueNumber.intValue(), type);
/** END Custom change: get type information in array-store instructions */
governingMethod.addStatement(S);
}
/**
* Process an element indicating an Aaload
*
* @param atts
*/
private void processAaload(Attributes atts) {
//<aaload def="foo" ref="arg1" index="the-answer" />
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
String R = atts.getValue(A_REF);
if (R == null) {
Assertions.UNREACHABLE("Must specify ref for aaload " + governingMethod);
}
Integer refNumber = symbolTable.get(R);
if (refNumber == null) {
Assertions.UNREACHABLE("Cannot lookup value: " + R);
}
// N.B: we currently ignore the index
String I = atts.getValue(A_INDEX);
if (I == null) {
Assertions.UNREACHABLE("Must specify index for aaload " + governingMethod);
}
String strType = atts.getValue(A_TYPE);
TypeReference type;
if (strType == null) {
type = TypeReference.JavaLangObject;
} else {
type = TypeReference.findOrCreate(governingLoader, strType);
}
// get the value def'fed
String defVar = atts.getValue(A_DEF);
if (symbolTable.keySet().contains(defVar)) {
Assertions.UNREACHABLE("Cannot def variable twice: " + defVar + " in " + governingMethod);
}
if (defVar == null) {
Assertions.UNREACHABLE("Must specify def for getfield " + governingMethod);
}
int defNum = nextLocal;
symbolTable.put(defVar, Integer.valueOf(nextLocal++));
SSAArrayLoadInstruction S = insts.ArrayLoadInstruction(governingMethod.getNumberOfStatements(), defNum, refNumber.intValue(), 0,
type);
governingMethod.addStatement(S);
}
/**
* Process an element indicating a return statement.
*
* @param atts
*/
private void processReturn(Attributes atts) {
Language lang = scope.getLanguage(governingLoader.getLanguage());
SSAInstructionFactory insts = lang.instructionFactory();
if (governingMethod.getReturnType() != null) {
String retV = atts.getValue(A_VALUE);
if (retV == null) {
SSAReturnInstruction R = insts.ReturnInstruction(governingMethod.getNumberOfStatements());
governingMethod.addStatement(R);
} else {
Integer valueNumber = symbolTable.get(retV);
if (valueNumber == null) {
if (!retV.equals(V_NULL)) {
Assertions.UNREACHABLE("Cannot return value with no def: " + retV);
} else {
valueNumber = symbolTable.get(V_NULL);
if (valueNumber == null) {
valueNumber = Integer.valueOf(nextLocal++);
symbolTable.put(V_NULL, valueNumber);
}
}
}
boolean isPrimitive = governingMethod.getReturnType().isPrimitiveType();
SSAReturnInstruction R = insts.ReturnInstruction(governingMethod.getNumberOfStatements(), valueNumber.intValue(), isPrimitive);
governingMethod.addStatement(R);
}
}
}
/**
* @param atts
*/
private void processConstant(Attributes atts) {
String var = atts.getValue(A_NAME);
if (var == null)
Assertions.UNREACHABLE("Must give name for constant");
Integer valueNumber = Integer.valueOf(nextLocal++);
symbolTable.put(var, valueNumber);
String typeString = atts.getValue(A_TYPE);
String valueString = atts.getValue(A_VALUE);
governingMethod.addConstant(valueNumber, (typeString.equals("int")) ? new ConstantValue(Integer.valueOf(valueString))
: (typeString.equals("long")) ? new ConstantValue(Long.valueOf(valueString))
: (typeString.equals("short")) ? new ConstantValue(Short.valueOf(valueString))
: (typeString.equals("float")) ? new ConstantValue(Float.valueOf(valueString))
: (typeString.equals("double")) ? new ConstantValue(Double.valueOf(valueString)) : null);
}
/**
* Process an element which indicates this method is "poison"
*
* @param atts
*/
private void processPoison(Attributes atts) {
String reason = atts.getValue(A_REASON);
governingMethod.addPoison(reason);
String level = atts.getValue(A_LEVEL);
if (level.equals("severe")) {
governingMethod.setPoisonLevel(Warning.SEVERE);
} else if (level.equals("moderate")) {
governingMethod.setPoisonLevel(Warning.MODERATE);
} else if (level.equals("mild")) {
governingMethod.setPoisonLevel(Warning.MILD);
} else {
Assertions.UNREACHABLE("Unexpected level: " + level);
}
}
/**
* Begin processing of a method. 1. Set the governing method. 2. Initialize the nextLocal variable
*
* @param atts
*/
private void startMethod(Attributes atts) {
String methodName = atts.getValue(A_NAME);
Atom mName = Atom.findOrCreateUnicodeAtom(methodName);
String descString = atts.getValue(A_DESCRIPTOR);
Language lang = scope.getLanguage(governingLoader.getLanguage());
Descriptor D = Descriptor.findOrCreateUTF8(lang, descString);
MethodReference ref = MethodReference.findOrCreate(governingClass, mName, D);
governingMethod = new MethodSummary(ref);
if (DEBUG) {
System.err.println(("Register method summary: " + ref));
}
summaries.put(ref, governingMethod);
boolean isStatic = false;
String staticString = atts.getValue(A_STATIC);
if (staticString != null) {
if (staticString.equals("true")) {
isStatic = true;
governingMethod.setStatic(true);
} else if (staticString.equals("false")) {
isStatic = false;
governingMethod.setStatic(false);
} else {
Assertions.UNREACHABLE("Invalid attribute value " + A_STATIC + ": " + staticString);
}
}
String factoryString = atts.getValue(A_FACTORY);
if (factoryString != null) {
if (factoryString.equals("true")) {
governingMethod.setFactory(true);
} else if (factoryString.equals("false")) {
governingMethod.setFactory(false);
} else {
Assertions.UNREACHABLE("Invalid attribute value " + A_FACTORY + ": " + factoryString);
}
}
// This is somewhat gross, but it is to deal with the fact that
// some non-Java languages have notions of arguments that do not
// map nicely to descriptors.
int nParams;
String specifiedArgs = atts.getValue(A_NUM_ARGS);
if (specifiedArgs == null) {
nParams = ref.getNumberOfParameters();
if (!isStatic) {
nParams += 1;
}
} else {
nParams = Integer.parseInt(specifiedArgs);
}
// note that symbol tables reserve v0 for "unknown", so v1 gets assigned
// to the first parameter "arg0", and so forth.
nextLocal = nParams + 1;
symbolTable = HashMapFactory.make(5);
// create symbols for the parameters
for (int i = 0; i < nParams; i++) {
symbolTable.put("arg" + i, Integer.valueOf(i + 1));
}
int pn = 1;
String paramDescString = atts.getValue(A_PARAM_NAMES);
if (paramDescString != null) {
StringTokenizer paramNames = new StringTokenizer(paramDescString);
while (paramNames.hasMoreTokens()) {
symbolTable.put(paramNames.nextToken(), pn++);
}
}
Map<Integer,Atom> nameTable = HashMapFactory.make();
for(Map.Entry<String, Integer> x : symbolTable.entrySet()) {
if (! x.getKey().startsWith("arg")) {
nameTable.put(x.getValue(), Atom.findOrCreateUnicodeAtom(x.getKey()));
}
}
governingMethod.setValueNames(nameTable);
}
/**
* Method classLoaderName2Ref.
*
* @param clName
* @return ClassLoaderReference
*/
private ClassLoaderReference classLoaderName2Ref(String clName) {
return scope.getLoader(Atom.findOrCreateUnicodeAtom(clName));
}
/**
* Method classLoaderName2Ref.
*
* @param clName
* @return ClassLoaderReference
*/
private TypeReference className2Ref(String clName) {
return TypeReference.findOrCreate(governingLoader, TypeName.string2TypeName(clName));
}
}
}