currentBasicBlock.frame.setInputFrameFromDescriptor( symbolTable, accessFlags, descriptor, numLocal); currentBasicBlock.frame.accept(this); } else { if (type == Opcodes.F_NEW) { currentBasicBlock.frame.setInputFrameFromApiFormat( symbolTable, numLocal, local, numStack, stack); currentBasicBlock.frame.accept(this); Frame implicitFirstFrame = new Frame(new Label()); implicitFirstFrame.setInputFrameFromDescriptor( symbolTable, accessFlags, descriptor, argumentsSize); implicitFirstFrame.accept(this); currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]); currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]);
/** * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the * instruction just after the given one. It is assumed that the value of this object when this * method is called is the stack map frame status just before the given instruction is executed. */ @Override void execute( final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) { super.execute(opcode, arg, symbolArg, symbolTable); Frame successor = new Frame(null); merge(symbolTable, successor, 0); copyFrom(successor); } }
String catchTypeDescriptor = handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor; int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor); firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals); firstFrame.accept(this); int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax; if (maxBlockStackSize > maxStackSize) { maxStackSize = maxBlockStackSize; Label successorBlock = outgoingEdge.successor.getCanonicalInstance(); boolean successorBlockChanged = basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info); if (successorBlockChanged && successorBlock.nextListElement == null) { if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) { basicBlock.frame.accept(this); Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable"); visitFrameEnd();
/** * Pushes the abstract type corresponding to the given descriptor on the output frame stack. * * @param symbolTable the type table to use to lookup and store type {@link Symbol}. * @param descriptor a type or method descriptor (in which case its return type is pushed). */ private void push(final SymbolTable symbolTable, final String descriptor) { int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0; int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset); if (abstractType != 0) { push(abstractType); if (abstractType == LONG || abstractType == DOUBLE) { push(TOP); } } }
concreteOutputType = getInitializedType(symbolTable, concreteOutputType); frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i); frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i); frameChanged = true; frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0); return frameChanged; int concreteOutputType = inputStack[i]; if (initializations != null) { concreteOutputType = getInitializedType(symbolTable, concreteOutputType); frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i); concreteOutputType = getInitializedType(symbolTable, concreteOutputType); merge(symbolTable, concreteOutputType, dstFrame.inputStack, numInputStack + i);
break; case Opcodes.ACONST_NULL: push(NULL); break; case Opcodes.ICONST_M1: case Opcodes.SIPUSH: case Opcodes.ILOAD: push(INTEGER); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.LLOAD: push(LONG); push(TOP); break; case Opcodes.FCONST_0: case Opcodes.FCONST_2: case Opcodes.FLOAD: push(FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.DLOAD: push(DOUBLE); push(TOP); break; case Opcodes.LDC:
/** * Ends the current basic block. This method must be used in the case where the current basic * block does not have any successor. * * <p>WARNING: this method must be called after the currently visited instruction has been put in * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic * block after the current instruction). */ private void endCurrentBasicBlockWithNoSuccessor() { if (compute == COMPUTE_ALL_FRAMES) { Label nextBasicBlock = new Label(); nextBasicBlock.frame = new Frame(nextBasicBlock); nextBasicBlock.resolve(code.data, code.length); lastBasicBlock.nextBasicBlock = nextBasicBlock; lastBasicBlock = nextBasicBlock; currentBasicBlock = null; } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; currentBasicBlock = null; } }
@Override public void visitTypeInsn(final int opcode, final String type) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. Symbol typeSymbol = symbolTable.addConstantClass(type); code.put12(opcode, typeSymbol.index); // If needed, update the maximum stack size and number of locals, and stack map frames. if (currentBasicBlock != null) { if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable); } else if (opcode == Opcodes.NEW) { // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF. int size = relativeStackSize + 1; if (size > maxRelativeStackSize) { maxRelativeStackSize = size; } relativeStackSize = size; } } }
break; case Opcodes.ACONST_NULL: push(NULL); break; case Opcodes.ICONST_M1: case Opcodes.SIPUSH: case Opcodes.ILOAD: push(INTEGER); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.LLOAD: push(LONG); push(TOP); break; case Opcodes.FCONST_0: case Opcodes.FCONST_2: case Opcodes.FLOAD: push(FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.DLOAD: push(DOUBLE); push(TOP); break; case Opcodes.LDC:
/** * Pops as many abstract types from the output frame stack as described by the given descriptor. * * @param descriptor a type or method descriptor (in which case its argument types are popped). */ private void pop(final String descriptor) { char firstDescriptorChar = descriptor.charAt(0); if (firstDescriptorChar == '(') { pop((Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1); } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') { pop(2); } else { pop(1); } }
/** * Returns the abstract type corresponding to the given public API frame element type. * * @param symbolTable the type table to use to lookup and store type {@link Symbol}. * @param type a frame element type described using the same format as in {@link * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating * a NEW instruction (for uninitialized types). * @return the abstract type corresponding to the given frame element type. */ static int getAbstractTypeFromApiFormat(final SymbolTable symbolTable, final Object type) { if (type instanceof Integer) { return CONSTANT_KIND | ((Integer) type).intValue(); } else if (type instanceof String) { String descriptor = Type.getObjectType((String) type).getDescriptor(); return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0); } else { return UNINITIALIZED_KIND | symbolTable.addUninitializedType("", ((Label) type).bytecodeOffset); } }
/** * Pushes a new type onto the output frame stack. * * @param cw * the ClassWriter to which this label belongs. * @param desc * the descriptor of the type to be pushed. Can also be a method * descriptor (in this case this method pushes its return type * onto the output frame stack). */ private void push(final ClassWriter cw, final String desc) { int type = type(cw, desc); if (type != 0) { push(type); if (type == LONG || type == DOUBLE) { push(TOP); } } }
t = init(cw, t); changed |= merge(cw, t, frame.inputLocals, i); for (i = 0; i < nLocal; ++i) { t = inputLocals[i]; changed |= merge(cw, t, frame.inputLocals, i); changed = true; changed |= merge(cw, edge, frame.inputStack, 0); return changed; t = inputStack[i]; if (initializations != null) { t = init(cw, t); changed |= merge(cw, t, frame.inputStack, i); t = init(cw, t); changed |= merge(cw, t, frame.inputStack, nInputStack + i);
f.initInputFrame(cw, access, args, this.maxLocals); visitFrame(f); while (e != null) { Label n = e.successor.getFirst(); boolean change = f.merge(cw, n.frame, e.info); if (change && n.next == null) {
int inputLocalIndex = 0; for (int i = 0; i < numLocal; ++i) { inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]); if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) { inputLocals[inputLocalIndex++] = TOP; int inputStackIndex = 0; for (int i = 0; i < numStack; ++i) { inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]); if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { inputStack[inputStackIndex++] = TOP;
break; case Opcodes.ACONST_NULL: push(NULL); break; case Opcodes.ICONST_M1: case Opcodes.SIPUSH: case Opcodes.ILOAD: push(INTEGER); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.LLOAD: push(LONG); push(TOP); break; case Opcodes.FCONST_0: case Opcodes.FCONST_2: case Opcodes.FLOAD: push(FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.DLOAD: push(DOUBLE); push(TOP); break; case Opcodes.LDC:
label.frame = new Frame(label); } else if (compute == COMPUTE_INSERTED_FRAMES) { if (currentBasicBlock == null) {
@Override public void visitInsn(final int opcode) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. code.putByte(opcode); // If needed, update the maximum stack size and number of locals, and stack map frames. if (currentBasicBlock != null) { if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { currentBasicBlock.frame.execute(opcode, 0, null, null); } else { int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; if (size > maxRelativeStackSize) { maxRelativeStackSize = size; } relativeStackSize = size; } if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { endCurrentBasicBlockWithNoSuccessor(); } } }
break; case Opcodes.ACONST_NULL: push(NULL); break; case Opcodes.ICONST_M1: case Opcodes.SIPUSH: case Opcodes.ILOAD: push(INTEGER); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.LLOAD: push(LONG); push(TOP); break; case Opcodes.FCONST_0: case Opcodes.FCONST_2: case Opcodes.FLOAD: push(FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.DLOAD: push(DOUBLE); push(TOP); break; case Opcodes.LDC:
/** * Pushes the abstract type corresponding to the given descriptor on the output frame stack. * * @param symbolTable the type table to use to lookup and store type {@link Symbol}. * @param descriptor a type or method descriptor (in which case its return type is pushed). */ private void push(final SymbolTable symbolTable, final String descriptor) { int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0; int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset); if (abstractType != 0) { push(abstractType); if (abstractType == LONG || abstractType == DOUBLE) { push(TOP); } } }