< prev index next >

src/share/vm/runtime/sharedRuntime.cpp

Print this page

        

@@ -37,11 +37,14 @@
 #include "gc/shared/gcLocker.inline.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "logging/log.hpp"
 #include "memory/universe.inline.hpp"
+#include "oops/fieldStreams.hpp"
+#include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/forte.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiRedefineClassesTrace.hpp"
 #include "prims/methodHandles.hpp"
 #include "prims/nativeLookup.hpp"

@@ -1153,11 +1156,12 @@
     bc = bytecode.invoke_code();
   }
 
   bool has_receiver = bc != Bytecodes::_invokestatic &&
                       bc != Bytecodes::_invokedynamic &&
-                      bc != Bytecodes::_invokehandle;
+                      bc != Bytecodes::_invokehandle &&
+                      bc != Bytecodes::_invokedirect;
 
   // Find receiver for non-static call
   if (has_receiver) {
     // This register map must be update since we need to find the receiver for
     // compiled frames. The receiver might be in a register.

@@ -1365,13 +1369,13 @@
 #ifdef ASSERT
   address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below
 #endif
 
   if (is_virtual) {
-    assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle, "sanity check");
+    assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect, "sanity check");
     bool static_bound = call_info.resolved_method()->can_be_statically_bound();
-    KlassHandle h_klass(THREAD, invoke_code == Bytecodes::_invokehandle ? NULL : receiver->klass());
+    KlassHandle h_klass(THREAD, (invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect) ? NULL : receiver->klass());
     CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
                      is_optimized, static_bound, virtual_call_info,
                      CHECK_(methodHandle()));
   } else {
     // static call

@@ -2497,19 +2501,74 @@
                                                       address c2i_entry,
                                                       address c2i_unverified_entry) {
   return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
 }
 
+// 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;
+  sig.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.appendAll(&embedded);
+    } else {
+      sig.push(SigEntry(bt, offset));
+      if (bt == T_LONG || bt == T_DOUBLE) {
+        sig.push(SigEntry(T_VOID, offset));
+      }
+    }
+  }
+  int offset = base_off + vk->size_helper()*HeapWordSize - (base_off > 0 ? vk->first_field_offset() : 0);
+  sig.push(SigEntry(T_VOID, offset)); // hack: use T_VOID to mark end of value type fields
+  if (base_off == 0) {
+    sig.sort(SigEntry::compare);
+  }
+  assert(sig.at(0)._bt == T_VALUETYPE && sig.at(sig.length()-1)._bt == T_VOID, "broken structure");
+  return sig;
+}
+
 AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
   // Use customized signature handler.  Need to lock around updates to
   // the AdapterHandlerTable (it is not safe for concurrent readers
   // and a single writer: this could be fixed if it becomes a
   // problem).
 
   ResourceMark rm;
 
-  NOT_PRODUCT(int insts_size);
+  NOT_PRODUCT(int insts_size = 0);
   AdapterBlob* new_adapter = NULL;
   AdapterHandlerEntry* entry = NULL;
   AdapterFingerPrint* fingerprint = NULL;
   {
     MutexLocker mu(AdapterHandlerLibrary_lock);

@@ -2528,26 +2587,82 @@
     if (method->is_abstract()) {
       return _abstract_method_handler;
     }
 
     // Fill in the signature array, for the calling-convention call.
-    int total_args_passed = method->size_of_parameters(); // All args on stack
+    GrowableArray<SigEntry> sig;
+    {
+      MutexUnlocker mul(AdapterHandlerLibrary_lock);
+      Thread* THREAD = Thread::current();
+      Handle class_loader(THREAD, method->method_holder()->class_loader());
+      Handle protection_domain(THREAD, method->method_holder()->protection_domain());
+      GrowableArray<BasicType> sig_bt_tmp;
+      int value_klasses = 0;
 
-    BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
-    VMRegPair* regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
     int i = 0;
-    if (!method->is_static())  // Pass in receiver first
-      sig_bt[i++] = T_OBJECT;
+      if (!method->is_static()) {  // Pass in receiver first
+        Klass* holder = method->method_holder();
+        if (ValueTypePassFieldsAsArgs && holder->is_value()) {
+          value_klasses++;
+          ValueKlass* vk = ValueKlass::cast(holder);
+          const GrowableArray<SigEntry>& sig_vk = collect_fields(vk);
+          sig.appendAll(&sig_vk);
+        } else {
+          sig.push(SigEntry(T_OBJECT));
+        }
+      }
     for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
-      sig_bt[i++] = ss.type();  // Collect remaining bits of signature
-      if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
-        sig_bt[i++] = T_VOID;   // Longs & doubles take 2 Java slots
+        if (ValueTypePassFieldsAsArgs && ss.type() == T_VALUETYPE) {
+          value_klasses++;
+          Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD);
+          assert(k != NULL && !HAS_PENDING_EXCEPTION, "");
+          ValueKlass* vk = ValueKlass::cast(k);
+          const GrowableArray<SigEntry>& sig_vk = collect_fields(vk);
+          sig.appendAll(&sig_vk);
+        } else {
+          sig.push(SigEntry(ss.type()));
+          if (ss.type() == T_LONG || ss.type() == T_DOUBLE) {
+            sig.push(SigEntry(T_VOID));
+          }
+        }
+      }
     }
