< prev index next >

src/hotspot/share/ci/ciTypeFlow.cpp

Print this page
@@ -23,10 +23,11 @@
   */
  
  #include "precompiled.hpp"
  #include "ci/ciConstant.hpp"
  #include "ci/ciField.hpp"
+ #include "ci/ciInlineKlass.hpp"
  #include "ci/ciMethod.hpp"
  #include "ci/ciMethodData.hpp"
  #include "ci/ciObjArrayKlass.hpp"
  #include "ci/ciStreams.hpp"
  #include "ci/ciTypeArrayKlass.hpp"

@@ -272,13 +273,23 @@
    assert(t1 != t2, "checked in caller");
    if (t1->equals(top_type())) {
      return t2;
    } else if (t2->equals(top_type())) {
      return t1;
-   } else if (t1->is_primitive_type() || t2->is_primitive_type()) {
+   }
+   // Unwrap after saving nullness information and handling top meets
+   bool null_free1 = t1->is_null_free();
+   bool null_free2 = t2->is_null_free();
+   if (t1->unwrap() == t2->unwrap() && null_free1 == null_free2) {
+     return t1;
+   }
+   t1 = t1->unwrap();
+   t2 = t2->unwrap();
+ 
+   if (t1->is_primitive_type() || t2->is_primitive_type()) {
      // Special case null_type.  null_type meet any reference type T
-     // is T.  null_type meet null_type is null_type.
+     // is T. null_type meet null_type is null_type.
      if (t1->equals(null_type())) {
        if (!t2->is_primitive_type() || t2->equals(null_type())) {
          return t2;
        }
      } else if (t2->equals(null_type())) {

@@ -288,54 +299,63 @@
      }
  
      // At least one of the two types is a non-top primitive type.
      // The other type is not equal to it.  Fall to bottom.
      return bottom_type();
-   } else {
-     // Both types are non-top non-primitive types.  That is,
-     // both types are either instanceKlasses or arrayKlasses.
-     ciKlass* object_klass = analyzer->env()->Object_klass();
-     ciKlass* k1 = t1->as_klass();
-     ciKlass* k2 = t2->as_klass();
-     if (k1->equals(object_klass) || k2->equals(object_klass)) {
-       return object_klass;
-     } else if (!k1->is_loaded() || !k2->is_loaded()) {
-       // Unloaded classes fall to java.lang.Object at a merge.
-       return object_klass;
-     } else if (k1->is_interface() != k2->is_interface()) {
-       // When an interface meets a non-interface, we get Object;
-       // This is what the verifier does.
-       return object_klass;
-     } else if (k1->is_array_klass() || k2->is_array_klass()) {
-       // When an array meets a non-array, we get Object.
-       // When objArray meets typeArray, we also get Object.
-       // And when typeArray meets different typeArray, we again get Object.
-       // But when objArray meets objArray, we look carefully at element types.
-       if (k1->is_obj_array_klass() && k2->is_obj_array_klass()) {
-         // Meet the element types, then construct the corresponding array type.
-         ciKlass* elem1 = k1->as_obj_array_klass()->element_klass();
-         ciKlass* elem2 = k2->as_obj_array_klass()->element_klass();
-         ciKlass* elem  = type_meet_internal(elem1, elem2, analyzer)->as_klass();
-         // Do an easy shortcut if one type is a super of the other.
-         if (elem == elem1) {
-           assert(k1 == ciObjArrayKlass::make(elem), "shortcut is OK");
-           return k1;
-         } else if (elem == elem2) {
-           assert(k2 == ciObjArrayKlass::make(elem), "shortcut is OK");
-           return k2;
-         } else {
-           return ciObjArrayKlass::make(elem);
-         }
+   }
+ 
+   // Both types are non-top non-primitive types.  That is,
+   // both types are either instanceKlasses or arrayKlasses.
+   ciKlass* object_klass = analyzer->env()->Object_klass();
+   ciKlass* k1 = t1->as_klass();
+   ciKlass* k2 = t2->as_klass();
+   if (k1->equals(object_klass) || k2->equals(object_klass)) {
+     return object_klass;
+   } else if (!k1->is_loaded() || !k2->is_loaded()) {
+     // Unloaded classes fall to java.lang.Object at a merge.
+     return object_klass;
+   } else if (k1->is_interface() != k2->is_interface()) {
+     // When an interface meets a non-interface, we get Object;
+     // This is what the verifier does.
+     return object_klass;
+   } else if (k1->is_array_klass() || k2->is_array_klass()) {
+     // When an array meets a non-array, we get Object.
+     // When (obj/flat)Array meets typeArray, we also get Object.
+     // And when typeArray meets different typeArray, we again get Object.
+     // But when (obj/flat)Array meets (obj/flat)Array, we look carefully at element types.
+     if ((k1->is_obj_array_klass() || k1->is_flat_array_klass()) &&
+         (k2->is_obj_array_klass() || k2->is_flat_array_klass())) {
+       bool null_free = k1->as_array_klass()->is_elem_null_free() &&
+                        k2->as_array_klass()->is_elem_null_free();
+       ciType* elem1 = k1->as_array_klass()->element_klass();
+       ciType* elem2 = k2->as_array_klass()->element_klass();
+       ciType* elem = elem1;
+       if (elem1 != elem2) {
+         elem = type_meet_internal(elem1, elem2, analyzer)->as_klass();
+       }
+       // Do an easy shortcut if one type is a super of the other.
+       if (elem == elem1 && !elem->is_inlinetype()) {
+         assert(k1 == ciArrayKlass::make(elem, null_free), "shortcut is OK");
+         return k1;
+       } else if (elem == elem2 && !elem->is_inlinetype()) {
+         assert(k2 == ciArrayKlass::make(elem, null_free), "shortcut is OK");
+         return k2;
        } else {
-         return object_klass;
+         return ciArrayKlass::make(elem, null_free);
        }
      } else {
-       // Must be two plain old instance klasses.
-       assert(k1->is_instance_klass(), "previous cases handle non-instances");
-       assert(k2->is_instance_klass(), "previous cases handle non-instances");
-       return k1->least_common_ancestor(k2);
+       return object_klass;
+     }
+   } else {
+     // Must be two plain old instance klasses.
+     assert(k1->is_instance_klass(), "previous cases handle non-instances");
+     assert(k2->is_instance_klass(), "previous cases handle non-instances");
+     ciType* result = k1->least_common_ancestor(k2);
+     if (null_free1 && null_free2 && result->is_inlinetype()) {
+       result = analyzer->mark_as_null_free(result);
      }
+     return result;
    }
  }
  
  
  // ------------------------------------------------------------------

@@ -393,17 +413,26 @@
      // even if it were possible for an OSR entry point to be at bci zero.
    }
    // "Push" the method signature into the first few locals.
    state->set_stack_size(-max_locals());
    if (!method()->is_static()) {
-     state->push(method()->holder());
+     ciType* holder = method()->holder();
+     if (holder->is_inlinetype()) {
+       // The receiver is null-free
+       holder = mark_as_null_free(holder);
+     }
+     state->push(holder);
      assert(state->tos() == state->local(0), "");
    }
    for (ciSignatureStream str(method()->signature());
         !str.at_return_type();
         str.next()) {
-     state->push_translate(str.type());
+     ciType* arg = str.type();
+     if (str.is_null_free()) {
+       arg = mark_as_null_free(arg);
+     }
+     state->push_translate(arg);
    }
    // Set the rest of the locals to bottom.
    Cell cell = state->next_cell(state->tos());
    state->set_stack_size(0);
    int limit = state->limit_cell();

