< prev index next >

src/share/vm/runtime/sharedRuntime.cpp

Print this page

        

*** 37,47 **** --- 37,50 ---- #include "gc/shared/gcLocker.inline.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" #include "memory/universe.inline.hpp" + #include "oops/fieldStreams.hpp" + #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" + #include "oops/valueKlass.hpp" #include "prims/forte.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp"
*** 1153,1163 **** bc = bytecode.invoke_code(); } bool has_receiver = bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic && ! bc != Bytecodes::_invokehandle; // Find receiver for non-static call if (has_receiver) { // This register map must be update since we need to find the receiver for // compiled frames. The receiver might be in a register. --- 1156,1167 ---- bc = bytecode.invoke_code(); } bool has_receiver = bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic && ! bc != Bytecodes::_invokehandle && ! bc != Bytecodes::_invokedirect; // Find receiver for non-static call if (has_receiver) { // This register map must be update since we need to find the receiver for // compiled frames. The receiver might be in a register.
*** 1365,1377 **** #ifdef ASSERT address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below #endif if (is_virtual) { ! assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle, "sanity check"); bool static_bound = call_info.resolved_method()->can_be_statically_bound(); ! KlassHandle h_klass(THREAD, invoke_code == Bytecodes::_invokehandle ? NULL : receiver->klass()); CompiledIC::compute_monomorphic_entry(callee_method, h_klass, is_optimized, static_bound, virtual_call_info, CHECK_(methodHandle())); } else { // static call --- 1369,1381 ---- #ifdef ASSERT address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below #endif if (is_virtual) { ! assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect, "sanity check"); bool static_bound = call_info.resolved_method()->can_be_statically_bound(); ! KlassHandle h_klass(THREAD, (invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect) ? NULL : receiver->klass()); CompiledIC::compute_monomorphic_entry(callee_method, h_klass, is_optimized, static_bound, virtual_call_info, CHECK_(methodHandle())); } else { // static call
*** 2497,2515 **** address c2i_entry, address c2i_unverified_entry) { return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); } AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { // Use customized signature handler. Need to lock around updates to // the AdapterHandlerTable (it is not safe for concurrent readers // and a single writer: this could be fixed if it becomes a // problem). ResourceMark rm; ! NOT_PRODUCT(int insts_size); AdapterBlob* new_adapter = NULL; AdapterHandlerEntry* entry = NULL; AdapterFingerPrint* fingerprint = NULL; { MutexLocker mu(AdapterHandlerLibrary_lock); --- 2501,2574 ---- address c2i_entry, address c2i_unverified_entry) { return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); } + // Value type arguments are not passed by reference, instead each + // field of the value type is passed as an argument. This helper + // function collects the fields of the value types (including embedded + // value type's fields) in a list. Included with the field's type is + // the offset of each field in the value type: i2c and c2i adapters + // need that to load or store fields. Finally, the list of fields is + // sorted in order of increasing offsets: the adapters and the + // compiled code need and agreed upon order of fields. + // + // The list of basic type that is returned starts with a T_VALUETYPE + // and ends with an extra T_VOID. T_VALUETYPE/T_VOID are used as + // delimiters. Every entry between the two is a field of the value + // type. If there's an embedded value type in the list, it also starts + // with a T_VALUETYPE and ends with a T_VOID. This is so we can + // generate a unique fingerprint for the method's adapters and we can + // generate the list of basic types from the interpreter point of view + // (value types passed as reference: iterate on the list until a + // T_VALUETYPE, drop everything until and including the closing + // T_VOID) or the compiler point of view (each field of the value + // types is an argument: drop all T_VALUETYPE/T_VOID from the list). + static GrowableArray<SigEntry> collect_fields(ValueKlass* vk, int base_off = 0) { + GrowableArray<SigEntry> sig; + sig.push(SigEntry(T_VALUETYPE, base_off)); + for (JavaFieldStream fs(vk); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) continue; + fieldDescriptor& fd = fs.field_descriptor(); + BasicType bt = fd.field_type(); + int offset = base_off + fd.offset() - (base_off > 0 ? vk->first_field_offset() : 0); + if (bt == T_VALUETYPE) { + Symbol* signature = fd.signature(); + JavaThread* THREAD = JavaThread::current(); + oop loader = vk->class_loader(); + oop protection_domain = vk->protection_domain(); + Klass* klass = SystemDictionary::resolve_or_null(signature, + Handle(THREAD, loader), Handle(THREAD, protection_domain), + THREAD); + assert(klass != NULL && !HAS_PENDING_EXCEPTION, "lookup shouldn't fail"); + const GrowableArray<SigEntry>& embedded = collect_fields(ValueKlass::cast(klass), offset); + sig.appendAll(&embedded); + } else { + sig.push(SigEntry(bt, offset)); + if (bt == T_LONG || bt == T_DOUBLE) { + sig.push(SigEntry(T_VOID, offset)); + } + } + } + int offset = base_off + vk->size_helper()*HeapWordSize - (base_off > 0 ? vk->first_field_offset() : 0); + sig.push(SigEntry(T_VOID, offset)); // hack: use T_VOID to mark end of value type fields + if (base_off == 0) { + sig.sort(SigEntry::compare); + } + assert(sig.at(0)._bt == T_VALUETYPE && sig.at(sig.length()-1)._bt == T_VOID, "broken structure"); + return sig; + } + AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { // Use customized signature handler. Need to lock around updates to // the AdapterHandlerTable (it is not safe for concurrent readers // and a single writer: this could be fixed if it becomes a // problem). ResourceMark rm; ! NOT_PRODUCT(int insts_size = 0); AdapterBlob* new_adapter = NULL; AdapterHandlerEntry* entry = NULL; AdapterFingerPrint* fingerprint = NULL; { MutexLocker mu(AdapterHandlerLibrary_lock);
*** 2528,2553 **** if (method->is_abstract()) { return _abstract_method_handler; } // Fill in the signature array, for the calling-convention call. ! int total_args_passed = method->size_of_parameters(); // All args on stack - BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); - VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); int i = 0; ! if (!method->is_static()) // Pass in receiver first ! sig_bt[i++] = T_OBJECT; for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) { ! sig_bt[i++] = ss.type(); // Collect remaining bits of signature ! if (ss.type() == T_LONG || ss.type() == T_DOUBLE) ! sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots } ! assert(i == total_args_passed, ""); // Lookup method signature's fingerprint ! entry = _adapters->lookup(total_args_passed, sig_bt); #ifdef ASSERT AdapterHandlerEntry* shared_entry = NULL; // Start adapter sharing verification only after the VM is booted. if (VerifyAdapterSharing && (entry != NULL)) { --- 2587,2668 ---- if (method->is_abstract()) { return _abstract_method_handler; } // Fill in the signature array, for the calling-convention call. ! GrowableArray<SigEntry> sig; ! { ! MutexUnlocker mul(AdapterHandlerLibrary_lock); ! Thread* THREAD = Thread::current(); ! Handle class_loader(THREAD, method->method_holder()->class_loader()); ! Handle protection_domain(THREAD, method->method_holder()->protection_domain()); ! GrowableArray<BasicType> sig_bt_tmp; ! int value_klasses = 0; int i = 0; ! if (!method->is_static()) { // Pass in receiver first ! Klass* holder = method->method_holder(); ! if (ValueTypePassFieldsAsArgs && holder->is_value()) { ! value_klasses++; ! ValueKlass* vk = ValueKlass::cast(holder); ! const GrowableArray<SigEntry>& sig_vk = collect_fields(vk); ! sig.appendAll(&sig_vk); ! } else { ! sig.push(SigEntry(T_OBJECT)); ! } ! } for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) { ! if (ValueTypePassFieldsAsArgs && ss.type() == T_VALUETYPE) { ! value_klasses++; ! Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD); ! assert(k != NULL && !HAS_PENDING_EXCEPTION, ""); ! ValueKlass* vk = ValueKlass::cast(k); ! const GrowableArray<SigEntry>& sig_vk = collect_fields(vk); ! sig.appendAll(&sig_vk); ! } else { ! sig.push(SigEntry(ss.type())); ! if (ss.type() == T_LONG || ss.type() == T_DOUBLE) { ! sig.push(SigEntry(T_VOID)); ! } ! } ! } } ! ! int values = 0; ! if (ValueTypePassFieldsAsArgs) { ! for (int i = 0; i < sig.length(); i++) { ! if (sig.at(i)._bt == T_VALUETYPE) { ! values++; ! } ! } ! } ! int total_args_passed_cc = sig.length() - 2 * values; ! BasicType* sig_bt_cc = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_cc); ! ! int j = 0; ! for (int i = 0; i < sig.length(); i++) { ! if (!ValueTypePassFieldsAsArgs) { ! sig_bt_cc[j++] = sig.at(i)._bt; ! } else if (sig.at(i)._bt != T_VALUETYPE && ! (sig.at(i)._bt != T_VOID || ! sig.at(i-1)._bt == T_LONG || ! sig.at(i-1)._bt == T_DOUBLE)) { ! sig_bt_cc[j++] = sig.at(i)._bt; ! } ! } ! assert(j == total_args_passed_cc, ""); ! ! int total_args_passed_fp = sig.length(); ! BasicType* sig_bt_fp = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_fp); ! for (int i = 0; i < sig.length(); i++) { ! sig_bt_fp[i] = sig.at(i)._bt; ! } ! ! VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed_cc); // Lookup method signature's fingerprint ! entry = _adapters->lookup(total_args_passed_fp, sig_bt_fp); #ifdef ASSERT AdapterHandlerEntry* shared_entry = NULL; // Start adapter sharing verification only after the VM is booted. if (VerifyAdapterSharing && (entry != NULL)) {
*** 2559,2572 **** if (entry != NULL) { return entry; } // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage ! int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); // Make a C heap allocated version of the fingerprint to store in the adapter ! fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt); // StubRoutines::code2() is initialized after this function can be called. As a result, // VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated // prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C // stub that ensure that an I2C stub is called from an interpreter frame. --- 2674,2687 ---- if (entry != NULL) { return entry; } // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage ! int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt_cc, regs, total_args_passed_cc, false); // Make a C heap allocated version of the fingerprint to store in the adapter ! fingerprint = new AdapterFingerPrint(total_args_passed_fp, sig_bt_fp); // StubRoutines::code2() is initialized after this function can be called. As a result, // VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated // prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C // stub that ensure that an I2C stub is called from an interpreter frame.
*** 2578,2594 **** CodeBuffer buffer(buf); short buffer_locs[20]; buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); MacroAssembler _masm(&buffer); entry = SharedRuntime::generate_i2c2i_adapters(&_masm, - total_args_passed, comp_args_on_stack, ! sig_bt, regs, ! fingerprint); #ifdef ASSERT if (VerifyAdapterSharing) { if (shared_entry != NULL) { assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match"); // Release the one just created and return the original --- 2693,2710 ---- CodeBuffer buffer(buf); short buffer_locs[20]; buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); + MacroAssembler _masm(&buffer); entry = SharedRuntime::generate_i2c2i_adapters(&_masm, comp_args_on_stack, ! sig, regs, ! fingerprint, ! new_adapter); #ifdef ASSERT if (VerifyAdapterSharing) { if (shared_entry != NULL) { assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match"); // Release the one just created and return the original
*** 2598,2608 **** entry->save_code(buf->code_begin(), buffer.insts_size()); } } #endif - new_adapter = AdapterBlob::create(&buffer); NOT_PRODUCT(insts_size = buffer.insts_size()); } if (new_adapter == NULL) { // CodeCache is full, disable compilation // Ought to log this but compile log is only per compile thread --- 2714,2723 ----
*** 3072,3076 **** --- 3187,3238 ---- } } return activation; } + // We are at a compiled code to interpreter call. We need backing + // buffers for all value type arguments. Allocate an object array to + // hold them (convenient because once we're done with it we don't have + // to worry about freeing it). + JRT_ENTRY(void, SharedRuntime::allocate_value_types(JavaThread* thread)) + { + assert(ValueTypePassFieldsAsArgs, "no reason to call this"); + ResourceMark rm; + JavaThread* THREAD = thread; + vframeStream vfst(thread); + methodHandle caller(thread, vfst.method()); + int bci = vfst.bci(); + Bytecode_invoke bytecode(caller, bci); + methodHandle callee = bytecode.static_target(CHECK); + + int nb_slots = 0; + if (!callee->is_static() && callee->method_holder()->is_value()) { + nb_slots++; + } + Handle class_loader(THREAD, callee->method_holder()->class_loader()); + Handle protection_domain(THREAD, callee->method_holder()->protection_domain()); + for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) { + if (ss.type() == T_VALUETYPE) { + nb_slots++; + } + } + objArrayHandle array = ObjArrayKlass::cast(Universe::objectArrayKlassObj())->allocate(nb_slots, CHECK); + int i = 0; + if (!callee->is_static() && callee->method_holder()->is_value()) { + ValueKlass* vk = ValueKlass::cast(callee->method_holder()); + oop res = vk->allocate_instance(CHECK); + array->obj_at_put(i, res); + i++; + } + for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) { + if (ss.type() == T_VALUETYPE) { + Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD); + assert(k != NULL && !HAS_PENDING_EXCEPTION, ""); + ValueKlass* vk = ValueKlass::cast(k); + oop res = vk->allocate_instance(CHECK); + array->obj_at_put(i, res); + i++; + } + } + thread->set_vm_result(array()); + } + JRT_END
< prev index next >