< 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 >