diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java index 80507c9de..cb298b77e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java @@ -35,6 +35,7 @@ import com.ibm.wala.ssa.SSANewInstruction; import com.ibm.wala.ssa.SSAReturnInstruction; import com.ibm.wala.types.MethodReference; import com.ibm.wala.types.TypeReference; +import static com.ibm.wala.types.TypeName.*; import com.ibm.wala.util.collections.HashMapFactory; import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.debug.Assertions; @@ -227,8 +228,17 @@ public abstract class AbstractReflectionInterpreter implements SSAContextInterpr if (t.isArrayType()) { // for now, just allocate an array of size 1 in each dimension. - int dim = t.getDimensionality(); - int[] extents = new int[dim]; + int dims = 0; + int dim = t.getDerivedMask(); + if ((dim&ElementMask) == PrimitiveMask) { + dim >>= 2; + } + while ((dim&ElementMask) == ArrayMask) { + dims++; + dim >>=2; + } + + int[] extents = new int[dims]; Arrays.fill(extents, 1); SSANewInstruction a = insts.NewInstruction(alloc, ref, extents); addInstruction(t, a, true); diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java index 1a30fb6ed..79461a789 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java @@ -18,6 +18,7 @@ import java.util.Set; import com.ibm.wala.cfg.ControlFlowGraph; import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.ArrayClass; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.CodeScanner; import com.ibm.wala.classLoader.IClass; @@ -155,7 +156,7 @@ public class CloneInterpreter implements SSAContextInterpreter { if (klass.isArrayClass()) { int length = nextLocal++; statements.add(insts.ArrayLengthInstruction(length, 1)); - int[] sizes = new int[klass.getReference().getDimensionality()]; + int[] sizes = new int[((ArrayClass)klass).getDimensionality()]; Arrays.fill(sizes, length); N = insts.NewInstruction(retValue, ref, sizes); } else { diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java index c95dc411f..61a3af2cd 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java @@ -25,6 +25,7 @@ import com.ibm.wala.analysis.typeInference.SetType; import com.ibm.wala.analysis.typeInference.TypeAbstraction; import com.ibm.wala.cfg.ControlFlowGraph; import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.ArrayClass; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.CodeScanner; import com.ibm.wala.classLoader.IClass; @@ -528,7 +529,7 @@ class FactoryBypassInterpreter extends AbstractReflectionInterpreter { NewSiteReference ref = NewSiteReference.make(getNewSiteForType(T), T); SSANewInstruction a = null; if (T.isArrayType()) { - int[] sizes = new int[T.getDimensionality()]; + int[] sizes = new int[((ArrayClass)klass).getDimensionality()]; initValueNumberForConstantOne(); Arrays.fill(sizes, valueNumberForConstantOne); a = insts.NewInstruction(i, ref, sizes); diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java index 44c6f34e3..69101ccc4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java @@ -19,6 +19,7 @@ import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.shrikeBT.Constants; import com.ibm.wala.types.Selector; import com.ibm.wala.types.TypeName; +import static com.ibm.wala.types.TypeName.*; import com.ibm.wala.types.TypeReference; import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.debug.Assertions; @@ -234,7 +235,17 @@ public class ArrayClass implements IClass, Constants { } public int getDimensionality() { - return getReference().getDimensionality(); + int mask = getReference().getDerivedMask(); + if ((mask&PrimitiveMask) == PrimitiveMask) { + mask >>= 2; + } + int dims = 0; + while ((mask&ArrayMask) == ArrayMask) { + mask >>= 2; + dims++; + } + assert dims>0; + return dims; } /** diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java index 25e71a6dd..61bee7603 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java @@ -16,6 +16,7 @@ import java.util.Iterator; import java.util.Map; import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.ArrayClass; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IMethod; @@ -174,7 +175,7 @@ public abstract class AbstractRootMethod extends SyntheticMethod { int instance = nextLocal++; NewSiteReference ref = NewSiteReference.make(statements.size(), T); assert T.isArrayType(); - assert T.getDimensionality() == 1; + assert ((ArrayClass)cha.lookupClass(T)).getDimensionality() == 1; int[] sizes = new int[1]; Arrays.fill(sizes, getValueNumberForIntConstant(length)); SSANewInstruction result = insts.NewInstruction(instance, ref, sizes); @@ -206,7 +207,7 @@ public abstract class AbstractRootMethod extends SyntheticMethod { if (T.isReferenceType()) { NewSiteReference ref = NewSiteReference.make(statements.size(), T); if (T.isArrayType()) { - int[] sizes = new int[T.getDimensionality()]; + int[] sizes = new int[((ArrayClass)cha.lookupClass(T)).getDimensionality()]; Arrays.fill(sizes, getValueNumberForIntConstant(1)); result = insts.NewInstruction(instance, ref, sizes); } else { @@ -229,7 +230,7 @@ public abstract class AbstractRootMethod extends SyntheticMethod { int alloc = nextLocal++; SSANewInstruction ni = null; if (e.isArrayType()) { - int[] sizes = new int[T.getDimensionality()]; + int[] sizes = new int[((ArrayClass)cha.lookupClass(T)).getDimensionality()]; Arrays.fill(sizes, getValueNumberForIntConstant(1)); ni = insts.NewInstruction(alloc, n, sizes); } else { diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/modref/ModRef.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/modref/ModRef.java index a86e7f726..6a8c64b4d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/modref/ModRef.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/modref/ModRef.java @@ -15,6 +15,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import com.ibm.wala.classLoader.ArrayClass; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IField; import com.ibm.wala.dataflow.graph.BitVectorSolver; @@ -259,7 +260,7 @@ public class ModRef { @Override public void visitNew(SSANewInstruction instruction) { if (instruction.getConcreteType().isArrayType()) { - int dim = instruction.getConcreteType().getDimensionality(); + int dim = ((ArrayClass)n.getClassHierarchy().lookupClass(instruction.getConcreteType())).getDimensionality(); if (dim > 1) { // we need to handle the top-level allocation, just like the 1D case InstanceKey ik = h.getInstanceKeyForAllocation(n, instruction.getNewSite()); diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/XMLMethodSummaryReader.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/XMLMethodSummaryReader.java index cdd4bdafb..6aebd572e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/XMLMethodSummaryReader.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/XMLMethodSummaryReader.java @@ -45,6 +45,7 @@ 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 static 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; @@ -515,7 +516,11 @@ public class XMLMethodSummaryReader implements BytecodeConstants { Assertions.productionAssertion(size != null); Integer sNumber = symbolTable.get(size); Assertions.productionAssertion(sNumber != null); - Assertions.productionAssertion(type.getDimensionality() == 1); + Assertions.productionAssertion( + // array of objects + type.getDerivedMask()==ArrayMask || + // array of primitives + type.getDerivedMask()==((ArrayMask<<2)|PrimitiveMask)); a = insts.NewInstruction(defNum, ref, new int[] { sNumber.intValue() }); } else { a = insts.NewInstruction(defNum, ref); diff --git a/com.ibm.wala.core/src/com/ibm/wala/types/TypeName.java b/com.ibm.wala.core/src/com/ibm/wala/types/TypeName.java index 1d6b22919..9fac1b754 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/types/TypeName.java +++ b/com.ibm.wala.core/src/com/ibm/wala/types/TypeName.java @@ -27,6 +27,14 @@ import com.ibm.wala.util.strings.StringStuff; */ public final class TypeName implements Serializable { + public static final byte ArrayMask = 0x01; + public static final byte PointerMask = 0x02; + public static final byte ReferenceMask = 0x03; + public static final byte PrimitiveMask = 0x04; + + public static final byte ElementMask = 0x07; + public static final byte ElementBits = 3; + /* Serial version */ private static final long serialVersionUID = -3256390509887654326L; @@ -54,12 +62,17 @@ public final class TypeName implements Serializable { Atom className = Atom.findOrCreate(StringStuff.parseForClass(name, start, length)); ImmutableByteArray p = StringStuff.parseForPackage(name, start, length); Atom packageName = (p == null) ? null : Atom.findOrCreate(p); - short dim = StringStuff.parseForArrayDimensionality(name, start, length); + int dim = StringStuff.parseForArrayDimensionality(name, start, length); boolean innermostPrimitive = StringStuff.classIsPrimitive(name, start, length); - if (innermostPrimitive && (dim == 0)) { - dim = -1; + if (innermostPrimitive) { + if (dim == 0) { + dim = -1; + } else { + dim <<= ElementBits; + dim |= PrimitiveMask; + } } - TypeNameKey t = new TypeNameKey(packageName, className, dim, innermostPrimitive); + TypeNameKey t = new TypeNameKey(packageName, className, dim); return findOrCreate(t); } @@ -82,12 +95,12 @@ public final class TypeName implements Serializable { if (className == null) { throw new IllegalArgumentException("null className"); } - TypeNameKey T = new TypeNameKey(packageName, className, (short) 0, false); + TypeNameKey T = new TypeNameKey(packageName, className, 0); return findOrCreate(T); } - private static TypeName findOrCreate(Atom packageName, Atom className, short dim, boolean innermostPrimitive) { - TypeNameKey T = new TypeNameKey(packageName, className, dim, innermostPrimitive); + public static TypeName findOrCreate(Atom packageName, Atom className, int dim) { + TypeNameKey T = new TypeNameKey(packageName, className, dim); return findOrCreate(T); } @@ -141,29 +154,52 @@ public final class TypeName implements Serializable { * @return the name of the array element type for an array */ public TypeName parseForArrayElementName() { - short newDim = (short) (key.dim - 1); - if (newDim == 0 && key.innermostPrimitive) { - newDim = -1; + int newDim; + if ((key.dim&ElementMask) == PrimitiveMask) { + int tmpDim = key.dim>>(2*ElementBits); + if (tmpDim == 0) { + newDim = -1; + } else { + newDim = (tmpDim<>ElementBits; } - return findOrCreate(key.packageName, key.className, newDim, key.innermostPrimitive); + + return findOrCreate(key.packageName, key.className, newDim); } /** * @return a type name that represents an array of this element type */ - public TypeName getArrayTypeForElementType() { - short newDim = (short) (key.dim + 1); - if (newDim == 0) { - newDim = 1; + private TypeName getDerivedTypeForElementType(byte mask) { + int newDim; + if (key.dim == -1) { + newDim = mask< primitive 0 => class >0 => array + * Dimensionality: -1 => primitive + * 0 => class + * >0 => mask of levels of array, reference, pointer */ - private final short dim; - - /** - * Is the innermost element type a primitive? TODO: encode in dim? - */ - private final boolean innermostPrimitive; + private final int dim; /** * This should be the only constructor */ - private TypeNameKey(Atom packageName, Atom className, short dim, boolean innermostPrimitive) { + private TypeNameKey(Atom packageName, Atom className, int dim) { this.packageName = packageName; this.className = className; this.dim = dim; - this.innermostPrimitive = innermostPrimitive; } @Override public boolean equals(Object obj) { if (obj instanceof TypeNameKey) { TypeNameKey other = (TypeNameKey) obj; - return className == other.className && packageName == other.packageName && dim == other.dim - && innermostPrimitive == other.innermostPrimitive; + return className == other.className && packageName == other.packageName && dim == other.dim; } else { return false; } @@ -246,7 +277,7 @@ public final class TypeName implements Serializable { */ @Override public int hashCode() { - int result = className.hashCode() * 5009 + dim * 5011 + (innermostPrimitive ? 5021 : 5023); + int result = className.hashCode() * 5009 + dim * 5011; if (packageName != null) { result += packageName.hashCode(); } @@ -256,14 +287,7 @@ public final class TypeName implements Serializable { @Override public String toString() { StringBuffer result = new StringBuffer(); - for (short i = 0; i < dim; i++) { - result.append("["); - } - if (!innermostPrimitive) { - result.append("L"); - } else if (packageName != null && innermostPrimitive) { - result.append("P"); - } + toStringPrefix(result); if (packageName != null) { result.append(packageName.toString()); @@ -274,17 +298,34 @@ public final class TypeName implements Serializable { return result.toString(); } + private void toStringPrefix(StringBuffer result) { + boolean isPrimitive = (dim==-1) || (dim&ElementMask)==PrimitiveMask; + if (dim != -1) { + for (int d = (dim&ElementMask) == PrimitiveMask? dim>>ElementBits: dim; d != 0; d>>=ElementBits) { + switch (d&ElementMask) { + case ArrayMask: + result.append("["); + break; + case PointerMask: + result.append("*"); + break; + case ReferenceMask: + result.append("&"); + break; + } + } + } + if (!isPrimitive) { + result.append("L"); + } else if (packageName != null && isPrimitive) { + result.append("P"); + } + } + public String toUnicodeString() { try { StringBuffer result = new StringBuffer(); - for (short i = 0; i < dim; i++) { - result.append("["); - } - if (!innermostPrimitive) { - result.append("L"); - } else if (packageName != null && innermostPrimitive) { - result.append("P"); - } + toStringPrefix(result); if (packageName != null) { result.append(packageName.toUnicodeString()); diff --git a/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java b/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java index 0d8446de8..bc25877a4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java @@ -318,6 +318,10 @@ public final class TypeReference implements Serializable { public final static byte ArrayTypeCode = '['; + public final static byte PointerTypeCode = '*'; + + public final static byte ReferenceTypeCode = '&'; + // TODO! the following two are unsound hacks; kill them. final static TypeName NullName = TypeName.string2TypeName("null"); @@ -412,6 +416,30 @@ public final class TypeReference implements Serializable { } } + public static TypeReference findOrCreateReferenceTo(TypeReference t) { + if (t == null) { + throw new IllegalArgumentException("t is null"); + } + TypeName name = t.getName(); + if (t.isPrimitiveType()) { + return findOrCreate(ClassLoaderReference.Primordial, name.getReferenceTypeForElementType()); + } else { + return findOrCreate(t.getClassLoader(), name.getReferenceTypeForElementType()); + } + } + + public static TypeReference findOrCreatePointerTo(TypeReference t) { + if (t == null) { + throw new IllegalArgumentException("t is null"); + } + TypeName name = t.getName(); + if (t.isPrimitiveType()) { + return findOrCreate(ClassLoaderReference.Primordial, name.getPointerTypeForElementType()); + } else { + return findOrCreate(t.getClassLoader(), name.getPointerTypeForElementType()); + } + } + /** * NB: All type names should use '/' and not '.' as a separator. eg. Ljava/lang/Class * @@ -456,8 +484,8 @@ public final class TypeReference implements Serializable { * Return the dimensionality of the type. By convention, class types have dimensionality 0, primitives -1, and arrays * the number of [ in their descriptor. */ - public final int getDimensionality() { - return name.getDimensionality(); + public final int getDerivedMask() { + return name.getDerivedMask(); } /** diff --git a/com.ibm.wala.core/src/com/ibm/wala/util/strings/StringStuff.java b/com.ibm.wala.core/src/com/ibm/wala/util/strings/StringStuff.java index bb71f952d..6ab8df37c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/util/strings/StringStuff.java +++ b/com.ibm.wala.core/src/com/ibm/wala/util/strings/StringStuff.java @@ -10,6 +10,11 @@ *******************************************************************************/ package com.ibm.wala.util.strings; +import static com.ibm.wala.types.TypeName.*; +import static com.ibm.wala.types.TypeReference.ArrayTypeCode; +import static com.ibm.wala.types.TypeReference.PointerTypeCode; +import static com.ibm.wala.types.TypeReference.ReferenceTypeCode; + import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -263,28 +268,19 @@ public class StringStuff { continue; } - case TypeReference.ArrayTypeCode: { + case TypeReference.ArrayTypeCode: + case TypeReference.PointerTypeCode: + case TypeReference.ReferenceTypeCode: { int off = i - 1; - while (b.get(i) == TypeReference.ArrayTypeCode) { - ++i; + while (StringStuff.isTypeCodeChar(b, i)) { + ++i; } TypeName T = null; byte c = b.get(i++); - if (c == TypeReference.ClassTypeCode) { + if (c == TypeReference.ClassTypeCode || c == TypeReference.OtherPrimitiveTypeCode) { while (b.get(i++) != ';') ; T = TypeName.findOrCreate(b, off, i - off - 1); - } else if (c == TypeReference.OtherPrimitiveTypeCode) { - int typeOff = i; - - while (b.get(i++) != ';') - ; - - T = l.lookupPrimitiveType(new String(b.substring(typeOff, i - typeOff - 1))); - while (--typeOff > off) { - T = T.getArrayTypeForElementType(); - } - } else { T = TypeName.findOrCreate(b, off, i - off); } @@ -309,6 +305,12 @@ public class StringStuff { } } + public static boolean isTypeCodeChar(ImmutableByteArray name, int i) { + return name.b[i] == TypeReference.ArrayTypeCode || + name.b[i] == TypeReference.PointerTypeCode || + name.b[i] == TypeReference.ReferenceTypeCode; + } + /** * Given that name[start:start+length] is a Type name in JVM format, parse it for the package * @@ -329,7 +331,10 @@ public class StringStuff { if (lastSlash == -1) { return null; } - short dim = parseForArrayDimensionality(name, start, length); + short dim = 0; + while (isTypeCodeChar(name, start+dim)) { + dim++; + } return new ImmutableByteArray(name.b, start + 1 + dim, lastSlash - start - 1 - dim); } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("invalid name " + name + " start: " + start + " length: " + length); @@ -366,7 +371,7 @@ public class StringStuff { } try { if (parseForPackage(name, start, length) == null) { - while (name.b[start] == '[') { + while (isTypeCodeChar(name, start)) { start++; length--; } @@ -410,22 +415,30 @@ public class StringStuff { * @return dimensionality - something like "1" or "2" * @throws IllegalArgumentException if b == null */ - public static short parseForArrayDimensionality(ImmutableByteArray b, int start, int length) throws IllegalArgumentException, + public static int parseForArrayDimensionality(ImmutableByteArray b, int start, int length) throws IllegalArgumentException, IllegalArgumentException { if (b == null) { throw new IllegalArgumentException("b == null"); } try { + int code = 0; for (int i = start; i < start + length; ++i) { - if (b.b[i] != '[') { - return (short) (i - start); + if (isTypeCodeChar(b, i)) { + code <<= ElementBits; + switch (b.b[i]) { + case ArrayTypeCode: code |= ArrayMask; break; + case PointerTypeCode: code |= PointerMask; break; + case ReferenceTypeCode: code |= ReferenceMask; break; + default: + throw new IllegalArgumentException("ill-formed array descriptor " + b); + } } } + return code; } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("ill-formed array descriptor " + b); } - throw new IllegalArgumentException("ill-formed array descriptor " + b); } /** @@ -443,7 +456,7 @@ public class StringStuff { try { int i = start; for (; i < start + length; ++i) { - if (b.b[i] != '[') { + if (! isTypeCodeChar(b, i)) { break; } } @@ -477,7 +490,7 @@ public class StringStuff { throw new IllegalArgumentException("name is null"); } try { - while (length > 0 && name.b[start] == '[') { + while (length > 0 && isTypeCodeChar(name, start)) { start++; length--; }