< prev index next >

src/hotspot/cpu/x86/macroAssembler_x86.cpp

Print this page

        

@@ -3426,10 +3426,24 @@
   movl(temp_reg, Address(klass, Klass::access_flags_offset()));
   testl(temp_reg, JVM_ACC_VALUE);
   jcc(Assembler::notZero, is_value);
 }
 
+void MacroAssembler::test_klass_is_empty_value(Register klass, Register temp_reg, Label& is_empty_value) {
+#ifdef ASSERT
+  {
+    Label done_check;
+    test_klass_is_value(klass, temp_reg, done_check);
+    stop("test_klass_is_empty_value with none value klass");
+    bind(done_check);
+  }
+#endif
+  movb(temp_reg, Address(klass, InstanceKlass::extra_flags_offset()));
+  testb(temp_reg, InstanceKlass::_extra_is_empty_value);
+  jcc(Assembler::notZero, is_empty_value);
+}
+
 void MacroAssembler::test_field_is_flattenable(Register flags, Register temp_reg, Label& is_flattenable) {
   movl(temp_reg, flags);
   shrl(temp_reg, ConstantPoolCacheEntry::is_flattenable_field_shift);
   andl(temp_reg, 0x1);
   testl(temp_reg, temp_reg);

@@ -4302,10 +4316,138 @@
 
 void MacroAssembler::testptr(Register dst, Register src) {
   LP64_ONLY(testq(dst, src)) NOT_LP64(testl(dst, src));
 }
 
+// Object / value buffer allocation...
+//
+// Kills klass and rsi on LP64
+void MacroAssembler::allocate_instance(Register klass, Register new_obj,
+                                       Register t1, Register t2,
+                                       bool clear_fields, Label& alloc_failed)
+{
+  Label done, initialize_header, initialize_object, slow_case, slow_case_no_pop;
+  Register layout_size = t1;
+  assert(new_obj == rax, "needs to be rax, according to barrier asm eden_allocate");
+  assert_different_registers(klass, new_obj, t1, t2);
+
+#ifdef ASSERT
+  {
+    Label L;
+    cmpb(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
+    jcc(Assembler::equal, L);
+    stop("klass not initialized");
+    bind(L);
+  }
+#endif
+
+  // get instance_size in InstanceKlass (scaled to a count of bytes)
+  movl(layout_size, Address(klass, Klass::layout_helper_offset()));
+  // test to see if it has a finalizer or is malformed in some way
+  testl(layout_size, Klass::_lh_instance_slow_path_bit);
+  jcc(Assembler::notZero, slow_case_no_pop);
+
+  // Allocate the instance:
+  //  If TLAB is enabled:
+  //    Try to allocate in the TLAB.
+  //    If fails, go to the slow path.
+  //  Else If inline contiguous allocations are enabled:
+  //    Try to allocate in eden.
+  //    If fails due to heap end, go to slow path.
+  //
+  //  If TLAB is enabled OR inline contiguous is enabled:
+  //    Initialize the allocation.
+  //    Exit.
+  //
+  //  Go to slow path.
+  const bool allow_shared_alloc =
+    Universe::heap()->supports_inline_contig_alloc();
+
+  push(klass);
+  const Register thread = LP64_ONLY(r15_thread) NOT_LP64(klass);
+#ifndef _LP64
+  if (UseTLAB || allow_shared_alloc) {
+    get_thread(thread);
+  }
+#endif // _LP64
+
+  if (UseTLAB) {
+    tlab_allocate(thread, new_obj, layout_size, 0, klass, t2, slow_case);
+    if (ZeroTLAB || (!clear_fields)) {
+      // the fields have been already cleared
+      jmp(initialize_header);
+    } else {
+      // initialize both the header and fields
+      jmp(initialize_object);
+    }
+  } else {
+    // Allocation in the shared Eden, if allowed.
+    //
+    eden_allocate(thread, new_obj, layout_size, 0, t2, slow_case);
+  }
+
+  // If UseTLAB or allow_shared_alloc are true, the object is created above and
+  // there is an initialize need. Otherwise, skip and go to the slow path.
+  if (UseTLAB || allow_shared_alloc) {
+    if (clear_fields) {
+      // The object is initialized before the header.  If the object size is
+      // zero, go directly to the header initialization.
+      bind(initialize_object);
+      decrement(layout_size, sizeof(oopDesc));
+      jcc(Assembler::zero, initialize_header);
+
+      // Initialize topmost object field, divide size by 8, check if odd and
+      // test if zero.
+      Register zero = klass;
+      xorl(zero, zero);    // use zero reg to clear memory (shorter code)
+      shrl(layout_size, LogBytesPerLong); // divide by 2*oopSize and set carry flag if odd
+
+  #ifdef ASSERT
+      // make sure instance_size was multiple of 8
+      Label L;
+      // Ignore partial flag stall after shrl() since it is debug VM
+      jcc(Assembler::carryClear, L);
+      stop("object size is not multiple of 2 - adjust this code");
+      bind(L);
+      // must be > 0, no extra check needed here
+  #endif
+
+      // initialize remaining object fields: instance_size was a multiple of 8
+      {
+        Label loop;
+        bind(loop);
+        movptr(Address(new_obj, layout_size, Address::times_8, sizeof(oopDesc) - 1*oopSize), zero);
+        NOT_LP64(movptr(Address(new_obj, layout_size, Address::times_8, sizeof(oopDesc) - 2*oopSize), zero));
+        decrement(layout_size);
+        jcc(Assembler::notZero, loop);
+      }
+    } // clear_fields
+
+    // initialize object header only.
+    bind(initialize_header);
+    pop(klass);
+    Register mark_word = t2;
+    movptr(mark_word, Address(klass, Klass::prototype_header_offset()));
+    movptr(Address(new_obj, oopDesc::mark_offset_in_bytes ()), mark_word);
+#ifdef _LP64
+    xorl(rsi, rsi);                 // use zero reg to clear memory (shorter code)
+    store_klass_gap(new_obj, rsi);  // zero klass gap for compressed oops
+#endif
+    movptr(t2, klass);         // preserve klass
+    store_klass(new_obj, t2);  // src klass reg is potentially compressed
+
+    jmp(done);
+  }
+
+  bind(slow_case);
+  pop(klass);
+  bind(slow_case_no_pop);
+  jmp(alloc_failed);
+
+  bind(done);
+}
+
 // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
 void MacroAssembler::tlab_allocate(Register thread, Register obj,
                                    Register var_size_in_bytes,
                                    int con_size_in_bytes,
                                    Register t1,

@@ -4379,10 +4521,60 @@
   }
 
   bind(done);
 }
 
+void MacroAssembler::get_value_field_klass(Register klass, Register index, Register value_klass) {
+  movptr(value_klass, Address(klass, InstanceKlass::value_field_klasses_offset()));
+#ifdef ASSERT
+  {
+    Label done;
+    cmpptr(value_klass, 0);
+    jcc(Assembler::notEqual, done);
+    stop("get_value_field_klass contains no inline klasses");
+    bind(done);
+  }
+#endif
+  movptr(value_klass, Address(value_klass, index, Address::times_ptr));
+}
+
+void MacroAssembler::get_default_value_oop(Register value_klass, Register temp_reg, Register obj) {
+#ifdef ASSERT
+  {
+    Label done_check;
+    test_klass_is_value(value_klass, temp_reg, done_check);
+    stop("get_default_value_oop from non-value klass");
+    bind(done_check);
+  }
+#endif
+  Register offset = temp_reg;
+  // Getting the offset of the pre-allocated default value
+  movptr(offset, Address(value_klass, in_bytes(InstanceKlass::adr_valueklass_fixed_block_offset())));
+  movl(offset, Address(offset, in_bytes(ValueKlass::default_value_offset_offset())));
+
+  // Getting the mirror
+  movptr(obj, Address(value_klass, in_bytes(Klass::java_mirror_offset())));
+  resolve_oop_handle(obj, value_klass);
+
+  // Getting the pre-allocated default value from the mirror
+  Address field(obj, offset, Address::times_1);
+  load_heap_oop(obj, field);
+}
+
+void MacroAssembler::get_empty_value_oop(Register value_klass, Register temp_reg, Register obj) {
+#ifdef ASSERT
+  {
+    Label done_check;
+    test_klass_is_empty_value(value_klass, temp_reg, done_check);
+    stop("get_empty_value from non-empty value klass");
+    bind(done_check);
+  }
+#endif
+  get_default_value_oop(value_klass, temp_reg, obj);
+}
+
+
 // Look up the method for a megamorphic invokeinterface call.
 // The target method is determined by <intf_klass, itable_index>.
 // The receiver klass is in recv_klass.
 // On success, the result will be in method_result, and execution falls through.
 // On failure, execution transfers to the given label.

@@ -5394,10 +5586,32 @@
   } else {
     bs->store_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3);
   }
 }
 
+void MacroAssembler::access_value_copy(DecoratorSet decorators, Register src, Register dst,
+                                       Register value_klass) {
+  BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+  bs->value_copy(this, decorators, src, dst, value_klass);
+}
+
+void MacroAssembler::first_field_offset(Register value_klass, Register offset) {
+  movptr(offset, Address(value_klass, InstanceKlass::adr_valueklass_fixed_block_offset()));
+  movl(offset, Address(offset, ValueKlass::first_field_offset_offset()));
+}
+
+void MacroAssembler::data_for_oop(Register oop, Register data, Register value_klass) {
+  // ((address) (void*) o) + vk->first_field_offset();
+  Register offset = (data == oop) ? rscratch1 : data;
+  first_field_offset(value_klass, offset);
+  if (data == oop) {
+    addptr(data, offset);
+  } else {
+    lea(data, Address(oop, offset));
+  }
+}
+
 void MacroAssembler::resolve(DecoratorSet decorators, Register obj) {
   // Use stronger ACCESS_WRITE|ACCESS_READ by default.
   if ((decorators & (ACCESS_READ | ACCESS_WRITE)) == 0) {
     decorators |= ACCESS_READ | ACCESS_WRITE;
   }
< prev index next >