// defineclass.cc - defining a class from .class format.
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
This file is part of libgcj.
// these go in some separate functions, to avoid having _Jv_InitClass
// inserted all over the place.
-static void throw_internal_error (char *msg)
+static void throw_internal_error (const char *msg)
__attribute__ ((__noreturn__));
static void throw_no_class_def_found_error (jstring msg)
__attribute__ ((__noreturn__));
-static void throw_no_class_def_found_error (char *msg)
+static void throw_no_class_def_found_error (const char *msg)
__attribute__ ((__noreturn__));
static void throw_class_format_error (jstring msg)
__attribute__ ((__noreturn__));
* public or private members here.
*/
-struct _Jv_ClassReader {
+struct _Jv_ClassReader
+{
// do verification? Currently, there is no option to disable this.
// This flag just controls the verificaiton done by the class loader;
// the class to define (see java-interp.h)
jclass def;
-
+
// the classes associated interpreter data.
_Jv_InterpClass *def_interp;
+ // The name we found.
+ _Jv_Utf8Const **found_name;
+
+ // True if this is a 1.5 class file.
+ bool is_15;
+
+
/* check that the given number of input bytes are available */
inline void check (int num)
{
}
_Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length,
- java::security::ProtectionDomain *pd)
+ java::security::ProtectionDomain *pd,
+ _Jv_Utf8Const **name_result)
{
if (klass == 0 || length < 0 || offset+length > data->length)
throw_internal_error ("arguments to _Jv_DefineClass");
bytes = (unsigned char*) (elements (data)+offset);
len = length;
pos = 0;
+ is_15 = false;
+
def = klass;
+ found_name = name_result;
def->size_in_bytes = -1;
def->vtable_method_count = -1;
void read_one_method_attribute (int method);
void read_one_code_attribute (int method);
void read_one_field_attribute (int field);
- void throw_class_format_error (char *msg);
+ void throw_class_format_error (const char *msg);
/** check an utf8 entry, without creating a Utf8Const object */
- bool is_attribute_name (int index, char *name);
+ bool is_attribute_name (int index, const char *name);
/** here goes the class-loader members defined out-of-line */
void handleConstantPool ();
*/
};
+// Note that *NAME_RESULT will only be set if the class is registered
+// with the class loader. This is how the caller can know whether
+// unregistration is require.
void
_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length,
- java::security::ProtectionDomain *pd)
+ java::security::ProtectionDomain *pd,
+ _Jv_Utf8Const **name_result)
{
- _Jv_ClassReader reader (klass, data, offset, length, pd);
+ _Jv_ClassReader reader (klass, data, offset, length, pd, name_result);
reader.parse();
/* that's it! */
\f
/** This section defines the parsing/scanning of the class data */
+// Major and minor version numbers for various releases.
+#define MAJOR_1_1 45
+#define MINOR_1_1 3
+#define MAJOR_1_2 46
+#define MINOR_1_2 0
+#define MAJOR_1_3 47
+#define MINOR_1_3 0
+#define MAJOR_1_4 48
+#define MINOR_1_4 0
+#define MAJOR_1_5 49
+#define MINOR_1_5 0
+
void
_Jv_ClassReader::parse ()
{
int magic = read4 ();
-
- /* FIXME: Decide which range of version numbers to allow */
-
- /* int minor_version = */ read2u ();
- /* int major_verson = */ read2u ();
-
if (magic != (int) 0xCAFEBABE)
throw_class_format_error ("bad magic number");
+ int minor_version = read2u ();
+ int major_version = read2u ();
+ if (major_version < MAJOR_1_1 || major_version > MAJOR_1_5
+ || (major_version == MAJOR_1_5 && minor_version > MINOR_1_5))
+ throw_class_format_error ("unrecognized class file version");
+ is_15 = (major_version == MAJOR_1_5);
+
pool_count = read2u ();
read_constpool ();
// 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->aux_info = (void *) _Jv_AllocRawObj (sizeof (_Jv_InterpClass));
def_interp = (_Jv_InterpClass *) def->aux_info;
int interfaces_count = read2u ();
void _Jv_ClassReader::read_constpool ()
{
tags = (unsigned char*) _Jv_AllocBytes (pool_count);
- offsets = (unsigned int *) _Jv_AllocBytes (sizeof (int)
- * pool_count) ;
+ offsets = (unsigned int *) _Jv_AllocBytes (sizeof (int) * pool_count) ;
/** first, we scan the constant pool, collecting tags and offsets */
tags[0] = JV_CONSTANT_Undefined;
}
bool
-_Jv_ClassReader::is_attribute_name (int index, char *name)
+_Jv_ClassReader::is_attribute_name (int index, const char *name)
{
check_tag (index, JV_CONSTANT_Utf8);
int len = get2u (bytes+offsets[index]);
int attributes_count = read2u ();
check_tag (name_index, JV_CONSTANT_Utf8);
- prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8);
+ prepare_pool_entry (name_index, JV_CONSTANT_Utf8);
- check_tag (name_index, JV_CONSTANT_Utf8);
+ check_tag (descriptor_index, JV_CONSTANT_Utf8);
prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8);
handleMethod (i, access_flags, name_index,
int table_len = read2u ();
_Jv_LineTableEntry* table
- = (_Jv_LineTableEntry *) JvAllocBytes (table_len
- * sizeof (_Jv_LineTableEntry));
+ = (_Jv_LineTableEntry *) _Jv_AllocBytes (table_len
+ * sizeof (_Jv_LineTableEntry));
for (int i = 0; i < table_len; i++)
{
table[i].bytecode_pc = read2u ();
{
/** now, we actually define the class' constant pool */
- // the pool is scanned explicitly by the collector
jbyte *pool_tags = (jbyte*) _Jv_AllocBytes (pool_count);
_Jv_word *pool_data
- = (_Jv_word*) _Jv_AllocBytes (pool_count * sizeof (_Jv_word));
-
+ = (_Jv_word*) _Jv_AllocRawObj (pool_count * sizeof (_Jv_word));
+
def->constants.tags = pool_tags;
def->constants.data = pool_data;
def->constants.size = pool_count;
pool_data[this_class].clazz = def;
pool_tags[this_class] = JV_CONSTANT_ResolvedClass;
- if (super_class == 0 && ! (access_flags & Modifier::INTERFACE))
+ if (super_class == 0)
{
- // FIXME: Consider this carefully!
- if (! _Jv_equalUtf8Consts (def->name, java::lang::Object::class$.name))
- throw_no_class_def_found_error ("loading java.lang.Object");
+ // Note that this is ok if we are defining java.lang.Object.
+ // But there is no way to have this class be interpreted.
+ throw_class_format_error ("no superclass reference");
}
def->state = JV_STATE_PRELOADING;
// lock here, as our caller has acquired it.
_Jv_RegisterInitiatingLoader (def, def->loader);
+ // Note that we found a name so that unregistration can happen if
+ // needed.
+ *found_name = def->name;
+
if (super_class != 0)
{
// Load the superclass.
_Jv_Utf8Const* super_name = pool_data[super_class].utf8;
// Load the superclass using our defining loader.
- jclass the_super = _Jv_FindClass (super_name,
- def->loader);
+ jclass the_super = _Jv_FindClass (super_name, def->loader);
// This will establish that we are allowed to be a subclass,
// and check for class circularity error.
void _Jv_ClassReader::handleInterfacesBegin (int count)
{
- def->interfaces = (jclass*) _Jv_AllocBytes (count*sizeof (jclass));
+ def->interfaces = (jclass*) _Jv_AllocRawObj (count*sizeof (jclass));
def->interface_count = count;
}
void _Jv_ClassReader::handleFieldsBegin (int count)
{
- def->fields = (_Jv_Field*)
- _Jv_AllocBytes (count * sizeof (_Jv_Field));
+ def->fields = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
def->field_count = count;
- def_interp->field_initializers = (_Jv_ushort*)
- _Jv_AllocBytes (count * sizeof (_Jv_ushort));
+ def_interp->field_initializers
+ = (_Jv_ushort*) _Jv_AllocRawObj (count * sizeof (_Jv_ushort));
for (int i = 0; i < count; i++)
def_interp->field_initializers[i] = (_Jv_ushort) 0;
}
void
_Jv_ClassReader::handleMethodsBegin (int count)
{
- def->methods = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) * count);
+ def->methods = (_Jv_Method *) _Jv_AllocRawObj (sizeof (_Jv_Method) * count);
def_interp->interpreted_methods
- = (_Jv_MethodBase **) _Jv_AllocBytes (sizeof (_Jv_MethodBase *)
- * count);
+ = (_Jv_MethodBase **) _Jv_AllocRawObj (sizeof (_Jv_MethodBase *)
+ * count);
for (int i = 0; i < count; i++)
{
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
+ // flags are not set. Verify flags for interface methods. Verify
// modifiers for initializers.
}
}
{
int size = _Jv_InterpMethod::size (exc_table_length, code_length);
_Jv_InterpMethod *method =
- (_Jv_InterpMethod*) (_Jv_AllocBytes (size));
+ (_Jv_InterpMethod*) (_Jv_AllocRawObj (size));
method->max_stack = max_stack;
method->max_locals = max_locals;
method->code_length = code_length;
method->exc_count = exc_table_length;
+ method->is_15 = is_15;
method->defining_class = def;
method->self = &def->methods[method_index];
method->prepared = NULL;
else
{
_Jv_JNIMethod *m = (_Jv_JNIMethod *)
- _Jv_AllocBytes (sizeof (_Jv_JNIMethod));
+ _Jv_AllocRawObj (sizeof (_Jv_JNIMethod));
m->defining_class = def;
m->self = method;
m->function = NULL;
{
if (def_interp->interpreted_methods[i] != 0)
throw_class_format_error ("code provided for abstract method");
+ method->ncode = (void *) &_Jv_ThrowAbstractMethodError;
}
else
{
}
}
-void _Jv_ClassReader::throw_class_format_error (char *msg)
+void _Jv_ClassReader::throw_class_format_error (const char *msg)
{
jstring str;
if (def->name != NULL)
}
static void
-throw_no_class_def_found_error (char *msg)
+throw_no_class_def_found_error (const char *msg)
{
throw_no_class_def_found_error (JvNewStringLatin1 (msg));
}
}
static void
-throw_internal_error (char *msg)
+throw_internal_error (const char *msg)
{
throw new java::lang::InternalError (JvNewStringLatin1 (msg));
}
while (ptr && UTF8_PEEK (ptr, limit) != ')')
ptr = _Jv_VerifyOne (ptr, limit, false);
- if (UTF8_GET (ptr, limit) != ')')
+ if (! ptr || UTF8_GET (ptr, limit) != ')')
return false;
// get the return type