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