< prev index next >
src/share/vm/runtime/sharedRuntime.cpp
Print this page
@@ -2642,65 +2642,10 @@
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);
@@ -2763,11 +2708,11 @@
// 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);
+ const GrowableArray<SigEntry>& sig_vk = vk->collect_fields();
sig_extended.appendAll(&sig_vk);
}
} else {
sig_extended.push(SigEntry(T_OBJECT));
}
@@ -2776,46 +2721,29 @@
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);
+ 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 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;
+ 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);
-
- 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");
+ 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,5 +3335,172 @@
}
}
}
}
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(®_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(®_map);
+
+#ifdef ASSERT
+ ValueKlass* verif_vk = ValueKlass::returned_value_type(reg_map);
+ javaVFrame* vf = javaVFrame::cast(vframe::new_vframe(&callerFrame, ®_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 >