-    assert(i == total_args_passed, "");
+
+    int values = 0;
+    if (ValueTypePassFieldsAsArgs) {
+      for (int i = 0; i < sig.length(); i++) {
+        if (sig.at(i)._bt == T_VALUETYPE) {
+          values++;
+        }
+      }
+    }
+    int total_args_passed_cc = sig.length() - 2 * values;
+    BasicType* sig_bt_cc = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_cc);
+    
+    int j = 0;
+    for (int i = 0; i < sig.length(); i++) {
+      if (!ValueTypePassFieldsAsArgs) {
+        sig_bt_cc[j++] = sig.at(i)._bt;
+      } else if (sig.at(i)._bt != T_VALUETYPE &&
+                 (sig.at(i)._bt != T_VOID ||
+                  sig.at(i-1)._bt == T_LONG ||
+                  sig.at(i-1)._bt == T_DOUBLE)) {
+        sig_bt_cc[j++] = sig.at(i)._bt;
+      }
+    }
+    assert(j == total_args_passed_cc, "");
+
+    int total_args_passed_fp = sig.length();
+    BasicType* sig_bt_fp = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_fp);
+    for (int i = 0; i < sig.length(); i++) {
+      sig_bt_fp[i] = sig.at(i)._bt;
+    }
+
+    VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed_cc);
 
     // Lookup method signature's fingerprint
-    entry = _adapters->lookup(total_args_passed, sig_bt);
+    entry = _adapters->lookup(total_args_passed_fp, sig_bt_fp);
 
 #ifdef ASSERT
     AdapterHandlerEntry* shared_entry = NULL;
     // Start adapter sharing verification only after the VM is booted.
     if (VerifyAdapterSharing && (entry != NULL)) {

@@ -2559,14 +2674,14 @@
     if (entry != NULL) {
       return entry;
     }
 
     // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
-    int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
+    int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt_cc, regs, total_args_passed_cc, false);
 
     // Make a C heap allocated version of the fingerprint to store in the adapter
-    fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
+    fingerprint = new AdapterFingerPrint(total_args_passed_fp, sig_bt_fp);
 
     // StubRoutines::code2() is initialized after this function can be called. As a result,
     // VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated
     // prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C
     // stub that ensure that an I2C stub is called from an interpreter frame.

@@ -2578,17 +2693,18 @@
       CodeBuffer buffer(buf);
       short buffer_locs[20];
       buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
                                              sizeof(buffer_locs)/sizeof(relocInfo));
 
+
       MacroAssembler _masm(&buffer);
       entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
-                                                     total_args_passed,
                                                      comp_args_on_stack,
-                                                     sig_bt,
+                                                     sig,
                                                      regs,
-                                                     fingerprint);
+                                                     fingerprint,
+                                                     new_adapter);
 #ifdef ASSERT
       if (VerifyAdapterSharing) {
         if (shared_entry != NULL) {
           assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match");
           // Release the one just created and return the original

@@ -2598,11 +2714,10 @@
           entry->save_code(buf->code_begin(), buffer.insts_size());
         }
       }
 #endif
 
-      new_adapter = AdapterBlob::create(&buffer);
       NOT_PRODUCT(insts_size = buffer.insts_size());
     }
     if (new_adapter == NULL) {
       // CodeCache is full, disable compilation
       // Ought to log this but compile log is only per compile thread

@@ -3072,5 +3187,52 @@
     }
   }
   return activation;
 }
 
+// We are at a compiled code to interpreter call. We need backing
+// buffers for all value type arguments. Allocate an object array to
+// hold them (convenient because once we're done with it we don't have
+// to worry about freeing it).
+JRT_ENTRY(void, SharedRuntime::allocate_value_types(JavaThread* thread))
+{
+  assert(ValueTypePassFieldsAsArgs, "no reason to call this");
+  ResourceMark rm;
+  JavaThread* THREAD = thread;
+  vframeStream vfst(thread);
+  methodHandle caller(thread, vfst.method());
+  int bci   = vfst.bci();
+  Bytecode_invoke bytecode(caller, bci);
+  methodHandle callee = bytecode.static_target(CHECK);
+
+  int nb_slots = 0;
+  if (!callee->is_static() && callee->method_holder()->is_value()) {
+    nb_slots++;
+  }
+  Handle class_loader(THREAD, callee->method_holder()->class_loader());
+  Handle protection_domain(THREAD, callee->method_holder()->protection_domain());
+  for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) {
+    if (ss.type() == T_VALUETYPE) {
+      nb_slots++;
+    }
+  }
+  objArrayHandle array = ObjArrayKlass::cast(Universe::objectArrayKlassObj())->allocate(nb_slots, CHECK);
+  int i = 0;
+  if (!callee->is_static() && callee->method_holder()->is_value()) {
+    ValueKlass* vk = ValueKlass::cast(callee->method_holder());
+    oop res = vk->allocate_instance(CHECK);
+    array->obj_at_put(i, res);
+    i++;
+  }
+  for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) {
+    if (ss.type() == T_VALUETYPE) {
+      Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD);
+      assert(k != NULL && !HAS_PENDING_EXCEPTION, "");
+      ValueKlass* vk = ValueKlass::cast(k);
+      oop res = vk->allocate_instance(CHECK);
+      array->obj_at_put(i, res);
+      i++;
+    }
+  }
+  thread->set_vm_result(array());
+}
+JRT_END
< prev index next >