< prev index next >

src/hotspot/share/oops/method.cpp

Print this page
@@ -55,10 +55,11 @@
  #include "oops/methodData.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "oops/objArrayOop.inline.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/symbol.hpp"
+ #include "oops/inlineKlass.inline.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/methodHandles.hpp"
  #include "runtime/arguments.hpp"
  #include "runtime/atomic.hpp"
  #include "runtime/frame.inline.hpp"

@@ -115,11 +116,10 @@
  
    if (access_flags.is_native()) {
      clear_native_function();
      set_signature_handler(NULL);
    }
- 
    NOT_PRODUCT(set_compiled_invocation_count(0);)
  }
  
  // Release Method*.  The nmethod will be gone when we get here because
  // we've walked the code cache.

@@ -152,15 +152,25 @@
  address Method::get_c2i_entry() {
    assert(adapter() != NULL, "must have");
    return adapter()->get_c2i_entry();
  }
  
+ address Method::get_c2i_inline_entry() {
+   assert(adapter() != NULL, "must have");
+   return adapter()->get_c2i_inline_entry();
+ }
+ 
  address Method::get_c2i_unverified_entry() {
    assert(adapter() != NULL, "must have");
    return adapter()->get_c2i_unverified_entry();
  }
  
+ address Method::get_c2i_unverified_inline_entry() {
+   assert(adapter() != NULL, "must have");
+   return adapter()->get_c2i_unverified_inline_entry();
+ }
+ 
  address Method::get_c2i_no_clinit_check_entry() {
    assert(VM_Version::supports_fast_class_init_checks(), "");
    assert(adapter() != NULL, "must have");
    return adapter()->get_c2i_no_clinit_check_entry();
  }

@@ -663,16 +673,35 @@
    set_size_of_parameters(fp.size_of_parameters());
    constMethod()->set_result_type(fp.return_type());
    constMethod()->set_fingerprint(fp.fingerprint());
  }
  
+ // InlineKlass the method is declared to return. This must not
+ // safepoint as it is called with references live on the stack at
+ // locations the GC is unaware of.
+ InlineKlass* Method::returned_inline_type(Thread* thread) const {
+   SignatureStream ss(signature());
+   while (!ss.at_return_type()) {
+     ss.next();
+   }
+   Handle class_loader(thread, method_holder()->class_loader());
+   Handle protection_domain(thread, method_holder()->protection_domain());
+   Klass* k = NULL;
+   {
+     NoSafepointVerifier nsv;
+     k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, JavaThread::cast(thread));
+   }
+   assert(k != NULL && !thread->has_pending_exception(), "can't resolve klass");
+   return InlineKlass::cast(k);
+ }
+ 
  bool Method::is_vanilla_constructor() const {
    // Returns true if this method is a vanilla constructor, i.e. an "<init>" "()V" method
    // which only calls the superclass vanilla constructor and possibly does stores of
    // zero constants to local fields:
    //
-   //   aload_0
+   //   aload_0, _fast_aload_0, or _nofast_aload_0
    //   invokespecial
    //   indexbyte1
    //   indexbyte2
    //
    // followed by an (optional) sequence of:

@@ -692,11 +721,12 @@
    int size = code_size();
    // Check if size match
    if (size == 0 || size % 5 != 0) return false;
    address cb = code_base();
    int last = size - 1;
-   if (cb[0] != Bytecodes::_aload_0 || cb[1] != Bytecodes::_invokespecial || cb[last] != Bytecodes::_return) {
+   if ((cb[0] != Bytecodes::_aload_0 && cb[0] != Bytecodes::_fast_aload_0 && cb[0] != Bytecodes::_nofast_aload_0) ||
+        cb[1] != Bytecodes::_invokespecial || cb[last] != Bytecodes::_return) {
      // Does not call superclass default constructor
      return false;
    }
    // Check optional sequence
    for (int i = 4; i < last; i += 5) {

@@ -838,10 +868,15 @@
      case Bytecodes::_areturn:
        break;
      default:
        return false;
    }
+   if (InlineTypeReturnedAsFields && result_type() == T_INLINE_TYPE) {
+     // Don't treat this as (trivial) getter method because the
+     // inline type should be returned in a scalarized form.
+     return false;
+   }
    return true;
  }
  
  bool Method::is_setter() const {
    if (code_size() != 6) return false;

@@ -859,10 +894,15 @@
      default:
        return false;
    }
    if (java_code_at(2) != Bytecodes::_putfield) return false;
    if (java_code_at(5) != Bytecodes::_return)   return false;
+   if (has_scalarized_args()) {
+     // Don't treat this as (trivial) setter method because the
+     // inline type argument should be passed in a scalarized form.
+     return false;
+   }
    return true;
  }
  
  bool Method::is_constant_getter() const {
    int last_index = code_size() - 1;

@@ -872,29 +912,31 @@
            Bytecodes::is_const(java_code_at(0)) &&
            Bytecodes::length_for(java_code_at(0)) == last_index &&
            Bytecodes::is_return(java_code_at(last_index)));
  }
  
