
org.aion.avm.core.ArraySuperResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javaee-rt Show documentation
Show all versions of javaee-rt Show documentation
An Execution Environment for Java SCOREs
package org.aion.avm.core;
import org.aion.avm.ArrayRenamer;
import org.aion.avm.ArrayUtil;
import org.aion.avm.NameStyle;
import org.aion.avm.core.exceptionwrapping.ExceptionWrapperNameMapper;
import org.aion.avm.core.types.ClassHierarchy;
import org.aion.avm.core.types.CommonType;
import i.RuntimeAssertionError;
/**
* A class that is used to determine a tightest common super class of two types, where at least one
* of the two types must be an array type (either pre- or post- rename, it does not matter).
*
* If this resolver as well as {@link PlainTypeSuperResolver} and {@link PlainTypeSuperResolver} are
* called on any two types then at least one of the resolvers will return a non-null and therefore
* valid answer.
*/
public final class ArraySuperResolver {
private final ClassHierarchy classHierarchy;
private final ClassRenamer classRenamer;
private final PlainTypeSuperResolver plainTypeSuperResolver;
public ArraySuperResolver(ClassHierarchy classHierarchy, ClassRenamer classRenamer) {
if (classHierarchy == null) {
throw new NullPointerException("Cannot construct ArraySuperResolver with null class hierarchy.");
}
if (classRenamer == null) {
throw new NullPointerException("Cannot construct ArraySuperResolver with null class renamer.");
}
this.classHierarchy = classHierarchy;
this.classRenamer = classRenamer;
this.plainTypeSuperResolver = new PlainTypeSuperResolver(this.classHierarchy, this.classRenamer);
}
/**
* Returns a tightest common super class of the two given types if at least one of them is an
* array type.
*
* Returns null if neither of the two given types are arrays.
*
* @param type1dotName The first type.
* @param type2dotName The second type.
* @return a tightest common super class or null.
*/
public String getTightestSuperClassIfGivenArray(String type1dotName, String type2dotName) {
RuntimeAssertionError.assertTrue(type1dotName != null);
RuntimeAssertionError.assertTrue(type2dotName != null);
boolean type1isArray = ArrayUtil.isArray(NameStyle.DOT_NAME, type1dotName);
boolean type2isArray = ArrayUtil.isArray(NameStyle.DOT_NAME, type2dotName);
boolean type1isSpecialArray = type1isArray && ArrayUtil.isSpecialPostRenameArray(NameStyle.DOT_NAME, type1dotName);
boolean type2isSpecialArray = type2isArray && ArrayUtil.isSpecialPostRenameArray(NameStyle.DOT_NAME, type2dotName);
boolean atLeastOneSpecialArray = type1isSpecialArray || type2isSpecialArray;
if (type1isArray && type2isArray) {
return atLeastOneSpecialArray ? findSuperOfAtLeastOneSpecialArray(type1dotName, type2dotName) : findSuperOfTwoArrays(type1dotName, type2dotName);
} else if (type1isArray || type2isArray) {
return atLeastOneSpecialArray ? findSuperOfAtLeastOneSpecialArray(type1dotName, type2dotName) : findSuperOfArrayAndNonArray(type1dotName, type2dotName);
} else {
return null;
}
}
/**
* A special array is one of our internal types: Array, IArray, ObjectArray, IObjectArray
*
* Assumption: at least one of the two arrays is a special array.
*/
private String findSuperOfAtLeastOneSpecialArray(String array1, String array2) {
boolean array1isSpecialArray = ArrayUtil.isSpecialPostRenameArray(NameStyle.DOT_NAME, array1);
boolean array2isSpecialArray = ArrayUtil.isSpecialPostRenameArray(NameStyle.DOT_NAME, array2);
if (array1isSpecialArray ^ array2isSpecialArray) {
return findSuperOfSpecialArrayAndOther(array1, array2);
} else {
// Special arrays are in the hierarchy, we can query it directly.
String commonSuper = this.classHierarchy.getTightestCommonSuperClass(array1, array2);
// If the super class is ambiguous return IObject, otherwise return the super class.
if (commonSuper == null) {
return CommonType.I_OBJECT.dotName;
} else {
return commonSuper;
}
}
}
/**
* Returns a tightest common super class of the two types, under the assumption that both of them
* are arrays.
*/
private String findSuperOfTwoArrays(String array1dotName, String array2dotName) {
boolean array1isPreRename = this.classRenamer.isPreRename(array1dotName);
boolean array2isPreRename = this.classRenamer.isPreRename(array2dotName);
if (array1isPreRename && array2isPreRename) {
return findSuperOfTwoPreRenameArrays(array1dotName, array2dotName);
} else if (!array1isPreRename && !array2isPreRename) {
return findSuperOfTwoPostRenameArrays(array1dotName, array2dotName);
} else {
// We have a pre- and post-rename array, they can only unify to java.lang.Object
return CommonType.JAVA_LANG_OBJECT.dotName;
}
}
/**
* Returns a tightest common super class of the two types, under the assumption that one of them
* is an array and the other is not.
*
* Returns java.lang.Object when:
* 1. array is pre-rename.
* 2. one type is pre-rename, other is post-rename.
* 3. array is post-rename and the non-array is an exception wrapper.
*
* Returns IObject when:
* 1. both types are post-rename and either the array is a unifying object array or the non-array
* is an interface.
*
* Returns shadow Object otherwise.
*/
private String findSuperOfArrayAndNonArray(String type1dotName, String type2dotName) {
String arrayDotName = ArrayUtil.isArray(NameStyle.DOT_NAME, type1dotName) ? type1dotName : type2dotName;
String nonArrayDotName = arrayDotName.equals(type1dotName) ? type2dotName : type1dotName;
if (ArrayUtil.isPreRenameArray(arrayDotName)) {
// If the array is pre-rename then it can only unify to java.lang.Object
return CommonType.JAVA_LANG_OBJECT.dotName;
} else {
if (this.classRenamer.isPreRename(nonArrayDotName)) {
// Then we have a pre- and post-rename unification, these unify to java.lang.Object
return CommonType.JAVA_LANG_OBJECT.dotName;
} else {
// Exception wrappers descend from java.lang.Throwable so we unify to java.lang.Object
if (ExceptionWrapperNameMapper.isExceptionWrapperDotName(nonArrayDotName)) {
return CommonType.JAVA_LANG_OBJECT.dotName;
}
boolean arrayIsUnifyingType = ArrayUtil.isPostRenameUnifyingTypeObjectArray(NameStyle.DOT_NAME, arrayDotName);
boolean nonArrayIsInterface = this.classHierarchy.postRenameTypeIsInterface(nonArrayDotName);
if (arrayIsUnifyingType || nonArrayIsInterface) {
return CommonType.I_OBJECT.dotName;
} else {
return CommonType.SHADOW_OBJECT.dotName;
}
}
}
}
private String findSuperOfTwoPreRenameArrays(String array1preRename, String array2preRename) {
boolean array1isPrimitiveArray = ArrayUtil.isPreRenamePrimitiveArray(array1preRename);
boolean array2isPrimitiveArray = ArrayUtil.isPreRenamePrimitiveArray(array2preRename);
if (array1isPrimitiveArray && array2isPrimitiveArray) {
// Primitive arrays unify to java.lang.Object only, unless they are equal.
return array1preRename.equals(array2preRename) ? array1preRename : CommonType.JAVA_LANG_OBJECT.dotName;
} else if (!array1isPrimitiveArray && !array2isPrimitiveArray) {
return findSuperOfTwoPreRenameObjectArrays(array1preRename, array2preRename);
} else {
// We have a primitive and an object array, they can only unify to java.lang.Object
return ArrayRenamer.prependPreRenameObjectArrayPrefix(CommonType.JAVA_LANG_OBJECT.dotName, 1);
}
}
private String findSuperOfTwoPostRenameArrays(String array1postRename, String array2postRename) {
boolean array1isPrimitiveArray = ArrayUtil.isPostRenamePrimitiveArray(NameStyle.DOT_NAME, array1postRename);
boolean array2isPrimitiveArray = ArrayUtil.isPostRenamePrimitiveArray(NameStyle.DOT_NAME, array2postRename);
if (array1isPrimitiveArray && array2isPrimitiveArray) {
// Primitive arrays unify to shadow Object only, unless they are equal.
return (array1postRename.equals(array2postRename)) ? array1postRename : CommonType.SHADOW_OBJECT.dotName;
} else if (!array1isPrimitiveArray && !array2isPrimitiveArray) {
return findSuperOfTwoPostRenameObjectArrays(array1postRename, array2postRename);
} else {
// We have a primitive and object array. They unify to IObject if the object array is a unifying type.
// Otherwise, they unify to shadow Object.
boolean objectIsUnifyingArray = (array1isPrimitiveArray)
? ArrayUtil.isPostRenameUnifyingTypeObjectArray(NameStyle.DOT_NAME, array2postRename)
: ArrayUtil.isPostRenameUnifyingTypeObjectArray(NameStyle.DOT_NAME, array1postRename);
return objectIsUnifyingArray ? CommonType.I_OBJECT.dotName : CommonType.SHADOW_OBJECT.dotName;
}
}
private String findSuperOfTwoPostRenameObjectArrays(String array1postRename, String array2postRename) {
int dimension1 = ArrayUtil.dimensionOfPostRenameObjectArray(NameStyle.DOT_NAME, array1postRename);
int dimension2 = ArrayUtil.dimensionOfPostRenameObjectArray(NameStyle.DOT_NAME, array2postRename);
if (dimension1 == dimension2) {
// They have the same dimension so we get an array of the super class of their base types.
String baseType1 = ArrayRenamer.getPostRenameObjectArrayWrapperUnderlyingTypeName(NameStyle.DOT_NAME, array1postRename);
String baseType2 = ArrayRenamer.getPostRenameObjectArrayWrapperUnderlyingTypeName(NameStyle.DOT_NAME, array2postRename);
// We cannot have an array of array or array of exception wrapper so we have two plain types.
String superOfBases = this.plainTypeSuperResolver.getTightestSuperClassIfGivenPlainType(baseType1, baseType2);
RuntimeAssertionError.assertTrue(superOfBases != null);
// IObject is given when super is ambiguous, in this case we have to wrap as a unifying type.
boolean superIsIObject = superOfBases.equals(CommonType.I_OBJECT.dotName);
boolean array1isConcreteType = ArrayUtil.isPostRenameConcreteTypeObjectArray(NameStyle.DOT_NAME, array1postRename);
boolean array2isConcreteType = ArrayUtil.isPostRenameConcreteTypeObjectArray(NameStyle.DOT_NAME, array2postRename);
if (!superIsIObject && array1isConcreteType && array2isConcreteType) {
// We have two concrete types array, they must unify to a concrete type array.
return superOfBases.equals(CommonType.SHADOW_OBJECT.dotName)
? CommonType.SHADOW_OBJECT.dotName
: ArrayRenamer.wrapAsConcreteObjectArray(NameStyle.DOT_NAME, superOfBases, dimension1);
} else {
// A unifying array is present so the two must unify to a unifying type.
return ArrayRenamer.wrapAsUnifyingObjectArray(NameStyle.DOT_NAME, superOfBases, dimension1);
}
} else {
// They differ in dimension, so they can only unify to IObject or shadow Object.
boolean array1isUnifyingType = ArrayUtil.isPostRenameUnifyingTypeObjectArray(NameStyle.DOT_NAME, array1postRename);
boolean array2isUnifyingType = ArrayUtil.isPostRenameUnifyingTypeObjectArray(NameStyle.DOT_NAME, array2postRename);
if (array1isUnifyingType || array2isUnifyingType) {
return CommonType.I_OBJECT.dotName;
} else {
return CommonType.SHADOW_OBJECT.dotName;
}
}
}
private String findSuperOfTwoPreRenameObjectArrays(String array1, String array2) {
int dimension1 = ArrayUtil.dimensionOfPreRenameObjectArray(array1);
int dimension2 = ArrayUtil.dimensionOfPreRenameObjectArray(array2);
if (dimension1 == dimension2) {
// They are the same dimension so these will have a complex unification.
// We need the base types of each of the two arrays so that we can unify them.
String baseType1 = ArrayRenamer.getPreRenameObjectArrayWrapperUnderlyingTypeName(array1);
String baseType2 = ArrayRenamer.getPreRenameObjectArrayWrapperUnderlyingTypeName(array2);
// We are left with two plain types as our base types.
String superOfBases = this.plainTypeSuperResolver.getTightestSuperClassIfGivenPlainType(baseType1, baseType2);
RuntimeAssertionError.assertTrue(superOfBases != null);
return ArrayRenamer.prependPreRenameObjectArrayPrefix(superOfBases, dimension1);
} else {
// They differ in dimensions and can only unify to java.lang.Object
return ArrayRenamer.prependPreRenameObjectArrayPrefix(CommonType.JAVA_LANG_OBJECT.dotName, 1);
}
}
private String findSuperOfSpecialArrayAndOther(String type1dotName, String type2dotName) {
String specialArray = (ArrayUtil.isSpecialPostRenameArray(NameStyle.DOT_NAME, type1dotName)) ? type1dotName : type2dotName;
String otherType = specialArray.equals(type1dotName) ? type2dotName : type1dotName;
if (this.classRenamer.isPreRename(otherType)) {
return CommonType.JAVA_LANG_OBJECT.dotName;
} else {
// Both types are post-rename. Other may still be an array or an exception wrapper.
if (ExceptionWrapperNameMapper.isExceptionWrapperDotName(otherType)) {
// Exception wrappers descend from java.lang.Throwable so they can only unify to java.lang.Object here
return CommonType.JAVA_LANG_OBJECT.dotName;
} else if (ArrayUtil.isPostRenameArray(NameStyle.DOT_NAME, otherType)) {
if (ArrayUtil.isPostRenameSingleDimensionPrimitiveArray(NameStyle.DOT_NAME, otherType)) {
// The primitive array unifies to the special array if it is its parent, otherwise it
// unifies to shadow Object or IObject depending on which special array we have.
if (specialArray.equals(CommonType.ARRAY.dotName) || specialArray.equals(CommonType.I_ARRAY.dotName)) {
return specialArray;
} else if (specialArray.equals(CommonType.OBJECT_ARRAY.dotName)) {
return CommonType.SHADOW_OBJECT.dotName;
} else if (specialArray.equals(CommonType.I_OBJECT_ARRAY.dotName)) {
return CommonType.I_OBJECT.dotName;
} else {
throw RuntimeAssertionError.unreachable("Expected a special array type: " + specialArray);
}
} else if (ArrayUtil.isPostRenameMultiDimensionPrimitiveArray(NameStyle.DOT_NAME, otherType)) {
// Multi-dimensional primitive arrays unify to IObject if the special array is an interface, otherwise shadow Object
if (specialArray.equals(CommonType.I_OBJECT_ARRAY.dotName) || specialArray.equals(CommonType.I_ARRAY.dotName)) {
return CommonType.I_OBJECT.dotName;
} else if (specialArray.equals(CommonType.ARRAY.dotName) || specialArray.equals(CommonType.OBJECT_ARRAY.dotName)) {
return CommonType.SHADOW_OBJECT.dotName;
} else {
throw RuntimeAssertionError.unreachable("Expected a special array type: " + specialArray);
}
} else if (ArrayUtil.isPostRenameConcreteTypeObjectArray(NameStyle.DOT_NAME, otherType)) {
// The concrete array unifies to the special array if it is its parent, otherwise it
// unifies to shadow Object or IObject depending on which special array we have.
if (specialArray.equals(CommonType.OBJECT_ARRAY.dotName) || specialArray.equals(CommonType.I_OBJECT_ARRAY.dotName)) {
return specialArray;
} else if (specialArray.equals(CommonType.ARRAY.dotName)) {
return CommonType.SHADOW_OBJECT.dotName;
} else if (specialArray.equals(CommonType.I_ARRAY.dotName)) {
return CommonType.I_OBJECT.dotName;
} else {
throw RuntimeAssertionError.unreachable("Expected a special array type: " + specialArray);
}
} else if (ArrayUtil.isPostRenameUnifyingTypeObjectArray(NameStyle.DOT_NAME, otherType)) {
// A unifying array type unifies to its parent IObjectArray or else IObject
if (specialArray.equals(CommonType.I_OBJECT_ARRAY.dotName)) {
return specialArray;
} else if (specialArray.equals(CommonType.OBJECT_ARRAY.dotName) || specialArray.equals(CommonType.I_ARRAY.dotName) || specialArray.equals(CommonType.ARRAY.dotName)) {
return CommonType.I_OBJECT.dotName;
} else {
throw RuntimeAssertionError.unreachable("Expected a special array type: " + specialArray);
}
} else {
throw RuntimeAssertionError.unreachable("Expected a post-rename array: " + otherType);
}
} else {
// Then other is not an exception wrapper or an array, just a plain type. The two can
// only unify to IObject and shadow Object
boolean specialTypeIsInterface = specialArray.equals(CommonType.I_OBJECT_ARRAY.dotName) || specialArray.equals(CommonType.I_ARRAY.dotName);
boolean otherTypeIsInterface = this.classHierarchy.postRenameTypeIsInterface(otherType);
if (specialTypeIsInterface || otherTypeIsInterface) {
return CommonType.I_OBJECT.dotName;
} else {
return CommonType.SHADOW_OBJECT.dotName;
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy