< prev index next >

src/share/vm/runtime/sharedRuntime.cpp

Print this page

        

*** 2642,2706 **** address c2i_unverified_entry, Symbol* sig_extended) { return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, sig_extended); } - // 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_extended; - sig_extended.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_extended.appendAll(&embedded); - } else { - sig_extended.push(SigEntry(bt, offset)); - if (bt == T_LONG || bt == T_DOUBLE) { - sig_extended.push(SigEntry(T_VOID, offset)); - } - } - } - int offset = base_off + vk->size_helper()*HeapWordSize - (base_off > 0 ? vk->first_field_offset() : 0); - sig_extended.push(SigEntry(T_VOID, offset)); // hack: use T_VOID to mark end of value type fields - if (base_off == 0) { - sig_extended.sort(SigEntry::compare); - } - assert(sig_extended.at(0)._bt == T_VALUETYPE && sig_extended.at(sig_extended.length()-1)._bt == T_VOID, "broken structure"); - return sig_extended; - } - AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { AdapterHandlerEntry* entry = get_adapter0(method); if (method->is_shared()) { // See comments around Method::link_method() MutexLocker mu(AdapterHandlerLibrary_lock); --- 2642,2651 ----
*** 2763,2773 **** // would use T_VALUETYPE but we can't because T_VALUETYPE // is used here as a marker right before the list of // fields for the value type. sig_extended.push(SigEntry(T_OBJECT)); } else { ! const GrowableArray<SigEntry>& sig_vk = collect_fields(vk); sig_extended.appendAll(&sig_vk); } } else { sig_extended.push(SigEntry(T_OBJECT)); } --- 2708,2718 ---- // would use T_VALUETYPE but we can't because T_VALUETYPE // is used here as a marker right before the list of // fields for the value type. sig_extended.push(SigEntry(T_OBJECT)); } else { ! const GrowableArray<SigEntry>& sig_vk = vk->collect_fields(); sig_extended.appendAll(&sig_vk); } } else { sig_extended.push(SigEntry(T_OBJECT)); }
*** 2776,2821 **** if (ValueTypePassFieldsAsArgs && ss.type() == T_VALUETYPE) { Klass* k = ss.as_klass(Handle(THREAD, holder->class_loader()), Handle(THREAD, holder->protection_domain()), SignatureStream::ReturnNull, THREAD); assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?"); - assert(k != SystemDictionary::___Value_klass(), "unsupported"); ValueKlass* vk = ValueKlass::cast(k); ! const GrowableArray<SigEntry>& sig_vk = collect_fields(vk); sig_extended.appendAll(&sig_vk); } else { sig_extended.push(SigEntry(ss.type())); if (ss.type() == T_LONG || ss.type() == T_DOUBLE) { sig_extended.push(SigEntry(T_VOID)); } } } } ! int values = 0; ! if (ValueTypePassFieldsAsArgs) { ! for (int i = 0; i < sig_extended.length(); i++) { ! if (sig_extended.at(i)._bt == T_VALUETYPE) { ! values++; ! } ! } ! } ! int total_args_passed_cc = sig_extended.length() - 2 * values; BasicType* sig_bt_cc = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_cc); ! ! int j = 0; ! for (int i = 0; i < sig_extended.length(); i++) { ! if (!ValueTypePassFieldsAsArgs) { ! sig_bt_cc[j++] = sig_extended.at(i)._bt; ! } else if (sig_extended.at(i)._bt != T_VALUETYPE && ! (sig_extended.at(i)._bt != T_VOID || ! sig_extended.at(i-1)._bt == T_LONG || ! sig_extended.at(i-1)._bt == T_DOUBLE)) { ! sig_bt_cc[j++] = sig_extended.at(i)._bt; ! } ! } ! assert(j == total_args_passed_cc, "bad number of arguments"); int total_args_passed_fp = sig_extended.length(); BasicType* sig_bt_fp = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_fp); for (int i = 0; i < sig_extended.length(); i++) { sig_bt_fp[i] = sig_extended.at(i)._bt; --- 2721,2749 ---- if (ValueTypePassFieldsAsArgs && ss.type() == T_VALUETYPE) { Klass* k = ss.as_klass(Handle(THREAD, holder->class_loader()), Handle(THREAD, holder->protection_domain()), SignatureStream::ReturnNull, THREAD); assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?"); ValueKlass* vk = ValueKlass::cast(k); ! if (vk == SystemDictionary::___Value_klass()) { ! sig_extended.push(SigEntry(T_OBJECT)); ! } else { ! const GrowableArray<SigEntry>& sig_vk = vk->collect_fields(); sig_extended.appendAll(&sig_vk); + } } else { sig_extended.push(SigEntry(ss.type())); if (ss.type() == T_LONG || ss.type() == T_DOUBLE) { sig_extended.push(SigEntry(T_VOID)); } } } } ! int total_args_passed_cc = ValueTypePassFieldsAsArgs ? SigEntry::count_fields(sig_extended) : sig_extended.length(); BasicType* sig_bt_cc = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_cc); ! SigEntry::fill_sig_bt(sig_extended, sig_bt_cc, total_args_passed_cc, ValueTypePassFieldsAsArgs); int total_args_passed_fp = sig_extended.length(); BasicType* sig_bt_fp = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_fp); for (int i = 0; i < sig_extended.length(); i++) { sig_bt_fp[i] = sig_extended.at(i)._bt;
*** 3407,3411 **** --- 3335,3506 ---- } } } } JRT_END + + // We're returning from an interpreted method: load each field into a + // register following the calling convention + JRT_LEAF(void, SharedRuntime::load_value_type_fields_in_regs(JavaThread* thread, oopDesc* res)) + { + assert(res->klass()->is_value(), "only value types here"); + ResourceMark rm; + RegisterMap reg_map(thread); + frame stubFrame = thread->last_frame(); + frame callerFrame = stubFrame.sender(&reg_map); + assert(callerFrame.is_interpreted_frame(), "should be coming from interpreter"); + + ValueKlass* vk = ValueKlass::cast(res->klass()); + + VMRegPair* regs; + int nb_fields; + const GrowableArray<SigEntry>& sig_vk = vk->return_convention(regs, nb_fields); + + if (regs == NULL) { + // The fields of the value klass don't fit in registers, bail out + return; + } + + int j = 1; + for (int i = 0; i < sig_vk.length(); i++) { + BasicType bt = sig_vk.at(i)._bt; + if (bt == T_VALUETYPE) { + continue; + } + if (bt == T_VOID) { + if (sig_vk.at(i-1)._bt == T_LONG || + sig_vk.at(i-1)._bt == T_DOUBLE) { + j++; + } + continue; + } + int off = sig_vk.at(i)._offset; + VMRegPair pair = regs[j]; + address loc = reg_map.location(pair.first()); + switch(bt) { + case T_BOOLEAN: + *(intptr_t*)loc = *(jboolean*)((address)res + off); + break; + case T_CHAR: + *(intptr_t*)loc = *(jchar*)((address)res + off); + break; + case T_BYTE: + *(intptr_t*)loc = *(jbyte*)((address)res + off); + break; + case T_SHORT: + *(intptr_t*)loc = *(jshort*)((address)res + off); + break; + case T_INT: { + jint v = *(jint*)((address)res + off); + *(intptr_t*)loc = v; + break; + } + case T_LONG: + #ifdef _LP64 + *(intptr_t*)loc = *(jlong*)((address)res + off); + #else + Unimplemented(); + #endif + break; + case T_OBJECT: + case T_ARRAY: { + oop v = NULL; + if (!UseCompressedOops) { + oop* p = (oop*)((address)res + off); + v = oopDesc::load_heap_oop(p); + } else { + narrowOop* p = (narrowOop*)((address)res + off); + v = oopDesc::load_decode_heap_oop(p); + } + *(oop*)loc = v; + break; + } + case T_FLOAT: + *(jfloat*)loc = *(jfloat*)((address)res + off); + break; + case T_DOUBLE: + *(jdouble*)loc = *(jdouble*)((address)res + off); + break; + default: + ShouldNotReachHere(); + } + j++; + } + assert(j == nb_fields, "missed a field?"); + + #ifdef ASSERT + VMRegPair pair = regs[0]; + address loc = reg_map.location(pair.first()); + assert(*(oopDesc**)loc == res, "overwritten object"); + #endif + + thread->set_vm_result(res); + } + JRT_END + + // We've returned to an interpreted method, the interpreter needs a + // reference to a value type instance. Allocate it and initialize it + // from field's values in registers. + JRT_BLOCK_ENTRY(void, SharedRuntime::store_value_type_fields_to_buf(JavaThread* thread, intptr_t res)) + { + ResourceMark rm; + RegisterMap reg_map(thread); + frame stubFrame = thread->last_frame(); + frame callerFrame = stubFrame.sender(&reg_map); + + #ifdef ASSERT + ValueKlass* verif_vk = ValueKlass::returned_value_type(reg_map); + javaVFrame* vf = javaVFrame::cast(vframe::new_vframe(&callerFrame, &reg_map, thread)); + Method* m = vf->method(); + int bci = vf->bci(); + Bytecode_invoke inv(m, bci); + + { + NoSafepointVerifier nsv; + methodHandle callee = inv.static_target(thread); + assert(!thread->has_pending_exception(), "call resolution should work"); + ValueKlass* verif_vk2 = callee->returned_value_type(thread); + assert(verif_vk == NULL || verif_vk == verif_vk2 || + verif_vk2 == SystemDictionary::___Value_klass(), "Bad value klass"); + + } + #endif + + if (Universe::heap()->is_in_reserved((void*)res)) { + // We're not returning with value type fields in registers (the + // calling convention didn't allow it for this value klass) + thread->set_vm_result((oopDesc*)res); + assert(verif_vk == NULL, "broken calling convention"); + return; + } + + ValueKlass* vk = (ValueKlass*)res; + assert(verif_vk == vk, "broken calling convention"); + + VMRegPair* regs; + int nb_fields; + const GrowableArray<SigEntry>& sig_vk = vk->return_convention(regs, nb_fields); + assert(regs != NULL, "return convention should allow return as fields"); + + regs++; + nb_fields--; + + // Allocate handles for every oop fields so they are safe in case of + // a safepoint when allocating + GrowableArray<Handle> handles; + vk->save_oop_fields(sig_vk, reg_map, regs, handles, nb_fields); + + // It's unsafe to safepoint until we are here + + Handle new_vt; + JRT_BLOCK; + { + Thread* THREAD = thread; + oop vt = vk->realloc_result(sig_vk, reg_map, regs, handles, nb_fields, CHECK); + new_vt = Handle(thread, vt); + } + JRT_BLOCK_END; + + thread->set_vm_result(new_vt()); + } + JRT_END +
< prev index next >