// $Id: getclass.cpp,v 1.7 1999/03/09 14:37:17 shields Exp $ copyright notice #include "config.h" #include <sys/stat.h> #include "control.h" #include "semantic.h" #include "access.h" #include "getclass.h" #include "zip.h" inline u1 Semantic::GetU1(char *buffer) { return *buffer; } inline u2 Semantic::GetU2(char *buffer) { u2 i = (u1) *buffer++; return (i << 8) + (u1) *buffer; } inline u4 Semantic::GetU4(char *buffer) { u4 i = (u1) *buffer++; i = (i << 8) + (u1) *buffer++; i = (i << 8) + (u1) *buffer++; return (i << 8) + (u1) *buffer; } inline u1 Semantic::GetAndSkipU1(char *&buffer) { return (u1) *buffer++; } inline u2 Semantic::GetAndSkipU2(char *&buffer) { u2 i = (u1) *buffer++; return (i << 8) + (u1) *buffer++; } inline u4 Semantic::GetAndSkipU4(char *&buffer) { u4 i = (u1) *buffer++; i = (i << 8) + (u1) *buffer++; i = (i << 8) + (u1) *buffer++; return (i << 8) + (u1) *buffer++; } inline void Semantic::Skip(char *&buffer, int n) { buffer += n; } TypeSymbol *Semantic::ProcessNestedType(TypeSymbol *base_type, NameSymbol *name_symbol, LexStream::TokenIndex tok) { TypeSymbol *inner_type = base_type -> FindTypeSymbol(name_symbol); if (! inner_type) { int length = base_type -> ExternalNameLength() + 1 + name_symbol -> NameLength(); // +1 for $,... +1 for $ wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(external_name, base_type -> ExternalName()); wcscat(external_name, StringConstant::US__DS_); wcscat(external_name, name_symbol -> Name()); NameSymbol *external_name_symbol = control.FindOrInsertName(external_name, length); delete [] external_name; inner_type = base_type -> InsertNestedTypeSymbol(name_symbol); inner_type -> outermost_type = base_type -> outermost_type; inner_type -> supertypes_closure = new SymbolSet; inner_type -> subtypes = new SymbolSet; inner_type -> SetExternalIdentity(external_name_symbol); inner_type -> SetOwner(base_type); inner_type -> SetSignature(control); FileSymbol *file_symbol = Control::GetFile(base_type -> ContainingPackage(), external_name_symbol, control.option.depend); if (file_symbol) { inner_type -> file_symbol = file_symbol; inner_type -> SetLocation(); ReadClassFile(inner_type, tok); } else { inner_type -> SetSymbolTable(1); // this symbol table will only contain a default constructor inner_type -> super = control.Object(); inner_type -> MarkBad(); AddDefaultConstructor(inner_type); ReportSemError(SemanticError::TYPE_NOT_FOUND, tok, tok, inner_type -> ContainingPackage() -> PackageName(), inner_type -> ExternalName()); } } return inner_type; } TypeSymbol *Semantic::RetrieveNestedTypes(TypeSymbol *base_type, wchar_t *signature, LexStream::TokenIndex tok) { int len; for (len = 0; signature[len] != U_NULL && signature[len] != U_DOLLAR; len++) ; NameSymbol *name_symbol = control.FindOrInsertName(signature, len); TypeSymbol *inner_type = ProcessNestedType(base_type, name_symbol, tok); return (signature[len] == U_DOLLAR ? RetrieveNestedTypes(inner_type, &signature[len + 1], tok) : inner_type); } TypeSymbol *Semantic::ReadType(TypeSymbol *base_type, wchar_t *signature, LexStream::TokenIndex tok) { int total_length; for (total_length = 0; signature[total_length] != U_NULL && signature[total_length] != U_DOLLAR; total_length++) ; if (signature[total_length] != U_NULL && Code::IsDigit(signature[total_length + 1])) // an anonymous or a local type? { for (total_length += 2; Code::IsDigit(signature[total_length]); total_length++) // will stop at next '$' or '\0' !!! ; if (signature[total_length] != U_NULL) // not an anonymous type ? then, it's a local type: scan local name { for (total_length++; signature[total_length] != U_NULL && signature[total_length] != U_DOLLAR; total_length++) ; } } int len; for (len = total_length - 1; len >= 0 && signature[len] != U_SLASH; len--) ; wchar_t *name = &(signature[len + 1]); // // When a package name is specified in the signature, we look for the type in question // in that package, i.e., we redefine package. Otherwise, we search for the type in the // unnamed package. // PackageSymbol *package = NULL; // // Which package? // if (len >= 0) { wchar_t *package_name = new wchar_t[len + 1]; for (int i = 0; i < len; i++) package_name[i] = signature[i]; package_name[len] = U_NULL; package = control.ProcessPackage(package_name); if (package -> directory.Length() == 0) { ReportSemError(SemanticError::PACKAGE_NOT_FOUND, tok, tok, package -> PackageName()); } delete [] package_name; } else package = control.unnamed_package; // // Process type // NameSymbol *name_symbol = control.FindOrInsertName(name, total_length - (len + 1)); TypeSymbol *type = package -> FindTypeSymbol(name_symbol); if (type) { if (type -> SourcePending()) control.ProcessHeaders(type -> file_symbol); } else { FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend); // // If we are dealing with the unnamed package, ... // if ((! file_symbol) && package == control.unnamed_package) file_symbol = Control::GetFile(control.unnamed_package, name_symbol, control.option.depend); // // If a file_symbol was not found, ReadType will issue an error message // type = ReadType(file_symbol, package, name_symbol, tok); // // If we have to do a full check and we have a case where a ".class" file // depends on a ".java" file then we should signal that the ".java" file // associated with the ".class" file should be recompiled. // if (control.option.full_check && (! control.option.depend) && file_symbol && file_symbol -> IsJava() && (! file_symbol -> IsZip())) { control.recompilation_file_set.AddElement(file_symbol); if (! control.option.incremental && control.option.pedantic) { ReportSemError(SemanticError::RECOMPILATION, tok, tok, base_type -> ContainingPackage() -> Name(), base_type -> ExternalName(), type -> ContainingPackage() -> Name(), type -> ExternalName()); } } } // // Establish a dependence from base_type (read from a class file) to type. // AddDependence(base_type, type, tok); return (signature[total_length] == U_DOLLAR ? RetrieveNestedTypes(type, &signature[total_length + 1], tok) : type); } TypeSymbol *Semantic::ProcessSignature(TypeSymbol *base_type, char *signature, LexStream::TokenIndex tok) { TypeSymbol *type; int num_dimensions = 0; for (; *signature == U_LEFT_BRACKET; signature++) num_dimensions++; switch(*signature) { case U_B: type = control.byte_type; break; case U_C: type = control.char_type; break; case U_D: type = control.double_type; break; case U_F: type = control.float_type; break; case U_I: type = control.int_type; break; case U_J: type = control.long_type; break; case U_L: { // // The signature is of the form: "L<filename>;" - So, +1 to skip the 'L' // char *str; for (str = signature++; *str != U_SEMICOLON; str++) ; int len = str - signature; wchar_t *type_name = new wchar_t[len + 1]; ConvertUtf8ToUnicode(type_name, signature, len); type = ReadType(base_type, type_name, tok); delete [] type_name; } break; case U_S: type = control.short_type; break; case U_Z: type = control.boolean_type; break; case U_V: type = control.void_type; break; default: assert(! "KNOW WHAT TO DO WITH SIGNATURE"); break; } return (num_dimensions == 0 ? type : type -> GetArrayType((Semantic *)this, num_dimensions)); } inline TypeSymbol *Semantic::GetClassPool(TypeSymbol *base_type, TypeSymbol **class_pool, char **constant_pool, int index, LexStream::TokenIndex tok) { if (! class_pool[index]) { u2 name_index = Constant_Class_info::NameIndex(constant_pool[index]); char *str = Constant_Utf8_info::Bytes(constant_pool[name_index]); if (*str == U_LEFT_BRACKET) class_pool[index] = ProcessSignature(base_type, str, tok); else { u2 length = Constant_Utf8_info::Length(constant_pool[name_index]); char *p; for (p = &str[length - 1]; Code::IsDigit(*p); p--) ; if (*p != U_DOLLAR) // not an anonymous class { wchar_t *type_name = new wchar_t[length + 1]; ConvertUtf8ToUnicode(type_name, str, length); class_pool[index] = ReadType(base_type, type_name, tok); delete [] type_name; } } } return class_pool[index]; } void Semantic::ReadClassFile(TypeSymbol *type, LexStream::TokenIndex tok) { #ifdef TEST control.class_file_id++; control.class_files_read++; #endif FileSymbol *file_symbol = type -> file_symbol; if (control.option.verbose) { cout << "[read "; Unicode::Cout(file_symbol -> FileName()); cout << "]\n"; } if (file_symbol -> IsZip()) { ZipFile *zipfile = new ZipFile(file_symbol); if (zipfile -> Buffer() == NULL) { type -> SetSymbolTable(1); // this symbol table will only contain a default constructor if (type != control.Object()) type -> super = (type == control.Throwable() ? control.Object() : control.Throwable()); type -> MarkBad(); AddDefaultConstructor(type); ReportSemError(SemanticError::COMPRESSED_ZIP_FILE, tok, tok, file_symbol -> PathSym() -> Name(), type -> ContainingPackage() -> PackageName(), type -> ExternalName()); } else if (! ProcessClassFile(type, zipfile -> Buffer(), file_symbol -> uncompressed_size, tok)) ProcessBadClass(type, tok); delete zipfile; } else { #ifdef UNIX_FILE_SYSTEM FILE *classfile = ::SystemFopen(file_symbol -> FileName(), "rb"); if (classfile == NULL) { type -> SetSymbolTable(1); // this symbol table will only contain a default constructor if (type != control.Object()) type -> super = (type == control.Throwable() ? control.Object() : control.Throwable()); type -> MarkBad(); AddDefaultConstructor(type); ReportSemError(SemanticError::CANNOT_OPEN_CLASS_FILE, tok, tok, type -> ContainingPackage() -> PackageName(), type -> ExternalName()); } else { struct stat status; ::SystemStat(file_symbol -> FileName(), &status); char *class_buffer = new char[status.st_size]; fread(class_buffer, sizeof(char), status.st_size, classfile); fclose(classfile); if (! ProcessClassFile(type, class_buffer, status.st_size, tok)) ProcessBadClass(type, tok); delete [] class_buffer; } #elif defined(WIN32_FILE_SYSTEM) HANDLE classfile = CreateFile(file_symbol -> FileName(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); HANDLE mapfile = (classfile == INVALID_HANDLE_VALUE ? classfile : CreateFileMapping(classfile, NULL, PAGE_READONLY, 0, 0, NULL)); char *class_buffer = (mapfile == INVALID_HANDLE_VALUE ? NULL : (char *) MapViewOfFile(mapfile, FILE_MAP_READ, 0, 0, 0)); if (class_buffer == NULL) { type -> SetSymbolTable(1); // this symbol table will only contain a default constructor if (type != control.Object()) type -> super = (type == control.Throwable() ? control.Object() : control.Throwable()); type -> MarkBad(); AddDefaultConstructor(type); ReportSemError(SemanticError::CANNOT_OPEN_CLASS_FILE, tok, tok, type -> ContainingPackage() -> PackageName(), type -> ExternalName()); } else { DWORD high_order, size = GetFileSize(classfile, &high_order); size = (size == 0xFFFFFFFF && GetLastError() != NO_ERROR ? 0 : size); if (! ProcessClassFile(type, class_buffer, size, tok)) ProcessBadClass(type, tok); UnmapViewOfFile(class_buffer); CloseHandle(mapfile); CloseHandle(classfile); } #endif } return; } void Semantic::ProcessBadClass(TypeSymbol *type, LexStream::TokenIndex tok) { if (! type -> Table()) // if there is no symbol table, add one type -> SetSymbolTable(1); // this symbol table will only contain a default constructor if ((! type -> super) && type != control.Object()) // if there is no super type, add one type -> super = (type == control.Throwable() ? control.Object() : control.Throwable()); type -> MarkBad(); if (! type -> FindConstructorSymbol()) // if there are no constructors, add a default one AddDefaultConstructor(type); ReportSemError(SemanticError::INVALID_CLASS_FILE, tok, tok, type -> ContainingPackage() -> PackageName(), type -> ExternalName()); return; } bool Semantic::ProcessClassFile(TypeSymbol *type, char *buffer, int buffer_size, LexStream::TokenIndex tok) { char *buffer_tail = &buffer[buffer_size]; type -> MarkHeaderProcessed(); type -> MarkConstructorMembersProcessed(); type -> MarkMethodMembersProcessed(); type -> MarkFieldMembersProcessed(); type -> MarkLocalClassProcessingCompleted(); type -> MarkSourceNoLongerPending(); Skip(buffer, 8); // u4 magic; // u2 minor_version; // u2 major_version; if (! InRange(buffer, buffer_tail, 2)) return false; u2 constant_pool_count = GetAndSkipU2(buffer); char **constant_pool = new char*[constant_pool_count]; TypeSymbol **class_pool = (TypeSymbol **) memset(new TypeSymbol*[constant_pool_count], 0, constant_pool_count * sizeof(TypeSymbol *)); constant_pool[0] = NULL; int *next_pool_index = new int[constant_pool_count], Class_root = 0, NameAndType_root = 0; for (int i = 1; i < constant_pool_count; i++) { constant_pool[i] = buffer; if (! InRange(buffer, buffer_tail, 1)) return false; u1 tag = GetAndSkipU1(buffer); if (tag == Cp_Info::CONSTANT_Long || tag == Cp_Info::CONSTANT_Double) ++i; // skip the next entry for eight-byte constants u2 length; switch(tag) { case Cp_Info::CONSTANT_Utf8: if (! InRange(buffer, buffer_tail, 2)) return false; length = GetAndSkipU2(buffer); break; case Cp_Info::CONSTANT_Class: length = 2; // set_NameIndex(GetU2(classfile)); next_pool_index[i] = Class_root; // save index of class constant Class_root = i; break; case Cp_Info::CONSTANT_String: length = 2; // set_NameIndex(GetU2(classfile)); break; case Cp_Info::CONSTANT_NameAndType: length = 4; // set_class_index(GetU2(classfile)); set_name_and_type_index(GetU2(classfile)); // or // set_NameIndex(GetU2(classfile)); set_DescriptorIndex(GetU2(classfile)); // or // SetBytes(GetU4(classfile)); next_pool_index[i] = NameAndType_root; // save index of class constant NameAndType_root = i; break; case Cp_Info::CONSTANT_Fieldref: case Cp_Info::CONSTANT_Methodref: case Cp_Info::CONSTANT_InterfaceMethodref: case Cp_Info::CONSTANT_Integer: case Cp_Info::CONSTANT_Float: length = 4; // set_class_index(GetU2(classfile)); set_name_and_type_index(GetU2(classfile)); // or // set_NameIndex(GetU2(classfile)); set_DescriptorIndex(GetU2(classfile)); // or // SetBytes(GetU4(classfile)); break; case Cp_Info::CONSTANT_Long: case Cp_Info::CONSTANT_Double: length = 8; // set_HighBytes(GetU4(classfile)); // set_LowBytes(GetU4(classfile)); break; default: cerr << "chaos: CODE \"" << (int) tag << "\" is an invalid tag !!!\n"; cerr.flush(); break; } Skip(buffer, length); } // // We are now ready to process this class file. If type is a nested // class, we will set its untransformed access flags properly later... // if (! InRange(buffer, buffer_tail, 2)) return false; type -> access_flags = GetAndSkipU2(buffer); if (! InRange(buffer, buffer_tail, 2)) return false; u2 this_class_index = GetAndSkipU2(buffer); // The index of this class u2 name_index = Constant_Class_info::NameIndex(constant_pool[this_class_index]); char *type_name = Constant_Utf8_info::Bytes(constant_pool[name_index]); u2 type_name_length = Constant_Utf8_info::Length(constant_pool[name_index]); int n; for (n = type_name_length; n >= 0 && type_name[n] != U_SLASH; n--) ; bool matched_package_names; if (type -> ContainingPackage() -> PackageNameLength() == n) { wchar_t *package_name = type -> ContainingPackage() -> PackageName(); int i; for (i = 0; i < n && package_name[i] == type_name[i]; i++) ; matched_package_names = (i == n); } else matched_package_names = (n < 0 && type -> ContainingPackage() == control.unnamed_package); if (! matched_package_names) { type -> SetSymbolTable(1); // this symbol table will only contain a default constructor if (type != control.Object()) type -> super = (type == control.Throwable() ? control.Object() : control.Throwable()); type -> MarkBad(); AddDefaultConstructor(type); if (n < 0) n = 0; wchar_t *package_name = new wchar_t[n + 1]; for (int i = 0; i < n; i++) package_name[i] = type_name[i]; package_name[n] = U_NULL; if (type -> ContainingPackage() == control.unnamed_package) ReportSemError(SemanticError::TYPE_NOT_IN_UNNAMED_PACKAGE, tok, tok, type -> ExternalName(), type -> file_symbol -> directory_symbol -> PathSym() -> Name(), package_name); else ReportSemError(SemanticError::TYPE_IN_WRONG_PACKAGE, tok, tok, type -> ExternalName(), type -> ContainingPackage() -> PackageName(), package_name); delete [] package_name; } else { if ((! type -> IsNested()) && (n < 0)) // An outermost type contained in the unnamed package? { TypeSymbol *old_type = (TypeSymbol *) control.unnamed_package_types.Image(type -> Identity()); if (! old_type) control.unnamed_package_types.AddElement(type); else { ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION, tok, tok, type -> Name(), old_type -> FileLoc()); } } // // On systems such as NT and Win-95 that are not case-sensitive, // we need to confirm that the type name specified matches the name // in the class file. // assert(type_name_length - (n + 1) == type -> ExternalNameLength()); int i; for (i = 0; i < type -> ExternalNameLength(); i++) { if (type_name[(n + 1) + i] != type -> ExternalName()[i]) break; } if (i < type -> ExternalNameLength()) { wchar_t *name = new wchar_t[type_name_length + 1]; for (int k = 0; k < type_name_length; k++) name[k] = type_name[k]; name[type_name_length] = U_NULL; ReportSemError(SemanticError::TYPE_NAME_MISMATCH, tok, tok, type -> ContainingPackage() -> PackageName(), type -> ExternalName(), name); delete [] name; } // // ... Start doing real work !!! // if (! InRange(buffer, buffer_tail, 2)) return false; u2 super_class = GetAndSkipU2(buffer); if (super_class) { type -> super = GetClassPool(type, class_pool, constant_pool, super_class, tok); type -> outermost_type -> supertypes_closure -> AddElement(type -> super -> outermost_type); type -> outermost_type -> supertypes_closure -> Union(*type -> super -> outermost_type -> supertypes_closure); } if (! InRange(buffer, buffer_tail, 2)) return false; for (int j = GetAndSkipU2(buffer); j > 0; j--) { if (! InRange(buffer, buffer_tail, 2)) return false; u2 interface_index = GetAndSkipU2(buffer); type -> AddInterface(GetClassPool(type, class_pool, constant_pool, interface_index, tok)); type -> outermost_type -> supertypes_closure -> AddElement(type -> super -> outermost_type); type -> outermost_type -> supertypes_closure -> Union(*type -> super -> outermost_type -> supertypes_closure); } // // Read all the fields // if (! InRange(buffer, buffer_tail, 2)) return false; u2 fields_count = GetAndSkipU2(buffer); VariableSymbol **fields = new VariableSymbol*[fields_count]; for (int k = 0; k < fields_count; k++) { if (! InRange(buffer, buffer_tail, 6)) return false; u2 access_flags = GetAndSkipU2(buffer); u2 name_index = GetAndSkipU2(buffer); u2 descriptor_index = GetAndSkipU2(buffer); u2 length = Constant_Utf8_info::Length(constant_pool[name_index]); wchar_t *variable_name = new wchar_t[length + 1]; ConvertUtf8ToUnicode(variable_name, Constant_Utf8_info::Bytes(constant_pool[name_index]), length); NameSymbol *name_symbol = control.FindOrInsertName(variable_name, length); delete [] variable_name; VariableSymbol *symbol = new VariableSymbol(name_symbol); fields[k] = symbol; symbol -> SetOwner(type); symbol -> MarkComplete(); symbol -> SetFlags(access_flags); symbol -> SetSignatureString(Constant_Utf8_info::Bytes(constant_pool[descriptor_index]), Constant_Utf8_info::Length(constant_pool[descriptor_index])); if (! InRange(buffer, buffer_tail, 2)) return false; int j = GetAndSkipU2(buffer); for (; j > 0; j--) { if (! InRange(buffer, buffer_tail, 2)) return false; u2 name_index = GetAndSkipU2(buffer); if (Constant_Utf8_info::Length(constant_pool[name_index]) == StringConstant::U8S_Synthetic_length && memcmp(Constant_Utf8_info::Bytes(constant_pool[name_index]), StringConstant::U8S_Synthetic, StringConstant::U8S_Synthetic_length * sizeof(char)) == 0) { symbol -> MarkSynthetic(); if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, 4); // u4 attribute_length() { return attribute_length_; } // there is no info associated with a Synthetic attribute break; // If the field is synthetic, remaining attributes don't matter... } else if (Constant_Utf8_info::Length(constant_pool[name_index]) == StringConstant::U8S_ConstantValue_length && memcmp(Constant_Utf8_info::Bytes(constant_pool[name_index]), StringConstant::U8S_ConstantValue, StringConstant::U8S_ConstantValue_length * sizeof(char)) == 0) { Skip(buffer, 4); // u4 attribute_length; if (! InRange(buffer, buffer_tail, 2)) return false; u2 constantvalue_index = GetAndSkipU2(buffer); u1 tag = Cp_Info::Tag(constant_pool[constantvalue_index]); if (tag == Cp_Info::CONSTANT_Integer) { int value = Constant_Integer_info::Value(constant_pool[constantvalue_index]); symbol -> initial_value = control.int_pool.FindOrInsert(value); } else if (tag == Cp_Info::CONSTANT_Long) { LongInt value = Constant_Long_info::Value(constant_pool[constantvalue_index]); symbol -> initial_value = control.long_pool.FindOrInsert(value); } else if (tag == Cp_Info::CONSTANT_Float) { IEEEfloat value = Constant_Float_info::Value(constant_pool[constantvalue_index]); symbol -> initial_value = control.float_pool.FindOrInsert(value); } else if (tag == Cp_Info::CONSTANT_Double) { IEEEdouble value = Constant_Double_info::Value(constant_pool[constantvalue_index]); symbol -> initial_value = control.double_pool.FindOrInsert(value); } else if (tag == Cp_Info::CONSTANT_String) { u2 string_index = Constant_String_info::StringIndex(constant_pool[constantvalue_index]); u2 length = Constant_Utf8_info::Length(constant_pool[string_index]); char *value = Constant_Utf8_info::Bytes(constant_pool[string_index]); symbol -> initial_value = control.Utf8_pool.FindOrInsert(value, length); } else if (tag == Cp_Info::CONSTANT_Utf8) { u2 length = Constant_Utf8_info::Length(constant_pool[constantvalue_index]); char *value = Constant_Utf8_info::Bytes(constant_pool[constantvalue_index]); symbol -> initial_value = control.Utf8_pool.FindOrInsert(value, length); } else { cerr << "chaos: Constant tag \"" << (int) tag << "\" is an invalid tag !!!\n"; cerr.flush(); } } else { if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, GetAndSkipU4(buffer)); // u4 attribute_length() { return attribute_length_; } // u1 *info; /* info[attribute_length] */ } } // // Skip remaining attributes // while (--j > 0) { Skip(buffer, 2); // u2 name_index if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, GetAndSkipU4(buffer)); // u4 attribute_length() { return attribute_length_; } // u1 *info; /* info[attribute_length] */ } } // // Read all the methods // if (! InRange(buffer, buffer_tail, 2)) return false; u2 methods_count = GetAndSkipU2(buffer); MethodSymbol **methods = new MethodSymbol*[methods_count]; for (int l = 0; l < methods_count; l++) { if (! InRange(buffer, buffer_tail, 6)) return false; u2 access_flags = GetAndSkipU2(buffer); u2 name_index = GetAndSkipU2(buffer); u2 descriptor_index = GetAndSkipU2(buffer); u2 length = Constant_Utf8_info::Length(constant_pool[name_index]); wchar_t *method_name = new wchar_t[length + 1]; ConvertUtf8ToUnicode(method_name, Constant_Utf8_info::Bytes(constant_pool[name_index]), length); NameSymbol *name_symbol = control.FindOrInsertName(method_name, length); delete [] method_name; if (! InRange(buffer, buffer_tail, 2)) return false; int j = GetAndSkipU2(buffer); // number of attributes if (name_symbol == control.clinit_name_symbol) { methods[l] = NULL; j++; // see the loop (way) below that skips the remaining attributes } else { MethodSymbol *method = new MethodSymbol(name_symbol); methods[l] = method; method -> SetContainingType(type); method -> SetFlags(access_flags); char *signature = Constant_Utf8_info::Bytes(constant_pool[descriptor_index]); int length = Constant_Utf8_info::Length(constant_pool[descriptor_index]); method -> SetSignature(control.Utf8_pool.FindOrInsert(signature, length)); // // Read the exception that can be thrown by this method // for (; j > 0; j--) { if (! InRange(buffer, buffer_tail, 2)) return false; u2 name_index = GetAndSkipU2(buffer); if (Constant_Utf8_info::Length(constant_pool[name_index]) == StringConstant::U8S_Synthetic_length && memcmp(Constant_Utf8_info::Bytes(constant_pool[name_index]), StringConstant::U8S_Synthetic, StringConstant::U8S_Synthetic_length * sizeof(char)) == 0) { method -> MarkSynthetic(); if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, 4); // u4 attribute_length() { return attribute_length_; } // there is no info associated with a Synthetic attribute break; // If the field is synthetic, remaining attributes don't matter... } else if (Constant_Utf8_info::Length(constant_pool[name_index]) == StringConstant::U8S_Exceptions_length && memcmp(Constant_Utf8_info::Bytes(constant_pool[name_index]), StringConstant::U8S_Exceptions, StringConstant::U8S_Exceptions_length * sizeof(char)) == 0) { Skip(buffer, 4); // attribute_length = GetAndSkipU4(buffer); if (! InRange(buffer, buffer_tail, 2)) return false; for (int k = GetAndSkipU2(buffer); k > 0; k--) { if (! InRange(buffer, buffer_tail, 2)) return false; int index = GetAndSkipU2(buffer); u2 name_index = Constant_Class_info::NameIndex(constant_pool[index]); method -> AddThrowsSignature(Constant_Utf8_info::Bytes(constant_pool[name_index]), Constant_Utf8_info::Length(constant_pool[name_index])); } } else { if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, GetAndSkipU4(buffer)); // u4 attribute_length() { return attribute_length_; } // u1 *info; /* info[attribute_length] */ } } } // // Skip remaining attributes // while (--j > 0) { Skip(buffer, 2); // u2 name_index if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, GetAndSkipU4(buffer)); // u4 attribute_length() { return attribute_length_; } // u1 *info; /* info[attribute_length] */ } } // // Process InnerClasses attributes // if (! InRange(buffer, buffer_tail, 2)) return false; u2 attributes_count = GetAndSkipU2(buffer); Tuple<u2> inner_name_indexes(8); for (int a = 0; a < attributes_count; a++) { if (! InRange(buffer, buffer_tail, 2)) return false; u2 name_index = GetAndSkipU2(buffer); if (Constant_Utf8_info::Length(constant_pool[name_index]) == StringConstant::U8S_InnerClasses_length && memcmp(Constant_Utf8_info::Bytes(constant_pool[name_index]), StringConstant::U8S_InnerClasses, StringConstant::U8S_InnerClasses_length * sizeof(char)) == 0) { Skip(buffer, 4); // attribute_length = GetAndSkipU4(buffer); if (! InRange(buffer, buffer_tail, 2)) return false; for (int k = GetAndSkipU2(buffer); k > 0; k--) { if (! InRange(buffer, buffer_tail, 8)) return false; u2 inner_class_info_index = GetAndSkipU2(buffer); u2 outer_class_info_index = GetAndSkipU2(buffer); u2 inner_name_index = GetAndSkipU2(buffer); u2 inner_class_access_flags = GetAndSkipU2(buffer); // // Recall that the untransformed access flag is the one specified // in the inner_class attribute. (See 1.1 document) // if (inner_class_info_index == this_class_index) type -> access_flags = inner_class_access_flags; // // This guard statement is used to identify only inner classes that are // not anonymous classes and are immediately contained within this class. // Recall that an inner class may not be enclosed (directly on indirectly) // in another class with the same name. Therefore when outer_class_info_index // matches this_class_index they both refer to "this" class (that we are currently processing). // else if ((outer_class_info_index == this_class_index) && (inner_class_info_index != 0) && // an inner class (inner_name_index != 0)) // not an anonymous class { // // When length is 0, the inner class in question is "this" class ? // the one we are currently reading ? // u2 length = Constant_Utf8_info::Length(constant_pool[inner_name_index]); if (length > 0) inner_name_indexes.Next() = inner_name_index; } } break; // We are only interested in the inner classes attribute } else { if (! InRange(buffer, buffer_tail, 4)) return false; Skip(buffer, GetAndSkipU4(buffer)); // u4 attribute_length() { return attribute_length_; } // u1 *info; /* info[attribute_length] */ } } // // No need to skip the remaining attributes // // while (--j > 0) // { // Skip(buffer, 2); // u2 name_index // Skip(buffer, GetAndSkipU4(buffer)); // u4 attribute_length() { return attribute_length_; } // // u1 *info; /* info[attribute_length] */ // } // // // We now have enough information to make a good estimate for the size of the // symbol table we need for this class. // type -> SetSymbolTable(fields_count + methods_count + inner_name_indexes.Length()); // // . Read in all class files that are referenced in CONSTANT_Class // structures in this class file. // // . Read in all class files that are referenced in CONSTANT_NameAndType // structures in this class file. // if (control.option.full_check && (control.option.unzip || (! type -> file_symbol -> IsZip()))) { for (int h = Class_root; h != 0; h = next_pool_index[h]) GetClassPool(type, class_pool, constant_pool, h, tok); for (int j = NameAndType_root; j != 0; j = next_pool_index[j]) { u2 descriptor_index = Constant_NameAndType_info::DescriptorIndex(constant_pool[j]); char *signature = Constant_Utf8_info::Bytes(constant_pool[descriptor_index]); if (! class_pool[descriptor_index]) { if (*signature != U_LEFT_PARENTHESIS) // ')' indicates a field descriptor class_pool[descriptor_index] = ProcessSignature(type, Constant_Utf8_info::Bytes(constant_pool[descriptor_index]), tok); else // a method descriptor { signature++; // +1 to skip initial '(' while (*signature != U_RIGHT_PARENTHESIS) { char *str; for (str = signature; *str == U_LEFT_BRACKET; str++) ; if (*str == U_L) { for (str++; *str != U_SEMICOLON; str++) ; } int len = str - signature + 1; signature += len; // make signature point to next type } signature++; // skip L')' class_pool[descriptor_index] = ProcessSignature(type, signature, tok); // save the return type in first spot } } } // // Process all the fields, then the methods, then the inner types. // Read in all the types associated with the signatures. // for (int k = 0; k < fields_count; k++) { type -> InsertVariableSymbol(fields[k]); fields[k] -> ProcessVariableSignature((Semantic *) this, tok); } for (int l = 0; l < methods_count; l++) { if (methods[l]) { MethodSymbol *method = type -> FindMethodSymbol(methods[l] -> name_symbol); if (! method) { if (methods[l] -> name_symbol == control.init_name_symbol) type -> InsertConstructorSymbol(methods[l]); else type -> InsertMethodSymbol(methods[l]); } else type -> Overload(method, methods[l]); methods[l] -> ProcessMethodSignature((Semantic *) this, tok); } } for (int m = 0; m < inner_name_indexes.Length(); m++) { u2 inner_name_index = inner_name_indexes[m]; type -> AddNestedTypeSignature(Constant_Utf8_info::Bytes(constant_pool[inner_name_index]), Constant_Utf8_info::Length(constant_pool[inner_name_index])); } type -> ProcessNestedTypeSignatures((Semantic *) this, tok); } else { // // Process all the fields, then the methods, then the inner types. // for (int k = 0; k < fields_count; k++) type -> InsertVariableSymbol(fields[k]); for (int l = 0; l < methods_count; l++) { if (methods[l]) { MethodSymbol *method = type -> FindMethodSymbol(methods[l] -> name_symbol); if (! method) { if (methods[l] -> name_symbol == control.init_name_symbol) type -> InsertConstructorSymbol(methods[l]); else type -> InsertMethodSymbol(methods[l]); } else type -> Overload(method, methods[l]); } } for (int m = 0; m < inner_name_indexes.Length(); m++) { u2 inner_name_index = inner_name_indexes[m]; type -> AddNestedTypeSignature(Constant_Utf8_info::Bytes(constant_pool[inner_name_index]), Constant_Utf8_info::Length(constant_pool[inner_name_index])); } } delete [] fields; delete [] methods; // // Release extra space. This is an optimization. // type -> CompressSpace(); } delete [] next_pool_index; delete [] class_pool; delete [] constant_pool; return true; }