< prev index next >

src/cpu/x86/vm/sharedRuntime_x86_64.cpp

Print this page

        

@@ -26,10 +26,11 @@
 #ifndef _WINDOWS
 #include "alloca.h"
 #endif
 #include "asm/macroAssembler.hpp"
 #include "asm/macroAssembler.inline.hpp"
+#include "classfile/symbolTable.hpp"
 #include "code/debugInfoRec.hpp"
 #include "code/icBuffer.hpp"
 #include "code/vtableStubs.hpp"
 #include "interpreter/interpreter.hpp"
 #include "oops/compiledICHolder.hpp"

@@ -593,11 +594,12 @@
                                    BasicType bt,
                                    BasicType prev_bt,
                                    size_t size_in_bytes,
                                    const VMRegPair& reg_pair,
                                    const Address& to,
-                                   int extraspace) {
+                                   int extraspace,
+                                   bool is_oop) {
   assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here");
   if (bt == T_VOID) {
     assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");
     return;
   }

@@ -621,16 +623,25 @@
   assert(r_2->is_valid() == wide, "invalid size");
   if (!r_1->is_valid()) {
     assert(!r_2->is_valid(), "must be invalid");
     return;
   }
-  if (r_1->is_stack()) {
+
+  if (!r_1->is_XMMRegister()) {
+    Register val = rax;
+    assert_different_registers(to.base(), val);
+    if(r_1->is_stack()) {
     int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace;
-    __ load_sized_value(rax, Address(rsp, ld_off), size_in_bytes, /* is_signed */ false);
-    __ store_sized_value(to, rax, size_in_bytes);
-  } else if (r_1->is_Register()) {
-    __ store_sized_value(to, r_1->as_Register(), size_in_bytes);
+      __ load_sized_value(val, Address(rsp, ld_off), size_in_bytes, /* is_signed */ false);
+    } else {
+      val = r_1->as_Register();
+    }
+    if (is_oop) {
+      __ store_heap_oop(to, val);
+    } else {
+      __ store_sized_value(to, val, size_in_bytes);
+    }
   } else {
     if (wide) {
       __ movdbl(to, r_1->as_XMMRegister());
     } else {
       __ movflt(to, r_1->as_XMMRegister());

@@ -653,16 +664,17 @@
   // compiled target.  If there is one, we need to patch the caller's call.
   patch_callers_callsite(masm);
 
   __ bind(skip_fixup);
 
+  bool has_value_argument = false;
   if (ValueTypePassFieldsAsArgs) {
-    // Is there a value type arguments?
-    int i = 0;
-    for (; i < sig_extended.length() && sig_extended.at(i)._bt != T_VALUETYPE; i++);
-
-    if (i < sig_extended.length()) {
+    // Is there a value type argument?
+    for (int i = 0; i < sig_extended.length() && !has_value_argument; i++) {
+      has_value_argument = (sig_extended.at(i)._bt == T_VALUETYPE);
+    }
+    if (has_value_argument) {
       // There is at least a value type argument: we're coming from
       // compiled code so we have no buffers to back the value
       // types. Allocate the buffers here with a runtime call.
       oop_maps = new OopMapSet();
       OopMap* map = NULL;

@@ -692,19 +704,16 @@
       __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
 
       __ bind(no_exception);
 
       // We get an array of objects from the runtime call
-      int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(T_OBJECT);
       __ get_vm_result(r13, r15_thread);
       __ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live?
-      __ addptr(r13, offset_in_bytes);
-      __ mov(r10, r13);
+      __ mov(r10, r13); // Cannot use r10 above because it's trashed by movptr()
     }
   }
 
-
   // Since all args are passed on the stack, total_args_passed *
   // Interpreter::stackElementSize is the space we need. Plus 1 because
   // we also account for the return address location since
   // we store it first rather than hold it in rax across all the shuffling
   int total_args_passed = compute_total_args_passed_int(sig_extended);

@@ -734,10 +743,11 @@
   // T_VALUETYPE/T_VOID. next_vt_arg is the next value type argument:
   // used to get the buffer for that argument from the pool of buffers
   // we allocated above and want to pass to the
   // interpreter. next_arg_int is the next argument from the
   // interpreter point of view (value types are passed by reference).
+  bool has_oop_field = false;
   for (int next_arg_comp = 0, ignored = 0, next_vt_arg = 0, next_arg_int = 0;
        next_arg_comp < sig_extended.length(); next_arg_comp++) {
     assert(ignored <= next_arg_comp, "shouldn't skip over more slot than there are arguments");
     assert(next_arg_int < total_args_passed, "more arguments for the interpreter than expected?");
     BasicType bt = sig_extended.at(next_arg_comp)._bt;

@@ -746,11 +756,11 @@
       int next_off = st_off - Interpreter::stackElementSize;
       const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off;
       const VMRegPair reg_pair = regs[next_arg_comp-ignored];
       size_t size_in_bytes = reg_pair.second()->is_valid() ? 8 : 4;
       gen_c2i_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL,
-                             size_in_bytes, reg_pair, Address(rsp, offset), extraspace);
+                             size_in_bytes, reg_pair, Address(rsp, offset), extraspace, false);
       next_arg_int++;
 #ifdef ASSERT
       if (bt == T_LONG || bt == T_DOUBLE) {
         // Overwrite the unused slot with known junk
         __ mov64(rax, CONST64(0xdeadffffdeadaaaa));

@@ -758,11 +768,12 @@
       }
 #endif /* ASSERT */
     } else {
       ignored++;
       // get the buffer from the just allocated pool of buffers
-      __ load_heap_oop(r11, Address(r10, next_vt_arg * type2aelembytes(T_VALUETYPE)));
+      int index = arrayOopDesc::base_offset_in_bytes(T_OBJECT) + next_vt_arg * type2aelembytes(T_VALUETYPE);
+      __ load_heap_oop(r11, Address(r10, index));
       next_vt_arg++; next_arg_int++;
       int vt = 1;
       // write fields we get from compiled code in registers/stack
       // slots to the buffer: we know we are done with that value type
       // argument when we hit the T_VOID that acts as an end of value

@@ -783,19 +794,39 @@
           ignored++;
         } else {
           int off = sig_extended.at(next_arg_comp)._offset;
           assert(off > 0, "offset in object should be positive");
           size_t size_in_bytes = is_java_primitive(bt) ? type2aelembytes(bt) : wordSize;
+          bool is_oop = (bt == T_OBJECT || bt == T_ARRAY);
+          has_oop_field = has_oop_field || is_oop;
           gen_c2i_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL,
-                                 size_in_bytes, regs[next_arg_comp-ignored], Address(r11, off), extraspace);
+                                 size_in_bytes, regs[next_arg_comp-ignored], Address(r11, off), extraspace, is_oop);
         }
       } while (vt != 0);
       // pass the buffer to the interpreter
       __ movptr(Address(rsp, st_off), r11);
     }
   }
 
