< prev index next >

src/share/vm/opto/library_call.cpp

Print this page

        

@@ -45,10 +45,11 @@
 #include "opto/opaquenode.hpp"
 #include "opto/parse.hpp"
 #include "opto/runtime.hpp"
 #include "opto/subnode.hpp"
 #include "prims/nativeLookup.hpp"
+#include "prims/unsafe.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "trace/traceMacros.hpp"
 
 class LibraryIntrinsic : public InlineCallGenerator {
   // Extend the set of intrinsics known to the runtime:

@@ -225,17 +226,17 @@
   bool inline_pow();
   Node* finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName);
   bool inline_min_max(vmIntrinsics::ID id);
   Node* generate_min_max(vmIntrinsics::ID id, Node* x, Node* y);
   // This returns Type::AnyPtr, RawPtr, or OopPtr.
-  int classify_unsafe_addr(Node* &base, Node* &offset);
-  Node* make_unsafe_address(Node* base, Node* offset);
+  int classify_unsafe_addr(Node* &base, Node* &offset, bool decode_offset);
+  Node* make_unsafe_address(Node* base, Node* offset, bool decode_offset);
   // Helper for inline_unsafe_access.
   // Generates the guards that check whether the result of
   // Unsafe.getObject should be recorded in an SATB log buffer.
   void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar);
-  bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile);
+  bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned = false);
   static bool klass_needs_init_guard(Node* kls);
   bool inline_unsafe_allocate();
   bool inline_unsafe_copyMemory();
   bool inline_native_currentThread();
 #ifdef TRACE_HAVE_INTRINSICS

@@ -822,19 +823,19 @@
   case vmIntrinsics::_putIntVolatile:           return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,      is_volatile);
   case vmIntrinsics::_putLongVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,     is_volatile);
   case vmIntrinsics::_putFloatVolatile:         return inline_unsafe_access(!is_native_ptr,  is_store, T_FLOAT,    is_volatile);
   case vmIntrinsics::_putDoubleVolatile:        return inline_unsafe_access(!is_native_ptr,  is_store, T_DOUBLE,   is_volatile);
 
-  case vmIntrinsics::_getShortUnaligned:        return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,   !is_volatile);
-  case vmIntrinsics::_getCharUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,    !is_volatile);
-  case vmIntrinsics::_getIntUnaligned:          return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,     !is_volatile);
-  case vmIntrinsics::_getLongUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,    !is_volatile);
-
-  case vmIntrinsics::_putShortUnaligned:        return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,   !is_volatile);
-  case vmIntrinsics::_putCharUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,    !is_volatile);
-  case vmIntrinsics::_putIntUnaligned:          return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,     !is_volatile);
-  case vmIntrinsics::_putLongUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,    !is_volatile);
+  case vmIntrinsics::_getShortUnaligned:        return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,   !is_volatile, /*unaligned=*/true);
+  case vmIntrinsics::_getCharUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,    !is_volatile, /*unaligned=*/true);
+  case vmIntrinsics::_getIntUnaligned:          return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,     !is_volatile, /*unaligned=*/true);
+  case vmIntrinsics::_getLongUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,    !is_volatile, /*unaligned=*/true);
+
+  case vmIntrinsics::_putShortUnaligned:        return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,   !is_volatile, /*unaligned=*/true);
+  case vmIntrinsics::_putCharUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,    !is_volatile, /*unaligned=*/true);
+  case vmIntrinsics::_putIntUnaligned:          return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,     !is_volatile, /*unaligned=*/true);
+  case vmIntrinsics::_putLongUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,    !is_volatile, /*unaligned=*/true);
 
   case vmIntrinsics::_compareAndSwapObject:     return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg);
   case vmIntrinsics::_compareAndSwapInt:        return inline_unsafe_load_store(T_INT,    LS_cmpxchg);
   case vmIntrinsics::_compareAndSwapLong:       return inline_unsafe_load_store(T_LONG,   LS_cmpxchg);
 

@@ -2278,11 +2279,11 @@
   }
   */
 }
 
 inline int
