/*
* Copyright ( C ) 2007 The Android Open Source Project
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
package com.android.dx.cf.code;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeBearer;
import com.android.dx.util.Hex;
/**
* Utility methods to merge various frame information .
*/
public final class Merger {
/**
* This class is uninstantiable .
*/
private Merger() {
// This space intentionally left blank.
}
/**
* Merges two locals arrays . If the merged result is the same as the first
* argument , then return the first argument ( not a copy ) .
*
* @ param locals1 { @ code non - null ; } a locals array
* @ param locals2 { @ code non - null ; } another locals array
* @ return { @ code non - null ; } the result of merging the two locals arrays
*/
public static OneLocalsArray mergeLocals(OneLocalsArray locals1,
OneLocalsArray locals2) {
if (locals1 == locals2) {
// Easy out.
return locals1;
}
int sz = locals1.getMaxLocals();
OneLocalsArray result = null ;
if (locals2.getMaxLocals() != sz) {
throw new SimException("mismatched maxLocals values" );
}
for (int i = 0 ; i < sz; i++) {
TypeBearer tb1 = locals1.getOrNull(i);
TypeBearer tb2 = locals2.getOrNull(i);
TypeBearer resultType = mergeType(tb1, tb2);
if (resultType != tb1) {
/*
* We only need to do anything when the result differs
* from what is in the first array , since that ' s what the
* result gets initialized to .
*/
if (result == null ) {
result = locals1.copy();
}
if (resultType == null ) {
result.invalidate(i);
} else {
result.set(i, resultType);
}
}
}
if (result == null ) {
return locals1;
}
result.setImmutable();
return result;
}
/**
* Merges two stacks . If the merged result is the same as the first
* argument , then return the first argument ( not a copy ) .
*
* @ param stack1 { @ code non - null ; } a stack
* @ param stack2 { @ code non - null ; } another stack
* @ return { @ code non - null ; } the result of merging the two stacks
*/
public static ExecutionStack mergeStack(ExecutionStack stack1,
ExecutionStack stack2) {
if (stack1 == stack2) {
// Easy out.
return stack1;
}
int sz = stack1.size();
ExecutionStack result = null ;
if (stack2.size() != sz) {
throw new SimException("mismatched stack depths" );
}
for (int i = 0 ; i < sz; i++) {
TypeBearer tb1 = stack1.peek(i);
TypeBearer tb2 = stack2.peek(i);
TypeBearer resultType = mergeType(tb1, tb2);
if (resultType != tb1) {
/*
* We only need to do anything when the result differs
* from what is in the first stack , since that ' s what the
* result gets initialized to .
*/
if (result == null ) {
result = stack1.copy();
}
try {
if (resultType == null ) {
throw new SimException("incompatible: " + tb1 + ", " +
tb2);
} else {
result.change(i, resultType);
}
} catch (SimException ex) {
ex.addContext("...while merging stack[" + Hex.u2(i) + "]" );
throw ex;
}
}
}
if (result == null ) {
return stack1;
}
result.setImmutable();
return result;
}
/**
* Merges two frame types .
*
* @ param ft1 { @ code non - null ; } a frame type
* @ param ft2 { @ code non - null ; } another frame type
* @ return { @ code non - null ; } the result of merging the two types
*/
public static TypeBearer mergeType(TypeBearer ft1, TypeBearer ft2) {
if ((ft1 == null ) || ft1.equals(ft2)) {
return ft1;
} else if (ft2 == null ) {
return null ;
} else {
Type type1 = ft1.getType();
Type type2 = ft2.getType();
if (type1 == type2) {
return type1;
} else if (type1.isReference() && type2.isReference()) {
if (type1 == Type.KNOWN_NULL) {
/*
* A known - null merges with any other reference type to
* be that reference type .
*/
return type2;
} else if (type2 == Type.KNOWN_NULL) {
/*
* The same as above , but this time it ' s type2 that ' s
* the known - null .
*/
return type1;
} else if (type1.isArray() && type2.isArray()) {
TypeBearer componentUnion =
mergeType(type1.getComponentType(),
type2.getComponentType());
if (componentUnion == null ) {
/*
* At least one of the types is a primitive type ,
* so the merged result is just Object .
*/
return Type.OBJECT;
}
return ((Type) componentUnion).getArrayType();
} else {
/*
* All other unequal reference types get merged to be
* Object in this phase . This is fine here , but it
* won ' t be the right thing to do in the verifier .
*/
return Type.OBJECT;
}
} else if (type1.isIntlike() && type2.isIntlike()) {
/*
* Merging two non - identical int - like types results in
* the type int .
*/
return Type.INT ;
} else {
return null ;
}
}
}
/**
* Returns whether the given supertype is possibly assignable from
* the given subtype . This takes into account primitiveness ,
* int - likeness , known - nullness , and array dimensions , but does
* not assume anything about class hierarchy other than that the
* type { @ code Object } is the supertype of all reference
* types and all arrays are assignable to
* { @ code Serializable } and { @ code Cloneable } .
*
* @ param supertypeBearer { @ code non - null ; } the supertype
* @ param subtypeBearer { @ code non - null ; } the subtype
*/
public static boolean isPossiblyAssignableFrom(TypeBearer supertypeBearer,
TypeBearer subtypeBearer) {
Type supertype = supertypeBearer.getType();
Type subtype = subtypeBearer.getType();
if (supertype.equals(subtype)) {
// Easy out.
return true ;
}
int superBt = supertype.getBasicType();
int subBt = subtype.getBasicType();
// Treat return types as Object for the purposes of this method.
if (superBt == Type.BT_ADDR) {
supertype = Type.OBJECT;
superBt = Type.BT_OBJECT;
}
if (subBt == Type.BT_ADDR) {
subtype = Type.OBJECT;
subBt = Type.BT_OBJECT;
}
if ((superBt != Type.BT_OBJECT) || (subBt != Type.BT_OBJECT)) {
/*
* No two distinct primitive types are assignable in this sense ,
* unless they are both int - like .
*/
return supertype.isIntlike() && subtype.isIntlike();
}
// At this point, we know both types are reference types.
if (supertype == Type.KNOWN_NULL) {
/*
* A known - null supertype is only assignable from another
* known - null ( handled in the easy out at the top of the
* method ) .
*/
return false ;
} else if (subtype == Type.KNOWN_NULL) {
/*
* A known - null subtype is in fact assignable to any
* reference type .
*/
return true ;
} else if (supertype == Type.OBJECT) {
/*
* Object is assignable from any reference type .
*/
return true ;
} else if (supertype.isArray()) {
// The supertype is an array type.
if (! subtype.isArray()) {
// The subtype isn't an array, and so can't be assignable.
return false ;
}
/*
* Strip off as many matched component types from both
* types as possible , and check the assignability of the
* results .
*/
do {
supertype = supertype.getComponentType();
subtype = subtype.getComponentType();
} while (supertype.isArray() && subtype.isArray());
return isPossiblyAssignableFrom(supertype, subtype);
} else if (subtype.isArray()) {
/*
* Other than Object ( handled above ) , array types are
* assignable only to Serializable and Cloneable .
*/
return (supertype == Type.SERIALIZABLE) ||
(supertype == Type.CLONEABLE);
} else {
/*
* All other unequal reference types are considered at
* least possibly assignable .
*/
return true ;
}
}
}
Messung V0.5 in Prozent C=94 H=95 G=94
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-27)
¤
*© Formatika GbR, Deutschland