+  // If a value type was allocated and initialized, apply post barrier to all oop fields
+  if (has_value_argument && has_oop_field) {
+    __ push_CPU_state();
+
+    // Allocate argument register save area
+    if (frame::arg_reg_save_area_bytes != 0) {
+      __ subptr(rsp, frame::arg_reg_save_area_bytes);
+    }
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::apply_post_barriers), r15_thread, r10, rbx);
+    // De-allocate argument register save area
+    if (frame::arg_reg_save_area_bytes != 0) {
+      __ addptr(rsp, frame::arg_reg_save_area_bytes);
+    }
+
+    __ pop_CPU_state();
+    __ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live?
+  }
+
   // Schedule the branch target address early.
   __ movptr(rcx, Address(rbx, in_bytes(Method::interpreter_entry_offset())));
   __ jmp(rcx);
 }
 

@@ -815,11 +846,12 @@
 static void gen_i2c_adapter_helper(MacroAssembler* masm,
                                    BasicType bt,
                                    BasicType prev_bt,
                                    size_t size_in_bytes,
                                    const VMRegPair& reg_pair,
-                                   const Address& from) {
+                                   const Address& from,
+                                   bool is_oop) {
   assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here");
   if (bt == T_VOID) {
     // Longs and doubles are passed in native word order, but misaligned
     // in the 32-bit build.
     assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");

@@ -836,22 +868,25 @@
     assert(!r_2->is_valid(), "must be invalid");
     return;
   }
 
   bool is_signed = (bt != T_CHAR) && (bt != T_BOOLEAN);
-  if (r_1->is_stack()) {
-    // Convert stack slot to an SP offset (+ wordSize to account for return address)
-    int st_off = reg_pair.first()->reg2stack() * VMRegImpl::stack_slot_size + wordSize;
+  if (!r_1->is_XMMRegister()) {
     // We can use r13 as a temp here because compiled code doesn't need r13 as an input
     // and if we end up going thru a c2i because of a miss a reasonable value of r13
     // will be generated.
-    __ load_sized_value(r13, from, size_in_bytes, is_signed);
-    __ movq(Address(rsp, st_off), r13);
-  } else if (r_1->is_Register()) {
-    Register r = r_1->as_Register();
-    assert(r != rax, "must be different");
-    __ load_sized_value(r, from, size_in_bytes, is_signed);
+    Register dst = r_1->is_stack() ? r13 : r_1->as_Register();
+    if (is_oop) {
+      __ load_heap_oop(dst, from);
+    } else {
+      __ load_sized_value(dst, from, size_in_bytes, is_signed);
+    }
+    if (r_1->is_stack()) {
+      // Convert stack slot to an SP offset (+ wordSize to account for return address)
+      int st_off = reg_pair.first()->reg2stack() * VMRegImpl::stack_slot_size + wordSize;
+      __ movq(Address(rsp, st_off), dst);
+    }
   } else {
     if (wide) {
       __ movdbl(r_1->as_XMMRegister(), from);
     } else {
       __ movflt(r_1->as_XMMRegister(), from);

@@ -989,11 +1024,11 @@
       int next_off = ld_off - Interpreter::stackElementSize;
       int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off;
       const VMRegPair reg_pair = regs[next_arg_comp-ignored];
       size_t size_in_bytes = reg_pair.second()->is_valid() ? 8 : 4;
       gen_i2c_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL,
-                             size_in_bytes, reg_pair, Address(saved_sp, offset));
+                             size_in_bytes, reg_pair, Address(saved_sp, offset), false);
       next_arg_int++;
     } else {
       next_arg_int++;
       ignored++;
       // get the buffer for that value type

@@ -1019,11 +1054,12 @@
           ignored++;
         } else {
           int off = sig_extended.at(next_arg_comp)._offset;
           assert(off > 0, "offset in object should be positive");
           size_t size_in_bytes = is_java_primitive(bt) ? type2aelembytes(bt) : wordSize;
-          gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off));
+          bool is_oop = (bt == T_OBJECT || bt == T_ARRAY);
+          gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off), is_oop);
         }
       } while (vt != 0);
     }
   }
 

