methodOop ConstantPoolCacheEntry::method_if_resolved(constantPoolHandle cpool) { if (is_secondary_entry()) { if (!is_f1_null()) return f2_as_vfinal_method(); return NULL; } // Decode the action of set_method and set_interface_call Bytecodes::Code invoke_code = bytecode_1(); if (invoke_code != (Bytecodes::Code)0) { oop f1 = _f1; if (f1 != NULL) { switch (invoke_code) { case Bytecodes::_invokeinterface: assert(f1->is_klass(), ""); return klassItable::method_for_itable_index(klassOop(f1), f2_as_index()); case Bytecodes::_invokestatic: case Bytecodes::_invokespecial: assert(!has_appendix(), ""); assert(f1->is_method(), ""); return methodOop(f1); } } } invoke_code = bytecode_2(); if (invoke_code != (Bytecodes::Code)0) { switch (invoke_code) { case Bytecodes::_invokevirtual: if (is_vfinal()) { // invokevirtual methodOop m = f2_as_vfinal_method(); assert(m->is_method(), ""); return m; } else { int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index()); if (cpool->tag_at(holder_index).is_klass()) { klassOop klass = cpool->resolved_klass_at(holder_index); if (!Klass::cast(klass)->oop_is_instance()) klass = SystemDictionary::Object_klass(); return instanceKlass::cast(klass)->method_at_vtable(f2_as_index()); } } break; case Bytecodes::_invokehandle: case Bytecodes::_invokedynamic: return f2_as_vfinal_method(); } } return NULL; }
oop ConstantPoolCacheEntry::method_type_if_resolved(constantPoolHandle cpool) { if (is_f1_null() || !has_method_type()) return NULL; const int ref_index = f2_as_index() + _indy_resolved_references_method_type_offset; objArrayOop resolved_references = cpool->resolved_references(); return resolved_references->obj_at(ref_index); }
oop ConstantPoolCacheEntry::appendix_if_resolved(const constantPoolHandle& cpool) { if (!has_appendix()) return NULL; const int ref_index = f2_as_index() + _indy_resolved_references_appendix_offset; objArrayOop resolved_references = cpool->resolved_references(); return resolved_references->obj_at(ref_index); }
Method* ConstantPoolCacheEntry::method_if_resolved(constantPoolHandle cpool) { // Decode the action of set_method and set_interface_call Bytecodes::Code invoke_code = bytecode_1(); if (invoke_code != (Bytecodes::Code)0) { Metadata* f1 = f1_ord(); if (f1 != NULL) { switch (invoke_code) { case Bytecodes::_invokeinterface: assert(f1->is_klass(), ""); return klassItable::method_for_itable_index((Klass*)f1, f2_as_index()); case Bytecodes::_invokestatic: case Bytecodes::_invokespecial: assert(!has_appendix(), ""); case Bytecodes::_invokehandle: case Bytecodes::_invokedynamic: assert(f1->is_method(), ""); return (Method*)f1; } } } invoke_code = bytecode_2(); if (invoke_code != (Bytecodes::Code)0) { switch (invoke_code) { case Bytecodes::_invokevirtual: if (is_vfinal()) { // invokevirtual Method* m = f2_as_vfinal_method(); assert(m->is_method(), ""); return m; } else { int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index()); if (cpool->tag_at(holder_index).is_klass()) { Klass* klass = cpool->resolved_klass_at(holder_index); if (!klass->oop_is_instance()) klass = SystemDictionary::Object_klass(); return InstanceKlass::cast(klass)->method_at_vtable(f2_as_index()); } } break; } } return NULL; }
void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool, Bytecodes::Code invoke_code, const CallInfo &call_info) { // NOTE: This CPCE can be the subject of data races. // There are three words to update: flags, refs[f2], f1 (in that order). // Writers must store all other values before f1. // Readers must test f1 first for non-null before reading other fields. // Competing writers must acquire exclusive access via a lock. // A losing writer waits on the lock until the winner writes f1 and leaves // the lock, so that when the losing writer returns, he can use the linked // cache entry. MonitorLockerEx ml(cpool->lock()); if (!is_f1_null()) { return; } const methodHandle adapter = call_info.resolved_method(); const Handle appendix = call_info.resolved_appendix(); const Handle method_type = call_info.resolved_method_type(); const bool has_appendix = appendix.not_null(); const bool has_method_type = method_type.not_null(); // Write the flags. set_method_flags(as_TosState(adapter->result_type()), ((has_appendix ? 1 : 0) << has_appendix_shift ) | ((has_method_type ? 1 : 0) << has_method_type_shift) | ( 1 << is_final_shift ), adapter->size_of_parameters()); if (TraceInvokeDynamic) { tty->print_cr("set_method_handle bc=%d appendix="PTR_FORMAT"%s method_type="PTR_FORMAT"%s method="PTR_FORMAT" ", invoke_code, (void *)appendix(), (has_appendix ? "" : " (unused)"), (void *)method_type(), (has_method_type ? "" : " (unused)"), (intptr_t)adapter()); adapter->print(); if (has_appendix) appendix()->print(); } // Method handle invokes and invokedynamic sites use both cp cache words. // refs[f2], if not null, contains a value passed as a trailing argument to the adapter. // In the general case, this could be the call site's MethodType, // for use with java.lang.Invokers.checkExactType, or else a CallSite object. // f1 contains the adapter method which manages the actual call. // In the general case, this is a compiled LambdaForm. // (The Java code is free to optimize these calls by binding other // sorts of methods and appendices to call sites.) // JVM-level linking is via f1, as if for invokespecial, and signatures are erased. // The appendix argument (if any) is added to the signature, and is counted in the parameter_size bits. // Even with the appendix, the method will never take more than 255 parameter slots. // // This means that given a call site like (List)mh.invoke("foo"), // the f1 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;', // not '(Ljava/lang/String;)Ljava/util/List;'. // The fact that String and List are involved is encoded in the MethodType in refs[f2]. // This allows us to create fewer method oops, while keeping type safety. // objArrayHandle resolved_references = cpool->resolved_references(); // Store appendix, if any. if (has_appendix) { const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset; assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob"); assert(resolved_references->obj_at(appendix_index) == NULL, "init just once"); resolved_references->obj_at_put(appendix_index, appendix()); } // Store MethodType, if any. if (has_method_type) { const int method_type_index = f2_as_index() + _indy_resolved_references_method_type_offset; assert(method_type_index >= 0 && method_type_index < resolved_references->length(), "oob"); assert(resolved_references->obj_at(method_type_index) == NULL, "init just once"); resolved_references->obj_at_put(method_type_index, method_type()); } release_set_f1(adapter()); // This must be the last one to set (see NOTE above)! // The interpreter assembly code does not check byte_2, // but it is used by is_resolved, method_if_resolved, etc. set_bytecode_1(invoke_code); NOT_PRODUCT(verify(tty)); if (TraceInvokeDynamic) { this->print(tty, 0); } }