in asm/src/main/java/org/objectweb/asm/Frame.java [1173:1258]
final boolean merge(
final SymbolTable symbolTable, final Frame dstFrame, final int catchTypeIndex) {
boolean frameChanged = false;
// Compute the concrete types of the local variables at the end of the basic block corresponding
// to this frame, by resolving its abstract output types, and merge these concrete types with
// those of the local variables in the input frame of dstFrame.
int numLocal = inputLocals.length;
int numStack = inputStack.length;
if (dstFrame.inputLocals == null) {
dstFrame.inputLocals = new int[numLocal];
frameChanged = true;
}
for (int i = 0; i < numLocal; ++i) {
int concreteOutputType;
if (outputLocals != null && i < outputLocals.length) {
int abstractOutputType = outputLocals[i];
if (abstractOutputType == 0) {
// If the local variable has never been assigned in this basic block, it is equal to its
// value at the beginning of the block.
concreteOutputType = inputLocals[i];
} else {
concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
}
} else {
// If the local variable has never been assigned in this basic block, it is equal to its
// value at the beginning of the block.
concreteOutputType = inputLocals[i];
}
// concreteOutputType might be an uninitialized type from the input locals or from the input
// stack. However, if a constructor has been called for this class type in the basic block,
// then this type is no longer uninitialized at the end of basic block.
if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
}
frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i);
}
// If dstFrame is an exception handler block, it can be reached from any instruction of the
// basic block corresponding to this frame, in particular from the first one. Therefore, the
// input locals of dstFrame should be compatible (i.e. merged) with the input locals of this
// frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one
// element stack containing the caught exception type).
if (catchTypeIndex > 0) {
for (int i = 0; i < numLocal; ++i) {
frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i);
}
if (dstFrame.inputStack == null) {
dstFrame.inputStack = new int[1];
frameChanged = true;
}
frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0);
return frameChanged;
}
// Compute the concrete types of the stack operands at the end of the basic block corresponding
// to this frame, by resolving its abstract output types, and merge these concrete types with
// those of the stack operands in the input frame of dstFrame.
int numInputStack = inputStack.length + outputStackStart;
if (dstFrame.inputStack == null) {
dstFrame.inputStack = new int[numInputStack + outputStackTop];
frameChanged = true;
}
// First, do this for the stack operands that have not been popped in the basic block
// corresponding to this frame, and which are therefore equal to their value in the input
// frame (except for uninitialized types, which may have been initialized).
for (int i = 0; i < numInputStack; ++i) {
int concreteOutputType = inputStack[i];
if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
}
frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i);
}
// Then, do this for the stack operands that have pushed in the basic block (this code is the
// same as the one above for local variables).
for (int i = 0; i < outputStackTop; ++i) {
int abstractOutputType = outputStack[i];
int concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
}
frameChanged |=
merge(symbolTable, concreteOutputType, dstFrame.inputStack, numInputStack + i);
}
return frameChanged;
}