- bool Method::is_initializer() const {
-   return is_object_initializer() || is_static_initializer();
+ bool Method::is_object_constructor_or_class_initializer() const {
+   return (is_object_constructor() || is_class_initializer());
  }
  
- bool Method::has_valid_initializer_flags() const {
-   return (is_static() ||
-           method_holder()->major_version() < 51);
- }
- 
- bool Method::is_static_initializer() const {
+ bool Method::is_class_initializer() const {
    // For classfiles version 51 or greater, ensure that the clinit method is
    // static.  Non-static methods with the name "<clinit>" are not static
    // initializers. (older classfiles exempted for backward compatibility)
-   return name() == vmSymbols::class_initializer_name() &&
-          has_valid_initializer_flags();
+   return (name() == vmSymbols::class_initializer_name() &&
+           (is_static() ||
+            method_holder()->major_version() < 51));
+ }
+ 
+ // A method named <init>, if non-static, is a classic object constructor.
+ bool Method::is_object_constructor() const {
+    return name() == vmSymbols::object_initializer_name() && !is_static();
  }
  
- bool Method::is_object_initializer() const {
-    return name() == vmSymbols::object_initializer_name();
+ // A static method named <init> is a factory for an inline class.
+ bool Method::is_static_init_factory() const {
+    return name() == vmSymbols::object_initializer_name() && is_static();
  }
  
  bool Method::needs_clinit_barrier() const {
    return is_static() && !method_holder()->is_initialized();
  }

@@ -948,11 +990,11 @@
    return best_line;
  }
  
  
  bool Method::is_klass_loaded_by_klass_index(int klass_index) const {
-   if( constants()->tag_at(klass_index).is_unresolved_klass() ) {
+   if( constants()->tag_at(klass_index).is_unresolved_klass()) {
      Thread *thread = Thread::current();
      Symbol* klass_name = constants()->klass_name_at(klass_index);
      Handle loader(thread, method_holder()->class_loader());
      Handle prot  (thread, method_holder()->protection_domain());
      return SystemDictionary::find_instance_klass(klass_name, loader, prot) != NULL;

@@ -964,11 +1006,13 @@
  
  bool Method::is_klass_loaded(int refinfo_index, bool must_be_resolved) const {
    int klass_index = constants()->klass_ref_index_at(refinfo_index);
    if (must_be_resolved) {
      // Make sure klass is resolved in constantpool.
-     if (constants()->tag_at(klass_index).is_unresolved_klass()) return false;
+     if (constants()->tag_at(klass_index).is_unresolved_klass()) {
+       return false;
+     }
    }
    return is_klass_loaded_by_klass_index(klass_index);
  }
  
  

@@ -1133,12 +1177,16 @@
  void Method::clear_code() {
    // this may be NULL if c2i adapters have not been made yet
    // Only should happen at allocate time.
    if (adapter() == NULL) {
      _from_compiled_entry    = NULL;
+     _from_compiled_inline_entry = NULL;
+     _from_compiled_inline_ro_entry = NULL;
    } else {
      _from_compiled_entry    = adapter()->get_c2i_entry();
+     _from_compiled_inline_entry = adapter()->get_c2i_inline_entry();
+     _from_compiled_inline_ro_entry = adapter()->get_c2i_inline_ro_entry();
    }
    OrderAccess::storestore();
    _from_interpreted_entry = _i2i_entry;
    OrderAccess::storestore();
    _code = NULL;

@@ -1169,10 +1217,12 @@
    Arguments::assert_is_dumping_archive();
    _code = NULL;
    _adapter = NULL;
    _i2i_entry = NULL;
    _from_compiled_entry = NULL;
+   _from_compiled_inline_entry = NULL;
+   _from_compiled_inline_ro_entry = NULL;
    _from_interpreted_entry = NULL;
  
    if (is_native()) {
      *native_function_addr() = NULL;
      set_signature_handler(NULL);

@@ -1239,23 +1289,35 @@
      }
    }
  
    mh->set_adapter_entry(adapter);
    mh->_from_compiled_entry = adapter->get_c2i_entry();
+   mh->_from_compiled_inline_entry = adapter->get_c2i_inline_entry();
+   mh->_from_compiled_inline_ro_entry = adapter->get_c2i_inline_ro_entry();
    return adapter->get_c2i_entry();
  }
  
  void Method::restore_unshareable_info(TRAPS) {
    assert(is_method() && is_valid_method(this), "ensure C++ vtable is restored");
  }
  
- address Method::from_compiled_entry_no_trampoline() const {
+ address Method::from_compiled_entry_no_trampoline(bool caller_is_c1) const {
    CompiledMethod *code = Atomic::load_acquire(&_code);
-   if (code) {
-     return code->verified_entry_point();
+   if (caller_is_c1) {
+     // C1 - inline type arguments are passed as objects
+     if (code) {
+       return code->verified_inline_entry_point();
+     } else {
+       return adapter()->get_c2i_inline_entry();
+     }
    } else {
-     return adapter()->get_c2i_entry();
+     // C2 - inline type arguments may be passed as fields
+     if (code) {
+       return code->verified_entry_point();
+     } else {
+       return adapter()->get_c2i_entry();
+     }
    }
  }
  
  // The verified_code_entry() must be called when a invoke is resolved
  // on this method.

@@ -1268,10 +1330,22 @@
    debug_only(NoSafepointVerifier nsv;)
    assert(_from_compiled_entry != NULL, "must be set");
    return _from_compiled_entry;
  }
  
+ address Method::verified_inline_code_entry() {
+   debug_only(NoSafepointVerifier nsv;)
+   assert(_from_compiled_inline_entry != NULL, "must be set");
+   return _from_compiled_inline_entry;
+ }
+ 
+ address Method::verified_inline_ro_code_entry() {
+   debug_only(NoSafepointVerifier nsv;)
+   assert(_from_compiled_inline_ro_entry != NULL, "must be set");
+   return _from_compiled_inline_ro_entry;
+ }
+ 
  // Check that if an nmethod ref exists, it has a backlink to this or no backlink at all
  // (could be racing a deopt).
  // Not inline to avoid circular ref.
  bool Method::check_code() const {
    // cached in a register or local.  There's a race on the value of the field.

@@ -1299,10 +1373,12 @@
      mh->set_highest_comp_level(comp_level);
    }
  
    OrderAccess::storestore();
    mh->_from_compiled_entry = code->verified_entry_point();
+   mh->_from_compiled_inline_entry = code->verified_inline_entry_point();
+   mh->_from_compiled_inline_ro_entry = code->verified_inline_ro_entry_point();
    OrderAccess::storestore();
    // Instantly compiled code can execute.
    if (!mh->is_method_handle_intrinsic())
      mh->_from_interpreted_entry = mh->get_i2c_entry();
  }

@@ -2333,18 +2409,24 @@
    if (intrinsic_id() != vmIntrinsics::_none)
      st->print_cr(" - intrinsic id:      %d %s", vmIntrinsics::as_int(intrinsic_id()), vmIntrinsics::name_at(intrinsic_id()));
    if (highest_comp_level() != CompLevel_none)
      st->print_cr(" - highest level:     %d", highest_comp_level());
    st->print_cr(" - vtable index:      %d",   _vtable_index);
+ #ifdef ASSERT
+   if (valid_itable_index())
+     st->print_cr(" - itable index:      %d",   itable_index());
+ #endif
    st->print_cr(" - i2i entry:         " INTPTR_FORMAT, p2i(interpreter_entry()));
    st->print(   " - adapters:          ");
    AdapterHandlerEntry* a = ((Method*)this)->adapter();
    if (a == NULL)
      st->print_cr(INTPTR_FORMAT, p2i(a));
    else
      a->print_adapter_on(st);
-   st->print_cr(" - compiled entry     " INTPTR_FORMAT, p2i(from_compiled_entry()));
+   st->print_cr(" - compiled entry           " INTPTR_FORMAT, p2i(from_compiled_entry()));
+   st->print_cr(" - compiled inline entry    " INTPTR_FORMAT, p2i(from_compiled_inline_entry()));
+   st->print_cr(" - compiled inline ro entry " INTPTR_FORMAT, p2i(from_compiled_inline_ro_entry()));
    st->print_cr(" - code size:         %d",   code_size());
    if (code_size() != 0) {
      st->print_cr(" - code start:        " INTPTR_FORMAT, p2i(code_base()));
      st->print_cr(" - code end (excl):   " INTPTR_FORMAT, p2i(code_base() + code_size()));
    }

@@ -2410,10 +2492,11 @@
  void Method::print_value_on(outputStream* st) const {
    assert(is_method(), "must be method");
    st->print("%s", internal_name());
    print_address_on(st);
    st->print(" ");
+   if (WizardMode) access_flags().print_on(st);
    name()->print_value_on(st);
    st->print(" ");
    signature()->print_value_on(st);
    st->print(" in ");
    method_holder()->print_value_on(st);
< prev index next >