// $Id: class.h,v 1.44 2004/05/03 13:24:40 elliott-oss Exp $ -*- c++ -*- // // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://ibm.com/developerworks/opensource/jikes. // Copyright (C) 1996, 2004 IBM Corporation and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // #ifndef class_INCLUDED #define class_INCLUDED #include "platform.h" #include "access.h" #include "tuple.h" #include "long.h" #include "double.h" #ifdef HAVE_JIKES_NAMESPACE namespace Jikes { // Open namespace Jikes block #endif // // This header defines the .class file format, for both reading in and writing // out valid classfiles. // class ClassFile; class ConstantPool; class Control; class TypeSymbol; // // The prefix CP stands for Constant Pool. This is the base class of all // constant pool information; subclasses give more detail. JVMS 4.4. // class CPInfo { public: enum ConstantPoolTag { CONSTANT_Class = 7, CONSTANT_Fieldref = 9, CONSTANT_Methodref = 10, CONSTANT_InterfaceMethodref = 11, CONSTANT_String = 8, CONSTANT_Integer = 3, CONSTANT_Float = 4, CONSTANT_Long = 5, CONSTANT_Double = 6, CONSTANT_NameAndType = 12, CONSTANT_Utf8 = 1 }; protected: const ConstantPoolTag tag; public: CPInfo(ConstantPoolTag _tag) : tag(_tag) {} virtual ~CPInfo() {} ConstantPoolTag Tag() const { return tag; } bool Large() const { return tag == CONSTANT_Long || tag == CONSTANT_Double; } bool Constant() const { return ((tag >= CPInfo::CONSTANT_Integer && tag <= CPInfo::CONSTANT_Double) || tag == CPInfo::CONSTANT_String); } // // This reads the next constant pool entry from buffer, advancing it to // the end of the entry. The user is responsible for deleting the result. // static CPInfo* AllocateCPInfo(ClassFile&); // // Subclasses should override, to write an entry to a .class file. // virtual void Put(OutputBuffer& out) const { out.PutU1((u1) tag); } // // Allows subclasses to perform data validation, once the entire constant // pool has been read. Return false on failure. // virtual bool Check(const ConstantPool&) const { return true; } #ifdef JIKES_DEBUG // // Prints all information about the constant value, ending the line. // virtual void Print(const ConstantPool&) const { Coutput << "unknown tag: " << (unsigned) tag << endl; } // // Prints shortened information, no newline. // virtual void Describe(const ConstantPool&) const { Coutput << "unknown tag: " << (unsigned) tag; } #endif // JIKES_DEBUG }; // // Specialization of Tuple to more gracefully handle invalid indices. This // is because slot 0 and slots following a long or double entry are invalid. // class ConstantPool : private Tuple { class CPInvalid : public CPInfo { public: CPInvalid() : CPInfo((ConstantPoolTag) 0) {} ~CPInvalid() {} virtual void Put(OutputBuffer&) const { assert(false && "trying to put invalid ConstantPool entry"); } virtual bool Check(const ConstantPool&) const { return false; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool&) const { Coutput << "invalid index" << endl; } virtual void Describe(const ConstantPool&) const { Coutput << "(invalid)"; } #endif // JIKES_DEBUG } invalid; public: ConstantPool(unsigned estimate = 0) : Tuple(estimate) { Next() = NULL; // The 0th entry is unused. } ConstantPool(unsigned log_blksize, unsigned base_increment) : Tuple(log_blksize, base_increment) { Next() = NULL; // The 0th entry is unused. } ~ConstantPool() {} // Inherit only the methods we know are safe. using Tuple::Length; using Tuple::SpaceAllocated; using Tuple::SpaceUsed; // // Note that unlike in Tuple<>, ConstantPool[] does not return an lvalue; // use SetNext(CPInfo*) instead. // inline const CPInfo* operator[](const unsigned i) const { if (i >= top) return &invalid; const CPInfo* result = Tuple::operator[](i); return result ? result : &invalid; } inline void Reset() { Tuple::Reset(); } void SetNext(CPInfo*); inline bool Valid(const unsigned i) { return i < top && Tuple::operator[](i); } bool Check() const; }; // // Describes a UTF8 sequence. JVMS 4.4.7. // class CPUtf8Info : public CPInfo { // u1 tag; // inherited from CPInfo const u2 len; u1* bytes; // bytes[length] bool valid; public: CPUtf8Info(const char* _bytes, unsigned length) : CPInfo(CONSTANT_Utf8) , len(length) , valid(true) { bytes = new u1[len + 1]; for (unsigned i = 0; i < len; i++) bytes[i] = (u1) _bytes[i]; bytes[len] = U_NULL; Init(len); assert(valid && length <= 0xffff); } CPUtf8Info(ClassFile&); virtual ~CPUtf8Info() { delete [] bytes; } // // If this UTF8 was valid, then Bytes returns a NULL-terminated string // that can be passed to strcmp() and friends, since Java's modified UTF8 // encoding ensures there are no embedded \0. However, since we already // know Length(), calling strlen() on the result is inefficient. // const char* Bytes() const { return (const char*) bytes; } u2 Length() const { return len; } virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU2(len); out.PutN(bytes, len); } virtual bool Check(const ConstantPool&) const { return valid; } private: void Init(u2); #ifdef JIKES_DEBUG // // When debugging, contents represents the String literal (less the // enclosing "") made of printing ASCII characters that will regenerate // the same sequence of bytes, provided the UTF8 was valid. Otherwise it // contains some hints as to where the UTF8 went wrong. It is a // NULL-terminated sequence, with no embedded NULLs. // ConvertibleArray contents; public: virtual void Print(const ConstantPool&) const { Coutput << "Utf8: length: " << (unsigned) len << ", bytes[]: " << contents.Array() << endl; } virtual void Describe(const ConstantPool&) const { Coutput << contents.Array(); } #endif // JIKES_DEBUG }; // // Describes a class or interface name. JVMS 4.4.1. // class CPClassInfo : public CPInfo { // u1 tag; // inherited from CPInfo const u2 name_index; TypeSymbol* type; // the associated type public: CPClassInfo(u2 _name_index) : CPInfo(CONSTANT_Class) , name_index(_name_index) , type(NULL) {} CPClassInfo(ClassFile&); virtual ~CPClassInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU2(name_index); } virtual bool Check(const ConstantPool& constant_pool) const { return constant_pool[name_index] -> Tag() == CONSTANT_Utf8; } const char* TypeName(const ConstantPool& constant_pool) const { assert(constant_pool[name_index] -> Tag() == CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[name_index]) -> Bytes(); } u2 TypeNameLength(const ConstantPool& constant_pool) const { assert(constant_pool[name_index] -> Tag() == CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[name_index]) -> Length(); } void SetType(TypeSymbol* t) { assert(! type); type = t; } TypeSymbol* Type() { return type; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool) const { Coutput << "Class: name: " << (unsigned) name_index; if (constant_pool[name_index] -> Tag() == CONSTANT_Utf8) { Coutput << "=\""; constant_pool[name_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; Coutput << endl; } virtual void Describe(const ConstantPool& constant_pool) const { if (constant_pool[name_index] -> Tag() == CONSTANT_Utf8) constant_pool[name_index] -> Describe(constant_pool); else Coutput << "(invalid)"; } #endif // JIKES_DEBUG }; // // Describes a field or method's declaring class, name, and type. JVMS 4.4.2. // class CPMemberInfo : public CPInfo { // u1 tag; // inherited from CPInfo const u2 class_index; const u2 name_and_type_index; public: CPMemberInfo(ConstantPoolTag _tag, u2 _class_index, u2 _name_and_type_index) : CPInfo(_tag) , class_index(_class_index) , name_and_type_index(_name_and_type_index) {} CPMemberInfo(ConstantPoolTag, ClassFile&); virtual ~CPMemberInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU2(class_index); out.PutU2(name_and_type_index); } virtual bool Check(const ConstantPool& constant_pool) const { return constant_pool[class_index] -> Tag() == CONSTANT_Class && (constant_pool[name_and_type_index] -> Tag() == CONSTANT_NameAndType); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool) const { switch (tag) { case CONSTANT_Fieldref: Coutput << "Field"; break; case CONSTANT_InterfaceMethodref: Coutput << "Interface"; // fallthrough case CONSTANT_Methodref: Coutput << "Method"; break; default: assert(false && "bad constant pool member tag"); } Coutput << ": class: " << (unsigned) class_index; if (constant_pool[class_index] -> Tag() == CONSTANT_Class) { Coutput << '='; constant_pool[class_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl << " name_and_type: " << (unsigned) name_and_type_index; if (constant_pool[name_and_type_index] -> Tag() == CONSTANT_NameAndType) { Coutput << "=<"; constant_pool[name_and_type_index] -> Describe(constant_pool); Coutput << ">"; } else Coutput << "(invalid)"; Coutput << endl; } virtual void Describe(const ConstantPool& constant_pool) const { if (constant_pool[class_index] -> Tag() == CONSTANT_Class) constant_pool[class_index] -> Describe(constant_pool); else Coutput << "(invalid)"; Coutput << "."; if (constant_pool[name_and_type_index] -> Tag() == CONSTANT_NameAndType) { constant_pool[name_and_type_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; } #endif // JIKES_DEBUG }; // // Describes a String literal. JVMS 4.4.3. // class CPStringInfo : public CPInfo { // u1 tag; // inherited from CPInfo const u2 string_index; public: CPStringInfo(u2 _string_index) : CPInfo(CONSTANT_String) , string_index(_string_index) {} CPStringInfo(ClassFile&); virtual ~CPStringInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU2(string_index); } virtual bool Check(const ConstantPool& constant_pool) const { return constant_pool[string_index] -> Tag() == CONSTANT_Utf8; } const char* Bytes(const ConstantPool& constant_pool) const { assert(constant_pool[string_index] -> Tag() == CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[string_index]) -> Bytes(); } u2 Length(const ConstantPool& constant_pool) const { assert(constant_pool[string_index] -> Tag() == CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[string_index]) -> Length(); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool) const { Coutput << "String: string: " << (unsigned) string_index; if (constant_pool[string_index] -> Tag() == CONSTANT_Utf8) { Coutput << "=\""; constant_pool[string_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; Coutput << endl; } virtual void Describe(const ConstantPool& constant_pool) const { if (constant_pool[string_index] -> Tag() == CONSTANT_Utf8) { Coutput << '"'; constant_pool[string_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; } #endif // JIKES_DEBUG }; // // Describes an int literal. JVMS 4.4.4. // class CPIntegerInfo : public CPInfo { // u1 tag; // inherited from CPInfo const u4 bytes; public: CPIntegerInfo(u4 _bytes) : CPInfo(CONSTANT_Integer) , bytes(_bytes) {} CPIntegerInfo(ClassFile&); virtual ~CPIntegerInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU4(bytes); } i4 Value() const { return (i4) bytes; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool&) const { Coutput << "Integer: bytes: 0x" << IntToString(bytes, 8).String() << " (" << (int) bytes << ')' << endl; } virtual void Describe(const ConstantPool&) const { Coutput << (int) bytes; } #endif // JIKES_DEBUG }; // // Describes a float literal. JVMS 4.4.4. // class CPFloatInfo : public CPInfo { // u1 tag; // inherited from CPInfo const IEEEfloat value; // u4 bytes public: CPFloatInfo(u4 bytes) : CPInfo(CONSTANT_Float) , value(bytes) {} CPFloatInfo(ClassFile&); virtual ~CPFloatInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU4(value.Word()); } const IEEEfloat& Value() const { return value; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool&) const { Coutput << "Float: bytes: 0x" << IntToString(value.Word(), 8).String() << " (" << FloatToString(value).String() << "F)" << endl; } virtual void Describe(const ConstantPool&) const { Coutput << FloatToString(value).String() << 'F'; } #endif // JIKES_DEBUG }; // // Describes a long literal. JVMS 4.4.5. // class CPLongInfo : public CPInfo { // u1 tag; // inherited from CPInfo const LongInt value; // u4 high_bytes, low_bytes; public: CPLongInfo(u4 high_bytes, u4 low_bytes) : CPInfo(CONSTANT_Long) , value(high_bytes, low_bytes) {} CPLongInfo(ClassFile&); virtual ~CPLongInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU4(value.HighWord()); out.PutU4(value.LowWord()); } const LongInt& Value() const { return value; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool&) const { Coutput << "Long: high: 0x" << IntToString(value.HighWord(), 8).String() << ", low: 0x" << IntToString(value.LowWord(), 8).String() << " (" << LongToString(value).String() << "L)" << endl; } virtual void Describe(const ConstantPool&) const { Coutput << LongToString(value).String() << 'L'; } #endif // JIKES_DEBUG }; // // Describes a double literal. JVMS 4.4.5. // class CPDoubleInfo : public CPInfo { // u1 tag; // inherited from CPInfo const IEEEdouble value; // u4 high_bytes, low_bytes; public: CPDoubleInfo(u4 high_bytes, u4 low_bytes) : CPInfo(CONSTANT_Double) , value(high_bytes, low_bytes) {} CPDoubleInfo(ClassFile&); virtual ~CPDoubleInfo() {} virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU4(value.HighWord()); out.PutU4(value.LowWord()); } const IEEEdouble& Value() const { return value; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool&) const { Coutput << "Double: high: 0x" << IntToString(value.HighWord(), 8).String() << ", low: 0x" << IntToString(value.LowWord(), 8).String() << " (" << DoubleToString(value).String() << ')' << endl; } virtual void Describe(const ConstantPool&) const { Coutput << DoubleToString(value).String(); } #endif // JIKES_DEBUG }; // // Describes a member name and its signature. JVMS 4.4.6. // class CPNameAndTypeInfo : public CPInfo { // u1 tag; // inherited from CPInfo const u2 name_index; const u2 descriptor_index; public: CPNameAndTypeInfo(u2 _name_index, u2 _descriptor_index) : CPInfo(CONSTANT_NameAndType) , name_index(_name_index) , descriptor_index(_descriptor_index) {} CPNameAndTypeInfo(ClassFile&); virtual ~CPNameAndTypeInfo() {} const char* Signature(const ConstantPool& constant_pool) const { assert(constant_pool[descriptor_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[descriptor_index]) -> Bytes(); } u2 SignatureLength(const ConstantPool& constant_pool) const { assert(constant_pool[descriptor_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[descriptor_index]) -> Length(); } virtual void Put(OutputBuffer& out) const { CPInfo::Put(out); out.PutU2(name_index); out.PutU2(descriptor_index); } virtual bool Check(const ConstantPool& constant_pool) const { return constant_pool[name_index] -> Tag() == CONSTANT_Utf8 && constant_pool[descriptor_index] -> Tag() == CONSTANT_Utf8; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool) const { Coutput << "NameAndType: name: " << (unsigned) name_index; if (constant_pool[name_index] -> Tag() == CONSTANT_Utf8) { Coutput << "=\""; constant_pool[name_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; Coutput << endl << " type: " << (unsigned) descriptor_index; if (constant_pool[descriptor_index] -> Tag() == CONSTANT_Utf8) { Coutput << "=\""; constant_pool[descriptor_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; Coutput << endl; } virtual void Describe(const ConstantPool& constant_pool) const { if (constant_pool[name_index] -> Tag() == CONSTANT_Utf8) constant_pool[name_index] -> Describe(constant_pool); else Coutput << "(invalid)"; Coutput << " "; if (constant_pool[descriptor_index] -> Tag() == CONSTANT_Utf8) constant_pool[descriptor_index] -> Describe(constant_pool); else Coutput << "(invalid)"; } #endif // JIKES_DEBUG }; // // FieldInfo and MethodInfo come next in the JVMS, but must appear after // we know about attributes. // class FieldInfo; class MethodInfo; // // Describes an arbitrary attribute. We subclass this for known attributes. // class AttributeInfo { public: enum AttributeInfoTag { ATTRIBUTE_ConstantValue, ATTRIBUTE_Code, ATTRIBUTE_Exceptions, ATTRIBUTE_InnerClasses, ATTRIBUTE_Synthetic, ATTRIBUTE_SourceFile, ATTRIBUTE_LineNumberTable, ATTRIBUTE_LocalVariableTable, ATTRIBUTE_Deprecated, ATTRIBUTE_Signature, // defined in JSR 14 ATTRIBUTE_Bridge, // defined in JSR 14? ATTRIBUTE_EnclosingMethod, // defined in JSR 14 ATTRIBUTE_LocalVariableTypeTable, // defined in JSR 14 ATTRIBUTE_StackMap, // defined in JSR 139 ATTRIBUTE_RuntimeVisibleAnnotations, // defined in JSR 175 ATTRIBUTE_RuntimeInvisibleAnnotations, // defined in JSR 175 ATTRIBUTE_RuntimeVisibleParameterAnnotations, // defined in JSR 175 ATTRIBUTE_RuntimeInvisibleParameterAnnotations, // defined in JSR 175 ATTRIBUTE_AnnotationDefault, // defined in JSR 175 // all others are currently unknown to jikes ATTRIBUTE_Generic }; protected: const AttributeInfoTag tag; const u2 attribute_name_index; u4 attribute_length; AttributeInfo(AttributeInfoTag _tag, u2 _name_index, u4 length = 0) : tag(_tag) , attribute_name_index(_name_index) , attribute_length(length) { assert(tag != ATTRIBUTE_Generic); } AttributeInfo(AttributeInfoTag, ClassFile&); public: virtual ~AttributeInfo() {} AttributeInfoTag Tag() const { return tag; } u2 AttributeNameIndex() const { return attribute_name_index; } u4 AttributeLength() const { return attribute_length; } static AttributeInfoTag Tag(const CPUtf8Info* name); // // This reads the next attribute from the buffer, advancing it to the // end of the attribute. The user is responsible for deleting the result. // static AttributeInfo* AllocateAttributeInfo(ClassFile&); // Subclasses must override if attribute_length != 0. virtual void Put(OutputBuffer& out) const { assert(tag != ATTRIBUTE_Generic); assert(attribute_name_index); out.PutU2(attribute_name_index); out.PutU4(attribute_length); } #ifdef JIKES_DEBUG void PrintPrefix(const char* category, const ConstantPool& constant_pool, int fill) const { Coutput.width(fill); Coutput << "" << category << ": name: " << (unsigned) attribute_name_index; if (constant_pool[attribute_name_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << "=\""; constant_pool[attribute_name_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; Coutput << ", length: " << (unsigned) attribute_length; } virtual void Print(const ConstantPool& constant_pool, int fill = 0) const = 0; #endif // JIKES_DEBUG }; // // An unknown attribute - we are allowed to read them from existing .class // files, but should never generate or write one. // class UnknownAttribute : public AttributeInfo { u1* info; // u1 info[attribute_length]; u4 info_length; // in corrupted file, info_length < attribute_length public: UnknownAttribute(ClassFile&); virtual ~UnknownAttribute() { delete [] info; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill) const { PrintPrefix("Unrecognized attribute", constant_pool, fill); Coutput << endl; Coutput.width(fill); Coutput << "" << " info: " << (unsigned) info_length << ' '; for (unsigned i = 0; i < info_length; i++) if (info[i] <= 0x20 || info[i] >= 0x7f) Coutput << "\\x" << IntToString(info[i], 2).String(); else Coutput << (char) info[i]; Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid only on final fields, this marks the initial value of a constant // variable. JVMS 4.7.2. // class ConstantValueAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo const u2 constantvalue_index; public: ConstantValueAttribute(u2 _name_index, u2 _constantvalue_index) : AttributeInfo(ATTRIBUTE_ConstantValue, _name_index, 2) , constantvalue_index(_constantvalue_index) {} ConstantValueAttribute(ClassFile&); virtual ~ConstantValueAttribute() {} virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(constantvalue_index); } const CPInfo* Value(const ConstantPool& constant_pool) const { assert(constant_pool[constantvalue_index] -> Constant()); return constant_pool[constantvalue_index]; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("ConstantValue", constant_pool, 0); Coutput << ", value: " << (unsigned) constantvalue_index << " ("; if (constant_pool[constantvalue_index] -> Constant()) { constant_pool[constantvalue_index] -> Describe(constant_pool); } else Coutput << "invalid"; Coutput << ')' << endl; } #endif // JIKES_DEBUG }; // // Valid only on methods, this is the throws clause. JVMS 4.7.4. // class ExceptionsAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // u2 number_of_exceptions; // computed as exception_index_table.Length() // exception_index_table[number_of_exceptions] Tuple exception_index_table; public: ExceptionsAttribute(u2 _name_index) : AttributeInfo(ATTRIBUTE_Exceptions, _name_index, 2) // +2 for number_of_exceptions , exception_index_table(6, 16) {} ExceptionsAttribute(ClassFile&); virtual ~ExceptionsAttribute() {} u2 NumberOfExceptions() const { return exception_index_table.Length(); } const CPClassInfo* Exception(u2 i, const ConstantPool& constant_pool) const { assert(constant_pool[exception_index_table[i]] -> Tag() == CPInfo::CONSTANT_Class); return (const CPClassInfo*) constant_pool[exception_index_table[i]]; } void AddExceptionIndex(u2 index) { attribute_length += 2; exception_index_table.Next() = index; } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(exception_index_table.Length()); for (unsigned i = 0; i < exception_index_table.Length(); i++) out.PutU2(exception_index_table[i]); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("Exceptions", constant_pool, 0); Coutput << ", count: " << (unsigned) exception_index_table.Length() << endl; for (unsigned i = 0; i < exception_index_table.Length(); i++) { Coutput << " " << (unsigned) exception_index_table[i]; if (constant_pool[exception_index_table[i]] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[exception_index_table[i]] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl; } } #endif // JIKES_DEBUG }; // // Valid only on classes, this lists information about all nested classes // mentioned in the constant pool. JVMS 4.7.5. // class InnerClassesAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // u2 number_of_classes; // computed as classes.Length() struct InnerClassesElement { u2 inner_class_info_index; u2 outer_class_info_index; u2 inner_name_index; AccessFlags inner_class_access_flags; // u2 inner_class_access_flags; }; Tuple classes; // classes[number_of_classes] public: InnerClassesAttribute(u2 _name_index) : AttributeInfo(ATTRIBUTE_InnerClasses, _name_index, 2) // +2 for number_of_classes , classes(6, 16) {} InnerClassesAttribute(ClassFile&); virtual ~InnerClassesAttribute() {} u2 InnerClassesLength() const { return classes.Length();} void AddInnerClass(u2 inner_class_info_index, u2 outer_class_info_index, u2 inner_name_index, AccessFlags inner_class_flags) { attribute_length += 8; InnerClassesElement& entry = classes.Next(); entry.inner_class_info_index = inner_class_info_index; entry.outer_class_info_index = outer_class_info_index; entry.inner_name_index = inner_name_index; entry.inner_class_access_flags.SetFlags(inner_class_flags); } const CPClassInfo* Inner(u2 i, const ConstantPool& constant_pool) const { assert(constant_pool[classes[i].inner_class_info_index] -> Tag() == CPInfo::CONSTANT_Class); return (const CPClassInfo*) constant_pool[classes[i].inner_class_info_index]; } const CPClassInfo* Outer(u2 i, const ConstantPool& constant_pool) const { assert(! classes[i].outer_class_info_index || (constant_pool[classes[i].outer_class_info_index] -> Tag() == CPInfo::CONSTANT_Class)); return classes[i].outer_class_info_index ? ((const CPClassInfo*) constant_pool[classes[i].outer_class_info_index]) : (const CPClassInfo*) NULL; } const char* Name(u2 i, const ConstantPool& constant_pool) const { assert(! classes[i].inner_name_index || (constant_pool[classes[i].inner_name_index] -> Tag() == CPInfo::CONSTANT_Utf8)); if (! classes[i].inner_name_index) return NULL; return ((const CPUtf8Info*) constant_pool[classes[i].inner_name_index]) -> Bytes(); } u2 NameLength(u2 i, const ConstantPool& constant_pool) const { assert(! classes[i].inner_name_index || (constant_pool[classes[i].inner_name_index] -> Tag() == CPInfo::CONSTANT_Utf8)); return classes[i].inner_name_index ? ((const CPUtf8Info*) constant_pool[classes[i].inner_name_index]) -> Length() : 0; } const AccessFlags& Flags(u2 i) const { return classes[i].inner_class_access_flags; } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(classes.Length()); for (unsigned i = 0; i < classes.Length(); i++) { out.PutU2(classes[i].inner_class_info_index); out.PutU2(classes[i].outer_class_info_index); out.PutU2(classes[i].inner_name_index); out.PutU2(classes[i].inner_class_access_flags.Flags()); } } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("InnerClasses", constant_pool, 0); Coutput << ", count: " << (unsigned) classes.Length() << endl; for (unsigned i = 0; i < classes.Length(); i++) { Coutput << " inner: " << (unsigned) classes[i].inner_class_info_index; if (constant_pool[classes[i].inner_class_info_index] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[classes[i].inner_class_info_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << ", outer: " << (unsigned) classes[i].outer_class_info_index; if (! classes[i].outer_class_info_index) Coutput << "(inner is local)"; else if (constant_pool[classes[i].outer_class_info_index] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[classes[i].outer_class_info_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl << " name: " << (unsigned) classes[i].inner_name_index; if (! classes[i].inner_name_index) Coutput << "(anonymous)"; else if (constant_pool[classes[i].inner_name_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[classes[i].inner_name_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << ", "; classes[i].inner_class_access_flags. Print(AccessFlags::ACCESS_TYPE); } } #endif // JIKES_DEBUG }; // // Valid for classes, methods, and fields, this marks a compiler-generated // entity that has no counterpart in source. JVMS 4.7.6. // class SyntheticAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo public: SyntheticAttribute(u2 _name_index) : AttributeInfo(ATTRIBUTE_Synthetic, _name_index) {} SyntheticAttribute(ClassFile&); virtual ~SyntheticAttribute() {} #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("Synthetic", constant_pool, 0); Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid only for classes, this names the source file. JVMS 4.7.7. // class SourceFileAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo const u2 sourcefile_index; public: SourceFileAttribute(u2 _name_index, u2 _sourcefile_index) : AttributeInfo(ATTRIBUTE_SourceFile, _name_index, 2) , sourcefile_index(_sourcefile_index) {} SourceFileAttribute(ClassFile&); virtual ~SourceFileAttribute() {} const char* SourceFile(const ConstantPool& constant_pool) const { assert(constant_pool[sourcefile_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((CPUtf8Info*) constant_pool[sourcefile_index]) -> Bytes(); } u2 SourceFileLength(const ConstantPool& constant_pool) const { assert(constant_pool[sourcefile_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((CPUtf8Info*) constant_pool[sourcefile_index]) -> Length(); } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(sourcefile_index); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("SourceFile", constant_pool, 0); Coutput << ", name: " << (unsigned) sourcefile_index; if (constant_pool[sourcefile_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << "=\""; constant_pool[sourcefile_index] -> Describe(constant_pool); Coutput << '"'; } else Coutput << "(invalid)"; Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid only for code, this correlates bytecode offsets to source file line // numbers. JVMS 4.7.8. // class LineNumberTableAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // u2 line_number_table_length; // computed as line_number_table.Length() struct LineNumberElement { u2 start_pc; u2 line_number; }; // line_number_table[line_number_table_length] Tuple line_number_table; public: LineNumberTableAttribute(u2 _name_index) : AttributeInfo(ATTRIBUTE_LineNumberTable, _name_index, 2) // +2 for line_number_table_length , line_number_table(6, 16) {} LineNumberTableAttribute(ClassFile&); virtual ~LineNumberTableAttribute() {} u2 LineNumberTableLength() const { return line_number_table.Length(); } void AddLineNumber(u2 start_pc, u2 line_number) { if (line_number_table.Length() > 1) { LineNumberElement& other = line_number_table.Top(); if (start_pc == other.start_pc) { other.line_number = line_number; return; } } attribute_length += 4; LineNumberElement& entry = line_number_table.Next(); entry.start_pc = start_pc; entry.line_number = line_number; } void SetMax(u2 max_pc) { unsigned i = line_number_table.Length(); while(--i > 0 && line_number_table[i].start_pc > max_pc) line_number_table[i].start_pc = max_pc; } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(line_number_table.Length()); for (unsigned i = 0; i < line_number_table.Length(); i++) { out.PutU2(line_number_table[i].start_pc); out.PutU2(line_number_table[i].line_number); } } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 2) const { assert(fill == 2); PrintPrefix("LineNumberTable", constant_pool, 2); Coutput << ", count: " << (unsigned) line_number_table.Length() << endl; for (unsigned i = 0; i < line_number_table.Length(); i++) { Coutput << " pc: " << (unsigned) line_number_table[i].start_pc << ", line_number: " << (unsigned) line_number_table[i].line_number << endl; } } #endif // JIKES_DEBUG }; // // Valid only for code, LocalVariableTable gives local variable name, scope, // and type information relative to bytecode offsets. JVMS 4.7.10. // Also, the LocalVariableTypeTable gives generic type information. // class LocalVariableTableAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // u2 local_variable_length; // computed as local_variable_table.Length() struct LocalVariableElement { u2 start_pc; u2 length; u2 name_index; u2 descriptor_index; u2 index; }; // local_variable_table[local_variable_table_length] Tuple local_variable_table; public: LocalVariableTableAttribute(u2 _name_index, bool generic = false) : AttributeInfo(generic ? ATTRIBUTE_LocalVariableTypeTable : ATTRIBUTE_LocalVariableTable, _name_index, 2) // +2 for local_variable_table_length , local_variable_table(6, 16) {} LocalVariableTableAttribute(ClassFile&, bool generic); virtual ~LocalVariableTableAttribute() {} u2 LocalVariableTableLength() const { return local_variable_table.Length(); } // // make entry in local variable table // void AddLocalVariable(u2 start, u2 end, u2 name, u2 descriptor, u2 index) { assert(end >= start); if (end > start) { attribute_length += 10; LocalVariableElement& entry = local_variable_table.Next(); entry.start_pc = start; entry.length = end - start; entry.name_index = name; entry.descriptor_index = descriptor; entry.index = index; } } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(local_variable_table.Length()); for (unsigned i = 0; i < local_variable_table.Length(); i++) { out.PutU2(local_variable_table[i].start_pc); out.PutU2(local_variable_table[i].length); out.PutU2(local_variable_table[i].name_index); out.PutU2(local_variable_table[i].descriptor_index); out.PutU2(local_variable_table[i].index); } } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 2) const { assert(fill == 2); PrintPrefix(tag == ATTRIBUTE_LocalVariableTable ? "LocalVariableTable" : "LocalVariableTypeTable", constant_pool, 2); Coutput << ", count: " << (unsigned) local_variable_table.Length() << endl; for (unsigned i = 0; i < local_variable_table.Length(); i++) { unsigned index = local_variable_table[i].name_index; Coutput << " pc: " << (unsigned) local_variable_table[i].start_pc << ", length: " << (unsigned) local_variable_table[i].length << "(pc: " << (unsigned) (local_variable_table[i].start_pc + local_variable_table[i].length) << "), name: " << index; if (constant_pool[index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[index] -> Describe(constant_pool); } else Coutput << "(invalid)"; index = local_variable_table[i].descriptor_index; Coutput << endl << " type: " << index; if (constant_pool[index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << ", index: " << (unsigned) local_variable_table[i].index << endl; } } #endif // JIKES_DEBUG }; // // Valid for classes, methods, and fields, this marks an entity as // deprecated. JVMS 4.7.10. // class DeprecatedAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo public: DeprecatedAttribute(u2 _name_index) : AttributeInfo(ATTRIBUTE_Deprecated, _name_index) {} DeprecatedAttribute(ClassFile&); virtual ~DeprecatedAttribute() {} #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("Deprecated", constant_pool, 0); Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid for classes, methods, and fields, this gives the parameterized type // signature for a generic type. JSR 14 section 7. // class SignatureAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo const u2 signature_index; public: SignatureAttribute(u2 name_index, u2 index) : AttributeInfo(ATTRIBUTE_Signature, name_index, 2) , signature_index(index) {} SignatureAttribute(ClassFile&); virtual ~SignatureAttribute() {} virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(signature_index); } const CPUtf8Info* Signature(const ConstantPool& constant_pool) const { assert(constant_pool[signature_index] -> Tag() == CPInfo::CONSTANT_Utf8); return (const CPUtf8Info*) constant_pool[signature_index]; } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("Signature", constant_pool, 0); Coutput << endl << " signature: " << (unsigned) signature_index; if (constant_pool[signature_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[signature_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid for methods, this marks the method as a bridge for covariant returns. // JSR 14? (mentioned in JSR 200). // class BridgeAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo public: BridgeAttribute(u2 name_index, u2 index) : AttributeInfo(ATTRIBUTE_Bridge, name_index) {} BridgeAttribute(ClassFile&); virtual ~BridgeAttribute() {} #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("Bridge", constant_pool, 0); Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid for code, this speeds up verification by listing the types of all // locals and stack elements at the start of each basic block. JSR 139 // appendix 1 section 2.1 (or JSR 30 section 5.3.1.2). // class StackMapAttribute : public AttributeInfo { public: class StackMapFrame { class VerificationTypeInfo { public: enum VerificationTypeInfoTag { TYPE_Top = 0, // also called Bogus TYPE_Integer = 1, TYPE_Float = 2, TYPE_Long = 4, TYPE_Double = 3, TYPE_Null = 5, TYPE_UninitializedThis = 6, TYPE_Object = 7, TYPE_Uninitialized = 8 }; private: VerificationTypeInfoTag tag; // u2 cpool_index for Object, // u2 offset for Unitialized // unused for remaining types u2 info; public: VerificationTypeInfo() : tag(TYPE_Top) {} void Read(ClassFile&); u2 Size() const { return tag >= TYPE_Object ? 3 : 1; } void Put(OutputBuffer& out) const { out.PutU1((u1) tag); if (tag >= TYPE_Object) out.PutU2(info); } #ifdef JIKES_DEBUG void Print(const ConstantPool& constant_pool, unsigned& index) const { Coutput << index++ << ':'; switch (tag) { case TYPE_Top: Coutput << "void"; break; case TYPE_Integer: Coutput << "int"; break; case TYPE_Float: Coutput << "float"; break; case TYPE_Long: Coutput << "long"; index++; break; case TYPE_Double: Coutput << "double"; index++; break; case TYPE_Null: Coutput << "null"; break; case TYPE_UninitializedThis: Coutput << "unitialized this"; break; case TYPE_Object: Coutput << (unsigned) info; if (constant_pool[info] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[info] -> Describe(constant_pool); } else Coutput << "(invalid)"; break; case TYPE_Uninitialized: Coutput << "unitialized since " << (unsigned) info; break; default: assert(false && "invalid VerificationTypeInfoTag"); } } #endif // JIKES_DEBUG }; private: u2 offset; // u2 locals_size; // computed as locals.Length() Tuple locals; // u2 stack_size; // computed as stack.Length() Tuple stack; u2 frame_size; // needed since VerificationTypeInfo is variable size public: StackMapFrame(u2 _offset) : offset(_offset) , locals(6, 16) , stack(6, 16) , frame_size(6) // +2 for offset, +2 for locals_size, +2 for stack_size {} StackMapFrame(ClassFile&); // Note that LocalsSize() + StackSize() + 6 <= FrameSize() u2 LocalsSize() const { return locals.Length(); } u2 StackSize() const { return stack.Length(); } u2 FrameSize() const { return frame_size; } void AddLocal(const VerificationTypeInfo& entry) { frame_size += entry.Size(); locals.Next() = entry; } void AddStack(const VerificationTypeInfo& entry) { frame_size += entry.Size(); stack.Next() = entry; } void Put(OutputBuffer& out) const { out.PutU2(offset); out.PutU2(locals.Length()); for (unsigned i = 0; i < locals.Length(); i++) locals[i].Put(out); out.PutU2(stack.Length()); for (unsigned j = 0; j < stack.Length(); j++) stack[j].Put(out); } #ifdef JIKES_DEBUG void Print(const ConstantPool& constant_pool) const { Coutput << " pc: " << (unsigned) offset << ", locals_size: " << (unsigned) locals.Length() << ", stack_size: " << (unsigned) stack.Length() << endl; unsigned index = 0; if (locals.Length()) { Coutput << " locals: "; locals[0].Print(constant_pool, index); for (unsigned i = 1; i < locals.Length(); i++) { Coutput << ", "; locals[i].Print(constant_pool, index); } Coutput << endl; } index = 0; if (stack.Length()) { Coutput << " stack: "; stack[0].Print(constant_pool, index); for (unsigned i = 1; i < stack.Length(); i++) { Coutput << ", "; stack[i].Print(constant_pool, index); } Coutput << endl; } } #endif // JIKES_DEBUG }; private: // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // u2 frame_count; // computed as frames.Length(); Tuple frames; // stack_map_frame[frame_count] public: StackMapAttribute(u2 name) : AttributeInfo(ATTRIBUTE_StackMap, name, 2) // +2 for frame_count , frames(6, 16) {} StackMapAttribute(ClassFile&); virtual ~StackMapAttribute() { for (unsigned i = 0; i < frames.Length(); i++) delete frames[i]; } u2 FrameCount() const { return frames.Length(); } void AddFrame(StackMapFrame* frame) { frames.Next() = frame; attribute_length += frame -> FrameSize(); } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(frames.Length()); for (unsigned i = 0; i < frames.Length(); i++) frames[i] -> Put(out); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 2) const { assert(fill == 2); PrintPrefix("StackMap", constant_pool, 2); Coutput << ", frames: " << (unsigned) frames.Length() << endl; for (unsigned i = 0; i < frames.Length(); i++) frames[i] -> Print(constant_pool); } #endif // JIKES_DEBUG }; // // Valid only on non-abstract non-native methods, this is the method // implementation. JVMS 4.7.3. // class CodeAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo u2 max_stack; u2 max_locals; // u4 code_length; // computed as code.Length(); Tuple code; // code[code_length] // u2 exception_table_length; // computed as exception_table.Length(); struct ExceptionElement { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; }; // exception_table[exception_table_length] Tuple exception_table; // u2 attribute_count; // computed as attributes.Length(); Tuple attributes; // attributes[attributes_count] // Remember location of known attributes. LineNumberTableAttribute* attr_linenumbers; LocalVariableTableAttribute* attr_locals; LocalVariableTableAttribute* attr_local_types; StackMapAttribute* attr_stackmap; public: CodeAttribute(u2 _name_index, u2 _max_locals) : AttributeInfo(ATTRIBUTE_Code, _name_index, 12) // +2 for max_stack, +2 for max_locals, +4 for code_length, // +2 for exception_table_length, +2 for attributes_count , max_stack(0) // filled in later , max_locals(_max_locals) , code(8, 4) , exception_table(6, 16) , attributes(6, 16) , attr_linenumbers(NULL) , attr_locals(NULL) , attr_stackmap(NULL) {} CodeAttribute(ClassFile&); virtual ~CodeAttribute() { for (unsigned i = 0; i < attributes.Length(); i++) delete attributes[i]; } u2 MaxStack() const { return max_stack; } void SetMaxStack(u2 val) { max_stack = val; } u2 MaxLocals() const { return max_locals; } void SetMaxLocals(u2 val) { max_locals = val; } u2 CodeLength() const { return CodeLengthExceeded() ? 65535 : (u2) code.Length(); } bool CodeLengthExceeded() const { return code.Length() > 65535; } void ResetCode(unsigned i, u1 byte) { code[i] = byte; } void AddCode(u1 byte) { code.Next() = byte; attribute_length++; } void DeleteCode(unsigned count) { assert(count <= code.Length()); code.Reset(code.Length() - count); attribute_length -= count; } u2 ExceptionTableLength() const { return exception_table.Length(); } void AddException(u2 start_pc, u2 end_pc, u2 handler_pc, u2 catch_type) { if (start_pc == end_pc) return; if (exception_table.Length()) { ExceptionElement& other = exception_table.Top(); if (end_pc == other.start_pc && handler_pc == other.handler_pc && catch_type == other.catch_type) { other.start_pc = start_pc; return; } } attribute_length += 8; ExceptionElement& entry = exception_table.Next(); entry.start_pc = start_pc; entry.end_pc = end_pc; entry.handler_pc = handler_pc; entry.catch_type = catch_type; } u2 AttributesCount() const { return attributes.Length(); } void AddAttribute(AttributeInfo* attribute) { attributes.Next() = attribute; attribute_length += 6 + attribute -> AttributeLength(); // +6 for name and length of attribute switch (attribute -> Tag()) { case AttributeInfo::ATTRIBUTE_LineNumberTable: assert(! attr_linenumbers); attr_linenumbers = (LineNumberTableAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_LocalVariableTable: assert(! attr_locals); attr_locals = (LocalVariableTableAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_LocalVariableTypeTable: assert(! attr_local_types); attr_local_types = (LocalVariableTableAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_StackMap: assert(! attr_stackmap); attr_stackmap = (StackMapAttribute*) attribute; break; default: assert(false && "adding unexpected code attribute"); } } virtual void Put(OutputBuffer& out) const { unsigned i; AttributeInfo::Put(out); out.PutU2(max_stack); out.PutU2(max_locals); out.PutU4(code.Length()); for (i = 0; i < code.Length(); i++) out.PutU1(code[i]); out.PutU2(exception_table.Length()); for (i = 0; i < exception_table.Length(); i++) { out.PutU2(exception_table[i].start_pc); out.PutU2(exception_table[i].end_pc); out.PutU2(exception_table[i].handler_pc); out.PutU2(exception_table[i].catch_type); } out.PutU2(attributes.Length()); for (i = 0; i < attributes.Length(); i++) attributes[i] -> Put(out); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const; #endif // JIKES_DEBUG }; // // Forward declaration, since AnnotationComponentValue and Annotation are // mutually referential. // class Annotation; // // Describes an annotation value, as used inside AnnotationsAttribute, // ParameterAnnotationsAttribute, and AnnotationDefaultAttribute. JSR 175 // section IX. // class AnnotationComponentValue { public: enum AnnotationComponentValueTag { COMPONENT_byte = U_B, COMPONENT_char = U_C, COMPONENT_double = U_D, COMPONENT_float = U_F, COMPONENT_int = U_I, COMPONENT_long = U_J, COMPONENT_short = U_S, COMPONENT_boolean = U_Z, COMPONENT_string = U_s, COMPONENT_enum = U_e, COMPONENT_class = U_c, COMPONENT_annotation = U_AT, COMPONENT_array = U_LB }; protected: const AnnotationComponentValueTag tag; public: AnnotationComponentValue(AnnotationComponentValueTag _tag) : tag(_tag) {} virtual ~AnnotationComponentValue() {} // // This reads the next component from the buffer, advancing it to the // end of the component. The user is responsible for deleting the result. // static AnnotationComponentValue* AllocateAnnotationComponentValue(ClassFile&); AnnotationComponentValueTag Tag() const { return tag; } // Subclasses must override. virtual u2 Length() const { return 1; } // +1 tag // Subclasses must override. virtual void Put(OutputBuffer& out) const { out.PutU1((u1) tag); } #ifdef JIKES_DEBUG // Subclasses must override. virtual void Print(const ConstantPool&) const { Coutput << "'; } #endif // JIKES_DEBUG }; // // Represents boolean, byte, short, char, int, long, float, double, String, // and Class annotation values. // class AnnotationComponentConstant : public AnnotationComponentValue { // u1 tag; // inherited from AnnotationComponentValue // u2 const_value_index for boolean, byte, short, char, int, long, float, // double, String, // u2 class_info_index for Class const u2 index; public: AnnotationComponentConstant(AnnotationComponentValueTag _tag, u2 _index) : AnnotationComponentValue(_tag) , index(_index) { assert(tag != COMPONENT_annotation && tag != COMPONENT_array && tag != COMPONENT_enum); } AnnotationComponentConstant(ClassFile&, AnnotationComponentValueTag); virtual ~AnnotationComponentConstant() {} virtual u2 Length() const { return 3; } // +1 tag, +2 index virtual void Put(OutputBuffer& out) const { AnnotationComponentValue::Put(out); out.PutU2(index); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& pool) const { Coutput << (unsigned) index << '='; pool[index] -> Describe(pool); switch (tag) { case COMPONENT_boolean: if (pool[index] -> Tag() == CPInfo::CONSTANT_Integer) { i4 value = ((CPIntegerInfo*) pool[index]) -> Value(); if (value == 0) Coutput << "(false)"; else if (value == 0) Coutput << "(true)"; else Coutput << "(invalid)"; } else Coutput << "(invalid)"; break; case COMPONENT_char: if (pool[index] -> Tag() == CPInfo::CONSTANT_Integer) { i4 value = ((CPIntegerInfo*) pool[index]) -> Value(); if (value == '\n') Coutput << "('\\n')"; else if (value == '\r') Coutput << "('\\r')"; else if (value == '\'') Coutput << "('\\'')"; else if (value == '\\') Coutput << "('\\\\')"; else if (value > 0x1f && value < 0x7f) Coutput << "('" << (char) value << "')"; else if (value >= 0 && value <= 0xffff) { Coutput << "('\\u" << IntToString(value, 4).String() << "')"; } else Coutput << "(invalid)"; } else Coutput << "(invalid)"; break; case COMPONENT_byte: if (pool[index] -> Tag() == CPInfo::CONSTANT_Integer) { i4 value = ((CPIntegerInfo*) pool[index]) -> Value(); if (value < -128 || value > 127) Coutput << "(invalid)"; } else Coutput << "(invalid)"; break; case COMPONENT_short: if (pool[index] -> Tag() == CPInfo::CONSTANT_Integer) { i4 value = ((CPIntegerInfo*) pool[index]) -> Value(); if (value < -32768 || value > 32767) Coutput << "(invalid)"; } else Coutput << "(invalid)"; break; case COMPONENT_int: if (pool[index] -> Tag() != CPInfo::CONSTANT_Integer) Coutput << "(invalid)"; break; case COMPONENT_long: if (pool[index] -> Tag() != CPInfo::CONSTANT_Long) Coutput << "(invalid)"; break; case COMPONENT_float: if (pool[index] -> Tag() != CPInfo::CONSTANT_Float) Coutput << "(invalid)"; break; case COMPONENT_double: if (pool[index] -> Tag() != CPInfo::CONSTANT_Double) Coutput << "(invalid)"; break; case COMPONENT_string: if (pool[index] -> Tag() != CPInfo::CONSTANT_String) Coutput << "(invalid)"; break; case COMPONENT_class: if (pool[index] -> Tag() != CPInfo::CONSTANT_Class) Coutput << "(invalid)"; break; default: assert(false && "invalid constant-valued attribute"); } } #endif // JIKES_DEBUG }; // // Represents enum constant annotation values. // class AnnotationComponentEnum : public AnnotationComponentValue { // u1 tag; // inherited from AnnotationComponentValue const u2 type_name_index; const u2 const_name_index; public: AnnotationComponentEnum(u2 type, u2 name) : AnnotationComponentValue(COMPONENT_enum) , type_name_index(type) , const_name_index(name) {} AnnotationComponentEnum(ClassFile&); virtual ~AnnotationComponentEnum() {} virtual u2 Length() const { return 5; } // +1 tag, +2 type, +2 name virtual void Put(OutputBuffer& out) const { AnnotationComponentValue::Put(out); out.PutU2(type_name_index); out.PutU2(const_name_index); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& pool) const { Coutput << (unsigned) type_name_index << '.' << (unsigned) const_name_index << '='; pool[type_name_index] -> Describe(pool); if (pool[type_name_index] -> Tag() != CPInfo::CONSTANT_Class) Coutput << "(invalid)"; Coutput << '.'; pool[const_name_index] -> Describe(pool); if (pool[type_name_index] -> Tag() != CPInfo::CONSTANT_Utf8) Coutput << "(invalid)"; } #endif // JIKES_DEBUG }; // // Represents nested annotation values. // class AnnotationComponentAnnotation : public AnnotationComponentValue { // u1 tag; // inherited from AnnotationComponentValue Annotation* attr_value; public: AnnotationComponentAnnotation(Annotation* nested) : AnnotationComponentValue(COMPONENT_annotation) , attr_value(nested) {} AnnotationComponentAnnotation(ClassFile&); virtual ~AnnotationComponentAnnotation(); virtual u2 Length() const; virtual void Put(OutputBuffer&) const; #ifdef JIKES_DEBUG virtual void Print(const ConstantPool&) const; #endif // JIKES_DEBUG }; // // Represents array annotation values. // class AnnotationComponentArray : public AnnotationComponentValue { // u1 tag; // inherited from AnnotationComponentValue // u2 num_values; // computed as values.Length() Tuple values; // values[num_values] u2 len; // cache the length public: AnnotationComponentArray() : AnnotationComponentValue(COMPONENT_array) , values(6, 16) , len(3) // +1 tag, +2 num_values {} AnnotationComponentArray(ClassFile&); virtual ~AnnotationComponentArray() { unsigned i = values.Length(); while (i--) delete values[i]; } u2 NumValues() const { return values.Length(); } void AddValue(AnnotationComponentValue* value) { values.Next() = value; len += value -> Length(); } virtual u2 Length() const { return len; } virtual void Put(OutputBuffer& out) const { AnnotationComponentValue::Put(out); out.PutU2(values.Length()); for (unsigned i = 0; i < values.Length(); i++) values[i] -> Put(out); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& pool) const { Coutput << '{'; unsigned count = values.Length(); if (count) values[0] -> Print(pool); for (unsigned i = 1; i < count; i++) { Coutput << ", "; values[i] -> Print(pool); } Coutput << '}'; } #endif // JIKES_DEBUG }; // // Describes an annotation, as used inside AnnotationComponentValue, // ParameterAnnotationsAttribute, and AnnotationDefaultAttribute. JSR 175 // section IX. // class Annotation { u2 type_index; // u2 num_components; // computed as components.Length() struct Component { u2 component_name_index; AnnotationComponentValue* component_value; }; Tuple components; // components[num_components] public: Annotation(u2 index) : type_index(index) , components(6, 16) {} Annotation(ClassFile&); ~Annotation() { unsigned i = components.Length(); while (i--) delete components[i].component_value; } u2 Length() const { u2 size = 4; // +2 type_index, +2 num_components unsigned i = components.Length(); while (i--) // +2 member_name_index size += 2 + components[i].component_value -> Length(); return size; } u1 NumComponents() const { return components.Length(); } void AddComponent(u2 name_index, AnnotationComponentValue* value) { Component& component = components.Next(); component.component_name_index = name_index; component.component_value = value; } void Put(OutputBuffer& out) const { out.PutU2(type_index); unsigned i = components.Length(); out.PutU1(i); while (i--) { out.PutU2(components[i].component_name_index); components[i].component_value -> Put(out); } } #ifdef JIKES_DEBUG void Print(const ConstantPool& pool) const { Coutput << (unsigned) type_index << "=@"; pool[type_index] -> Describe(pool); unsigned num_components = components.Length(); Coutput << ", length:" << num_components << '('; if (num_components) { Coutput << (unsigned) components[0].component_name_index << ':'; pool[components[0].component_name_index] -> Describe(pool); Coutput << '='; components[0].component_value -> Print(pool); } for (unsigned i = 1; i < num_components; i++) { Coutput << ", " << (unsigned) components[i].component_name_index << ':'; pool[components[i].component_name_index] -> Describe(pool); Coutput << '='; components[i].component_value -> Print(pool); } Coutput << ')'; } #endif // JIKES_DEBUG }; // // Valid on all classes, fields, and methods, this lists the RuntimeVisible // and RuntimeInvisible annotations tied to the item. JSR 175, section IX. // class AnnotationsAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // u2 num_annotations; // computed as annotations.Length() Tuple annotations; // annotations[num_annotations] public: AnnotationsAttribute(u2 _name_index, bool visible) : AttributeInfo((visible ? ATTRIBUTE_RuntimeVisibleAnnotations : ATTRIBUTE_RuntimeInvisibleAnnotations), _name_index, 2) // +2 for num_annotations , annotations(6, 16) {} AnnotationsAttribute(ClassFile&, bool visible); virtual ~AnnotationsAttribute() { unsigned i = annotations.Length(); while (i--) delete annotations[i]; } u2 NumAnnotations() const { return annotations.Length(); } void AddAnnotation(Annotation* annotation) { annotations.Next() = annotation; attribute_length += annotation -> Length(); } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(annotations.Length()); for (unsigned i = 0; i < annotations.Length(); i++) annotations[i] -> Put(out); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix((Tag() == ATTRIBUTE_RuntimeVisibleAnnotations ? "RuntimeVisibleAnnotations" : "RuntimeInvisibleAnnotations"), constant_pool, 0); Coutput << ", num_annotations: " << (unsigned) annotations.Length() << endl; for (unsigned i = 0; i < annotations.Length(); i++) { Coutput << " "; annotations[i] -> Print(constant_pool); Coutput << endl; } } #endif // JIKES_DEBUG }; // // Valid on all methods, this lists the RuntimeVisible and RuntimeInvisible // annotations tied to each parameter. JSR 175, section IX. // class ParameterAnnotationsAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo const u1 num_parameters; // u2 num_annotations; // computed as parameters[i].Length() // annotation annotations[num_annotations]; // computed as parameters[i] // parameter_annotations[num_parameters] Tuple* parameters; public: ParameterAnnotationsAttribute(u2 _name_index, bool visible, u1 params) : AttributeInfo((visible ? ATTRIBUTE_RuntimeVisibleParameterAnnotations : ATTRIBUTE_RuntimeInvisibleParameterAnnotations), _name_index, 1 + 2 * params) // +1 num_parameters, +2 num_annotations (num_parameters times) , num_parameters(params) , parameters(NULL) { if (params) parameters = new Tuple[params]; } ParameterAnnotationsAttribute(ClassFile&, bool visible); virtual ~ParameterAnnotationsAttribute() { for (unsigned i = num_parameters; i--; ) for (unsigned j = parameters[i].Length(); j--; ) delete parameters[i][j]; delete [] parameters; } u1 NumParameters() const { return num_parameters; } u2 NumAnnotations(u1 param) const { assert(param < num_parameters); return parameters[param].Length(); } void AddAnnotation(Annotation* annotation, u1 param) { assert(param < num_parameters); parameters[param].Next() = annotation; attribute_length += annotation -> Length(); } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU1(num_parameters); for (unsigned i = 0; i < num_parameters; i++) { out.PutU2(parameters[i].Length()); for (unsigned j = 0; j < parameters[i].Length(); j++) parameters[i][j] -> Put(out); } } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix((Tag() == ATTRIBUTE_RuntimeVisibleParameterAnnotations ? "RuntimeVisibleParameterAnnotations" : "RuntimeInvisibleParameterAnnotations"), constant_pool, 0); Coutput << ", num_parameters: " << (unsigned) num_parameters << endl; for (unsigned i = 0; i < num_parameters; i++) { Coutput << " param " << i << ": num_annotations: " << (unsigned) parameters[i].Length() << endl; for (unsigned j = 0; j < parameters[i].Length(); j++) { Coutput << " "; parameters[i][j] -> Print(constant_pool); Coutput << endl; } } } #endif // JIKES_DEBUG }; // // Valid only on method members of annotation types, this lists the default // return value for the annotation method. JSR 175, section IX. // class AnnotationDefaultAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo AnnotationComponentValue* default_value; public: AnnotationDefaultAttribute(u2 _name_index, AnnotationComponentValue* value) : AttributeInfo(ATTRIBUTE_AnnotationDefault, _name_index, value -> Length()) , default_value(value) {} AnnotationDefaultAttribute(ClassFile&); virtual ~AnnotationDefaultAttribute() { delete default_value; } const AnnotationComponentValue* DefaultValue() const { return default_value; } virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); default_value -> Put(out); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("AnnotationDefault", constant_pool, 0); Coutput << ", "; default_value -> Print(constant_pool); Coutput << endl; } #endif // JIKES_DEBUG }; // // Valid only on local and anonymous types, this lists the enclosing method // of the type. JSR 202? (mentioned in JSR 200). // class EnclosingMethodAttribute : public AttributeInfo { // u2 attribute_name_index; // inherited from AttributeInfo // u4 attribute_length; // inherited from AttributeInfo // // JSR 202 does not use a methodref, because classes defined in static or // instance initializers are given a name_and_type_index of 0. You can // determine whether a class with an unlisted enclosing method was // declared in or all s by the presence of a this$0 member. // const u2 class_index; const u2 name_and_type_index; public: EnclosingMethodAttribute(u2 _name_index, u2 type, u2 name) : AttributeInfo(ATTRIBUTE_EnclosingMethod, _name_index, 4) , class_index(type) , name_and_type_index(name) {} EnclosingMethodAttribute(ClassFile&); virtual ~EnclosingMethodAttribute() {} virtual void Put(OutputBuffer& out) const { AttributeInfo::Put(out); out.PutU2(class_index); out.PutU2(name_and_type_index); } #ifdef JIKES_DEBUG virtual void Print(const ConstantPool& constant_pool, int fill = 0) const { assert(! fill); PrintPrefix("EnclosingMethod", constant_pool, 0); Coutput << endl << " method: " << (unsigned) class_index << '.' << (unsigned) name_and_type_index; if (constant_pool[class_index] -> Tag() == CPInfo::CONSTANT_Class && (! name_and_type_index || (constant_pool[name_and_type_index] -> Tag() == CPInfo::CONSTANT_NameAndType))) { Coutput << '='; constant_pool[class_index] -> Describe(constant_pool); Coutput << '.'; if (name_and_type_index) constant_pool[name_and_type_index] -> Describe(constant_pool); else Coutput << ""; } else Coutput << "(invalid)"; Coutput << endl; } #endif // JIKES_DEBUG }; // // Describes a member field. JVMS 4.5. // class FieldInfo : public AccessFlags { // u2 access_flags; // inherited from AccessFlags u2 name_index; u2 descriptor_index; // u2 attributes_count; // computed as attributes.Length(); Tuple attributes; // attributes[attributes_count] // Remember location of known attributes. SyntheticAttribute* attr_synthetic; DeprecatedAttribute* attr_deprecated; SignatureAttribute* attr_signature; ConstantValueAttribute* attr_constantvalue; AnnotationsAttribute* attr_visible_annotations; AnnotationsAttribute* attr_invisible_annotations; public: FieldInfo() : name_index(0) , descriptor_index(0) , attr_synthetic(NULL) , attr_deprecated(NULL) , attr_signature(NULL) , attr_constantvalue(NULL) , attr_visible_annotations(NULL) , attr_invisible_annotations(NULL) {} FieldInfo(ClassFile&); ~FieldInfo() { for (unsigned i = 0; i < attributes.Length(); i++) delete attributes[i]; } inline void SetNameIndex(u2 _name_index) { name_index = _name_index; } const char* Name(const ConstantPool& constant_pool) const { assert(constant_pool[name_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[name_index]) -> Bytes(); } u2 NameLength(const ConstantPool& constant_pool) const { assert(constant_pool[name_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[name_index]) -> Length(); } inline void SetDescriptorIndex(u2 index) { descriptor_index = index; } const char* Signature(const ConstantPool&, const Control&) const; u2 SignatureLength(const ConstantPool&, const Control&) const; inline u2 AttributesCount() const { return attributes.Length(); } inline void AddAttribute(AttributeInfo* attribute) { attributes.Next() = attribute; switch (attribute -> Tag()) { case AttributeInfo::ATTRIBUTE_Synthetic: // // We must be adding the attribute because we are targetting an // older VM that doesn't recognize the access flag. // assert(! attr_synthetic && ACC_SYNTHETIC()); ResetACC_SYNTHETIC(); attr_synthetic = (SyntheticAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Deprecated: assert(! attr_deprecated); attr_deprecated = (DeprecatedAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Signature: assert(! attr_signature); attr_signature = (SignatureAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_ConstantValue: assert(! attr_constantvalue); attr_constantvalue = (ConstantValueAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeVisibleAnnotations: assert(! attr_visible_annotations); attr_visible_annotations = (AnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeInvisibleAnnotations: assert(! attr_invisible_annotations); attr_invisible_annotations = (AnnotationsAttribute*) attribute; break; default: assert(false && "adding unexpected field attribute"); } } bool Synthetic() const { return attr_synthetic || ACC_SYNTHETIC(); } bool Deprecated() const { return attr_deprecated != NULL; } const CPInfo* ConstantValue(const ConstantPool& constant_pool) const { return attr_constantvalue ? attr_constantvalue -> Value(constant_pool) : (const CPInfo*) NULL; } inline void Put(OutputBuffer& out) const { out.PutU2(access_flags); out.PutU2(name_index); out.PutU2(descriptor_index); out.PutU2(attributes.Length()); for (unsigned i = 0; i < attributes.Length(); i++) attributes[i] -> Put(out); } #ifdef JIKES_DEBUG void Print(const ConstantPool& constant_pool) const { Coutput << "field: "; AccessFlags::Print(ACCESS_VARIABLE); Coutput << ", name: " << (unsigned) name_index; if (constant_pool[name_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[name_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl << " type: " << (unsigned) descriptor_index; if (constant_pool[descriptor_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[descriptor_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << ", attributes: " << (unsigned) attributes.Length() << endl; for (unsigned i = 0; i < attributes.Length(); i++) attributes[i] -> Print(constant_pool); Coutput << endl; } #endif // JIKES_DEBUG }; // // Describes a member method, including constructors and the static // initializer. JVMS 4.6. // class MethodInfo : public AccessFlags { // u2 access_flags; // inherited from AccessFlags u2 name_index; u2 descriptor_index; // u2 attributes_count; // computed as attributes.Length(); Tuple attributes; // attributes[attributes_count] // Remember location of known attributes. SyntheticAttribute* attr_synthetic; DeprecatedAttribute* attr_deprecated; SignatureAttribute* attr_signature; BridgeAttribute* attr_bridge; CodeAttribute* attr_code; ExceptionsAttribute* attr_exceptions; AnnotationsAttribute* attr_visible_annotations; AnnotationsAttribute* attr_invisible_annotations; ParameterAnnotationsAttribute* attr_param_visible_annotations; ParameterAnnotationsAttribute* attr_param_invisible_annotations; AnnotationDefaultAttribute* attr_annotation_default; public: MethodInfo() : name_index(0) , descriptor_index(0) , attr_synthetic(NULL) , attr_deprecated(NULL) , attr_signature(NULL) , attr_bridge(NULL) , attr_code(NULL) , attr_exceptions(NULL) , attr_visible_annotations(NULL) , attr_invisible_annotations(NULL) , attr_param_visible_annotations(NULL) , attr_param_invisible_annotations(NULL) , attr_annotation_default(NULL) {} MethodInfo(ClassFile&); ~MethodInfo() { for (unsigned i = 0; i < attributes.Length(); i++) delete attributes[i]; } inline void SetNameIndex(u2 _name_index) { name_index = _name_index; } const char* Name(const ConstantPool& constant_pool) const { assert(constant_pool[name_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[name_index]) -> Bytes(); } u2 NameLength(const ConstantPool& constant_pool) const { assert(constant_pool[name_index] -> Tag() == CPInfo::CONSTANT_Utf8); return ((const CPUtf8Info*) constant_pool[name_index]) -> Length(); } inline void SetDescriptorIndex(u2 index) { descriptor_index = index; } const char* Signature(const ConstantPool&, const Control&) const; u2 SignatureLength(const ConstantPool&, const Control&) const; inline u2 AttributesCount() const { return attributes.Length(); } inline void AddAttribute(AttributeInfo* attribute) { attributes.Next() = attribute; switch (attribute -> Tag()) { case AttributeInfo::ATTRIBUTE_Synthetic: // // We must be adding the attribute because we are targetting an // older VM that doesn't recognize the access flag. // assert(! attr_synthetic && ACC_SYNTHETIC()); ResetACC_SYNTHETIC(); attr_synthetic = (SyntheticAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Deprecated: assert(! attr_deprecated); attr_deprecated = (DeprecatedAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Signature: assert(! attr_signature); attr_signature = (SignatureAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Bridge: assert(! attr_bridge); attr_bridge = (BridgeAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Code: assert(! attr_code); attr_code = (CodeAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Exceptions: assert(! attr_exceptions); attr_exceptions = (ExceptionsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeVisibleAnnotations: assert(! attr_visible_annotations); attr_visible_annotations = (AnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeInvisibleAnnotations: assert(! attr_invisible_annotations); attr_invisible_annotations = (AnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeVisibleParameterAnnotations: assert(! attr_param_visible_annotations); attr_param_visible_annotations = (ParameterAnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeInvisibleParameterAnnotations: assert(! attr_param_invisible_annotations); attr_param_invisible_annotations = (ParameterAnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_AnnotationDefault: assert(! attr_annotation_default); attr_annotation_default = (AnnotationDefaultAttribute*) attribute; break; default: assert(false && "adding unexpected method attribute"); } } bool Synthetic() const { return attr_synthetic || ACC_SYNTHETIC(); } bool Deprecated() const { return attr_deprecated != NULL; } bool Bridge() const { return attr_bridge != NULL; } const CodeAttribute* Code() const { return attr_code; } const ExceptionsAttribute* Exceptions() const { return attr_exceptions; } inline void Put(OutputBuffer& out) const { out.PutU2(access_flags); out.PutU2(name_index); out.PutU2(descriptor_index); out.PutU2(attributes.Length()); for (unsigned i = 0; i < attributes.Length(); i++) attributes[i] -> Put(out); } #ifdef JIKES_DEBUG void Print(const ConstantPool& constant_pool) const { Coutput << "method: "; AccessFlags::Print(ACCESS_METHOD); Coutput << " name: " << (unsigned) name_index; if (constant_pool[name_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[name_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl << " type: " << (unsigned) descriptor_index; if (constant_pool[descriptor_index] -> Tag() == CPInfo::CONSTANT_Utf8) { Coutput << '='; constant_pool[descriptor_index] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << ", attributes: " << (unsigned) attributes.Length() << endl; for (unsigned i = 0; i < attributes.Length(); i++) attributes[i] -> Print(constant_pool); Coutput << endl; } #endif // JIKES_DEBUG }; // // Here we have the complete definition of the .class file format. JVMS 4.1. // class ClassFile : public AccessFlags { enum { MAGIC = 0xcafebabe }; const char* problem; // why this file is invalid (NULL if it's okay) const char* buffer; // current location during input (NULL for output) const char* const buffer_tail; // last location during input protected: u4 magic; u2 minor_version; u2 major_version; // u2 constant_pool_count; // computed as constant_pool.Length() // cp_info constant_pool[constant_pool_count - 1] ConstantPool constant_pool; // note that constant_pool[0] is invalid // u2 access_flags; // inherited from AccessFlags u2 this_class; u2 super_class; // u2 interfaces_count // computed as interfaces.Length() Tuple interfaces; // u2 interfaces[interfaces_count] // u2 fields_count // computed as fields.Length() Tuple fields; // field_info fields[fields_count] // u2 methods_count // computed as methods.Length() Tuple methods; // method_info methods[methods_count] // u2 attributes_count // computed as attributes.Length() // u2 attribute_info attributes[attributes_count] Tuple attributes; // Remember location of known attributes. SyntheticAttribute* attr_synthetic; DeprecatedAttribute* attr_deprecated; SignatureAttribute* attr_signature; SourceFileAttribute* attr_sourcefile; InnerClassesAttribute* attr_innerclasses; AnnotationsAttribute* attr_visible_annotations; AnnotationsAttribute* attr_invisible_annotations; EnclosingMethodAttribute* attr_enclosing_method; public: // // Construct a class file for output, given the finished type. // ClassFile() : problem(NULL) , buffer(NULL) , buffer_tail(NULL) , magic(MAGIC) , constant_pool(8, 4) , interfaces(6, 16) , fields(6, 16) , methods(6, 16) , attributes(6, 16) , attr_synthetic(NULL) , attr_deprecated(NULL) , attr_signature(NULL) , attr_sourcefile(NULL) , attr_innerclasses(NULL) , attr_visible_annotations(NULL) , attr_invisible_annotations(NULL) , attr_enclosing_method(NULL) {} // // Read a class from input. Note that we try to parse to the end of the // file, even after encountering an error, for purposes of decompiling. // ClassFile(const char*, unsigned); ~ClassFile() { unsigned i; for (i = 1; i < constant_pool.Length(); i++) if (constant_pool.Valid(i)) delete constant_pool[i]; for (i = 0; i < fields.Length(); i++) delete fields[i]; for (i = 0; i < methods.Length(); i++) delete methods[i]; for (i = 0; i < attributes.Length(); i++) delete attributes[i]; } u2 ConstantPoolCount() const { return constant_pool.Length(); } const ConstantPool& Pool() const { return constant_pool; } CPClassInfo* ThisClass() { return constant_pool[this_class] -> Tag() == CPInfo::CONSTANT_Class ? (CPClassInfo*) constant_pool[this_class] : (CPClassInfo*) NULL; } CPClassInfo* SuperClass() { return constant_pool[super_class] -> Tag() == CPInfo::CONSTANT_Class ? (CPClassInfo*) constant_pool[super_class] : (CPClassInfo*) NULL; } u2 InterfacesCount() const { return interfaces.Length(); } CPClassInfo* Interface(u2 i) { return constant_pool[interfaces[i]] -> Tag() == CPInfo::CONSTANT_Class ? (CPClassInfo*) constant_pool[interfaces[i]] : (CPClassInfo*) NULL; } u2 FieldsCount() const { return fields.Length(); } const FieldInfo* Field(u2 i) const { return fields[i]; } u2 MethodsCount() const { return methods.Length();} const MethodInfo* Method(u2 i) const { return methods[i]; } u2 AttributesCount() const { return attributes.Length(); } const AttributeInfo* Attribute(u2 i) const { return attributes[i]; } inline void AddAttribute(AttributeInfo* attribute) { attributes.Next() = attribute; switch (attribute -> Tag()) { case AttributeInfo::ATTRIBUTE_Synthetic: // // We must be adding the attribute because we are targetting an // older VM that doesn't recognize the access flag. // assert(! attr_synthetic && ACC_SYNTHETIC()); ResetACC_SYNTHETIC(); attr_synthetic = (SyntheticAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Deprecated: assert(! attr_deprecated); attr_deprecated = (DeprecatedAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_Signature: assert(! attr_signature); attr_signature = (SignatureAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_SourceFile: assert(! attr_sourcefile); attr_sourcefile = (SourceFileAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_InnerClasses: assert(! attr_innerclasses); attr_innerclasses = (InnerClassesAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeVisibleAnnotations: assert(! attr_visible_annotations); attr_visible_annotations = (AnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_RuntimeInvisibleAnnotations: assert(! attr_invisible_annotations); attr_invisible_annotations = (AnnotationsAttribute*) attribute; break; case AttributeInfo::ATTRIBUTE_EnclosingMethod: assert(! attr_enclosing_method); attr_enclosing_method = (EnclosingMethodAttribute*) attribute; break; default: assert(false && "adding unexpected class attribute"); } } bool Synthetic() const { return attr_synthetic || ACC_SYNTHETIC(); } bool Deprecated() const { return attr_deprecated != NULL; } const char* SourceFile() const { return attr_sourcefile ? attr_sourcefile -> SourceFile(constant_pool) : (const char*) NULL; } u2 SourceFileLength() const { return attr_sourcefile ? attr_sourcefile -> SourceFileLength(constant_pool) : 0; } const InnerClassesAttribute* InnerClasses() const { return attr_innerclasses; } const SignatureAttribute* Signature() const { return attr_signature; } void Write(TypeSymbol* unit_type) const; bool Valid() const { return (problem == NULL); } void MarkInvalid(const char* reason) { problem = reason; } const char* DescribeProblem() const { return problem; } inline u1 GetU1() { if (buffer == buffer_tail) { MarkInvalid("couldn't read u1"); return 0; } return (u1) *buffer++; } inline u2 GetU2() { if (buffer + 1 >= buffer_tail) { MarkInvalid("couldn't read u2"); buffer = buffer_tail; return 0; } u2 i = (u1) *buffer++; i = (i << 8) | (u1) *buffer++; return i; } inline u2 PeekU2() { if (buffer + 1 >= buffer_tail) { MarkInvalid("couldn't peek u2"); return 0; } u2 i = (u1) *buffer; i = (i << 8) | (u1) buffer[1]; return i; } inline u4 GetU4() { if (buffer + 3 >= buffer_tail) { MarkInvalid("couldn't get u4"); buffer = buffer_tail; return 0; } u4 i = (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; return i; } inline BaseLong GetU8() { if (buffer + 7 >= buffer_tail) { MarkInvalid("couldn't get u8"); buffer = buffer_tail; return 0; } BaseLong i = (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; i = (i << 8) | (u1) *buffer++; return i; } // // Gets max(len, rest of buffer) bytes, and stores it in a new u1[len + 1] // in the previously uninitialized bytes. The extra byte is set to U_NULL, // so if bytes had no embedded NULLs, it can be cast to (const char*) and // used in methods like strlen(). Returns the size of bytes, and caller // is responsible for calling delete[] on bytes. // inline u4 GetN(u1*& bytes, u4 len) { if (buffer + len > buffer_tail) { MarkInvalid("couldn't get n bytes"); len = buffer_tail - buffer; } bytes = new u1[len + 1]; if (len) memcpy(bytes, buffer, len); bytes[len] = U_NULL; buffer += len; return len; } inline void SkipN(u4 len) { if (buffer + len > buffer_tail) { MarkInvalid("couldn't skip n bytes"); buffer = buffer_tail; } else buffer += len; } #ifdef JIKES_DEBUG public: void Print() { unsigned i; if (problem) Coutput << " *** Not a valid Java .class file (" << problem << ")! ***" << endl; Coutput << "*** Magic number: 0x"; for (i = 32; i; i -= 4) { char c = (magic >> (i - 4)) & 0xf; Coutput << (char) (c < 10 ? c + '0' : c + 'a' - 10); } Coutput << ", version: " << major_version << '.' << minor_version << endl << endl << "### Constant pool: constant_pool_count: " << (unsigned) constant_pool.Length() << endl; for (i = 1; i < constant_pool.Length(); i++) { if (! constant_pool.Valid(i)) continue; Coutput.width(5); Coutput << i << ": "; constant_pool[i] -> Print(constant_pool); } Coutput << endl << "### "; AccessFlags::Print(ACCESS_TYPE); Coutput << "this_class: " << (unsigned) this_class; if (constant_pool[this_class] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[this_class] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl << "super_class: " << (unsigned) super_class; if (! super_class) Coutput << "(none)"; else if (constant_pool[super_class] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[super_class] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl << "interfaces_count: " << (unsigned) interfaces.Length() << endl; for (i = 0; i < interfaces.Length(); i++) { Coutput << " " << (unsigned) interfaces[i]; if (constant_pool[interfaces[i]] -> Tag() == CPInfo::CONSTANT_Class) { Coutput << '='; constant_pool[interfaces[i]] -> Describe(constant_pool); } else Coutput << "(invalid)"; Coutput << endl; } Coutput << endl << "### Fields: fields_count: " << (unsigned) fields.Length() << endl; for (i = 0; i < fields.Length(); i++) fields[i] -> Print(constant_pool); Coutput << endl << "### Methods: methods_count: " << (unsigned) methods.Length() << endl; for (i = 0; i < methods.Length(); i++) methods[i] -> Print(constant_pool); Coutput << endl << "### Attributes: attributes_count: " << (unsigned) attributes.Length() << endl; for (i = 0; i < attributes.Length(); i++) attributes[i] -> Print(constant_pool); } #endif // JIKES_DEBUG }; #ifdef HAVE_JIKES_NAMESPACE } // Close namespace Jikes block #endif #endif // class_INCLUDED