Index: verify.cc =================================================================== RCS file: /cvs/gcc/gcc/libjava/verify.cc,v retrieving revision 1.62 diff -u -r1.62 verify.cc --- verify.cc 19 Mar 2004 17:38:23 -0000 1.62 +++ verify.cc 21 May 2004 19:27:55 -0000 @@ -10,33 +10,22 @@ // Written by Tom Tromey -// Define VERIFY_DEBUG to enable debugging output. +// Uncomment this to enable debugging output. +// #define VERIFY_DEBUG -#include +#include "verify.h" -#include -#include -#include -#include - -// On Solaris 10/x86, indirectly includes , which -// defines PC since g++ predefines __EXTENSIONS__. Undef here to avoid clash -// with PC member of class _Jv_BytecodeVerifier below. +// On Solaris 10/x86, indirectly includes , +// which defines PC since g++ predefines __EXTENSIONS__. Undef here +// to avoid clash with PC member of class _Jv_BytecodeVerifier below. +// This might not be an issue in all environments, but it doesn't hurt +// to do this here unconditionally. #undef PC -#ifdef INTERPRETER - -#include -#include -#include -#include -#include - #ifdef VERIFY_DEBUG #include #endif /* VERIFY_DEBUG */ - // This is used to mark states which are not scheduled for // verification. #define INVALID_STATE ((state *) -1) @@ -127,6 +116,20 @@ // of "correct" is not well-defined, and this verifier differs from // others while remaining type-safe.) Some other tests live in the // libgcj test suite. +// +// This verifier is also written to be pluggable. This means that it +// is intended for use in a variety of environments, not just libgcj. +// As a result the verifier expects a number of type and method +// declarations to be declared in "verify.h". The intent is that you +// recompile the verifier for your particular environment. This +// approach was chosen so that operations could be inlined in verify.h +// as much as possible. +// +// See the verify.h that accompanies this copy of the verifier to see +// what types, preprocessor defines, and functions must be declared. +// The interface is ad hoc, but was defined so that it could be +// implemented to connect to a pure C program. +// class _Jv_BytecodeVerifier { private: @@ -142,7 +145,7 @@ template struct linked { - T *val; + T val; linked *next; }; @@ -159,7 +162,7 @@ // given PC if they both have different return-address types in the // same stack or local slot. This array is indexed by PC and holds // the list of all such states. - linked **states; + linked **states; // We keep a linked list of all the states which we must reverify. // This is the head of the list. @@ -170,18 +173,18 @@ char *flags; // The bytecode itself. - unsigned char *bytecode; + const unsigned char *bytecode; // The exceptions. - _Jv_InterpException *exception; + vfy_exception *exception; // Defining class. - jclass current_class; + vfy_jclass current_class; // This method. - _Jv_InterpMethod *current_method; + vfy_method *current_method; // A linked list of utf8 objects we allocate. This is really ugly, // but without this our utf8 objects would be collected. - linked<_Jv_Utf8Const> *utf8_list; + linked *utf8_list; // A linked list of all ref_intersection objects we allocate. ref_intersection *isect_list; @@ -189,51 +192,23 @@ // Create a new Utf-8 constant and return it. We do this to avoid // having our Utf-8 constants prematurely collected. FIXME this is // ugly. - _Jv_Utf8Const *make_utf8_const (char *s, int len) + vfy_string make_utf8_const (const char *s, int len) { - _Jv_Utf8Const *val = _Jv_makeUtf8Const (s, len); - _Jv_Utf8Const *r = (_Jv_Utf8Const *) _Jv_Malloc (sizeof (_Jv_Utf8Const) - + val->length - + 1); - r->length = val->length; - r->hash = val->hash; - memcpy (r->data, val->data, val->length + 1); - - linked<_Jv_Utf8Const> *lu - = (linked<_Jv_Utf8Const> *) _Jv_Malloc (sizeof (linked<_Jv_Utf8Const>)); - lu->val = r; + vfy_string val = vfy_make_string (s, len); + linked *lu + = (linked *) vfy_alloc (sizeof (linked)); + lu->val = val; lu->next = utf8_list; utf8_list = lu; - return r; + return val; } __attribute__ ((__noreturn__)) void verify_fail (char *s, jint pc = -1) { - using namespace java::lang; - StringBuffer *buf = new StringBuffer (); - - buf->append (JvNewStringLatin1 ("verification failed")); if (pc == -1) pc = start_PC; - if (pc != -1) - { - buf->append (JvNewStringLatin1 (" at PC ")); - buf->append (pc); - } - - _Jv_InterpMethod *method = current_method; - buf->append (JvNewStringLatin1 (" in ")); - buf->append (current_class->getName()); - buf->append ((jchar) ':'); - buf->append (JvNewStringUTF (method->get_method()->name->data)); - buf->append ((jchar) '('); - buf->append (JvNewStringUTF (method->get_method()->signature->data)); - buf->append ((jchar) ')'); - - buf->append (JvNewStringLatin1 (": ")); - buf->append (JvNewStringLatin1 (s)); - throw new java::lang::VerifyError (buf->toString ()); + vfy_fail (s, pc, current_class, current_method); } // This enum holds a list of tags for all the different types we @@ -284,9 +259,9 @@ union { // For a resolved reference type, this is a pointer to the class. - jclass klass; + vfy_jclass klass; // For other reference types, this it the name of the class. - _Jv_Utf8Const *name; + vfy_string name; } data; // Link to the next reference in the intersection. @@ -297,7 +272,7 @@ // FIXME: we should allocate these in chunks. ref_intersection *alloc_next; - ref_intersection (jclass klass, _Jv_BytecodeVerifier *verifier) + ref_intersection (vfy_jclass klass, _Jv_BytecodeVerifier *verifier) : ref_next (NULL) { is_resolved = true; @@ -306,7 +281,7 @@ verifier->isect_list = this; } - ref_intersection (_Jv_Utf8Const *name, _Jv_BytecodeVerifier *verifier) + ref_intersection (vfy_string name, _Jv_BytecodeVerifier *verifier) : ref_next (NULL) { is_resolved = false; @@ -328,7 +303,7 @@ bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier) { if (! is_resolved && ! other->is_resolved - && _Jv_equalUtf8Consts (data.name, other->data.name)) + && vfy_strings_equal (data.name, other->data.name)) return true; if (! is_resolved) resolve (verifier); @@ -367,17 +342,7 @@ { if (is_resolved) return; - - using namespace java::lang; - java::lang::ClassLoader *loader - = verifier->current_class->getClassLoaderInternal(); - // We might see either kind of name. Sigh. - if (data.name->data[0] == 'L' - && data.name->data[data.name->length - 1] == ';') - data.klass = _Jv_FindClassFromSignature (data.name->data, loader); - else - data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name), - false, loader); + data.klass = vfy_find_class (verifier->current_class, data.name); is_resolved = true; } @@ -398,8 +363,8 @@ // Avoid resolving if possible. if (! self->is_resolved && ! other_iter->is_resolved - && _Jv_equalUtf8Consts (self->data.name, - other_iter->data.name)) + && vfy_strings_equal (self->data.name, + other_iter->data.name)) continue; if (! self->is_resolved) @@ -420,9 +385,9 @@ { // assert (ref_next == NULL); if (is_resolved) - return data.klass->isArray (); + return vfy_is_abstract (data.klass); else - return data.name->data[0] == '['; + return vfy_string_bytes (data.name)[0] == '['; } bool isinterface (_Jv_BytecodeVerifier *verifier) @@ -430,7 +395,7 @@ // assert (ref_next == NULL); if (! is_resolved) resolve (verifier); - return data.klass->isInterface (); + return vfy_is_interface (data.klass); } bool isabstract (_Jv_BytecodeVerifier *verifier) @@ -438,11 +403,10 @@ // assert (ref_next == NULL); if (! is_resolved) resolve (verifier); - using namespace java::lang::reflect; - return Modifier::isAbstract (data.klass->getModifiers ()); + return vfy_is_abstract (data.klass); } - jclass getclass (_Jv_BytecodeVerifier *verifier) + vfy_jclass getclass (_Jv_BytecodeVerifier *verifier) { if (! is_resolved) resolve (verifier); @@ -454,16 +418,16 @@ int ndims = 0; if (is_resolved) { - jclass k = data.klass; - while (k->isArray ()) + vfy_jclass k = data.klass; + while (vfy_is_array (k)) { - k = k->getComponentType (); + k = vfy_get_component_type (k); ++ndims; } } else { - char *p = data.name->data; + const char *p = vfy_string_bytes (data.name); while (*p++ == '[') ++ndims; } @@ -472,18 +436,18 @@ void *operator new (size_t bytes) { - return _Jv_Malloc (bytes); + return vfy_alloc (bytes); } void operator delete (void *mem) { - _Jv_Free (mem); + vfy_free (mem); } }; // Return the type_val corresponding to a primitive signature // character. For instance `I' returns `int.class'. - type_val get_type_val_for_signature (jchar sig) + type_val get_type_val_for_signature (char sig) { type_val rt; switch (sig) @@ -522,27 +486,27 @@ } // Return the type_val corresponding to a primitive class. - type_val get_type_val_for_signature (jclass k) + type_val get_type_val_for_signature (vfy_jclass k) { - return get_type_val_for_signature ((jchar) k->method_count); + return get_type_val_for_signature (vfy_get_primitive_char (k)); } // This is like _Jv_IsAssignableFrom, but it works even if SOURCE or // TARGET haven't been prepared. - static bool is_assignable_from_slow (jclass target, jclass source) + static bool is_assignable_from_slow (vfy_jclass target, vfy_jclass source) { // First, strip arrays. - while (target->isArray ()) + while (vfy_is_array (target)) { // If target is array, source must be as well. - if (! source->isArray ()) + if (! vfy_is_array (source)) return false; - target = target->getComponentType (); - source = source->getComponentType (); + target = vfy_get_component_type (target); + source = vfy_get_component_type (source); } // Quick success. - if (target == &java::lang::Object::class$) + if (target == vfy_object_type ()) return true; do @@ -550,20 +514,21 @@ if (source == target) return true; - if (target->isPrimitive () || source->isPrimitive ()) + if (vfy_is_primitive (target) || vfy_is_primitive (source)) return false; - if (target->isInterface ()) + if (vfy_is_interface (target)) { - for (int i = 0; i < source->interface_count; ++i) + for (int i = 0; i < vfy_get_interface_count (source); ++i) { // We use a recursive call because we also need to // check superinterfaces. - if (is_assignable_from_slow (target, source->interfaces[i])) + if (is_assignable_from_slow (target, + vfy_get_interface (source, i))) return true; } } - source = source->getSuperclass (); + source = vfy_get_superclass (source); } while (source != NULL); @@ -616,7 +581,7 @@ } // Make a new instance given a class. - type (jclass k, _Jv_BytecodeVerifier *verifier) + type (vfy_jclass k, _Jv_BytecodeVerifier *verifier) { key = reference_type; klass = new ref_intersection (k, verifier); @@ -624,7 +589,7 @@ } // Make a new instance given the name of a class. - type (_Jv_Utf8Const *n, _Jv_BytecodeVerifier *verifier) + type (vfy_string n, _Jv_BytecodeVerifier *verifier) { key = reference_type; klass = new ref_intersection (n, verifier); @@ -643,12 +608,12 @@ // -lstdc++. void *operator new[] (size_t bytes) { - return _Jv_Malloc (bytes); + return vfy_alloc (bytes); } void operator delete[] (void *mem) { - _Jv_Free (mem); + vfy_free (mem); } type& operator= (type_val k) @@ -808,8 +773,8 @@ if (key != reference_type) verifier->verify_fail ("programmer error in type::element_type()", -1); - jclass k = klass->getclass (verifier)->getComponentType (); - if (k->isPrimitive ()) + vfy_jclass k = vfy_get_component_type (klass->getclass (verifier)); + if (vfy_is_primitive (k)) return type (verifier->get_type_val_for_signature (k)); return type (k, verifier); } @@ -822,9 +787,8 @@ if (key != reference_type) verifier->verify_fail ("internal error in type::to_array()"); - jclass k = klass->getclass (verifier); - return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()), - verifier); + vfy_jclass k = klass->getclass (verifier); + return type (vfy_get_array_class (k), verifier); } bool isreference () const @@ -1023,22 +987,22 @@ void *operator new[] (size_t bytes) { - return _Jv_Malloc (bytes); + return vfy_alloc (bytes); } void operator delete[] (void *mem) { - _Jv_Free (mem); + vfy_free (mem); } void *operator new (size_t bytes) { - return _Jv_Malloc (bytes); + return vfy_alloc (bytes); } void operator delete (void *mem) { - _Jv_Free (mem); + vfy_free (mem); } void copy (const state *copy, int max_stack, int max_locals) @@ -1379,8 +1343,8 @@ debug_print ("== New state in add_new_state\n"); new_state->print ("New", npc, current_method->max_stack, current_method->max_locals); - linked *nlink - = (linked *) _Jv_Malloc (sizeof (linked)); + linked *nlink + = (linked *) vfy_alloc (sizeof (linked)); nlink->val = new_state; nlink->next = states[npc]; states[npc] = nlink; @@ -1404,7 +1368,7 @@ // location. So in this situation we could pairwise compare and // reduce the number of parallel states. bool applicable = false; - for (linked *iter = states[npc]; iter != NULL; iter = iter->next) + for (linked *iter = states[npc]; iter != NULL; iter = iter->next) { state *new_state = iter->val; if (new_state->state_mergeable_p (from_state, @@ -1534,34 +1498,20 @@ invalidate_pc (); } - jclass construct_primitive_array_type (type_val prim) + vfy_jclass construct_primitive_array_type (type_val prim) { - jclass k = NULL; + vfy_jclass k = NULL; switch (prim) { case boolean_type: - k = JvPrimClass (boolean); - break; case char_type: - k = JvPrimClass (char); - break; case float_type: - k = JvPrimClass (float); - break; case double_type: - k = JvPrimClass (double); - break; case byte_type: - k = JvPrimClass (byte); - break; case short_type: - k = JvPrimClass (short); - break; case int_type: - k = JvPrimClass (int); - break; case long_type: - k = JvPrimClass (long); + k = vfy_get_primitive_type (int (prim)); break; // These aren't used here but we call them out to avoid @@ -1576,7 +1526,7 @@ default: verify_fail ("unknown type in construct_primitive_array_type"); } - k = _Jv_GetArrayClass (k, NULL); + k = vfy_get_array_class (k); return k; } @@ -1584,7 +1534,7 @@ // instruction starts. void branch_prepass () { - flags = (char *) _Jv_Malloc (current_method->code_length); + flags = (char *) vfy_alloc (current_method->code_length); for (int i = 0; i < current_method->code_length; ++i) flags[i] = 0; @@ -1860,6 +1810,7 @@ // These are unused here, but we call them out explicitly // so that -Wswitch-enum doesn't complain. +#ifndef VFY_FAST_OPCODES case op_putfield_1: case op_putfield_2: case op_putfield_4: @@ -1882,6 +1833,7 @@ case op_getstatic_4: case op_getstatic_8: case op_getstatic_a: +#endif // VFY_FAST_OPCODES default: verify_fail ("unrecognized instruction in branch_prepass", start_PC); @@ -1899,48 +1851,50 @@ // Verify exception handlers. for (int i = 0; i < current_method->exc_count; ++i) { - if (! (flags[exception[i].handler_pc.i] & FLAG_INSN_START)) + int handler, start, end, htype; + vfy_get_exception (exception, i, &handler, &start, &end, &htype); + if (! (flags[handler] & FLAG_INSN_START)) verify_fail ("exception handler not at instruction start", - exception[i].handler_pc.i); - if (! (flags[exception[i].start_pc.i] & FLAG_INSN_START)) + handler); + if (! (flags[start] & FLAG_INSN_START)) verify_fail ("exception start not at instruction start", - exception[i].start_pc.i); - if (exception[i].end_pc.i != current_method->code_length - && ! (flags[exception[i].end_pc.i] & FLAG_INSN_START)) + start); + if (end != current_method->code_length + && ! (flags[end] & FLAG_INSN_START)) verify_fail ("exception end not at instruction start", - exception[i].end_pc.i); + end); - flags[exception[i].handler_pc.i] |= FLAG_BRANCH_TARGET; + flags[handler] |= FLAG_BRANCH_TARGET; } } void check_pool_index (int index) { - if (index < 0 || index >= current_class->constants.size) + if (index < 0 || index >= vfy_get_constants_size (current_class)) verify_fail ("constant pool index out of range", start_PC); } type check_class_constant (int index) { check_pool_index (index); - _Jv_Constants *pool = ¤t_class->constants; - if (pool->tags[index] == JV_CONSTANT_ResolvedClass) - return type (pool->data[index].clazz, this); - else if (pool->tags[index] == JV_CONSTANT_Class) - return type (pool->data[index].utf8, this); + vfy_constants *pool = vfy_get_constants (current_class); + if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass) + return type (vfy_get_pool_class (pool, index), this); + else if (vfy_tag (pool, index) == JV_CONSTANT_Class) + return type (vfy_get_pool_string (pool, index), this); verify_fail ("expected class constant", start_PC); } type check_constant (int index) { check_pool_index (index); - _Jv_Constants *pool = ¤t_class->constants; - if (pool->tags[index] == JV_CONSTANT_ResolvedString - || pool->tags[index] == JV_CONSTANT_String) - return type (&java::lang::String::class$, this); - else if (pool->tags[index] == JV_CONSTANT_Integer) + vfy_constants *pool = vfy_get_constants (current_class); + if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedString + || vfy_tag (pool, index) == JV_CONSTANT_String) + return type (vfy_string_type (), this); + else if (vfy_tag (pool, index) == JV_CONSTANT_Integer) return type (int_type); - else if (pool->tags[index] == JV_CONSTANT_Float) + else if (vfy_tag (pool, index) == JV_CONSTANT_Float) return type (float_type); verify_fail ("String, int, or float constant expected", start_PC); } @@ -1948,10 +1902,10 @@ type check_wide_constant (int index) { check_pool_index (index); - _Jv_Constants *pool = ¤t_class->constants; - if (pool->tags[index] == JV_CONSTANT_Long) + vfy_constants *pool = vfy_get_constants (current_class); + if (vfy_tag (pool, index) == JV_CONSTANT_Long) return type (long_type); - else if (pool->tags[index] == JV_CONSTANT_Double) + else if (vfy_tag (pool, index) == JV_CONSTANT_Double) return type (double_type); verify_fail ("long or double constant expected", start_PC); } @@ -1959,26 +1913,23 @@ // Helper for both field and method. These are laid out the same in // the constant pool. type handle_field_or_method (int index, int expected, - _Jv_Utf8Const **name, - _Jv_Utf8Const **fmtype) + vfy_string *name, + vfy_string *fmtype) { check_pool_index (index); - _Jv_Constants *pool = ¤t_class->constants; - if (pool->tags[index] != expected) + vfy_constants *pool = vfy_get_constants (current_class); + if (vfy_tag (pool, index) != expected) verify_fail ("didn't see expected constant", start_PC); // Once we know we have a Fieldref or Methodref we assume that it // is correctly laid out in the constant pool. I think the code // in defineclass.cc guarantees this. - _Jv_ushort class_index, name_and_type_index; - _Jv_loadIndexes (&pool->data[index], - class_index, - name_and_type_index); - _Jv_ushort name_index, desc_index; - _Jv_loadIndexes (&pool->data[name_and_type_index], - name_index, desc_index); + vfy_uint_16 class_index, name_and_type_index; + vfy_load_indexes (pool, index, &class_index, &name_and_type_index); + vfy_uint_16 name_index, desc_index; + vfy_load_indexes (pool, name_and_type_index, &name_index, &desc_index); - *name = pool->data[name_index].utf8; - *fmtype = pool->data[desc_index].utf8; + *name = vfy_get_pool_string (pool, name_index); + *fmtype = vfy_get_pool_string (pool, desc_index); return check_class_constant (class_index); } @@ -1986,20 +1937,21 @@ // Return field's type, compute class' type if requested. type check_field_constant (int index, type *class_type = NULL) { - _Jv_Utf8Const *name, *field_type; + vfy_string name, field_type; type ct = handle_field_or_method (index, JV_CONSTANT_Fieldref, &name, &field_type); if (class_type) *class_type = ct; - if (field_type->data[0] == '[' || field_type->data[0] == 'L') + const char *b = vfy_string_bytes (field_type); + if (b[0] == '[' || b[0] == 'L') return type (field_type, this); - return get_type_val_for_signature (field_type->data[0]); + return get_type_val_for_signature (b[0]); } type check_method_constant (int index, bool is_interface, - _Jv_Utf8Const **method_name, - _Jv_Utf8Const **method_signature) + vfy_string *method_name, + vfy_string *method_signature) { return handle_field_or_method (index, (is_interface @@ -2008,9 +1960,9 @@ method_name, method_signature); } - type get_one_type (char *&p) + type get_one_type (const char *&p) { - char *start = p; + const char *start = p; int arraycount = 0; while (*p == '[') @@ -2026,7 +1978,7 @@ while (*p != ';') ++p; ++p; - _Jv_Utf8Const *name = make_utf8_const (start, p - start); + vfy_string name = make_utf8_const (start, p - start); return type (name, this); } @@ -2041,16 +1993,16 @@ return type (rt).promote (); } - jclass k = construct_primitive_array_type (rt); + vfy_jclass k = construct_primitive_array_type (rt); while (--arraycount > 0) - k = _Jv_GetArrayClass (k, NULL); + k = vfy_get_array_class (k); return type (k, this); } - void compute_argument_types (_Jv_Utf8Const *signature, + void compute_argument_types (vfy_string signature, type *types) { - char *p = signature->data; + const char *p = vfy_string_bytes (signature); // Skip `('. ++p; @@ -2059,9 +2011,9 @@ types[i++] = get_one_type (p); } - type compute_return_type (_Jv_Utf8Const *signature) + type compute_return_type (vfy_string signature) { - char *p = signature->data; + const char *p = vfy_string_bytes (signature); while (*p != ')') ++p; ++p; @@ -2070,7 +2022,7 @@ void check_return_type (type onstack) { - type rt = compute_return_type (current_method->self->signature); + type rt = compute_return_type (vfy_get_signature (current_method)); if (! rt.compatible (onstack, this)) verify_fail ("incompatible return type"); } @@ -2080,13 +2032,13 @@ bool initialize_stack () { int var = 0; - bool is_init = _Jv_equalUtf8Consts (current_method->self->name, - gcj::init_name); - bool is_clinit = _Jv_equalUtf8Consts (current_method->self->name, - gcj::clinit_name); + bool is_init = vfy_strings_equal (vfy_get_method_name (current_method), + vfy_init_name()); + bool is_clinit = vfy_strings_equal (vfy_get_method_name (current_method), + vfy_clinit_name()); using namespace java::lang::reflect; - if (! Modifier::isStatic (current_method->self->accflags)) + if (! vfy_is_static (current_method)) { type kurr (current_class, this); if (is_init) @@ -2107,9 +2059,9 @@ } // We have to handle wide arguments specially here. - int arg_count = _Jv_count_arguments (current_method->self->signature); + int arg_count = vfy_count_arguments (vfy_get_signature (current_method)); type arg_types[arg_count]; - compute_argument_types (current_method->self->signature, arg_types); + compute_argument_types (vfy_get_signature (current_method), arg_types); for (int i = 0; i < arg_count; ++i) { set_variable (var, arg_types[i]); @@ -2132,8 +2084,8 @@ // True if we are verifying an instance initializer. bool this_is_init = initialize_stack (); - states = (linked **) _Jv_Malloc (sizeof (linked *) - * current_method->code_length); + states = (linked **) vfy_alloc (sizeof (linked *) + * current_method->code_length); for (int i = 0; i < current_method->code_length; ++i) states[i] = NULL; @@ -2197,12 +2149,14 @@ // through them all. for (int i = 0; i < current_method->exc_count; ++i) { - if (PC >= exception[i].start_pc.i && PC < exception[i].end_pc.i) + int hpc, start, end, htype; + vfy_get_exception (exception, i, &hpc, &start, &end, &htype); + if (PC >= start && PC < end) { - type handler (&java::lang::Throwable::class$, this); - if (exception[i].handler_type.i != 0) - handler = check_class_constant (exception[i].handler_type.i); - push_exception_jump (handler, exception[i].handler_pc.i); + type handler (vfy_throwable_type (), this); + if (htype != 0) + handler = check_class_constant (htype); + push_exception_jump (handler, hpc); } } @@ -2821,7 +2775,7 @@ case op_invokestatic: case op_invokeinterface: { - _Jv_Utf8Const *method_name, *method_signature; + vfy_string method_name, method_signature; type class_type = check_method_constant (get_ushort (), opcode == op_invokeinterface, @@ -2839,17 +2793,17 @@ } bool is_init = false; - if (_Jv_equalUtf8Consts (method_name, gcj::init_name)) + if (vfy_strings_equal (method_name, vfy_init_name())) { is_init = true; if (opcode != op_invokespecial) verify_fail ("can't invoke "); } - else if (method_name->data[0] == '<') + else if (vfy_string_bytes (method_name)[0] == '<') verify_fail ("can't invoke method starting with `<'"); // Pop arguments and check types. - int arg_count = _Jv_count_arguments (method_signature); + int arg_count = vfy_count_arguments (method_signature); type arg_types[arg_count]; compute_argument_types (method_signature, arg_types); for (int i = arg_count - 1; i >= 0; --i) @@ -2926,7 +2880,7 @@ } break; case op_athrow: - pop_type (type (&java::lang::Throwable::class$, this)); + pop_type (type (vfy_throwable_type (), this)); invalidate_pc (); break; case op_checkcast: @@ -3017,6 +2971,7 @@ // These are unused here, but we call them out explicitly // so that -Wswitch-enum doesn't complain. +#ifndef VFY_FAST_OPCODES case op_putfield_1: case op_putfield_2: case op_putfield_4: @@ -3039,6 +2994,7 @@ case op_getstatic_4: case op_getstatic_8: case op_getstatic_a: +#endif // VFY_FAST_OPCODES default: // Unrecognized opcode. verify_fail ("unrecognized instruction in verify_instructions_0", @@ -3055,16 +3011,17 @@ verify_instructions_0 (); } - _Jv_BytecodeVerifier (_Jv_InterpMethod *m) + _Jv_BytecodeVerifier (vfy_method *m) { // We just print the text as utf-8. This is just for debugging // anyway. debug_print ("--------------------------------\n"); - debug_print ("-- Verifying method `%s'\n", m->self->name->data); + debug_print ("-- Verifying method `%s'\n", + vfy_string_bytes (vfy_get_method_name (m))); current_method = m; - bytecode = m->bytecode (); - exception = m->exceptions (); + bytecode = vfy_get_bytecode (m); + exception = vfy_get_exceptions (m); current_class = m->defining_class; states = NULL; @@ -3076,13 +3033,13 @@ ~_Jv_BytecodeVerifier () { if (flags) - _Jv_Free (flags); + vfy_free (flags); while (utf8_list != NULL) { - linked<_Jv_Utf8Const> *n = utf8_list->next; - _Jv_Free (utf8_list->val); - _Jv_Free (utf8_list); + linked *n = utf8_list->next; + vfy_free (utf8_list->val); + vfy_free (utf8_list); utf8_list = n; } @@ -3097,16 +3054,16 @@ { for (int i = 0; i < current_method->code_length; ++i) { - linked *iter = states[i]; + linked *iter = states[i]; while (iter != NULL) { - linked *next = iter->next; + linked *next = iter->next; delete iter->val; - _Jv_Free (iter); + vfy_free (iter); iter = next; } } - _Jv_Free (states); + vfy_free (states); } } }; @@ -3117,5 +3074,3 @@ _Jv_BytecodeVerifier v (meth); v.verify_instructions (); } - -#endif /* INTERPRETER */ Index: include/java-interp.h =================================================================== RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v retrieving revision 1.24 diff -u -r1.24 java-interp.h --- include/java-interp.h 20 Apr 2004 01:38:45 -0000 1.24 +++ include/java-interp.h 21 May 2004 19:27:55 -0000 @@ -1,6 +1,6 @@ // java-interp.h - Header file for the bytecode interpreter. -*- c++ -*- -/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -70,7 +70,7 @@ friend class _Jv_ClassReader; friend class _Jv_InterpMethod; - friend class _Jv_BytecodeVerifier; + friend class _Jv_VfyHelper; }; // Base class for method representations. Subclasses are interpreted @@ -146,11 +146,11 @@ static void dump_object(jobject o); friend class _Jv_ClassReader; + friend class _Jv_VfyHelper; friend class _Jv_BytecodeVerifier; friend class gnu::gcj::runtime::NameFinder; friend class gnu::gcj::runtime::StackTrace; - friend void _Jv_PrepareClass(jclass); #ifdef JV_MARKOBJ_DECL Index: include/verify.h =================================================================== RCS file: include/verify.h diff -N include/verify.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/verify.h 21 May 2004 19:27:55 -0000 @@ -0,0 +1,464 @@ +// verify.h - bytecode verification API + +/* Copyright (C) 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey + +#ifndef __JAVA_VERIFY_H__ +#define __JAVA_VERIFY_H__ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +// This is a fairly ugly approach, but it lets us write the verifier +// using a "plain C"-looking API, while minimizing the number of +// `friend' declarations elsewhere in libgcj, and allowing the latter +// half of this file to serve as a template for other verifier glue +// implementations. If you're reading this in order to plug the +// verifier into some other VM, you'll want to look at the section of +// required types, then skip the class definition, and look at the +// definitions of the required methods. Ignore the nasty defines. + +#define vfy_alloc _Jv_VfyHelper::alloc +#define vfy_clinit_name _Jv_VfyHelper::clinit_name +#define vfy_count_arguments _Jv_VfyHelper::count_arguments +#define vfy_fail _Jv_VfyHelper::fail +#define vfy_find_class _Jv_VfyHelper::find_class +#define vfy_free _Jv_VfyHelper::free +#define vfy_get_array_class _Jv_VfyHelper::get_array_class +#define vfy_get_bytecode _Jv_VfyHelper::get_bytecode +#define vfy_get_class_name _Jv_VfyHelper::get_class_name +#define vfy_get_component_type _Jv_VfyHelper::get_component_type +#define vfy_get_constants _Jv_VfyHelper::get_constants +#define vfy_get_constants_size _Jv_VfyHelper::get_constants_size +#define vfy_get_exception _Jv_VfyHelper::get_exception +#define vfy_get_exceptions _Jv_VfyHelper::get_exceptions +#define vfy_get_interface_count _Jv_VfyHelper::get_interface_count +#define vfy_get_interface _Jv_VfyHelper::get_interface +#define vfy_get_method_name _Jv_VfyHelper::get_method_name +#define vfy_get_pool_class _Jv_VfyHelper::get_pool_class +#define vfy_get_pool_string _Jv_VfyHelper::get_pool_string +#define vfy_get_primitive_char _Jv_VfyHelper::get_primitive_char +#define vfy_get_primitive_type _Jv_VfyHelper::get_primitive_type +#define vfy_get_signature _Jv_VfyHelper::get_signature +#define vfy_get_superclass _Jv_VfyHelper::get_superclass +#define vfy_init_name _Jv_VfyHelper::init_name +#define vfy_is_abstract _Jv_VfyHelper::is_abstract +#define vfy_is_array _Jv_VfyHelper::is_array +#define vfy_is_interface _Jv_VfyHelper::is_interface +#define vfy_is_primitive _Jv_VfyHelper::is_primitive +#define vfy_is_static _Jv_VfyHelper::is_static +#define vfy_load_indexes _Jv_VfyHelper::load_indexes +#define vfy_make_string _Jv_VfyHelper::make_string +#define vfy_object_type _Jv_VfyHelper::object_type +#define vfy_string_bytes _Jv_VfyHelper::string_bytes +#define vfy_strings_equal _Jv_VfyHelper::strings_equal +#define vfy_string_type _Jv_VfyHelper::string_type +#define vfy_tag _Jv_VfyHelper::tag +#define vfy_throwable_type _Jv_VfyHelper::throwable_type + + + +// +// Required types and defines. +// + +// Define this if you do not have the fast opcodes defined. +// #define VFY_FAST_OPCODES + +// This is an opaque type, an instance of which is passed to the +// functions which extract information from the constant pool. The +// caller creates the instance and passes it to the verifier. +typedef _Jv_Constants vfy_constants; + +// The type representing a string. +typedef _Jv_Utf8Const *vfy_string; + +// The type representing a class or primitive type. Note that this +// must be different from vfy_string as far as C++ overloading is +// concerned. It must also support "==" and "!=" operations +// correctly. +typedef jclass vfy_jclass; + +// An unsigned jshort type. +typedef _Jv_ushort vfy_uint_16; + +// This represents an exception handler. A pointer to an instance of +// this type is handled opaquely and passed by the verifier to the +// glue code in order to extract information about a given exception +// handler. +typedef _Jv_InterpException vfy_exception; + +// This is an opaque type representing a single method. A pointer to +// this type is passed by the verifier to the glue code in order to +// get various bits of information about the particular method. +// This must be a structure with at least these fields: +// vfy_jclass defining_class; +// int max_stack; +// int max_locals; +// int code_length; +// int exc_count; +typedef _Jv_InterpMethod vfy_method; + + + +struct _Jv_VfyHelper +{ + static void *alloc (size_t bytes); + static void free (void *mem); + static bool strings_equal (vfy_string one, vfy_string two); + static const char *string_bytes (vfy_string s); + static vfy_string init_name (); + static vfy_string clinit_name (); + static int count_arguments (vfy_string signature); + static vfy_string get_signature (vfy_method *method); + static vfy_string get_method_name (vfy_method *method); + static bool is_static (vfy_method *method); + static const unsigned char *get_bytecode (vfy_method *method); + static vfy_exception *get_exceptions (vfy_method *method); + static void get_exception (vfy_exception *excdescs, int index, + int *handler, int *start, int *end, + int *handler_type); + static int tag (vfy_constants *pool, int index); + static void load_indexes (vfy_constants *pool, int index, + vfy_uint_16 *index0, vfy_uint_16 *index1); + static vfy_constants *get_constants (vfy_jclass klass); + static int get_constants_size (vfy_jclass klass); + static vfy_string get_pool_string (vfy_constants *pool, int index); + static vfy_jclass get_pool_class (vfy_constants *pool, int index); + static vfy_string make_string (const char *s, int len); + static vfy_string get_class_name (vfy_jclass klass); + static char get_primitive_char (vfy_jclass klass); + static int get_interface_count (vfy_jclass klass); + static vfy_jclass get_interface (vfy_jclass klass, int index); + static bool is_array (vfy_jclass klass); + static bool is_interface (vfy_jclass klass); + static bool is_primitive (vfy_jclass klass); + static vfy_jclass get_superclass (vfy_jclass klass); + static vfy_jclass get_array_class (vfy_jclass klass); + static vfy_jclass get_component_type (vfy_jclass klass); + static bool is_abstract (vfy_jclass klass); + static vfy_jclass find_class (vfy_jclass klass, vfy_string name); + static vfy_jclass object_type (); + static vfy_jclass string_type (); + static vfy_jclass throwable_type (void); + static vfy_jclass get_primitive_type (int type); + static __attribute__ ((__noreturn__)) int fail (const char *message, jint pc, + vfy_jclass klass, + vfy_method *method); +}; + +// Allocate some memory. +inline void *vfy_alloc (size_t bytes) +{ + return _Jv_Malloc (bytes); +} + +// Free some memory allocated by vfy_alloc. +inline void vfy_free (void *mem) +{ + _Jv_Free (mem); +} + +// Return true if the strings have the same contents. +inline bool vfy_strings_equal (vfy_string one, vfy_string two) +{ + return _Jv_equalUtf8Consts (one, two); +} + +// Returns a char* representing the bytes of the string. +inline const char *vfy_string_bytes (vfy_string s) +{ + return s->data; +} + +// Return a string representing "". +inline vfy_string vfy_init_name () +{ + return gcj::init_name; +} + +// Return a string representing "". +inline vfy_string vfy_clinit_name () +{ + return gcj::clinit_name; +} + +// Count the number of arguments in a method signature. +inline int vfy_count_arguments (vfy_string signature) +{ + return _Jv_count_arguments (signature); +} + +// Return a string holding the signature of the method. +inline vfy_string vfy_get_signature (vfy_method *method) +{ + return method->self->signature; +} + +// Return a string holding the name of the method. +inline vfy_string vfy_get_method_name (vfy_method *method) +{ + return method->self->name; +} + +// Return true if the method is static. +inline bool vfy_is_static (vfy_method *method) +{ + return java::lang::reflect::Modifier::isStatic (method->self->accflags); +} + +// Return a pointer to the bytecode of the method. +inline const unsigned char *vfy_get_bytecode (vfy_method *method) +{ + return method->bytecode(); +} + +// Return a pointer to the exception table for the method. +inline vfy_exception *vfy_get_exceptions (vfy_method *method) +{ + return method->exceptions(); +} + +// Given a pointer to the exception descriptions and an index, this +// must fill in the return parameters with the appropriate +// information about the particular exception. +inline void vfy_get_exception (vfy_exception *excdescs, int index, + int *handler, int *start, int *end, + int *handler_type) +{ + *handler = excdescs[index].handler_pc.i; + *start = excdescs[index].start_pc.i; + *end = excdescs[index].end_pc.i; + *handler_type = excdescs[index].handler_type.i; +} + +// Return the tag corresponding to an entry in the constant pool. +inline int vfy_tag (vfy_constants *pool, int index) +{ + return pool->tags[index]; +} + +inline void vfy_load_indexes (vfy_constants *pool, int index, + vfy_uint_16 *index0, vfy_uint_16 *index1) +{ + _Jv_loadIndexes(&pool->data[index], *index0, *index1); +} + +// Return the constant pool for the class. +inline vfy_constants *vfy_get_constants (vfy_jclass klass) +{ + return &klass->constants; +} + +// Return the number of constants in the class' constant pool. +inline int vfy_get_constants_size (vfy_jclass klass) +{ + return klass->constants.size; +} + +// Return a string from the constant pool. +inline vfy_string vfy_get_pool_string (vfy_constants *pool, int index) +{ + return pool->data[index].utf8; +} + +// Return a class from the constant pool. +inline vfy_jclass vfy_get_pool_class (vfy_constants *pool, int index) +{ + return pool->data[index].clazz; +} + +// Create a new string given its contents and length. The contents +// are not necessarily \0-terminated. +inline vfy_string vfy_make_string (const char *s, int len) +{ + _Jv_Utf8Const *val = _Jv_makeUtf8Const ((char *) s, len); + _Jv_Utf8Const *r = (_Jv_Utf8Const *) _Jv_Malloc (sizeof (_Jv_Utf8Const) + + val->length + + 1); + r->length = val->length; + r->hash = val->hash; + memcpy (r->data, val->data, val->length + 1); + return r; +} + +// Return the name of this class. +inline vfy_string vfy_get_class_name (vfy_jclass klass) +{ + return klass->name; +} + +// Return the signature character given a primitive class. +inline char vfy_get_primitive_char (vfy_jclass klass) +{ + return (char) klass->method_count; +} + +// Return the number of interfaces implemented by the class. +inline int vfy_get_interface_count (vfy_jclass klass) +{ + return klass->interface_count; +} + +// Return the Nth interface implemented by the class. +inline vfy_jclass vfy_get_interface (vfy_jclass klass, int index) +{ + return klass->interfaces[index]; +} + +// Return true if the type is an array. +inline bool vfy_is_array (vfy_jclass klass) +{ + return klass->isArray(); +} + +// Return true if the type is an interface. +inline bool vfy_is_interface (vfy_jclass klass) +{ + return klass->isInterface(); +} + +// Return true if the type is primitive. +inline bool vfy_is_primitive (vfy_jclass klass) +{ + return klass->isPrimitive(); +} + +// Return the superclass of the class. +inline vfy_jclass vfy_get_superclass (vfy_jclass klass) +{ + return klass->getSuperclass(); +} + +// Return a class which is an array with elements of the given class. +inline vfy_jclass vfy_get_array_class (vfy_jclass klass) +{ + return _Jv_GetArrayClass(klass, klass->getClassLoaderInternal()); +} + +// Return the component type of the given array class. +inline vfy_jclass vfy_get_component_type (vfy_jclass klass) +{ + return klass->getComponentType(); +} + +// Return true if this class is abstract. +inline bool vfy_is_abstract (vfy_jclass klass) +{ + return java::lang::reflect::Modifier::isAbstract(klass->getModifiers()); +} + +// Find a class given its name. The name might be a raw class name, +// or it might be a "L...;"-style signature. +inline vfy_jclass vfy_find_class (vfy_jclass klass, vfy_string name) +{ + using namespace java::lang; + ClassLoader *loader = klass->getClassLoaderInternal(); + if (name->data[0] == 'L' && name->data[name->length - 1] == ';') + return _Jv_FindClassFromSignature (name->data, loader); + return Class::forName (_Jv_NewStringUtf8Const (name), false, loader); +} + +// Return the class representing java.lang.Object. +inline vfy_jclass vfy_object_type () +{ + return &java::lang::Object::class$; +} + +// Return the class representing java.lang.String. +inline vfy_jclass vfy_string_type () +{ + return &java::lang::String::class$; +} + +// Return the class representing java.lang.Throwable. +inline vfy_jclass vfy_throwable_type (void) +{ + return &java::lang::Throwable::class$; +} + +// This is called when the verifier fails. This must throw an +// exception. `PC' is the PC of the failing instruction, or -1 if +// this can't be determined. +__attribute__ ((__noreturn__)) void vfy_fail (const char *message, jint pc, + vfy_jclass klass, + vfy_method *method) +{ + using namespace java::lang; + StringBuffer *buf = new StringBuffer (); + + buf->append (JvNewStringLatin1 ("verification failed")); + if (pc != -1) + { + buf->append (JvNewStringLatin1 (" at PC ")); + buf->append (pc); + } + + buf->append (JvNewStringLatin1 (" in ")); + buf->append (klass->getName()); + buf->append ((jchar) ':'); + buf->append (JvNewStringUTF (method->get_method()->name->data)); + buf->append ((jchar) '('); + buf->append (JvNewStringUTF (method->get_method()->signature->data)); + buf->append ((jchar) ')'); + + buf->append (JvNewStringLatin1 (": ")); + buf->append (JvNewStringLatin1 (message)); + throw new VerifyError (buf->toString ()); +} + +// Return the primitive type corresponding to the argument to +// `newarray'. +inline vfy_jclass vfy_get_primitive_type (int type) +{ + vfy_jclass k = NULL; + switch (type) + { + case 4: + k = JvPrimClass (boolean); + break; + case 5: + k = JvPrimClass (char); + break; + case 6: + k = JvPrimClass (float); + break; + case 7: + k = JvPrimClass (double); + break; + case 8: + k = JvPrimClass (byte); + break; + case 9: + k = JvPrimClass (short); + break; + case 10: + k = JvPrimClass (int); + break; + case 11: + k = JvPrimClass (long); + break; + } + return k; +} + +#endif // __JAVA_VERIFY_H__ Index: java/lang/Class.h =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v retrieving revision 1.66 diff -u -r1.66 Class.h --- java/lang/Class.h 21 Apr 2004 19:26:22 -0000 1.66 +++ java/lang/Class.h 21 May 2004 19:27:55 -0000 @@ -1,6 +1,6 @@ // Class.h - Header file for java.lang.Class. -*- c++ -*- -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -384,7 +384,7 @@ friend JV_MARKOBJ_DECL; #endif - friend class _Jv_BytecodeVerifier; + friend class _Jv_VfyHelper; friend class _Jv_StackTrace; friend class gnu::gcj::runtime::StackTrace; friend class java::io::VMObjectStreamClass;