X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fdefineclass.cc;h=111b1fb2ca2fb83120b23cdb293c8f4531783524;hb=afff762b4a3bc563d1ed26cad64930c4c9135cf7;hp=001fa0131f025ac7879c7939d10c34cfeb29096b;hpb=82733f8decd8b228c8152ae27fd102701250c456;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index 001fa0131f0..111b1fb2ca2 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -1,6 +1,6 @@ // defineclass.cc - defining a class from .class format. -/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation This file is part of libgcj. @@ -23,8 +23,10 @@ details. */ #include #include +#include #include #include +#include #include #include @@ -37,6 +39,7 @@ details. */ #include #include #include +#include using namespace gcj; @@ -75,7 +78,7 @@ struct _Jv_ClassReader { // allways on. You always want this as far as I can see, but it also // controls weither identifiers and type descriptors/signatures are // verified as legal. This could be somewhat more expensive since it - // will call Characher.isJavaIdentifier{Start,Part} for each character + // will call Character.isJavaIdentifier{Start,Part} for each character // in any identifier (field name or method name) it comes by. Thus, // it might be useful to turn off this verification for classes that // come from a trusted source. However, for GCJ, trusted classes are @@ -96,7 +99,10 @@ struct _Jv_ClassReader { unsigned int *offsets; // the class to define (see java-interp.h) - _Jv_InterpClass *def; + jclass def; + + // the classes associated interpreter data. + _Jv_InterpClass *def_interp; /* check that the given number of input bytes are available */ inline void check (int num) @@ -212,7 +218,8 @@ struct _Jv_ClassReader { throw_class_format_error ("erroneous type descriptor"); } - _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length) + _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length, + java::security::ProtectionDomain *pd) { if (klass == 0 || length < 0 || offset+length > data->length) throw_internal_error ("arguments to _Jv_DefineClass"); @@ -221,7 +228,12 @@ struct _Jv_ClassReader { bytes = (unsigned char*) (elements (data)+offset); len = length; pos = 0; - def = (_Jv_InterpClass*) klass; + def = klass; + + def->size_in_bytes = -1; + def->vtable_method_count = -1; + def->engine = &_Jv_soleInterpreterEngine; + def->protectionDomain = pd; } /** and here goes the parser members defined out-of-line */ @@ -268,9 +280,10 @@ struct _Jv_ClassReader { }; void -_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length) +_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length, + java::security::ProtectionDomain *pd) { - _Jv_ClassReader reader (klass, data, offset, length); + _Jv_ClassReader reader (klass, data, offset, length, pd); reader.parse(); /* that's it! */ @@ -306,8 +319,13 @@ _Jv_ClassReader::parse () handleClassBegin (access_flags, this_class, super_class); + // Allocate our aux_info here, after the name is set, to fulfill our + // contract with the collector interface. + def->aux_info = (void *) _Jv_AllocBytes (sizeof (_Jv_InterpClass)); + def_interp = (_Jv_InterpClass *) def->aux_info; + int interfaces_count = read2u (); - + handleInterfacesBegin (interfaces_count); for (int i = 0; i < interfaces_count; i++) @@ -330,10 +348,11 @@ _Jv_ClassReader::parse () if (pos != len) throw_class_format_error ("unused data before end of file"); - // tell everyone we're done. - def->state = JV_STATE_LOADED; + // Tell everyone we're done. + def->state = JV_STATE_READ; + if (gcj::verbose_class_flag) + _Jv_Linker::print_class_loaded (def); def->notifyAll (); - } void _Jv_ClassReader::read_constpool () @@ -403,15 +422,15 @@ void _Jv_ClassReader::read_fields () int name_index = read2u (); int descriptor_index = read2u (); int attributes_count = read2u (); - + check_tag (name_index, JV_CONSTANT_Utf8); prepare_pool_entry (name_index, JV_CONSTANT_Utf8); check_tag (descriptor_index, JV_CONSTANT_Utf8); prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8); - + handleField (i, access_flags, name_index, descriptor_index); - + for (int j = 0; j < attributes_count; j++) { read_one_field_attribute (i); @@ -510,30 +529,20 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index) throw_class_format_error ("only one Exceptions attribute allowed per method"); int num_exceptions = read2u (); - // We use malloc here because the GC won't scan the method - // objects. FIXME this means a memory leak if we GC a class. - // (Currently we never do.) _Jv_Utf8Const **exceptions = - (_Jv_Utf8Const **) _Jv_Malloc ((num_exceptions + 1) * sizeof (_Jv_Utf8Const *)); + (_Jv_Utf8Const **) _Jv_AllocBytes ((num_exceptions + 1) + * sizeof (_Jv_Utf8Const *)); int out = 0; _Jv_word *pool_data = def->constants.data; for (int i = 0; i < num_exceptions; ++i) { - try + int ndx = read2u (); + // JLS 2nd Ed. 4.7.5 requires that the tag not be 0. + if (ndx != 0) { - int ndx = read2u (); - // JLS 2nd Ed. 4.7.5 requires that the tag not be 0. - if (ndx != 0) - { - check_tag (ndx, JV_CONSTANT_Class); - exceptions[out++] = pool_data[ndx].utf8; - } - } - catch (java::lang::Throwable *exc) - { - _Jv_Free (exceptions); - throw exc; + check_tag (ndx, JV_CONSTANT_Class); + exceptions[out++] = pool_data[ndx].utf8; } } exceptions[out] = NULL; @@ -605,26 +614,54 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index) } } -void _Jv_ClassReader::read_one_code_attribute (int /*method*/) +void _Jv_ClassReader::read_one_code_attribute (int method_index) { - /* ignore for now, ... later we may want to pick up - line number information, for debugging purposes; - in fact, the whole debugger issue is open! */ - - /* int name = */ read2u (); + int name = read2u (); int length = read4 (); - skip (length); - + if (is_attribute_name (name, "LineNumberTable")) + { + _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *> + (def_interp->interpreted_methods[method_index]); + if (method->line_table != NULL) + throw_class_format_error ("Method already has LineNumberTable"); + + int table_len = read2u (); + _Jv_LineTableEntry* table + = (_Jv_LineTableEntry *) JvAllocBytes (table_len + * sizeof (_Jv_LineTableEntry)); + for (int i = 0; i < table_len; i++) + { + table[i].bytecode_pc = read2u (); + table[i].line = read2u (); + } + method->line_table_len = table_len; + method->line_table = table; + } + else + { + /* ignore unknown code attributes */ + skip (length); + } } void _Jv_ClassReader::read_one_class_attribute () { - /* we also ignore the class attributes, ... - some day we'll add inner-classes support. */ - - /* int name = */ read2u (); + int name = read2u (); int length = read4 (); - skip (length); + if (is_attribute_name (name, "SourceFile")) + { + int source_index = read2u (); + check_tag (source_index, JV_CONSTANT_Utf8); + prepare_pool_entry (source_index, JV_CONSTANT_Utf8); + def_interp->source_file_name = _Jv_NewStringUtf8Const + (def->constants.data[source_index].utf8); + } + else + { + /* Currently, we ignore most class attributes. + FIXME: Add inner-classes attributes support. */ + skip (length); + } } @@ -772,9 +809,9 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag) name_index, type_index); if (this_tag == JV_CONSTANT_Fieldref) - _Jv_VerifyFieldSignature (pool_data[type_index].utf8); + verify_field_signature (pool_data[type_index].utf8); else - _Jv_VerifyMethodSignature (pool_data[type_index].utf8); + verify_method_signature (pool_data[type_index].utf8); _Jv_Utf8Const* name = pool_data[name_index].utf8; @@ -847,8 +884,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag) void -_Jv_ClassReader::handleClassBegin - (int access_flags, int this_class, int super_class) +_Jv_ClassReader::handleClassBegin (int access_flags, int this_class, int super_class) { using namespace java::lang::reflect; @@ -861,7 +897,7 @@ _Jv_ClassReader::handleClassBegin // was ClassLoader.defineClass called with an expected class name? if (def->name == 0) { - jclass orig = _Jv_FindClassInCache (loadedName, def->loader); + jclass orig = def->loader->findLoadedClass(loadedName->toString()); if (orig == 0) { @@ -884,7 +920,7 @@ _Jv_ClassReader::handleClassBegin jstring msg = JvNewStringUTF ("loaded class "); msg = msg->concat (def->getName ()); msg = msg->concat (_Jv_NewStringUTF (" was in fact named ")); - jstring klass_name = _Jv_NewStringUTF (loadedName->data); + jstring klass_name = loadedName->toString(); msg = msg->concat (klass_name); throw_no_class_def_found_error (msg); @@ -901,16 +937,14 @@ _Jv_ClassReader::handleClassBegin throw_no_class_def_found_error ("loading java.lang.Object"); } - // In the pre-loading state, it can be looked up in the - // cache only by this thread! This allows the super-class - // to include references to this class. - def->state = JV_STATE_PRELOADING; - { - JvSynchronize sync (&java::lang::Class::class$); - _Jv_RegisterClass (def); - } + // Register this class with its defining loader as well (despite the + // name of the function we're calling), so that super class lookups + // work properly. If there is an error, our caller will unregister + // this class from the class loader. Also, we don't need to hold a + // lock here, as our caller has acquired it. + _Jv_RegisterInitiatingLoader (def, def->loader); if (super_class != 0) { @@ -943,23 +977,25 @@ _Jv_ClassReader::handleClassBegin def->notifyAll (); } -///// implements the checks described in sect. 5.3.5.3 +///// Implements the checks described in sect. 5.3.5.3 void _Jv_ClassReader::checkExtends (jclass sub, jclass super) { using namespace java::lang::reflect; - // having an interface or a final class as a superclass is no good + _Jv_Linker::wait_for_state (super, JV_STATE_LOADING); + + // Having an interface or a final class as a superclass is no good. if ((super->accflags & (Modifier::INTERFACE | Modifier::FINAL)) != 0) { throw_incompatible_class_change_error (sub->getName ()); } - // if the super class is not public, we need to check some more + // If the super class is not public, we need to check some more. if ((super->accflags & Modifier::PUBLIC) == 0) { - // With package scope, the classes must have the same - // class loader. + // With package scope, the classes must have the same class + // loader. if ( sub->loader != super->loader || !_Jv_ClassNameSamePackage (sub->name, super->name)) { @@ -967,7 +1003,7 @@ _Jv_ClassReader::checkExtends (jclass sub, jclass super) } } - for (; super != 0; super = super->superclass) + for (; super != 0; super = super->getSuperclass ()) { if (super == sub) throw_class_circularity_error (sub->getName ()); @@ -1047,10 +1083,10 @@ void _Jv_ClassReader::handleFieldsBegin (int count) def->fields = (_Jv_Field*) _Jv_AllocBytes (count * sizeof (_Jv_Field)); def->field_count = count; - def->field_initializers = (_Jv_ushort*) + def_interp->field_initializers = (_Jv_ushort*) _Jv_AllocBytes (count * sizeof (_Jv_ushort)); for (int i = 0; i < count; i++) - def->field_initializers[i] = (_Jv_ushort) 0; + def_interp->field_initializers[i] = (_Jv_ushort) 0; } void _Jv_ClassReader::handleField (int field_no, @@ -1065,36 +1101,40 @@ void _Jv_ClassReader::handleField (int field_no, _Jv_Field *field = &def->fields[field_no]; _Jv_Utf8Const *field_name = pool_data[name].utf8; -#ifndef COMPACT_FIELDS field->name = field_name; -#else - field->nameIndex = name; -#endif - if (verify) - verify_identifier (field_name); - - // ignore flags we don't know about. + // Ignore flags we don't know about. field->flags = flags & Modifier::ALL_FLAGS; + _Jv_Utf8Const* sig = pool_data[desc].utf8; + if (verify) { - if (field->flags & (Modifier::SYNCHRONIZED - | Modifier::NATIVE - | Modifier::INTERFACE - | Modifier::ABSTRACT)) - throw_class_format_error ("erroneous field access flags"); - + verify_identifier (field_name); + + for (int i = 0; i < field_no; ++i) + { + if (_Jv_equalUtf8Consts (field_name, def->fields[i].name) + && _Jv_equalUtf8Consts (sig, + // We know the other fields are + // unresolved. + (_Jv_Utf8Const *) def->fields[i].type)) + throw_class_format_error ("duplicate field name"); + } + + // At most one of PUBLIC, PRIVATE, or PROTECTED is allowed. if (1 < ( ((field->flags & Modifier::PUBLIC) ? 1 : 0) +((field->flags & Modifier::PRIVATE) ? 1 : 0) +((field->flags & Modifier::PROTECTED) ? 1 : 0))) throw_class_format_error ("erroneous field access flags"); - } - _Jv_Utf8Const* sig = pool_data[desc].utf8; + // FIXME: JVM spec S4.5: Verify ACC_FINAL and ACC_VOLATILE are not + // both set. Verify modifiers for interface fields. + + } if (verify) - _Jv_VerifyFieldSignature (sig); + verify_field_signature (sig); // field->type is really a jclass, but while it is still // unresolved we keep an _Jv_Utf8Const* instead. @@ -1124,7 +1164,7 @@ void _Jv_ClassReader::handleConstantValueAttribute (int field_index, throw_class_format_error ("field has multiple ConstantValue attributes"); field->flags |= _Jv_FIELD_CONSTANT_VALUE; - def->field_initializers[field_index] = value; + def_interp->field_initializers[field_index] = value; /* type check the initializer */ @@ -1144,7 +1184,7 @@ void _Jv_ClassReader::handleFieldsEnd () int low = 0; int high = def->field_count-1; _Jv_Field *fields = def->fields; - _Jv_ushort *inits = def->field_initializers; + _Jv_ushort *inits = def_interp->field_initializers; // this is kind of a raw version of quicksort. while (low < high) @@ -1186,13 +1226,13 @@ _Jv_ClassReader::handleMethodsBegin (int count) { def->methods = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) * count); - def->interpreted_methods + def_interp->interpreted_methods = (_Jv_MethodBase **) _Jv_AllocBytes (sizeof (_Jv_MethodBase *) * count); for (int i = 0; i < count; i++) { - def->interpreted_methods[i] = 0; + def_interp->interpreted_methods[i] = 0; def->methods[i].index = (_Jv_ushort) -1; } @@ -1219,7 +1259,7 @@ void _Jv_ClassReader::handleMethod // ignore unknown flags method->accflags = accflags & Modifier::ALL_FLAGS; - // intialize... + // Initialize... method->ncode = 0; method->throws = NULL; @@ -1231,17 +1271,25 @@ void _Jv_ClassReader::handleMethod else verify_identifier (method->name); - _Jv_VerifyMethodSignature (method->signature); + verify_method_signature (method->signature); - if (method->accflags & (Modifier::VOLATILE - | Modifier::TRANSIENT - | Modifier::INTERFACE)) - throw_class_format_error ("erroneous method access flags"); - + for (int i = 0; i < mth_index; ++i) + { + if (_Jv_equalUtf8Consts (method->name, def->methods[i].name) + && _Jv_equalUtf8Consts (method->signature, + def->methods[i].signature)) + throw_class_format_error ("duplicate method"); + } + + // At most one of PUBLIC, PRIVATE, or PROTECTED is allowed. if (1 < ( ((method->accflags & Modifier::PUBLIC) ? 1 : 0) +((method->accflags & Modifier::PRIVATE) ? 1 : 0) +((method->accflags & Modifier::PROTECTED) ? 1 : 0))) throw_class_format_error ("erroneous method access flags"); + + // FIXME: JVM spec S4.6: if ABSTRACT modifier is set, verify other + // flags are not set. Verify flags for interface methods. Verifiy + // modifiers for initializers. } } @@ -1260,13 +1308,16 @@ void _Jv_ClassReader::handleCodeAttribute method->defining_class = def; method->self = &def->methods[method_index]; method->prepared = NULL; + method->line_table_len = 0; + method->line_table = NULL; + // grab the byte code! memcpy ((void*) method->bytecode (), (void*) (bytes+code_start), code_length); - def->interpreted_methods[method_index] = method; + def_interp->interpreted_methods[method_index] = method; if ((method->self->accflags & java::lang::reflect::Modifier::STATIC)) { @@ -1283,7 +1334,7 @@ void _Jv_ClassReader::handleExceptionTableEntry int start_pc, int end_pc, int handler_pc, int catch_type) { _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *> - (def->interpreted_methods[method_index]); + (def_interp->interpreted_methods[method_index]); _Jv_InterpException *exc = method->exceptions (); exc[exc_index].start_pc.i = start_pc; @@ -1301,7 +1352,7 @@ void _Jv_ClassReader::handleMethodsEnd () _Jv_Method *method = &def->methods[i]; if ((method->accflags & Modifier::NATIVE) != 0) { - if (def->interpreted_methods[i] != 0) + if (def_interp->interpreted_methods[i] != 0) throw_class_format_error ("code provided for native method"); else { @@ -1310,7 +1361,7 @@ void _Jv_ClassReader::handleMethodsEnd () m->defining_class = def; m->self = method; m->function = NULL; - def->interpreted_methods[i] = m; + def_interp->interpreted_methods[i] = m; if ((method->accflags & Modifier::STATIC)) { @@ -1325,12 +1376,12 @@ void _Jv_ClassReader::handleMethodsEnd () } else if ((method->accflags & Modifier::ABSTRACT) != 0) { - if (def->interpreted_methods[i] != 0) + if (def_interp->interpreted_methods[i] != 0) throw_class_format_error ("code provided for abstract method"); } else { - if (def->interpreted_methods[i] == 0) + if (def_interp->interpreted_methods[i] == 0) throw_class_format_error ("method with no code"); } } @@ -1342,8 +1393,8 @@ void _Jv_ClassReader::throw_class_format_error (char *msg) if (def->name != NULL) { jsize mlen = strlen (msg); - unsigned char* data = (unsigned char*) def->name->data; - int ulen = def->name->length; + unsigned char* data = (unsigned char*) def->name->chars(); + int ulen = def->name->len(); unsigned char* limit = data + ulen; jsize nlen = _Jv_strLengthUtf8 ((char *) data, ulen); jsize len = nlen + mlen + 3; @@ -1475,8 +1526,8 @@ _Jv_VerifyOne (unsigned char* ptr, unsigned char* limit, bool void_ok) bool _Jv_VerifyFieldSignature (_Jv_Utf8Const*sig) { - unsigned char* ptr = (unsigned char*) sig->data; - unsigned char* limit = ptr + sig->length; + unsigned char* ptr = (unsigned char*) sig->chars(); + unsigned char* limit = ptr + sig->len(); ptr = _Jv_VerifyOne (ptr, limit, false); @@ -1486,8 +1537,8 @@ _Jv_VerifyFieldSignature (_Jv_Utf8Const*sig) bool _Jv_VerifyMethodSignature (_Jv_Utf8Const*sig) { - unsigned char* ptr = (unsigned char*) sig->data; - unsigned char* limit = ptr + sig->length; + unsigned char* ptr = (unsigned char*) sig->chars(); + unsigned char* limit = ptr + sig->len(); if (ptr == limit || UTF8_GET(ptr,limit) != '(') return false; @@ -1541,8 +1592,8 @@ is_identifier_part (int c) bool _Jv_VerifyIdentifier (_Jv_Utf8Const* name) { - unsigned char *ptr = (unsigned char*) name->data; - unsigned char *limit = ptr + name->length; + unsigned char *ptr = (unsigned char*) name->chars(); + unsigned char *limit = (unsigned char*) name->limit(); int ch; if ((ch = UTF8_GET (ptr, limit))==-1 @@ -1597,17 +1648,16 @@ _Jv_VerifyClassName (unsigned char* ptr, _Jv_ushort length) bool _Jv_VerifyClassName (_Jv_Utf8Const *name) { - return _Jv_VerifyClassName ((unsigned char*)&name->data[0], - (_Jv_ushort) name->length); + return _Jv_VerifyClassName ((unsigned char*)name->chars(), name->len()); } /* Returns true, if NAME1 and NAME2 represent classes in the same - package. */ + package. Neither NAME2 nor NAME2 may name an array type. */ bool _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2) { - unsigned char* ptr1 = (unsigned char*) name1->data; - unsigned char* limit1 = ptr1 + name1->length; + unsigned char* ptr1 = (unsigned char*) name1->chars(); + unsigned char* limit1 = (unsigned char*) name1->limit(); unsigned char* last1 = ptr1; @@ -1623,20 +1673,19 @@ _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2) } // Now the length of NAME1's package name is LEN. - int len = last1 - (unsigned char*) name1->data; + int len = last1 - (unsigned char*) name1->chars(); // If this is longer than NAME2, then we're off. - if (len > name2->length) + if (len > name2->len()) return false; // Then compare the first len bytes for equality. - if (memcmp ((void*) name1->data, (void*) name2->data, len) == 0) + if (memcmp ((void*) name1->chars(), (void*) name2->chars(), len) == 0) { // Check that there are no .'s after position LEN in NAME2. - unsigned char* ptr2 = (unsigned char*) name2->data + len; - unsigned char* limit2 = - (unsigned char*) name2->data + name2->length; + unsigned char* ptr2 = (unsigned char*) name2->chars() + len; + unsigned char* limit2 = (unsigned char*) name2->limit(); while (ptr2 < limit2) {