ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { super(Opcodes.ASM7); this.symbolTable = symbolTable; this.moduleNameIndex = name; this.moduleFlags = access; this.moduleVersionIndex = version; this.requires = new ByteVector(); this.exports = new ByteVector(); this.opens = new ByteVector(); this.usesIndex = new ByteVector(); this.provides = new ByteVector(); this.packageIndex = new ByteVector(); }
/** * Constructs a new, empty SymbolTable for the given ClassWriter. * * @param classWriter a ClassWriter. */ SymbolTable(final ClassWriter classWriter) { this.classWriter = classWriter; this.sourceClassReader = null; this.entries = new Entry[256]; this.constantPoolCount = 1; this.constantPool = new ByteVector(); }
/** * Returns the byte array form of the content of this attribute. The 6 header bytes * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned * ByteVector. * * @param classWriter the class to which this attribute must be added. This parameter can be used * to add the items that corresponds to this attribute to the constant pool of this class. * @param code the bytecode of the method corresponding to this code attribute, or {@literal null} * if this attribute is not a code attribute. Corresponds to the 'code' field of the Code * attribute. * @param codeLength the length of the bytecode of the method corresponding to this code * attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length' * field of the Code attribute. * @param maxStack the maximum stack size of the method corresponding to this code attribute, or * -1 if this attribute is not a code attribute. * @param maxLocals the maximum number of local variables of the method corresponding to this code * attribute, or -1 if this attribute is not a code attribute. * @return the byte array form of this attribute. */ protected ByteVector write( final ClassWriter classWriter, final byte[] code, final int codeLength, final int maxStack, final int maxLocals) { return new ByteVector(content); }
@Override public AnnotationVisitor visitAnnotationDefault() { defaultValue = new ByteVector(); return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null); }
/** * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by * updating the StackMapTable number_of_entries (except if the current frame is the first one, * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}. */ void visitFrameEnd() { if (previousFrame != null) { if (stackMapTableEntries == null) { stackMapTableEntries = new ByteVector(); } putFrame(); ++stackMapTableNumberOfEntries; } previousFrame = currentFrame; currentFrame = null; }
@Override public void visitLineNumber(final int line, final Label start) { if (lineNumberTable == null) { lineNumberTable = new ByteVector(); } ++lineNumberTableLength; lineNumberTable.putShort(start.bytecodeOffset); lineNumberTable.putShort(line); }
@Override public final void visitSource(final String file, final String debug) { if (file != null) { sourceFileIndex = symbolTable.addConstantUtf8(file); } if (debug != null) { debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE); } }
@Override public void visitNestMember(final String nestMember) { if (nestMemberClasses == null) { nestMemberClasses = new ByteVector(); } ++numberOfNestMemberClasses; nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index); }
@Override public void visitParameter(final String name, final int access) { if (parameters == null) { parameters = new ByteVector(); } ++parametersCount; parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access); }
@Override public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { // Create a ByteVector to hold an 'annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. ByteVector annotation = new ByteVector(); // Write type_index and reserve space for num_element_value_pairs. annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastRuntimeVisibleAnnotation = new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); } else { return lastRuntimeInvisibleAnnotation = new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); } }
@Override public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { // Create a ByteVector to hold an 'annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. ByteVector annotation = new ByteVector(); // Write type_index and reserve space for num_element_value_pairs. annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastRuntimeVisibleAnnotation = new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); } else { return lastRuntimeInvisibleAnnotation = new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); } }
@Override public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { // Create a ByteVector to hold an 'annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. ByteVector annotation = new ByteVector(); // Write type_index and reserve space for num_element_value_pairs. annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastRuntimeVisibleAnnotation = new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); } else { return lastRuntimeInvisibleAnnotation = new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); } }
@Override public AnnotationVisitor visitInsnAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { // Create a ByteVector to hold a 'type_annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. ByteVector typeAnnotation = new ByteVector(); // Write target_type, target_info, and target_path. TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation); TypePath.put(typePath, typeAnnotation); // Write type_index and reserve space for num_element_value_pairs. typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastCodeRuntimeVisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); } else { return lastCodeRuntimeInvisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); } }
@Override public AnnotationVisitor visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { // Create a ByteVector to hold a 'type_annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. ByteVector typeAnnotation = new ByteVector(); // Write target_type, target_info, and target_path. TypeReference.putTarget(typeRef, typeAnnotation); TypePath.put(typePath, typeAnnotation); // Write type_index and reserve space for num_element_value_pairs. typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastRuntimeVisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); } else { return lastRuntimeInvisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); } }
@Override public AnnotationVisitor visitTryCatchAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { // Create a ByteVector to hold a 'type_annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. ByteVector typeAnnotation = new ByteVector(); // Write target_type, target_info, and target_path. TypeReference.putTarget(typeRef, typeAnnotation); TypePath.put(typePath, typeAnnotation); // Write type_index and reserve space for num_element_value_pairs. typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastCodeRuntimeVisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); } else { return lastCodeRuntimeInvisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); } }
@Override public AnnotationVisitor visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { // Create a ByteVector to hold a 'type_annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. ByteVector typeAnnotation = new ByteVector(); // Write target_type, target_info, and target_path. TypeReference.putTarget(typeRef, typeAnnotation); TypePath.put(typePath, typeAnnotation); // Write type_index and reserve space for num_element_value_pairs. typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastRuntimeVisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); } else { return lastRuntimeInvisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); } }
@Override public final AnnotationVisitor visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { // Create a ByteVector to hold a 'type_annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. ByteVector typeAnnotation = new ByteVector(); // Write target_type, target_info, and target_path. TypeReference.putTarget(typeRef, typeAnnotation); TypePath.put(typePath, typeAnnotation); // Write type_index and reserve space for num_element_value_pairs. typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); if (visible) { return lastRuntimeVisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); } else { return lastRuntimeInvisibleTypeAnnotation = new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); } }
@Override public final void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { if (innerClasses == null) { innerClasses = new ByteVector(); } // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table // which represents a class or interface C that is not a package member must have exactly one // corresponding entry in the classes array". To avoid duplicates we keep track in the info // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has // already been added for C. If so, we store the index of this inner class entry (plus one) in // the info field. This trick allows duplicate detection in O(1) time. Symbol nameSymbol = symbolTable.addConstantClass(name); if (nameSymbol.info == 0) { ++numberOfInnerClasses; innerClasses.putShort(nameSymbol.index); innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); innerClasses.putShort(access); nameSymbol.info = numberOfInnerClasses; } // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method // and throw an exception if there is a difference? }
@Override public AnnotationVisitor visitParameterAnnotation( final int parameter, final String annotationDescriptor, final boolean visible) { // Create a ByteVector to hold an 'annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. ByteVector annotation = new ByteVector(); // Write type_index and reserve space for num_element_value_pairs. annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0); if (visible) { if (lastRuntimeVisibleParameterAnnotations == null) { lastRuntimeVisibleParameterAnnotations = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; } return lastRuntimeVisibleParameterAnnotations[parameter] = new AnnotationWriter( symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]); } else { if (lastRuntimeInvisibleParameterAnnotations == null) { lastRuntimeInvisibleParameterAnnotations = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; } return lastRuntimeInvisibleParameterAnnotations[parameter] = new AnnotationWriter( symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]); } }
ByteVector typeAnnotation = new ByteVector();