@@ -545,16 +574,16 @@
      }
    }
  }
  
  // ------------------------------------------------------------------
- // ciTypeFlow::StateVector::do_aaload
- void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) {
+ // ciTypeFlow::StateVector::do_aload
+ void ciTypeFlow::StateVector::do_aload(ciBytecodeStream* str) {
    pop_int();
-   ciObjArrayKlass* array_klass = pop_objArray();
+   ciArrayKlass* array_klass = pop_objOrFlatArray();
    if (array_klass == NULL) {
-     // Did aaload on a null reference; push a null and ignore the exception.
+     // Did aload on a null reference; push a null and ignore the exception.
      // This instruction will never continue normally.  All we have to do
      // is report a value that will meet correctly with any downstream
      // reference types on paths that will truly be executed.  This null type
      // meets with any reference type to yield that same reference type.
      // (The compiler will generate an unconditional exception here.)

@@ -575,30 +604,53 @@
      trap(str, element_klass,
           Deoptimization::make_trap_request
           (Deoptimization::Reason_unloaded,
            Deoptimization::Action_reinterpret));
    } else {
-     push_object(element_klass);
+     if (array_klass->is_elem_null_free()) {
+       push(outer()->mark_as_null_free(element_klass));
+     } else {
+       push_object(element_klass);
+     }
    }
  }
  
  
  // ------------------------------------------------------------------
  // ciTypeFlow::StateVector::do_checkcast
  void ciTypeFlow::StateVector::do_checkcast(ciBytecodeStream* str) {
    bool will_link;
    ciKlass* klass = str->get_klass(will_link);
+   bool null_free = str->has_Q_signature();
    if (!will_link) {
-     // VM's interpreter will not load 'klass' if object is NULL.
-     // Type flow after this block may still be needed in two situations:
-     // 1) C2 uses do_null_assert() and continues compilation for later blocks
-     // 2) C2 does an OSR compile in a later block (see bug 4778368).
-     pop_object();
-     do_null_assert(klass);
+     if (null_free) {
+       trap(str, klass,
+            Deoptimization::make_trap_request
+            (Deoptimization::Reason_unloaded,
+             Deoptimization::Action_reinterpret));
+     } else {
+       // VM's interpreter will not load 'klass' if object is NULL.
+       // Type flow after this block may still be needed in two situations:
+       // 1) C2 uses do_null_assert() and continues compilation for later blocks
+       // 2) C2 does an OSR compile in a later block (see bug 4778368).
+       pop_object();
+       do_null_assert(klass);
+     }
    } else {
-     pop_object();
-     push_object(klass);
+     ciType* type = pop_value();
+     null_free |= type->is_null_free();
+     type = type->unwrap();
+     if (type->is_loaded() && klass->is_loaded() &&
+         type != klass && type->is_subtype_of(klass)) {
+       // Useless cast, propagate more precise type of object
+       klass = type->as_klass();
+     }
+     if (klass->is_inlinetype() && null_free) {
+       push(outer()->mark_as_null_free(klass));
+     } else {
+       push_object(klass);
+     }
    }
  }
  
  // ------------------------------------------------------------------
  // ciTypeFlow::StateVector::do_getfield

@@ -615,11 +667,20 @@
    ciField* field = str->get_field(will_link);
    if (!will_link) {
      trap(str, field->holder(), str->get_field_holder_index());
    } else {
      ciType* field_type = field->type();
-     if (!field_type->is_loaded()) {
+     if (field->is_static() && field->is_null_free() &&
+         !field_type->as_instance_klass()->is_initialized()) {
+       // Deoptimize if we load from a static field with an uninitialized inline type
+       // because we need to throw an exception if initialization of the type failed.
+       trap(str, field_type->as_klass(),
+            Deoptimization::make_trap_request
+            (Deoptimization::Reason_unloaded,
+             Deoptimization::Action_reinterpret));
+       return;
+     } else if (!field_type->is_loaded()) {
        // Normally, we need the field's type to be loaded if we are to
        // do anything interesting with its value.
        // We used to do this:  trap(str, str->get_field_signature_index());
        //
        // There is one good reason not to trap here.  Execution can

@@ -636,10 +697,13 @@
        // here can make an OSR entry point unreachable, triggering the
        // assert on non_osr_block in ciTypeFlow::get_start_state.
        // (See bug 4379915.)
        do_null_assert(field_type->as_klass());
      } else {
+       if (field->is_null_free()) {
+         field_type = outer()->mark_as_null_free(field_type);
+       }
        push_translate(field_type);
      }
    }
  }
  

@@ -703,10 +767,13 @@
          // ever sees a non-null value, loading has occurred.
          //
          // See do_getstatic() for similar explanation, as well as bug 4684993.
          do_null_assert(return_type->as_klass());
        } else {
+         if (sigstr.is_null_free()) {
+           return_type = outer()->mark_as_null_free(return_type);
+         }
          push_translate(return_type);
        }
      }
    }
  }