-LibraryCallKit::classify_unsafe_addr(Node* &base, Node* &offset) {
+LibraryCallKit::classify_unsafe_addr(Node* &base, Node* &offset, bool decode_offset) {
   const TypePtr* base_type = TypePtr::NULL_PTR;
   if (base != NULL)  base_type = _gvn.type(base)->isa_ptr();
   if (base_type == NULL) {
     // Unknown type.
     return Type::AnyPtr;

@@ -2292,32 +2293,53 @@
     offset = MakeConX(0);
     return Type::RawPtr;
   } else if (base_type->base() == Type::RawPtr) {
     return Type::RawPtr;
   } else if (base_type->isa_oopptr()) {
+    Node* decoded_offset = offset;
+    if (decode_offset) {
+      decoded_offset = _gvn.transform(new RShiftXNode(offset, intcon(Unsafe::offset_shift)));
+    }
     // Base is never null => always a heap address.
     if (base_type->ptr() == TypePtr::NotNull) {
+      offset = decoded_offset;
       return Type::OopPtr;
     }
     // Offset is small => always a heap address.
     const TypeX* offset_type = _gvn.type(offset)->isa_intptr_t();
     if (offset_type != NULL &&
         base_type->offset() == 0 &&     // (should always be?)
         offset_type->_lo >= 0 &&
         !MacroAssembler::needs_explicit_null_check(offset_type->_hi)) {
+      offset = decoded_offset;
       return Type::OopPtr;
     }
     // Otherwise, it might either be oop+off or NULL+addr.
+    // For oop+off case the offset should be decoded first, but
+    // NULL+addr can be used as is.
+    IdealKit ideal(this);
+#define __ ideal.
+    IdealVariable off(ideal);
+    __ declarations_done();
+    __ set(off, offset);
+    __ if_then(base, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); {
+      __ set(off, decoded_offset);
+    } __ end_if();
+    // Final sync IdealKit and GraphKit.
+    decoded_offset = __ value(off);
+    final_sync(ideal);
+#undef __
+    offset = decoded_offset;
     return Type::AnyPtr;
   } else {
     // No information:
     return Type::AnyPtr;
   }
 }
 
-inline Node* LibraryCallKit::make_unsafe_address(Node* base, Node* offset) {
-  int kind = classify_unsafe_addr(base, offset);
+inline Node* LibraryCallKit::make_unsafe_address(Node* base, Node* offset, bool decode_offset) {
+  int kind = classify_unsafe_addr(base, offset, decode_offset);
   if (kind == Type::RawPtr) {
     return basic_plus_adr(top(), base, offset);
   } else {
     return basic_plus_adr(base, offset);
   }

@@ -2458,14 +2480,10 @@
   // Final sync IdealKit and GraphKit.
   final_sync(ideal);
 #undef __
 }
 
-
-// Interpret Unsafe.fieldOffset cookies correctly:
-extern jlong Unsafe_field_offset_to_byte_offset(jlong field_offset);
-
 const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_type, const TypePtr *adr_type, bool is_native_ptr) {
   // Attempt to infer a sharper value type from the offset and base type.
   ciKlass* sharpened_klass = NULL;
 
   // See if it is an instance field, with an object type.

@@ -2501,11 +2519,11 @@
     return tjp;
   }
   return NULL;
 }
 
-bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile) {
+bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) {
   if (callee()->is_static())  return false;  // caller must have the capability!
 
 #ifndef PRODUCT
   {
     ResourceMark rm;

@@ -2559,24 +2577,19 @@
   if (!is_native_ptr) {
     // The base is either a Java object or a value produced by Unsafe.staticFieldBase
     Node* base = argument(1);  // type: oop
     // The offset is a value produced by Unsafe.staticFieldOffset or Unsafe.objectFieldOffset
     offset = argument(2);  // type: long
-    // We currently rely on the cookies produced by Unsafe.xxxFieldOffset
-    // to be plain byte offsets, which are also the same as those accepted
-    // by oopDesc::field_base.
-    assert(Unsafe_field_offset_to_byte_offset(11) == 11,
-           "fieldOffset must be byte-scaled");
     // 32-bit machines ignore the high half!
     offset = ConvL2X(offset);
-    adr = make_unsafe_address(base, offset);
+    adr = make_unsafe_address(base, offset, /*decode=*/!unaligned);
     heap_base_oop = base;
     val = is_store ? argument(4) : NULL;
   } else {
     Node* ptr = argument(1);  // type: long
     ptr = ConvL2X(ptr);  // adjust Java long to machine word
-    adr = make_unsafe_address(NULL, ptr);
+    adr = make_unsafe_address(NULL, ptr, /*decode=*/false);
     val = is_store ? argument(3) : NULL;
   }
 
   const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
 

@@ -2650,12 +2663,19 @@
     // Try to constant fold a load from a constant field
     ciField* field = alias_type->field();
     if (heap_base_oop != top() &&
         field != NULL && field->is_constant() && field->layout_type() == type) {
       // final or stable field
-      const Type* con_type = Type::make_constant(alias_type->field(), heap_base_oop);
+      ciField* field = alias_type->field();
+      const Type* con_type = Type::make_constant(field, heap_base_oop);
       if (con_type != NULL) {
+        if (TrustFinalNonStaticFields &&
+            !field->is_static() && heap_base_oop->is_Con()) {
+          const TypeOopPtr* oop_ptr = heap_base_oop->bottom_type()->isa_oopptr();
+          ciObject* constant_oop = oop_ptr->const_oop();
+          C->dependencies()->assert_constant_field_value_instance(field, constant_oop);
+        }
         p = makecon(con_type);
       }
     }
     if (p == NULL) {
       MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered;

@@ -2704,10 +2724,21 @@
       val = ConvL2X(val);
       val = _gvn.transform(new CastX2PNode(val));
       break;
     }
 
+    { // Need to check all dependent nmethods when final field is updated through Unsafe.
+      Node* final_bit = _gvn.transform(new AndXNode(/*offset*/argument(2), MakeConX(Unsafe::final_mask)));
+      Node* cmp_final_bit = _gvn.transform(new CmpXNode(final_bit, MakeConX(0)));
+      Node* bol_final_bit = _gvn.transform(new BoolNode(cmp_final_bit, BoolTest::eq));
+
+      BuildCutout unless(this, bol_final_bit, PROB_MAX);
+      uncommon_trap(Deoptimization::Reason_intrinsic,
+                    Deoptimization::Action_none,
+                    NULL, "final_field_unsafe_update");
+    }
+
     MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered;
     if (type != T_OBJECT ) {
       (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile);
     } else {
       // Possibly an oop being stored to Java heap or native memory

@@ -2838,17 +2869,13 @@
   if (stopped()) {
     return true;
   }
 
   // Build field offset expression.
-  // We currently rely on the cookies produced by Unsafe.xxxFieldOffset
-  // to be plain byte offsets, which are also the same as those accepted
-  // by oopDesc::field_base.
-  assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled");
   // 32-bit machines ignore the high half of long offsets
   offset = ConvL2X(offset);
-  Node* adr = make_unsafe_address(base, offset);
+  Node* adr = make_unsafe_address(base, offset, /*decode=*/true);
   const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
 
   // For CAS, unlike inline_unsafe_access, there seems no point in
   // trying to refine types. Just use the coarse types here.
   const Type *value_type = Type::get_const_basic_type(type);

@@ -3033,14 +3060,13 @@
   if (stopped()) {
     return true;
   }
 
   // Build field offset expression.
-  assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled");
   // 32-bit machines ignore the high half of long offsets
   offset = ConvL2X(offset);
-  Node* adr = make_unsafe_address(base, offset);
+  Node* adr = make_unsafe_address(base, offset, /*decode=*/true);
   const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
   const Type *value_type = Type::get_const_basic_type(type);
   Compile::AliasType* alias_type = C->alias_type(adr_type);
 
   insert_mem_bar(Op_MemBarRelease);

@@ -4422,15 +4448,12 @@
   Node* src_off = ConvL2X(argument(2));  // type: long
   Node* dst_ptr =         argument(4);   // type: oop
   Node* dst_off = ConvL2X(argument(5));  // type: long
   Node* size    = ConvL2X(argument(7));  // type: long
 
-  assert(Unsafe_field_offset_to_byte_offset(11) == 11,
-         "fieldOffset must be byte-scaled");
-
-  Node* src = make_unsafe_address(src_ptr, src_off);
-  Node* dst = make_unsafe_address(dst_ptr, dst_off);
+  Node* src = make_unsafe_address(src_ptr, src_off, /*decode=*/true);
+  Node* dst = make_unsafe_address(dst_ptr, dst_off, /*decode=*/true);
 
   // Conservatively insert a memory barrier on all memory slices.
   // Do not let writes of the copy source or destination float below the copy.
   insert_mem_bar(Op_MemBarCPUOrder);
 
< prev index next >