/** * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant * pool already contains a similar item. <i>This method is intended for {@link Attribute} sub * classes, and is normally not needed by class generators or adapters.</i> * * @param value the String value. * @return the index of a new or already existing UTF8 item. */ // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). public int newUTF8(final String value) { return symbolTable.addConstantUtf8(value); }
/** * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the * attribute name in the constant pool. * * @return the size in bytes of this symbol table's BootstrapMethods attribute. */ int computeBootstrapMethodsSize() { if (bootstrapMethods != null) { addConstantUtf8(Constants.BOOTSTRAP_METHODS); return 8 + bootstrapMethods.length; } else { return 0; } }
/** * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this * ModuleWriter. Also add the names of these attributes in the constant pool. * * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes. */ int computeAttributesSize() { symbolTable.addConstantUtf8(Constants.MODULE); // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts. int size = 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; if (packageCount > 0) { symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES); // 6 attribute header bytes, and 2 bytes for package_count. size += 8 + packageIndex.length; } if (mainClassIndex > 0) { symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS); // 6 attribute header bytes, and 2 bytes for main_class_index. size += 8; } return size; }
@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); }
@Override public final ModuleVisitor visitModule( final String name, final int access, final String version) { return moduleWriter = new ModuleWriter( symbolTable, symbolTable.addConstantModule(name).index, access, version == null ? 0 : symbolTable.addConstantUtf8(version)); }
@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 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 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 void visitRequire(final String module, final int access, final String version) { requires .putShort(symbolTable.addConstantModule(module).index) .putShort(access) .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version)); requiresCount++; }
/** * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the * 6 attribute header bytes and the num_bootstrap_methods value. * * @param output where the JVMS BootstrapMethods attribute must be put. */ void putBootstrapMethods(final ByteVector output) { if (bootstrapMethods != null) { output .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS)) .putInt(bootstrapMethods.length + 2) .putShort(bootstrapMethodCount) .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); } }
/** * 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 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 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 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); } }