📄 natclass.cc
字号:
// Interface Dispatch Table" whose size is (number of methods + 1) words.// The first word is a pointer to the interface (i.e. the java.lang.Class// instance for that interface). The remaining words are pointers to the// actual methods that implement the methods declared in the interface,// in order of declaration.//// Append partial interface dispatch table for "iface" to "itable", at// position itable_pos.// Returns the offset at which the next partial ITable should be appended.jshort_Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, jshort pos){ using namespace java::lang::reflect; itable[pos++] = (void *) iface; _Jv_Method *meth; for (int j=0; j < iface->method_count; j++) { meth = NULL; for (jclass cl = klass; cl; cl = cl->getSuperclass()) { meth = _Jv_GetMethodLocal (cl, iface->methods[j].name, iface->methods[j].signature); if (meth) break; } if (meth && (meth->name->data[0] == '<')) { // leave a placeholder in the itable for hidden init methods. itable[pos] = NULL; } else if (meth) { if (Modifier::isStatic(meth->accflags)) throw new java::lang::IncompatibleClassChangeError (_Jv_GetMethodString (klass, meth->name)); if (Modifier::isAbstract(meth->accflags)) throw new java::lang::AbstractMethodError (_Jv_GetMethodString (klass, meth->name)); if (! Modifier::isPublic(meth->accflags)) throw new java::lang::IllegalAccessError (_Jv_GetMethodString (klass, meth->name)); itable[pos] = meth->ncode; } else { // The method doesn't exist in klass. Binary compatibility rules // permit this, so we delay the error until runtime using a pointer // to a method which throws an exception. itable[pos] = (void *) _Jv_ThrowNoSuchMethodError; } pos++; } return pos;}static _Jv_Mutex_t iindex_mutex;static bool iindex_mutex_initialized = false;// We need to find the correct offset in the Class Interface Dispatch // Table for a given interface. Once we have that, invoking an interface // method just requires combining the Method's index in the interface // (known at compile time) to get the correct method. Doing a type test // (cast or instanceof) is the same problem: Once we have a possible Partial // Interface Dispatch Table, we just compare the first element to see if it // matches the desired interface. So how can we find the correct offset? // Our solution is to keep a vector of candiate offsets in each interface // (idt->iface.ioffsets), and in each class we have an index // (idt->cls.iindex) used to select the correct offset from ioffsets.//// Calculate and return iindex for a new class. // ifaces is a vector of num interfaces that the class implements.// offsets[j] is the offset in the interface dispatch table for the// interface corresponding to ifaces[j].// May extend the interface ioffsets if required.jshort_Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num){ int i; int j; // Acquire a global lock to prevent itable corruption in case of multiple // classes that implement an intersecting set of interfaces being linked // simultaneously. We can assume that the mutex will be initialized // single-threaded. if (! iindex_mutex_initialized) { _Jv_MutexInit (&iindex_mutex); iindex_mutex_initialized = true; } _Jv_MutexLock (&iindex_mutex); for (i=1;; i++) /* each potential position in ioffsets */ { for (j=0;; j++) /* each iface */ { if (j >= num) goto found; if (i >= ifaces[j]->idt->iface.ioffsets[0]) continue; int ioffset = ifaces[j]->idt->iface.ioffsets[i]; /* We can potentially share this position with another class. */ if (ioffset >= 0 && ioffset != offsets[j]) break; /* Nope. Try next i. */ } } found: for (j = 0; j < num; j++) { int len = ifaces[j]->idt->iface.ioffsets[0]; if (i >= len) { /* Resize ioffsets. */ int newlen = 2 * len; if (i >= newlen) newlen = i + 3; jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets; jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, newlen * sizeof(jshort)); new_ioffsets[0] = newlen; while (len < newlen) new_ioffsets[len++] = -1; ifaces[j]->idt->iface.ioffsets = new_ioffsets; } ifaces[j]->idt->iface.ioffsets[i] = offsets[j]; } _Jv_MutexUnlock (&iindex_mutex); return i;}// Only used by serializationjava::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 serializationjava::lang::reflect::Method *java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *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;}// Private accessor method for Java code to retrieve the protection domain.java::security::ProtectionDomain *java::lang::Class::getProtectionDomain0 (){ return protectionDomain;}// Functions for indirect dispatch (symbolic virtual method binding) support.// Resolve entries in the virtual method offset symbol table // (klass->otable_syms). The vtable offset (in bytes) for each resolved method // is placed at the corresponding position in the virtual method offset table // (klass->otable). A single otable and otable_syms pair may be shared by many // classes.void_Jv_LinkOffsetTable(jclass klass){ //// FIXME: Need to lock the otable //// if (klass->otable == NULL || klass->otable->state != 0) return; klass->otable->state = 1; int index = 0; _Jv_MethodSymbol sym = klass->otable_syms[0]; while (sym.name != NULL) { jclass target_class = _Jv_FindClass (sym.class_name, NULL); _Jv_Method *meth = NULL; if (target_class != NULL) if (target_class->isInterface()) { // FIXME: This does not yet fully conform to binary compatibility // rules. It will break if a declaration is moved into a // superinterface. for (int i=0; i < target_class->method_count; i++) { meth = &target_class->methods[i]; if (_Jv_equalUtf8Consts (sym.name, meth->name) && _Jv_equalUtf8Consts (sym.signature, meth->signature)) { klass->otable->offsets[index] = i + 1; break; } } } else { // If the target class does not have a vtable_method_count yet, // then we can't tell the offsets for its methods, so we must lay // it out now. if (target_class->vtable_method_count == -1) { JvSynchronize sync (target_class); _Jv_LayoutVTableMethods (target_class); } meth = _Jv_LookupDeclaredMethod(target_class, sym.name, sym.signature); if (meth != NULL) { klass->otable->offsets[index] = _Jv_VTable::idx_to_offset (meth->index); } } if (meth == NULL) // FIXME: This should be special index for ThrowNoSuchMethod(). klass->otable->offsets[index] = -1; sym = klass->otable_syms[++index]; }}// Returns true if METH should get an entry in a VTable.static jbooleanisVirtualMethod (_Jv_Method *meth){ using namespace java::lang::reflect; return (((meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) == 0) && meth->name->data[0] != '<');}// This is put in empty vtable slots.static void_Jv_abstractMethodError (void){ throw new java::lang::AbstractMethodError();}// Prepare virtual method declarations in KLASS, and any superclasses as // required, by determining their vtable index, setting method->index, and// finally setting the class's vtable_method_count. Must be called with the// lock for KLASS held.void_Jv_LayoutVTableMethods (jclass klass){ if (klass->vtable != NULL || klass->isInterface() || klass->vtable_method_count != -1) return; jclass superclass = klass->superclass; if (superclass != NULL && superclass->vtable_method_count == -1) { JvSynchronize sync (superclass); _Jv_LayoutVTableMethods (superclass); } int index = (superclass == NULL ? 0 : superclass->vtable_method_count); for (int i = 0; i < klass->method_count; ++i) { _Jv_Method *meth = &klass->methods[i]; _Jv_Method *super_meth = NULL; if (! isVirtualMethod (meth)) continue; if (superclass != NULL) { super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, meth->signature); } if (super_meth) meth->index = super_meth->index; else if (! (meth->accflags & java::lang::reflect::Modifier::FINAL) && ! (klass->accflags & java::lang::reflect::Modifier::FINAL)) meth->index = index++; } klass->vtable_method_count = index;}// Set entries in VTABLE for virtual methods declared in KLASS. If// KLASS has an immediate abstract parent, recursively do its methods// first. FLAGS is used to determine which slots we've actually set.void_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable, jboolean *flags){ using namespace java::lang::reflect; jclass superclass = klass->getSuperclass(); if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT)) _Jv_SetVTableEntries (superclass, vtable, flags); for (int i = klass->method_count - 1; i >= 0; i--) { _Jv_Method *meth = &klass->methods[i]; if (meth->index == (_Jv_ushort) -1) continue; if ((meth->accflags & Modifier::ABSTRACT)) { vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError); flags[meth->index] = false; } else { vtable->set_method(meth->index, meth->ncode); flags[meth->index] = true; } }}// Allocate and lay out the virtual method table for KLASS. This will also// cause vtables to be generated for any non-abstract superclasses, and// virtual method layout to occur for any abstract superclasses. Must be// called with monitor lock for KLASS held.void_Jv_MakeVTable (jclass klass){ using namespace java::lang::reflect; if (klass->vtable != NULL || klass->isInterface() || (klass->accflags & Modifier::ABSTRACT)) return; // out before we can create a vtable. if (klass->vtable_method_count == -1) _Jv_LayoutVTableMethods (klass); // Allocate the new vtable. _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count); klass->vtable = vtable; jboolean flags[klass->vtable_method_count]; for (int i = 0; i < klass->vtable_method_count; ++i) flags[i] = false; // Copy the vtable of the closest non-abstract superclass. jclass superclass = klass->superclass; if (superclass != NULL) { while ((superclass->accflags & Modifier::ABSTRACT) != 0) superclass = superclass->superclass; if (superclass->vtable == NULL) { JvSynchronize sync (superclass); _Jv_MakeVTable (superclass); } for (int i = 0; i < superclass->vtable_method_count; ++i) { vtable->set_method (i, superclass->vtable->get_method (i)); flags[i] = true; } } // Set the class pointer and GC descriptor. vtable->clas = klass; vtable->gc_descr = _Jv_BuildGCDescr (klass); // For each virtual declared in klass and any immediate abstract // superclasses, set new vtable entry or override an old one. _Jv_SetVTableEntries (klass, vtable, flags); // It is an error to have an abstract method in a concrete class. if (! (klass->accflags & Modifier::ABSTRACT)) { for (int i = 0; i < klass->vtable_method_count; ++i) if (! flags[i]) // FIXME: messsage. throw new java::lang::AbstractMethodError (); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -