// natClass.cc - Implementation of java.lang.Class native methods. /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 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. */ #include #include #include #include #include #pragma implementation "Class.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace gcj; jclass java::lang::Class::forName (jstring className, jboolean initialize, java::lang::ClassLoader *loader) { if (! className) throw new java::lang::NullPointerException; jsize length = _Jv_GetStringUTFLength (className); char buffer[length]; _Jv_GetStringUTFRegion (className, 0, className->length(), buffer); _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length); if (! _Jv_VerifyClassName (name)) throw new java::lang::ClassNotFoundException (className); jclass klass = (buffer[0] == '[' ? _Jv_FindClassFromSignature (name->chars(), loader) : _Jv_FindClass (name, loader)); if (klass == NULL) throw new java::lang::ClassNotFoundException (className); if (initialize) _Jv_InitClass (klass); return klass; } jclass java::lang::Class::forName (jstring className) { java::lang::ClassLoader *loader = NULL; jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$); if (caller) loader = caller->getClassLoaderInternal(); return forName (className, true, loader); } java::lang::ClassLoader * java::lang::Class::getClassLoader (void) { java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); if (s != NULL) { jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$); return getClassLoader (caller); } return loader; } java::lang::ClassLoader * java::lang::Class::getClassLoader (jclass caller) { java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); if (s != NULL) { ClassLoader *caller_loader = caller->getClassLoaderInternal(); // If the caller has a non-null class loader, and that loader // is not this class' loader or an ancestor thereof, then do a // security check. if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader)) s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); } return loader; } java::lang::reflect::Constructor * java::lang::Class::getConstructor (JArray *param_types) { memberAccessCheck(java::lang::reflect::Member::PUBLIC); jstring partial_sig = getSignature (param_types, true); jint hash = partial_sig->hashCode (); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (methods[i].name, init_name) && _Jv_equal (methods[i].signature, partial_sig, hash)) { // Found it. For getConstructor, the constructor must be // public. using namespace java::lang::reflect; if (! Modifier::isPublic(methods[i].accflags)) break; Constructor *cons = new Constructor (); cons->offset = (char *) (&methods[i]) - (char *) methods; cons->declaringClass = this; return cons; } } throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name)); } JArray * java::lang::Class::getDeclaredConstructors (jboolean publicOnly) { int numConstructors = 0; int max = isPrimitive () ? 0 : method_count; int i; for (i = max; --i >= 0; ) { _Jv_Method *method = &methods[i]; if (method->name == NULL || ! _Jv_equalUtf8Consts (method->name, init_name)) continue; if (publicOnly && ! java::lang::reflect::Modifier::isPublic(method->accflags)) continue; numConstructors++; } JArray *result = (JArray *) JvNewObjectArray (numConstructors, &java::lang::reflect::Constructor::class$, NULL); java::lang::reflect::Constructor** cptr = elements (result); for (i = 0; i < max; i++) { _Jv_Method *method = &methods[i]; if (method->name == NULL || ! _Jv_equalUtf8Consts (method->name, init_name)) continue; if (publicOnly && ! java::lang::reflect::Modifier::isPublic(method->accflags)) continue; java::lang::reflect::Constructor *cons = new java::lang::reflect::Constructor (); cons->offset = (char *) method - (char *) methods; cons->declaringClass = this; *cptr++ = cons; } return result; } java::lang::reflect::Constructor * java::lang::Class::getDeclaredConstructor (JArray *param_types) { memberAccessCheck(java::lang::reflect::Member::DECLARED); jstring partial_sig = getSignature (param_types, true); jint hash = partial_sig->hashCode (); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (methods[i].name, init_name) && _Jv_equal (methods[i].signature, partial_sig, hash)) { // Found it. using namespace java::lang::reflect; Constructor *cons = new Constructor (); cons->offset = (char *) (&methods[i]) - (char *) methods; cons->declaringClass = this; return cons; } } throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name)); } java::lang::reflect::Field * java::lang::Class::getField (jstring name, jint hash) { java::lang::reflect::Field* rfield; for (int i = 0; i < field_count; i++) { _Jv_Field *field = &fields[i]; if (! _Jv_equal (field->name, name, hash)) continue; if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC)) continue; rfield = new java::lang::reflect::Field (); rfield->offset = (char*) field - (char*) fields; rfield->declaringClass = this; rfield->name = name; return rfield; } jclass superclass = getSuperclass(); if (superclass == NULL) return NULL; rfield = superclass->getField(name, hash); for (int i = 0; i < interface_count && rfield == NULL; ++i) rfield = interfaces[i]->getField (name, hash); return rfield; } java::lang::reflect::Field * java::lang::Class::getDeclaredField (jstring name) { memberAccessCheck(java::lang::reflect::Member::DECLARED); int hash = name->hashCode(); for (int i = 0; i < field_count; i++) { _Jv_Field *field = &fields[i]; if (! _Jv_equal (field->name, name, hash)) continue; java::lang::reflect::Field* rfield = new java::lang::reflect::Field (); rfield->offset = (char*) field - (char*) fields; rfield->declaringClass = this; rfield->name = name; return rfield; } throw new java::lang::NoSuchFieldException (name); } JArray * java::lang::Class::getDeclaredFields (jboolean public_only) { int size; if (public_only) { size = 0; for (int i = 0; i < field_count; ++i) { _Jv_Field *field = &fields[i]; if ((field->flags & java::lang::reflect::Modifier::PUBLIC)) ++size; } } else size = field_count; JArray *result = (JArray *) JvNewObjectArray (size, &java::lang::reflect::Field::class$, NULL); java::lang::reflect::Field** fptr = elements (result); for (int i = 0; i < field_count; i++) { _Jv_Field *field = &fields[i]; if (public_only && ! (field->flags & java::lang::reflect::Modifier::PUBLIC)) continue; java::lang::reflect::Field* rfield = new java::lang::reflect::Field (); rfield->offset = (char*) field - (char*) fields; rfield->declaringClass = this; *fptr++ = rfield; } return result; } void java::lang::Class::getSignature (java::lang::StringBuffer *buffer) { if (isPrimitive()) buffer->append((jchar) method_count); else { jstring name = getName(); if (name->charAt(0) != '[') buffer->append((jchar) 'L'); buffer->append(name); if (name->charAt(0) != '[') buffer->append((jchar) ';'); } } // This doesn't have to be native. It is an implementation detail // only called from the C++ code, though, so maybe this is clearer. jstring java::lang::Class::getSignature (JArray *param_types, jboolean is_constructor) { java::lang::StringBuffer *buf = new java::lang::StringBuffer (); buf->append((jchar) '('); // A NULL param_types means "no parameters". if (param_types != NULL) { jclass *v = elements (param_types); for (int i = 0; i < param_types->length; ++i) v[i]->getSignature(buf); } buf->append((jchar) ')'); if (is_constructor) buf->append((jchar) 'V'); return buf->toString(); } java::lang::reflect::Method * java::lang::Class::_getDeclaredMethod (jstring name, JArray *param_types) { jstring partial_sig = getSignature (param_types, false); jint p_len = partial_sig->length(); _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (methods[i].name, utf_name) && _Jv_equaln (methods[i].signature, partial_sig, p_len) && (methods[i].accflags & java::lang::reflect::Modifier::INVISIBLE) == 0) { // Found it. using namespace java::lang::reflect; Method *rmethod = new Method (); rmethod->offset = (char*) (&methods[i]) - (char*) methods; rmethod->declaringClass = this; return rmethod; } } return NULL; } JArray * java::lang::Class::getDeclaredMethods (void) { memberAccessCheck(java::lang::reflect::Member::DECLARED); int numMethods = 0; int max = isPrimitive () ? 0 : method_count; int i; for (i = max; --i >= 0; ) { _Jv_Method *method = &methods[i]; if (method->name == NULL || _Jv_equalUtf8Consts (method->name, clinit_name) || _Jv_equalUtf8Consts (method->name, init_name) || _Jv_equalUtf8Consts (method->name, finit_name) || (methods[i].accflags & java::lang::reflect::Modifier::INVISIBLE) != 0) continue; numMethods++; } JArray *result = (JArray *) JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL); java::lang::reflect::Method** mptr = elements (result); for (i = 0; i < max; i++) { _Jv_Method *method = &methods[i]; if (method->name == NULL || _Jv_equalUtf8Consts (method->name, clinit_name) || _Jv_equalUtf8Consts (method->name, init_name) || _Jv_equalUtf8Consts (method->name, finit_name) || (methods[i].accflags & java::lang::reflect::Modifier::INVISIBLE) != 0) continue; java::lang::reflect::Method* rmethod = new java::lang::reflect::Method (); rmethod->offset = (char*) method - (char*) methods; rmethod->declaringClass = this; *mptr++ = rmethod; } return result; } jstring java::lang::Class::getName (void) { return name->toString(); } JArray * java::lang::Class::getInterfaces (void) { jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL); jobject *data = elements (r); for (int i = 0; i < interface_count; ++i) { typedef unsigned int uaddr __attribute__ ((mode (pointer))); data[i] = interfaces[i]; if ((uaddr)data[i] < (uaddr)constants.size) fprintf (stderr, "ERROR !!!\n"); } return reinterpret_cast *> (r); } java::lang::reflect::Method * java::lang::Class::_getMethod (jstring name, JArray *param_types) { jstring partial_sig = getSignature (param_types, false); jint p_len = partial_sig->length(); _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); for (Class *klass = this; klass; klass = klass->getSuperclass()) { int i = klass->isPrimitive () ? 0 : klass->method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len) && (klass->methods[i].accflags & java::lang::reflect::Modifier::INVISIBLE) == 0) { // Found it. using namespace java::lang::reflect; // Method must be public. if (! Modifier::isPublic (klass->methods[i].accflags)) break; Method *rmethod = new Method (); rmethod->offset = ((char *) (&klass->methods[i]) - (char *) klass->methods); rmethod->declaringClass = klass; return rmethod; } } } // If we haven't found a match, and this class is an interface, then // check all the superinterfaces. if (isInterface()) { for (int i = 0; i < interface_count; ++i) { using namespace java::lang::reflect; Method *rmethod = interfaces[i]->_getMethod (name, param_types); if (rmethod != NULL) return rmethod; } } return NULL; } // This is a very slow implementation, since it re-scans all the // methods we've already listed to make sure we haven't duplicated a // method. It also over-estimates the required size, so we have to // shrink the result array later. jint java::lang::Class::_getMethods (JArray *result, jint offset) { jint count = 0; // First examine all local methods for (int i = isPrimitive () ? 0 : method_count; --i >= 0; ) { _Jv_Method *method = &methods[i]; if (method->name == NULL || _Jv_equalUtf8Consts (method->name, clinit_name) || _Jv_equalUtf8Consts (method->name, init_name) || _Jv_equalUtf8Consts (method->name, finit_name) || (method->accflags & java::lang::reflect::Modifier::INVISIBLE) != 0) continue; // Only want public methods. if (! java::lang::reflect::Modifier::isPublic (method->accflags)) continue; // This is where we over-count the slots required if we aren't // filling the result for real. if (result != NULL) { jboolean add = true; java::lang::reflect::Method **mp = elements (result); // If we already have a method with this name and signature, // then ignore this one. This can happen with virtual // methods. for (int j = 0; j < offset; ++j) { _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]); if (_Jv_equalUtf8Consts (method->name, meth_2->name) && _Jv_equalUtf8Consts (method->signature, meth_2->signature)) { add = false; break; } } if (! add) continue; } if (result != NULL) { using namespace java::lang::reflect; Method *rmethod = new Method (); rmethod->offset = (char *) method - (char *) methods; rmethod->declaringClass = this; Method **mp = elements (result); mp[offset + count] = rmethod; } ++count; } offset += count; // Now examine superclasses. if (getSuperclass () != NULL) { jint s_count = getSuperclass()->_getMethods (result, offset); offset += s_count; count += s_count; } // Finally, examine interfaces. for (int i = 0; i < interface_count; ++i) { int f_count = interfaces[i]->_getMethods (result, offset); count += f_count; offset += f_count; } return count; } JArray * java::lang::Class::getMethods (void) { using namespace java::lang::reflect; memberAccessCheck(Member::PUBLIC); // This will overestimate the size we need. jint count = _getMethods (NULL, 0); JArray *result = ((JArray *) JvNewObjectArray (count, &Method::class$, NULL)); // When filling the array for real, we get the actual count. Then // we resize the array. jint real_count = _getMethods (result, 0); if (real_count != count) { JArray *r2 = ((JArray *) JvNewObjectArray (real_count, &Method::class$, NULL)); Method **destp = elements (r2); Method **srcp = elements (result); for (int i = 0; i < real_count; ++i) *destp++ = *srcp++; result = r2; } return result; } jboolean java::lang::Class::isAssignableFrom (jclass klass) { // Arguments may not have been initialized, given ".class" syntax. // This ensures we can at least look at their superclasses. _Jv_Linker::wait_for_state (this, JV_STATE_LOADING); _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); return _Jv_IsAssignableFrom (klass, this); } jboolean java::lang::Class::isInstance (jobject obj) { if (! obj) return false; return _Jv_IsAssignableFrom (JV_CLASS (obj), this); } jobject java::lang::Class::newInstance (void) { memberAccessCheck(java::lang::reflect::Member::PUBLIC); if (isPrimitive () || isInterface () || isArray () || java::lang::reflect::Modifier::isAbstract(accflags)) throw new java::lang::InstantiationException (getName ()); _Jv_InitClass (this); _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature); if (! meth) throw new java::lang::InstantiationException (getName()); jobject r = _Jv_AllocObject (this); ((void (*) (jobject)) meth->ncode) (r); return r; } void java::lang::Class::finalize (void) { engine->unregister(this); } #ifdef INTERPRETER void _Jv_ClosureList::releaseClosures (_Jv_ClosureList **closures) { if (!closures) return; while (_Jv_ClosureList *current = *closures) { *closures = current->next; ffi_closure_free (current->ptr); } } void _Jv_ClosureList::registerClosure (jclass klass, void *ptr) { _Jv_ClosureList **closures = klass->engine->get_closure_list (klass); this->ptr = ptr; this->next = *closures; *closures = this; } #endif // This implements the initialization process for a class. From Spec // section 12.4.2. void java::lang::Class::initializeClass (void) { // Short-circuit to avoid needless locking (expression includes // JV_STATE_PHANTOM and JV_STATE_DONE). if (state >= JV_STATE_PHANTOM) return; // Step 1. We introduce a new scope so we can synchronize more // easily. { JvSynchronize sync (this); if (state < JV_STATE_LINKED) { try { _Jv_Linker::wait_for_state(this, JV_STATE_LINKED); } catch (java::lang::SecurityException *x) { throw x; } catch (java::lang::Throwable *x) { // Turn into a NoClassDefFoundError. java::lang::NoClassDefFoundError *result = new java::lang::NoClassDefFoundError(getName()); result->initCause(x); throw result; } } // Step 2. java::lang::Thread *self = java::lang::Thread::currentThread(); self = (java::lang::Thread *) ((long) self | 1); while (state == JV_STATE_IN_PROGRESS && thread && thread != self) wait (); // Steps 3 & 4. if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS) return; // Step 5. if (state == JV_STATE_ERROR) throw new java::lang::NoClassDefFoundError (getName()); // Step 6. thread = self; _Jv_Linker::wait_for_state (this, JV_STATE_LINKED); state = JV_STATE_IN_PROGRESS; } // Step 7. if (! isInterface () && superclass) { try { _Jv_InitClass (superclass); } catch (java::lang::SecurityException *x) { throw x; } catch (java::lang::Throwable *except) { // Caught an exception. JvSynchronize sync (this); state = JV_STATE_ERROR; notifyAll (); throw except; } } // Steps 8, 9, 10, 11. try { _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name, void_signature); if (meth) ((void (*) (void)) meth->ncode) (); } catch (java::lang::SecurityException *x) { throw x; } catch (java::lang::Throwable *except) { if (! java::lang::Error::class$.isInstance(except)) { try { except = new ExceptionInInitializerError (except); } catch (java::lang::Throwable *t) { except = t; } } JvSynchronize sync (this); state = JV_STATE_ERROR; notifyAll (); throw except; } JvSynchronize sync (this); state = JV_STATE_DONE; notifyAll (); } // Only used by serialization java::lang::reflect::Field * java::lang::Class::getPrivateField (jstring name) { int hash = name->hashCode (); java::lang::reflect::Field* rfield; for (int i = 0; i < field_count; i++) { _Jv_Field *field = &fields[i]; if (! _Jv_equal (field->name, name, hash)) continue; rfield = new java::lang::reflect::Field (); rfield->offset = (char*) field - (char*) fields; rfield->declaringClass = this; rfield->name = name; return rfield; } jclass superclass = getSuperclass(); if (superclass == NULL) return NULL; rfield = superclass->getPrivateField(name); for (int i = 0; i < interface_count && rfield == NULL; ++i) rfield = interfaces[i]->getPrivateField (name); return rfield; } // Only used by serialization java::lang::reflect::Method * java::lang::Class::getPrivateMethod (jstring name, JArray *param_types) { jstring partial_sig = getSignature (param_types, false); jint p_len = partial_sig->length(); _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); for (Class *klass = this; klass; klass = klass->getSuperclass()) { int i = klass->isPrimitive () ? 0 : klass->method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) { // Found it. using namespace java::lang::reflect; Method *rmethod = new Method (); rmethod->offset = ((char *) (&klass->methods[i]) - (char *) klass->methods); rmethod->declaringClass = klass; return rmethod; } } } throw new java::lang::NoSuchMethodException (name); } // Private accessor method for Java code to retrieve the protection domain. java::security::ProtectionDomain * java::lang::Class::getProtectionDomain0 () { return protectionDomain; } JArray * java::lang::Class::getSigners() { return hack_signers; } void java::lang::Class::setSigners(JArray *s) { hack_signers = s; } static unsigned char read_u1 (unsigned char *&p) { return *p++; } static unsigned char read_u1 (unsigned char *&p, unsigned char *next) { if (next - p < 1) throw new java::lang::InternalError(); return *p++; } static unsigned int read_u2 (unsigned char *&p) { unsigned int b1 = *p++; unsigned int b2 = *p++; return (b1 << 8) | b2; } static unsigned int read_u2 (unsigned char *&p, unsigned char *next) { if (next - p < 2) throw new java::lang::InternalError(); return read_u2 (p); } static int read_4 (unsigned char *&p) { int b1 = *p++; int b2 = *p++; int b3 = *p++; int b4 = *p++; return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4; } jstring java::lang::Class::getReflectionSignature (jint /*jv_attr_type*/ type, jint obj_index) { // We just re-parse the bytecode for this data each time. If // necessary we can cache results, but I suspect this is not // performance sensitive. unsigned char *bytes = reflection_data; if (bytes == NULL) return NULL; while (true) { int kind = read_u1 (bytes); if (kind == JV_DONE_ATTR) return NULL; int len = read_4 (bytes); unsigned char *next = bytes + len; if (kind != type) { bytes = next; continue; } if (type != JV_CLASS_ATTR) { unsigned short index = read_u2 (bytes, next); if (index != obj_index) { bytes = next; continue; } } int nt = read_u1 (bytes, next); if (nt != JV_SIGNATURE_KIND) { bytes = next; continue; } unsigned int cpool_idx = read_u2 (bytes, next); if (cpool_idx >= (unsigned int) constants.size || constants.tags[cpool_idx] != JV_CONSTANT_Utf8) { // We just ignore errors for now. It isn't clear what is // best to do here, as an encoding error here means a bug // either in the compiler or in defineclass.cc. return NULL; } return _Jv_NewStringUtf8Const (constants.data[cpool_idx].utf8); } } jstring java::lang::Class::getReflectionSignature (::java::lang::reflect::Constructor *c) { _Jv_Method *meth = _Jv_FromReflectedConstructor (c); unsigned short meth_index = meth - methods; return getReflectionSignature (JV_METHOD_ATTR, meth_index); } jstring java::lang::Class::getReflectionSignature (::java::lang::reflect::Method *m) { _Jv_Method *meth = _Jv_FromReflectedMethod (m); unsigned short meth_index = meth - methods; return getReflectionSignature (JV_METHOD_ATTR, meth_index); } jstring java::lang::Class::getReflectionSignature (::java::lang::reflect::Field *f) { _Jv_Field *fld = _Jv_FromReflectedField (f); unsigned short fld_index = fld - fields; return getReflectionSignature (JV_FIELD_ATTR, fld_index); } jstring java::lang::Class::getClassSignature() { return getReflectionSignature (JV_CLASS_ATTR, 0); } jint java::lang::Class::getEnclosingMethodData() { unsigned char *bytes = reflection_data; if (bytes == NULL) return 0; while (true) { int kind = read_u1 (bytes); if (kind == JV_DONE_ATTR) return 0; int len = read_4 (bytes); unsigned char *next = bytes + len; if (kind != JV_CLASS_ATTR) { bytes = next; continue; } int type = read_u1 (bytes, next); if (type != JV_ENCLOSING_METHOD_KIND) { bytes = next; continue; } int class_index = read_u2 (bytes, next); int method_index = read_u2 (bytes, next); _Jv_word result; _Jv_storeIndexes (&result, class_index, method_index); return result.i; } } jclass java::lang::Class::getEnclosingClass() { _Jv_word indexes; indexes.i = getEnclosingMethodData(); if (indexes.i == 0) // No enclosing method, but perhaps a member or anonymous class return getDeclaringClass(); _Jv_ushort class_index, method_index; _Jv_loadIndexes (&indexes, class_index, method_index); return _Jv_Linker::resolve_pool_entry (this, class_index).clazz; } ::java::lang::reflect::Method * java::lang::Class::getEnclosingMethod() { _Jv_word indexes; indexes.i = getEnclosingMethodData(); if (indexes.i == 0) return NULL; _Jv_ushort class_index, method_index; _Jv_loadIndexes (&indexes, class_index, method_index); jclass found_class; _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class, class_index, method_index, false, false); using namespace java::lang::reflect; Method *rmethod = new Method (); rmethod->offset = (char *) method - (char *) found_class->methods; rmethod->declaringClass = found_class; return rmethod; } ::java::lang::reflect::Constructor * java::lang::Class::getEnclosingConstructor() { _Jv_word indexes; indexes.i = getEnclosingMethodData(); if (indexes.i == 0) return NULL; _Jv_ushort class_index, method_index; _Jv_loadIndexes (&indexes, class_index, method_index); jclass found_class; _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class, class_index, method_index, false, false); using namespace java::lang::reflect; Constructor *cons = new Constructor (); cons->offset = (char *) method - (char *) found_class->methods; cons->declaringClass = this; return cons; } static void check_constant (_Jv_Constants *pool, jint cpool_index, jint type) { if (cpool_index <= 0 || cpool_index >= pool->size) throw new InternalError(JvNewStringLatin1("invalid constant pool index")); if ((pool->tags[cpool_index] & ~(JV_CONSTANT_ResolvedFlag|JV_CONSTANT_LazyFlag)) != type) { ::java::lang::StringBuffer *sb = new ::java::lang::StringBuffer(); sb->append(JvNewStringLatin1("expected pool constant ")); sb->append(type); sb->append(JvNewStringLatin1(" but got ")); sb->append(jint (pool->tags[cpool_index])); throw new InternalError(sb->toString()); } } // Forward declaration static ::java::lang::annotation::Annotation * parseAnnotation(jclass klass, _Jv_Constants *pool, unsigned char *&bytes, unsigned char *last); static jobject parseAnnotationElement(jclass klass, _Jv_Constants *pool, unsigned char *&bytes, unsigned char *last) { int tag = read_u1 (bytes, last); jobject result; switch (tag) { case 'B': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Integer); result = Byte::valueOf (pool->data[cindex].i); } break; case 'C': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Integer); result = Character::valueOf (pool->data[cindex].i); } break; case 'S': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Integer); result = Short::valueOf (pool->data[cindex].i); } break; case 'Z': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Integer); result = Boolean::valueOf (jboolean (pool->data[cindex].i)); } break; case 'I': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Integer); result = Integer::valueOf (pool->data[cindex].i); } break; case 'D': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Double); _Jv_word2 word; memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word)); result = Double::valueOf (word.d); } break; case 'F': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Float); result = Float::valueOf (pool->data[cindex].f); } break; case 'J': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Long); _Jv_word2 word; memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word)); result = Long::valueOf (word.l); } break; case 's': { int cindex = read_u2 (bytes, last); // Despite what the JVM spec says, compilers generate a Utf8 // constant here, not a String. check_constant (pool, cindex, JV_CONSTANT_Utf8); result = pool->data[cindex].utf8->toString(); } break; case 'e': { int type_name_index = read_u2 (bytes, last); check_constant (pool, type_name_index, JV_CONSTANT_Utf8); int const_name_index = read_u2 (bytes, last); check_constant (pool, const_name_index, JV_CONSTANT_Utf8); _Jv_Utf8Const *u_name = pool->data[type_name_index].utf8; _Jv_Utf8Const *e_name = pool->data[const_name_index].utf8; // FIXME: throw correct exceptions at the correct times. jclass e_class = _Jv_FindClassFromSignature(u_name->chars(), klass->getClassLoaderInternal()); result = ::java::lang::Enum::valueOf(e_class, e_name->toString()); } break; case 'c': { int cindex = read_u2 (bytes, last); check_constant (pool, cindex, JV_CONSTANT_Utf8); _Jv_Utf8Const *u_name = pool->data[cindex].utf8; jclass anno_class = _Jv_FindClassFromSignatureNoException(u_name->chars(), klass->getClassLoaderInternal()); // FIXME: not correct: we should lazily do this when trying to // read the element. This means that // AnnotationInvocationHandler needs to have a special case. if (! anno_class) // FIXME: original exception... throw new TypeNotPresentException(u_name->toString(), NULL); result = anno_class; } break; case '@': result = parseAnnotation (klass, pool, bytes, last); break; case '[': { int n_array_elts = read_u2 (bytes, last); jobjectArray aresult = _Jv_NewObjectArray (n_array_elts, &Object::class$, NULL); jobject *elts = elements (aresult); for (int i = 0; i < n_array_elts; ++i) elts[i] = parseAnnotationElement(klass, pool, bytes, last); result = aresult; } break; default: throw new java::lang::InternalError(); } return result; } static ::java::lang::annotation::Annotation * parseAnnotation(jclass klass, _Jv_Constants *pool, unsigned char *&bytes, unsigned char *last) { int type_index = read_u2 (bytes, last); check_constant (pool, type_index, JV_CONSTANT_Utf8); _Jv_Utf8Const *u_name = pool->data[type_index].utf8; jclass anno_class = _Jv_FindClassFromSignatureNoException(u_name->chars(), klass->getClassLoaderInternal()); // FIXME: what to do if anno_class==NULL? ::java::util::HashMap *hmap = new ::java::util::HashMap(); int npairs = read_u2 (bytes, last); for (int i = 0; i < npairs; ++i) { int name_index = read_u2 (bytes, last); check_constant (pool, name_index, JV_CONSTANT_Utf8); jstring name = _Jv_NewStringUtf8Const (pool->data[name_index].utf8); jobject value = parseAnnotationElement (klass, pool, bytes, last); // FIXME: any checks needed for name? hmap->put(name, value); } using namespace ::sun::reflect::annotation; return AnnotationInvocationHandler::create (anno_class, (::java::util::Map *) hmap); } static jobjectArray parseAnnotations(jclass klass, _Jv_Constants *pool, unsigned char *&bytes, unsigned char *last) { int num = read_u2 (bytes, last); jobjectArray result = _Jv_NewObjectArray (num, &::java::lang::annotation::Annotation::class$, NULL); jobject *elts = elements (result); for (int i = 0; i < num; ++i) elts[i] = parseAnnotation(klass, pool, bytes, last); return result; } static jobjectArray parseParameterAnnotations(jclass klass, _Jv_Constants *pool, unsigned char *&bytes, unsigned char *last) { jclass anno = &::java::lang::annotation::Annotation::class$; jclass annoary = _Jv_GetArrayClass (anno, anno->getClassLoaderInternal()); // FIXME: something should check the number of params versus the // method int n_params = read_u1 (bytes, last); jobjectArray result = _Jv_NewObjectArray (n_params, annoary, NULL); jobject *elts = elements (result); for (int i = 0; i < n_params; ++i) elts[i] = parseAnnotations(klass, pool, bytes, last); return result; } jobject java::lang::Class::getMethodDefaultValue(::java::lang::reflect::Method *meth) { // FIXME: could cache the value here... unsigned char *bytes = reflection_data; if (bytes == NULL) return 0; unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods; while (true) { int type = read_u1 (bytes); if (type == JV_DONE_ATTR) return NULL; int len = read_4 (bytes); unsigned char *next = bytes + len; if (type != JV_METHOD_ATTR) { bytes = next; continue; } int kind = read_u1 (bytes, next); if (kind != JV_ANNOTATION_DEFAULT_KIND) { bytes = next; continue; } int index = read_u2 (bytes, next); if (meth_index != index) { bytes = next; continue; } // FIXME: could cache here. If we do then we have to clone any // array result. return parseAnnotationElement(this, &this->constants, bytes, next); } } jobjectArray java::lang::Class::getDeclaredAnnotations(jint /* jv_attr_type */ member_type, jint member_index, jint /* jv_attr_kind */ kind_req) { using namespace java::lang::annotation; jobjectArray result; unsigned char *bytes = reflection_data; if (bytes == NULL) return 0; if (loader == NULL) loader = (ClassLoader *)VMClassLoader::bootLoader; result = (loader->getDeclaredAnnotations (this, member_type, member_index, kind_req)); if (result) return result; for (;;) { int type = read_u1 (bytes); if (type == JV_DONE_ATTR) return NULL; int len = read_4 (bytes); unsigned char *next = bytes + len; if (type != member_type) { bytes = next; continue; } int kind = read_u1 (bytes, next); if (kind != kind_req) { bytes = next; continue; } if (member_type != JV_CLASS_ATTR) { int index = read_u2 (bytes, next); if (member_index != index) { bytes = next; continue; } } if (kind_req == JV_PARAMETER_ANNOTATIONS_KIND) result = ((parseParameterAnnotations (this, &this->constants, bytes, next))); else result = ((parseAnnotations (this, &this->constants, bytes, next))); break; } return (loader->putDeclaredAnnotations (this, member_type, member_index, kind_req, result)); } jobjectArray java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Method *meth, jboolean is_param) { unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods; return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index, (is_param ? JV_PARAMETER_ANNOTATIONS_KIND : JV_ANNOTATIONS_KIND)); } jobjectArray java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Constructor *cons, jboolean is_param) { unsigned short meth_index = _Jv_FromReflectedConstructor (cons) - methods; return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index, (is_param ? JV_PARAMETER_ANNOTATIONS_KIND : JV_ANNOTATIONS_KIND)); } jobjectArray java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Field *fld) { unsigned short field_index = _Jv_FromReflectedField (fld) - fields; return getDeclaredAnnotations(JV_FIELD_ATTR, field_index, JV_ANNOTATIONS_KIND); } JArray< ::java::lang::annotation::Annotation *> * java::lang::Class::getDeclaredAnnotationsInternal() { return (JArray< ::java::lang::annotation::Annotation *> *) getDeclaredAnnotations(JV_CLASS_ATTR, 0, JV_ANNOTATIONS_KIND); } static jclass resolve_class_constant (jclass klass, _Jv_Constants *pool, int cpool_index) { check_constant (pool, cpool_index, JV_CONSTANT_Class); // FIXME: what is the correct thing to do with an exception here? return _Jv_Linker::resolve_pool_entry (klass, cpool_index, false).clazz; } jint java::lang::Class::findInnerClassAttribute() { unsigned char *bytes = reflection_data; if (bytes == NULL) return -1; while (true) { int type = read_u1 (bytes); if (type == JV_DONE_ATTR) break; // After the type but before the length. unsigned char *save = bytes; int len = read_4 (bytes); unsigned char *next = bytes + len; if (type != JV_CLASS_ATTR) { bytes = next; continue; } int kind = read_u1 (bytes, next); if (kind != JV_INNER_CLASSES_KIND) { bytes = next; continue; } return save - reflection_data; } return -1; } jint java::lang::Class::findDeclaredClasses(JArray *result, jboolean publicOnly, jint offset) { unsigned char *bytes = reflection_data + offset; int len = read_4 (bytes); unsigned char *next = bytes + len; // Skip a byte. read_u1 (bytes, next); int n_classes = read_u2 (bytes, next); int count = 0; for (int i = 0; i < n_classes; ++i) { int inner_class_index = read_u2 (bytes, next); int outer_class_index = read_u2 (bytes, next); /*int inner_name_index = */ read_u2 (bytes, next); int inner_flags = read_u2 (bytes, next); if (inner_class_index == 0 || outer_class_index == 0) continue; if (resolve_class_constant (this, &constants, outer_class_index) == this) { jclass inner = resolve_class_constant (this, &constants, inner_class_index); if (! publicOnly || ((inner_flags & java::lang::reflect::Modifier::PUBLIC) != 0)) { if (result) { jclass *elts = elements (result); elts[count] = inner; } ++count; } } } return count; } JArray * java::lang::Class::getDeclaredClasses (jboolean publicOnly) { int offset = findInnerClassAttribute(); int count; if (offset == -1) { // No InnerClasses attribute, so no declared classes. count = 0; } else count = findDeclaredClasses(NULL, publicOnly, offset); JArray *result = (JArray *) JvNewObjectArray (count, &java::lang::Class::class$, NULL); if (count > 0) findDeclaredClasses(result, publicOnly, offset); return result; } jclass java::lang::Class::getDeclaringClass (void) { int offset = findInnerClassAttribute(); if (offset == -1) return NULL; unsigned char *bytes = reflection_data + offset; int len = read_4 (bytes); unsigned char *next = bytes + len; // Skip a byte. read_u1 (bytes, next); int n_classes = read_u2 (bytes, next); for (int i = 0; i < n_classes; ++i) { int inner_class_index = read_u2 (bytes, next); int outer_class_index = read_u2 (bytes, next); /*int inner_name_index = */read_u2 (bytes, next); /*int inner_flags = */read_u2 (bytes, next); if (inner_class_index == 0 || outer_class_index == 0) continue; if (resolve_class_constant (this, &constants, inner_class_index) == this) return resolve_class_constant (this, &constants, outer_class_index); } return NULL; } jboolean java::lang::Class::isAnonymousClass() { int offset = findInnerClassAttribute(); if (offset == -1) return false; unsigned char *bytes = reflection_data + offset; int len = read_4 (bytes); unsigned char *next = bytes + len; // Skip a byte. read_u1 (bytes, next); int n_classes = read_u2 (bytes, next); for (int i = 0; i < n_classes; ++i) { int inner_class_index = read_u2 (bytes, next); /*int outer_class_index = */read_u2 (bytes, next); int inner_name_index = read_u2 (bytes, next); /*int inner_flags = */read_u2 (bytes, next); if (inner_class_index == 0) continue; if (resolve_class_constant (this, &constants, inner_class_index) == this) return inner_name_index == 0; } return false; } jboolean java::lang::Class::isLocalClass() { _Jv_word indexes; indexes.i = getEnclosingMethodData(); return indexes.i != 0; } jboolean java::lang::Class::isMemberClass() { // FIXME: is this correct? return !isLocalClass() && getDeclaringClass() != NULL; } // // Some class-related convenience functions. // // Find a method declared in the class. If it is not declared locally // (or if it is inherited), return NULL. _Jv_Method * _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) { for (int i = 0; i < klass->method_count; ++i) { if (_Jv_equalUtf8Consts (name, klass->methods[i].name) && _Jv_equalUtf8Consts (signature, klass->methods[i].signature)) return &klass->methods[i]; } return NULL; } _Jv_Method * _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature, jclass *declarer_result) { for (; klass; klass = klass->getSuperclass()) { _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); if (meth) { if (declarer_result) *declarer_result = klass; return meth; } } return NULL; } java::lang::reflect::Method * _Jv_GetReflectedMethod (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) { for (; klass; klass = klass->getSuperclass()) { _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); if (meth) { using namespace java::lang::reflect; Method *rmethod = new Method (); rmethod->offset = (char*) meth - (char*) klass->methods; rmethod->declaringClass = klass; return rmethod; } } return NULL; } #ifdef HAVE_TLS // NOTE: MCACHE_SIZE should be a power of 2 minus one. #define MCACHE_SIZE 31 struct _Jv_mcache { jclass klass; _Jv_Method *method; }; static __thread _Jv_mcache *method_cache; #endif // HAVE_TLS static void * _Jv_FindMethodInCache (jclass klass MAYBE_UNUSED, _Jv_Utf8Const *name MAYBE_UNUSED, _Jv_Utf8Const *signature MAYBE_UNUSED) { #ifdef HAVE_TLS _Jv_mcache *cache = method_cache; if (cache) { int index = name->hash16 () & MCACHE_SIZE; _Jv_mcache *mc = &cache[index]; _Jv_Method *m = mc->method; if (mc->klass == klass && _Jv_equalUtf8Consts (m->name, name) && _Jv_equalUtf8Consts (m->signature, signature)) return mc->method->ncode; } #endif // HAVE_TLS return NULL; } static void _Jv_AddMethodToCache (jclass klass MAYBE_UNUSED, _Jv_Method *method MAYBE_UNUSED) { #ifdef HAVE_TLS if (method_cache == NULL) method_cache = (_Jv_mcache *) _Jv_MallocUnchecked((MCACHE_SIZE + 1) * sizeof (_Jv_mcache)); // If the allocation failed, just keep going. if (method_cache != NULL) { int index = method->name->hash16 () & MCACHE_SIZE; method_cache[index].method = method; method_cache[index].klass = klass; } #endif // HAVE_TLS } // Free this thread's method cache. We explicitly manage this memory // as the GC does not yet know how to scan TLS on all platforms. void _Jv_FreeMethodCache () { #ifdef HAVE_TLS if (method_cache != NULL) { _Jv_Free(method_cache); method_cache = NULL; } #endif // HAVE_TLS } void * _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) { using namespace java::lang::reflect; void *ncode = _Jv_FindMethodInCache (klass, name, signature); if (ncode != 0) return ncode; for (; klass; klass = klass->getSuperclass()) { _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); if (! meth) continue; if (Modifier::isStatic(meth->accflags)) throw new java::lang::IncompatibleClassChangeError (_Jv_GetMethodString (klass, meth)); if (Modifier::isAbstract(meth->accflags)) throw new java::lang::AbstractMethodError (_Jv_GetMethodString (klass, meth)); if (! Modifier::isPublic(meth->accflags)) throw new java::lang::IllegalAccessError (_Jv_GetMethodString (klass, meth)); _Jv_AddMethodToCache (klass, meth); return meth->ncode; } throw new java::lang::IncompatibleClassChangeError; } // Fast interface method lookup by index. void * _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx) { _Jv_IDispatchTable *cldt = klass->idt; int idx = iface->ioffsets[cldt->iindex] + method_idx; return cldt->itable[idx]; } jboolean _Jv_IsAssignableFrom (jclass source, jclass target) { if (source == target) return true; // If target is array, so must source be. while (target->isArray ()) { if (! source->isArray()) return false; target = target->getComponentType(); source = source->getComponentType(); } if (target->isInterface()) { // Abstract classes have no IDT, and IDTs provide no way to check // two interfaces for assignability. if (__builtin_expect (source->idt == NULL || source->isInterface(), false)) return _Jv_InterfaceAssignableFrom (source, target); _Jv_IDispatchTable *cl_idt = source->idt; if (__builtin_expect ((target->ioffsets == NULL), false)) return false; // No class implementing TARGET has been loaded. jshort cl_iindex = cl_idt->iindex; if (cl_iindex < target->ioffsets[0]) { jshort offset = target->ioffsets[cl_iindex]; if (offset != -1 && offset < cl_idt->itable_length && cl_idt->itable[offset] == target) return true; } return false; } // Primitive TYPE classes are only assignable to themselves. if (__builtin_expect (target->isPrimitive() || source->isPrimitive(), false)) return false; if (target == &java::lang::Object::class$) return true; else if (source->ancestors == NULL || target->ancestors == NULL) { // We need this case when either SOURCE or TARGET has not has // its constant-time tables prepared. // At this point we know that TARGET can't be Object, so it is // safe to use that as the termination point. while (source && source != &java::lang::Object::class$) { if (source == target) return true; source = source->getSuperclass(); } } else if (source->depth >= target->depth && source->ancestors[source->depth - target->depth] == target) return true; return false; } // Interface type checking, the slow way. Returns TRUE if IFACE is a // superinterface of SOURCE. This is used when SOURCE is also an interface, // or a class with no interface dispatch table. jboolean _Jv_InterfaceAssignableFrom (jclass source, jclass iface) { for (int i = 0; i < source->interface_count; i++) { jclass interface = source->interfaces[i]; if (iface == interface || _Jv_InterfaceAssignableFrom (interface, iface)) return true; } if (!source->isInterface() && source->superclass && _Jv_InterfaceAssignableFrom (source->superclass, iface)) return true; return false; } jboolean _Jv_IsInstanceOf(jobject obj, jclass cl) { if (__builtin_expect (!obj, false)) return false; return _Jv_IsAssignableFrom (JV_CLASS (obj), cl); } void * _Jv_CheckCast (jclass c, jobject obj) { if (__builtin_expect (obj != NULL && ! _Jv_IsAssignableFrom(JV_CLASS (obj), c), false)) throw new java::lang::ClassCastException ((new java::lang::StringBuffer (obj->getClass()->getName()))->append (JvNewStringUTF(" cannot be cast to "))->append (c->getName())->toString()); return obj; } void _Jv_CheckArrayStore (jobject arr, jobject obj) { if (obj) { JvAssert (arr != NULL); jclass elt_class = (JV_CLASS (arr))->getComponentType(); if (elt_class == &java::lang::Object::class$) return; jclass obj_class = JV_CLASS (obj); if (__builtin_expect (! _Jv_IsAssignableFrom (obj_class, elt_class), false)) throw new java::lang::ArrayStoreException ((new java::lang::StringBuffer (JvNewStringUTF("Cannot store ")))->append (obj_class->getName())->append (JvNewStringUTF(" in array of type "))->append (elt_class->getName())->toString()); } } jboolean _Jv_IsAssignableFromSlow (jclass source, jclass target) { // First, strip arrays. while (target->isArray ()) { // If target is array, source must be as well. if (! source->isArray ()) return false; target = target->getComponentType (); source = source->getComponentType (); } // Quick success. if (target == &java::lang::Object::class$) return true; // Ensure that the classes have their supers installed. _Jv_Linker::wait_for_state (source, JV_STATE_LOADING); _Jv_Linker::wait_for_state (target, JV_STATE_LOADING); do { if (source == target) return true; if (target->isPrimitive () || source->isPrimitive ()) return false; if (target->isInterface ()) { for (int i = 0; i < source->interface_count; ++i) { // We use a recursive call because we also need to // check superinterfaces. if (_Jv_IsAssignableFromSlow (source->getInterface (i), target)) return true; } } source = source->getSuperclass (); } while (source != NULL); return false; } // Lookup an interface method by name. This is very similar to // purpose to _getMethod, but the interfaces are quite different. It // might be a good idea for _getMethod to call this function. // // Return true of the method is found, with the class in FOUND_CLASS // and the index in INDEX. bool _Jv_getInterfaceMethod (jclass search_class, jclass &found_class, int &index, const _Jv_Utf8Const *utf_name, const _Jv_Utf8Const *utf_sig) { for (jclass klass = search_class; klass; klass = klass->getSuperclass()) { // FIXME: Throw an exception? if (!klass->isInterface ()) return false; int max = klass->method_count; int offset = 0; for (int i = 0; i < max; ++i) { // Skip here, as it will not be in the IDT. if (klass->methods[i].name->first() == '<') continue; if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) && _Jv_equalUtf8Consts (klass->methods[i].signature, utf_sig)) { // Found it. using namespace java::lang::reflect; // FIXME: Method must be public. Throw an exception? if (! Modifier::isPublic (klass->methods[i].accflags)) break; found_class = klass; // Interface method indexes count from 1. index = offset + 1; return true; } ++offset; } } // If we haven't found a match, and this class is an interface, then // check all the superinterfaces. if (search_class->isInterface()) { for (int i = 0; i < search_class->interface_count; ++i) { using namespace java::lang::reflect; bool found = _Jv_getInterfaceMethod (search_class->interfaces[i], found_class, index, utf_name, utf_sig); if (found) return true; } } return false; } #ifdef INTERPRETER _Jv_MethodBase * _Jv_FindInterpreterMethod (jclass klass, jmethodID desired_method) { using namespace java::lang::reflect; _Jv_InterpClass *iclass = reinterpret_cast<_Jv_InterpClass *> (klass->aux_info); _Jv_MethodBase **imethods = _Jv_GetFirstMethod (iclass); for (int i = 0; i < JvNumMethods (klass); ++i) { _Jv_MethodBase *imeth = imethods[i]; if (imeth->get_method () == desired_method) return imeth; } return NULL; } #endif // Return Utf8 name of a class. This function is here for code that // can't access klass->name directly. _Jv_Utf8Const* _Jv_GetClassNameUtf8 (jclass klass) { return klass->name; } jclass _Jv_GetMethodDeclaringClass (jmethodID method) { _Jv_StackTrace::UpdateNCodeMap (); jobject obj = reinterpret_cast (method->ncode); return reinterpret_cast (_Jv_StackTrace::ncodeMap->get (obj)); } jbyte _Jv_GetClassState (jclass klass) { return klass->state; } #ifdef INTERPRETER jstring _Jv_GetInterpClassSourceFile (jclass klass) { if (_Jv_IsInterpretedClass (klass)) { _Jv_InterpClass *iclass = reinterpret_cast<_Jv_InterpClass *> (klass->aux_info); return iclass->source_file_name; } return NULL; } #endif