@@ -727,11 +794,15 @@
        ciObject* obj = con.as_object();
        if (obj->is_null_object()) {
          push_null();
        } else {
          assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass");
-         push_object(obj->klass());
+         ciType* type = obj->klass();
+         if (type->is_inlinetype()) {
+           type = outer()->mark_as_null_free(type);
+         }
+         push(type);
        }
      } else {
        push_translate(ciType::make(basic_type));
      }
    } else {

@@ -765,17 +836,50 @@
  // ------------------------------------------------------------------
  // ciTypeFlow::StateVector::do_new
  void ciTypeFlow::StateVector::do_new(ciBytecodeStream* str) {
    bool will_link;
    ciKlass* klass = str->get_klass(will_link);
-   if (!will_link || str->is_unresolved_klass()) {
+   if (!will_link || str->is_unresolved_klass() || klass->is_inlinetype()) {
      trap(str, klass, str->get_klass_index());
    } else {
      push_object(klass);
    }
  }
  
+ // ------------------------------------------------------------------
+ // ciTypeFlow::StateVector::do_defaultvalue
+ void ciTypeFlow::StateVector::do_defaultvalue(ciBytecodeStream* str) {
+   bool will_link;
+   ciKlass* klass = str->get_klass(will_link);
+   if (!will_link || str->is_unresolved_klass() || !klass->is_inlinetype()) {
+     trap(str, klass, str->get_klass_index());
+   } else {
+     push(outer()->mark_as_null_free(klass));
+   }
+ }
+ 
+ // ------------------------------------------------------------------
+ // ciTypeFlow::StateVector::do_withfield
+ void ciTypeFlow::StateVector::do_withfield(ciBytecodeStream* str) {
+   bool will_link;
+   ciField* field = str->get_field(will_link);
+   ciKlass* klass = field->holder();
+   if (!will_link) {
+     trap(str, klass, str->get_field_holder_index());
+   } else {
+     ciType* type = pop_value();
+     ciType* field_type = field->type();
+     if (field_type->is_two_word()) {
+       ciType* type2 = pop_value();
+       assert(type2->is_two_word(), "must be 2nd half");
+       assert(type == half_type(type2), "must be 2nd half");
+     }
+     pop_object();
+     push(outer()->mark_as_null_free(klass));
+   }
+ }
+ 
  // ------------------------------------------------------------------
  // ciTypeFlow::StateVector::do_newarray
  void ciTypeFlow::StateVector::do_newarray(ciBytecodeStream* str) {
    pop_int();
    ciKlass* klass = ciTypeArrayKlass::make((BasicType)str->get_index());

@@ -877,17 +981,17 @@
      tty->print_cr(">> Interpreting bytecode %d:%s", str->cur_bci(),
                    Bytecodes::name(str->cur_bc()));
    }
  
    switch(str->cur_bc()) {
-   case Bytecodes::_aaload: do_aaload(str);                       break;
+   case Bytecodes::_aaload: do_aload(str);                           break;
  
    case Bytecodes::_aastore:
      {
        pop_object();
        pop_int();
-       pop_objArray();
+       pop_objOrFlatArray();
        break;
      }
    case Bytecodes::_aconst_null:
      {
        push_null();

@@ -905,11 +1009,12 @@
        bool will_link;
        ciKlass* element_klass = str->get_klass(will_link);
        if (!will_link) {
          trap(str, element_klass, str->get_klass_index());
        } else {
-         push_object(ciObjArrayKlass::make(element_klass));
+         bool null_free = str->has_Q_signature();
+         push_object(ciArrayKlass::make(element_klass, null_free));
        }
        break;
      }
    case Bytecodes::_areturn:
    case Bytecodes::_ifnonnull:

@@ -1437,10 +1542,13 @@
  
    case Bytecodes::_multianewarray: do_multianewarray(str);          break;
  
    case Bytecodes::_new:      do_new(str);                           break;
  
+   case Bytecodes::_defaultvalue: do_defaultvalue(str);              break;
+   case Bytecodes::_withfield: do_withfield(str);                    break;
+ 
    case Bytecodes::_newarray: do_newarray(str);                      break;
  
    case Bytecodes::_pop:
      {
        pop();

@@ -1464,10 +1572,11 @@
        ciType* value2 = pop_value();
        push(value1);
        push(value2);
        break;
      }
+ 
    case Bytecodes::_wide:
    default:
      {
        // The iterator should skip this.
        ShouldNotReachHere();

@@ -1484,11 +1593,11 @@
  
  #ifndef PRODUCT
  // ------------------------------------------------------------------
  // ciTypeFlow::StateVector::print_cell_on
  void ciTypeFlow::StateVector::print_cell_on(outputStream* st, Cell c) const {
-   ciType* type = type_at(c);
+   ciType* type = type_at(c)->unwrap();
    if (type == top_type()) {
      st->print("top");
    } else if (type == bottom_type()) {
      st->print("bottom");
    } else if (type == null_type()) {

@@ -1746,13 +1855,16 @@
            _successors->append_if_missing(block);
          }
          break;
        }
  
-       case Bytecodes::_athrow:     case Bytecodes::_ireturn:
-       case Bytecodes::_lreturn:    case Bytecodes::_freturn:
-       case Bytecodes::_dreturn:    case Bytecodes::_areturn:
+       case Bytecodes::_athrow:
+       case Bytecodes::_ireturn:
+       case Bytecodes::_lreturn:
+       case Bytecodes::_freturn:
+       case Bytecodes::_dreturn:
+       case Bytecodes::_areturn:
        case Bytecodes::_return:
          _successors =
            new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
          // No successors
          break;

@@ -2976,10 +3088,15 @@
      // Record the first failure reason.
      _failure_reason = reason;
    }
  }
  
+ ciType* ciTypeFlow::mark_as_null_free(ciType* type) {
+   // Wrap the type to carry the information that it is null-free
+   return env()->make_null_free_wrapper(type);
+ }
+ 
  #ifndef PRODUCT
  // ------------------------------------------------------------------
  // ciTypeFlow::print_on
  void ciTypeFlow::print_on(outputStream* st) const {
    // Walk through CI blocks
< prev index next >