@@ -1097,11 +1133,46 @@
   int frame_size_in_words = 0;
   gen_c2i_adapter(masm, sig_extended, regs, skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words);
 
   __ flush();
   new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps);
-  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+
+  // If value types are passed as fields, save the extended signature as symbol in
+  // the AdapterHandlerEntry to be used by nmethod::preserve_callee_argument_oops().
+  Symbol* extended_signature = NULL;
+  if (ValueTypePassFieldsAsArgs) {
+    bool has_value_argument = false;
+    Thread* THREAD = Thread::current();
+    ResourceMark rm(THREAD);
+    int length = sig_extended.length();
+    // TODO is 256 enough? Can we determine the required length?
+    char* sig_str = NEW_RESOURCE_ARRAY(char, 256);
+    int idx = 0;
+    sig_str[idx++] = '(';
+    for (int index = 0; index < length; index++ ) {
+      BasicType bt = sig_extended.at(index)._bt;
+      if (bt == T_VALUETYPE || bt == T_VOID) {
+        has_value_argument = true;
+        continue; // Ignore wrapper types
+      }
+      sig_str[idx++] = type2char(bt);
+      if (bt == T_OBJECT) {
+        sig_str[idx++] = ';';
+      } else if (bt == T_ARRAY) {
+        // We don't know the array element type, put void as placeholder
+        sig_str[idx++] = 'V';
+      }
+    }
+    sig_str[idx++] = ')';
+    sig_str[idx++] = '\0';
+    if (has_value_argument) {
+      // Extended signature is only required if a value type argument is passed
+      extended_signature = SymbolTable::new_permanent_symbol(sig_str, THREAD);
+    }
+  }
+
+  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, extended_signature);
 }
 
 int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
                                          VMRegPair *regs,
                                          VMRegPair *regs2,
< prev index next >