< prev index next >

src/share/vm/oops/valueKlass.cpp

Print this page

        

*** 21,37 **** --- 21,39 ---- * questions. * */ #include "precompiled.hpp" + #include "gc/shared/gcLocker.inline.hpp" #include "interpreter/interpreter.hpp" #include "oops/oop.inline.hpp" #include "oops/fieldStreams.hpp" #include "oops/method.hpp" #include "oops/objArrayKlass.hpp" #include "oops/valueKlass.hpp" #include "oops/valueArrayKlass.hpp" + #include "runtime/signature.hpp" #include "utilities/copy.hpp" int ValueKlass::first_field_offset() const { #ifdef ASSERT int first_offset = INT_MAX;
*** 236,240 **** --- 238,503 ---- target_klass->initialize(CHECK_0); instanceOop value = target_klass->allocate_instance(CHECK_0); value_store(data_for_oop(src()), data_for_oop(value), true, true); return value; } + + // 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 types 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). + GrowableArray<SigEntry> ValueKlass::collect_fields(int base_off) const { + GrowableArray<SigEntry> sig_extended; + sig_extended.push(SigEntry(T_VALUETYPE, base_off)); + for (JavaFieldStream fs(this); !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 ? first_field_offset() : 0); + if (bt == T_VALUETYPE) { + Symbol* signature = fd.signature(); + JavaThread* THREAD = JavaThread::current(); + oop loader = class_loader(); + oop domain = protection_domain(); + ResetNoHandleMark rnhm; + HandleMark hm; + NoSafepointVerifier nsv; + Klass* klass = SystemDictionary::resolve_or_null(signature, + Handle(THREAD, loader), Handle(THREAD, domain), + THREAD); + assert(klass != NULL && !HAS_PENDING_EXCEPTION, "lookup shouldn't fail"); + const GrowableArray<SigEntry>& embedded = ValueKlass::cast(klass)->collect_fields(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 + size_helper()*HeapWordSize - (base_off > 0 ? 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; + } + + // Returns the basic types and registers for fields to return an + // instance of this value type in registers if possible. + GrowableArray<SigEntry> ValueKlass::return_convention(VMRegPair*& regs, int& nb_fields) const { + assert(ValueTypeReturnedAsFields, "inconsistent"); + const GrowableArray<SigEntry>& sig_vk = collect_fields(); + nb_fields = SigEntry::count_fields(sig_vk)+1; + BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, nb_fields); + sig_bt[0] = T_METADATA; + SigEntry::fill_sig_bt(sig_vk, sig_bt+1, nb_fields-1, true); + regs = NEW_RESOURCE_ARRAY(VMRegPair, nb_fields); + int total = SharedRuntime::java_return_convention(sig_bt, regs, nb_fields); + + if (total <= 0) { + regs = NULL; + } + + return sig_vk; + } + + // Create handles for all oop fields returned in registers that are + // going to be live across a safepoint. + bool ValueKlass::save_oop_results(RegisterMap& reg_map, GrowableArray<Handle>& handles) const { + if (ValueTypeReturnedAsFields) { + int nb_fields; + VMRegPair* regs; + const GrowableArray<SigEntry>& sig_vk = return_convention(regs, nb_fields); + + if (regs != NULL) { + regs++; + nb_fields--; + save_oop_fields(sig_vk, reg_map, regs, handles, nb_fields); + return true; + } + } + return false; + } + + // Same as above but with pre-computed return convention + void ValueKlass::save_oop_fields(const GrowableArray<SigEntry>& sig_vk, RegisterMap& reg_map, const VMRegPair* regs, GrowableArray<Handle>& handles, int nb_fields) const { + int j = 0; + Thread* thread = Thread::current(); + for (int i = 0; i < sig_vk.length(); i++) { + BasicType bt = sig_vk.at(i)._bt; + if (bt == T_OBJECT || bt == T_ARRAY) { + int off = sig_vk.at(i)._offset; + VMRegPair pair = regs[j]; + address loc = reg_map.location(pair.first()); + oop v = *(oop*)loc; + assert(v == NULL || v->is_oop(), "not an oop?"); + assert(Universe::heap()->is_in_or_null(v), "must be heap pointer"); + handles.push(Handle(thread, v)); + } + if (bt == T_VALUETYPE) { + continue; + } + if (bt == T_VOID && + sig_vk.at(i-1)._bt != T_LONG && + sig_vk.at(i-1)._bt != T_DOUBLE) { + continue; + } + j++; + } + assert(j == nb_fields, "missed a field?"); + } + + // Update oop fields in registers from handles after a safepoint + void ValueKlass::restore_oop_results(RegisterMap& reg_map, GrowableArray<Handle>& handles) const { + assert(ValueTypeReturnedAsFields, "inconsistent"); + int nb_fields; + VMRegPair* regs; + const GrowableArray<SigEntry>& sig_vk = return_convention(regs, nb_fields); + assert(regs != NULL, "inconsistent"); + + regs++; + nb_fields--; + + int j = 0; + for (int i = 0, k = 0; i < sig_vk.length(); i++) { + BasicType bt = sig_vk.at(i)._bt; + if (bt == T_OBJECT || bt == T_ARRAY) { + int off = sig_vk.at(i)._offset; + VMRegPair pair = regs[j]; + address loc = reg_map.location(pair.first()); + *(oop*)loc = handles.at(k++)(); + } + if (bt == T_VALUETYPE) { + continue; + } + if (bt == T_VOID && + sig_vk.at(i-1)._bt != T_LONG && + sig_vk.at(i-1)._bt != T_DOUBLE) { + continue; + } + j++; + } + assert(j == nb_fields, "missed a field?"); + } + + // Fields are in registers. Create an instance of the value type and + // initialize it with the values of the fields. + oop ValueKlass::realloc_result(const GrowableArray<SigEntry>& sig_vk, const RegisterMap& reg_map, const VMRegPair* regs, + const GrowableArray<Handle>& handles, int nb_fields, TRAPS) { + oop new_vt = allocate_instance(CHECK_NULL); + + int j = 0; + int k = 0; + 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: { + jboolean v = *(intptr_t*)loc; + *(jboolean*)((address)new_vt + off) = v; + break; + } + case T_CHAR: { + jchar v = *(intptr_t*)loc; + *(jchar*)((address)new_vt + off) = v; + break; + } + case T_BYTE: { + jbyte v = *(intptr_t*)loc; + *(jbyte*)((address)new_vt + off) = v; + break; + } + case T_SHORT: { + jshort v = *(intptr_t*)loc; + *(jshort*)((address)new_vt + off) = v; + break; + } + case T_INT: { + jint v = *(intptr_t*)loc; + *(jint*)((address)new_vt + off) = v; + break; + } + case T_LONG: { + #ifdef _LP64 + jlong v = *(intptr_t*)loc; + *(jlong*)((address)new_vt + off) = v; + #else + Unimplemented(); + #endif + break; + } + case T_OBJECT: + case T_ARRAY: { + Handle handle = handles.at(k++); + oop v = handle(); + if (!UseCompressedOops) { + oop* p = (oop*)((address)new_vt + off); + oopDesc::store_heap_oop(p, v); + } else { + narrowOop* p = (narrowOop*)((address)new_vt + off); + oopDesc::encode_store_heap_oop(p, v); + } + break; + } + case T_FLOAT: { + jfloat v = *(jfloat*)loc; + *(jfloat*)((address)new_vt + off) = v; + break; + } + case T_DOUBLE: { + jdouble v = *(jdouble*)loc; + *(jdouble*)((address)new_vt + off) = v; + break; + } + default: + ShouldNotReachHere(); + } + j++; + } + assert(j == nb_fields, "missed a field?"); + assert(k == handles.length(), "missed an oop?"); + return new_vt; + } + + ValueKlass* ValueKlass::returned_value_type(const RegisterMap& map) { + BasicType bt = T_METADATA; + VMRegPair pair; + int nb = SharedRuntime::java_return_convention(&bt, &pair, 1); + assert(nb == 1, "broken"); + + address loc = map.location(pair.first()); + intptr_t ptr = *(intptr_t*)loc; + if (Universe::heap()->is_in_reserved((void*)ptr)) { + return NULL; + } + return (ValueKlass*)ptr; + }
< prev index next >