annotation.put12('s', symbolTable.addConstantUtf8((String) value)); } else if (value instanceof Byte) { annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index); } else if (value instanceof Boolean) { int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0; annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index); } else if (value instanceof Character) { annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index); } else if (value instanceof Short) { annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index); } else if (value instanceof Type) { annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor())); } else if (value instanceof byte[]) { byte[] byteArray = (byte[]) value; annotation.put12('[', byteArray.length); for (byte byteValue : byteArray) { annotation.put12('B', symbolTable.addConstantInteger(byteValue).index); annotation.put12('[', booleanArray.length); for (boolean booleanValue : booleanArray) { annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index); annotation.put12('[', shortArray.length); for (short shortValue : shortArray) { annotation.put12('S', symbolTable.addConstantInteger(shortValue).index); annotation.put12('[', charArray.length); for (char charValue : charArray) { annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
@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; } } }
@Override public void visitIntInsn(final int opcode, final int operand) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. if (opcode == Opcodes.SIPUSH) { code.put12(opcode, operand); } else { // BIPUSH or NEWARRAY code.put11(opcode, operand); } // 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, operand, null, null); } else if (opcode != Opcodes.NEWARRAY) { // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY. int size = relativeStackSize + 1; if (size > maxRelativeStackSize) { maxRelativeStackSize = size; } relativeStackSize = size; } } }
code.put12(opcode, fieldrefSymbol.index);
@Override public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. Symbol descSymbol = symbolTable.addConstantClass(descriptor); code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions); // 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( Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable); } else { // No need to update maxRelativeStackSize (the stack size delta is always negative). relativeStackSize += 1 - numDimensions; } } }
@Override public AnnotationVisitor visitArray(final String name) { // Case of an element_value with an array_value field. // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1 ++numElementValuePairs; if (useNamedValues) { annotation.putShort(symbolTable.addConstantUtf8(name)); } // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the // end of an element_value of array type is similar to the end of an 'annotation' structure: an // unsigned short num_values followed by num_values element_value, versus an unsigned short // num_element_value_pairs, followed by num_element_value_pairs { element_name_index, // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to // visit the array elements. Its num_element_value_pairs will correspond to the number of array // elements and will be stored in what is in fact num_values. annotation.put12('[', 0); return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null); }
case CONSTRUCTOR_REFERENCE: case METHOD_REFERENCE: output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8); break; default:
@Override public void visitEnum(final String name, final String descriptor, final String value) { // Case of an element_value with an enum_const_value field. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. ++numElementValuePairs; if (useNamedValues) { annotation.putShort(symbolTable.addConstantUtf8(name)); } annotation .put12('e', symbolTable.addConstantUtf8(descriptor)) .putShort(symbolTable.addConstantUtf8(value)); }
@Override public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { // Case of an element_value with an annotation_value field. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. ++numElementValuePairs; if (useNamedValues) { annotation.putShort(symbolTable.addConstantUtf8(name)); } // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs. annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); return new AnnotationWriter(symbolTable, annotation, null); }
/** * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does * nothing if the constant pool already contains a similar item. * * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link * Symbol#CONSTANT_PACKAGE_TAG}. * @param value an internal class name, an arbitrary string, a method descriptor, a module or a * package name, depending on tag. * @return a new or already existing Symbol with the given value. */ private Symbol addConstantUtf8Reference(final int tag, final String value) { int hashCode = hash(tag, value); Entry entry = get(hashCode); while (entry != null) { if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) { return entry; } entry = entry.next; } constantPool.put12(tag, addConstantUtf8(value)); return put(new Entry(constantPoolCount++, tag, value, hashCode)); }
@Override public void visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. Symbol invokeDynamicSymbol = symbolTable.addConstantInvokeDynamic( name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index); code.putShort(0); // 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(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable); } else { int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes(); int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1; int size = relativeStackSize + stackSizeDelta; if (size > maxRelativeStackSize) { maxRelativeStackSize = size; } relativeStackSize = size; } } }
@Override public void visitIincInsn(final int var, final int increment) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. if ((var > 255) || (increment > 127) || (increment < -128)) { code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment); } else { code.putByte(Opcodes.IINC).put11(var, increment); } // If needed, update the maximum stack size and number of locals, and stack map frames. if (currentBasicBlock != null && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) { currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null); } if (compute != COMPUTE_NOTHING) { int currentMaxLocals = var + 1; if (currentMaxLocals > maxLocals) { maxLocals = currentMaxLocals; } } }
code.putByte(Constants.WIDE).put12(opcode, var); } else { code.put11(opcode, var);
@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; } } }
@Override public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { lastBytecodeOffset = code.length; // Add the instruction to the bytecode of the method. Symbol descSymbol = symbolTable.addConstantClass(descriptor); code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions); // 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( Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable); } else { // No need to update maxRelativeStackSize (the stack size delta is always negative). relativeStackSize += 1 - numDimensions; } } }
@Override public AnnotationVisitor visitArray(final String name) { // Case of an element_value with an array_value field. // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1 ++numElementValuePairs; if (useNamedValues) { annotation.putShort(symbolTable.addConstantUtf8(name)); } // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the // end of an element_value of array type is similar to the end of an 'annotation' structure: an // unsigned short num_values followed by num_values element_value, versus an unsigned short // num_element_value_pairs, followed by num_element_value_pairs { element_name_index, // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to // visit the array elements. Its num_element_value_pairs will correspond to the number of array // elements and will be stored in what is in fact num_values. annotation.put12('[', 0); return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null); }
@Override public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { // Case of an element_value with an annotation_value field. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. ++numElementValuePairs; if (useNamedValues) { annotation.putShort(symbolTable.addConstantUtf8(name)); } // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs. annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); return new AnnotationWriter(symbolTable, annotation, null); }
@Override public void visitEnum(final String name, final String descriptor, final String value) { // Case of an element_value with an enum_const_value field. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. ++numElementValuePairs; if (useNamedValues) { annotation.putShort(symbolTable.addConstantUtf8(name)); } annotation .put12('e', symbolTable.addConstantUtf8(descriptor)) .putShort(symbolTable.addConstantUtf8(value)); }