// 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;
def->engine = &_Jv_soleInterpreterEngine;
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,
}
}
-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 *) _Jv_AllocBytes (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);
+ }
}
{
/** 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");
}
- // 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);
+
+ // Note that we found a name so that unregistration can happen if
+ // needed.
+ *found_name = def->name;
if (super_class != 0)
{
_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;
+ method->line_table_len = 0;
+ method->line_table = NULL;
+
// grab the byte code!
memcpy ((void*) method->bytecode (),
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