< prev index next >

src/hotspot/share/oops/method.cpp

Print this page
@@ -58,10 +58,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/atomic.hpp"
  #include "runtime/arguments.hpp"
  #include "runtime/continuationEntry.hpp"

@@ -118,11 +119,10 @@
  
    if (access_flags.is_native()) {
      clear_native_function();
      set_signature_handler(nullptr);
    }
- 
    NOT_PRODUCT(set_compiled_invocation_count(0);)
    // Name is very useful for debugging.
    NOT_PRODUCT(_name = name;)
  }
  

@@ -156,15 +156,25 @@
  address Method::get_c2i_entry() {
    assert(adapter() != nullptr, "must have");
    return adapter()->get_c2i_entry();
  }
  
+ address Method::get_c2i_inline_entry() {
+   assert(adapter() != nullptr, "must have");
+   return adapter()->get_c2i_inline_entry();
+ }
+ 
  address Method::get_c2i_unverified_entry() {
    assert(adapter() != nullptr, "must have");
    return adapter()->get_c2i_unverified_entry();
  }
  
+ address Method::get_c2i_unverified_inline_entry() {
+   assert(adapter() != nullptr, "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() != nullptr, "must have");
    return adapter()->get_c2i_no_clinit_check_entry();
  }

@@ -385,11 +395,11 @@
  }
  
  void Method::metaspace_pointers_do(MetaspaceClosure* it) {
    log_trace(cds)("Iter(Method): %p", this);
  
-   if (!method_holder()->is_rewritten()) {
+   if (!method_holder()->is_rewritten() || CDSConfig::is_valhalla_preview()) {
      it->push(&_constMethod, MetaspaceClosure::_writable);
    } else {
      it->push(&_constMethod);
    }
    it->push(&_method_data);

@@ -662,10 +672,26 @@
  int Method::extra_stack_words() {
    // not an inline function, to avoid a header dependency on Interpreter
    return extra_stack_entries() * Interpreter::stackElementSize;
  }
  
+ // 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::returns_inline_type(Thread* thread) const {
+   assert(InlineTypeReturnedAsFields, "Inline types should never be returned as fields");
+   if (is_native()) {
+     return nullptr;
+   }
+   NoSafepointVerifier nsv;
+   SignatureStream ss(signature());
+   while (!ss.at_return_type()) {
+     ss.next();
+   }
+   return ss.as_inline_klass(method_holder());
+ }
+ 
  bool Method::compute_has_loops_flag() {
    BytecodeStream bcs(methodHandle(Thread::current(), this));
    Bytecodes::Code bc;
  
    while ((bc = bcs.next()) >= 0) {

@@ -810,10 +836,15 @@
      case Bytecodes::_areturn:
        break;
      default:
        return false;
    }
+   if (has_scalarized_return()) {
+     // 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;

@@ -831,38 +862,41 @@
      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;
    // Check if the first 1-3 bytecodes are a constant push
    // and the last bytecode is a return.
    return (2 <= code_size() && code_size() <= 4 &&
            Bytecodes::is_const(java_code_at(0)) &&
            Bytecodes::length_for(java_code_at(0)) == last_index &&
-           Bytecodes::is_return(java_code_at(last_index)));
+           Bytecodes::is_return(java_code_at(last_index)) &&
+           !has_scalarized_args());
  }
  
- 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));
  }
  
- bool Method::is_object_initializer() const {
-    return name() == vmSymbols::object_initializer_name();
+ // A method named <init>, is a classic object constructor.
+ bool Method::is_object_constructor() const {
+   return name() == vmSymbols::object_initializer_name();
  }
  
  bool Method::needs_clinit_barrier() const {
    return is_static() && !method_holder()->is_initialized();
  }

@@ -916,11 +950,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(thread, klass_name, loader, prot) != nullptr;

@@ -932,11 +966,13 @@
  
  bool Method::is_klass_loaded(int refinfo_index, Bytecodes::Code bc, bool must_be_resolved) const {
    int klass_index = constants()->klass_ref_index_at(refinfo_index, bc);
    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);
  }
  
  

@@ -1101,12 +1137,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() == nullptr) {
      _from_compiled_entry    = nullptr;
+     _from_compiled_inline_entry = nullptr;
+     _from_compiled_inline_ro_entry = nullptr;
    } 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 = nullptr;

@@ -1134,10 +1174,12 @@
    assert(CDSConfig::is_dumping_archive(), "sanity");
    _code = nullptr;
    _adapter = nullptr;
    _i2i_entry = nullptr;
    _from_compiled_entry = nullptr;
+   _from_compiled_inline_entry = nullptr;
+   _from_compiled_inline_ro_entry = nullptr;
    _from_interpreted_entry = nullptr;
  
    if (is_native()) {
      *native_function_addr() = nullptr;
      set_signature_handler(nullptr);

@@ -1159,10 +1201,12 @@
    set_queued_for_compilation(false);
    set_is_not_c2_compilable(false);
    set_is_not_c1_compilable(false);
    set_is_not_c2_osr_compilable(false);
    set_on_stack_flag(false);
+   set_has_scalarized_args(false);
+   set_has_scalarized_return(false);
  }
  #endif
  
  // Called when the method_holder is getting linked. Setup entrypoints so the method
  // is ready to be called from interpreter, compiler, and vtables.

@@ -1191,10 +1235,13 @@
    if (is_native() && !has_native_function()) {
      set_native_function(
        SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
        !native_bind_event_is_interesting);
    }
+   if (InlineTypeReturnedAsFields && returns_inline_type(THREAD) && !has_scalarized_return()) {
+     set_has_scalarized_return();
+   }
  
    // Setup compiler entrypoint.  This is made eagerly, so we do not need
    // special handling of vtables.  An alternative is to make adapters more
    // lazily by calling make_adapter() from from_compiled_entry() for the
    // normal calls.  For vtable calls life gets more complicated.  When a

@@ -1239,10 +1286,12 @@
      }
    }
  
    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();
  }
  
  // The verified_code_entry() must be called when a invoke is resolved
  // on this method.

@@ -1255,10 +1304,22 @@
    debug_only(NoSafepointVerifier nsv;)
    assert(_from_compiled_entry != nullptr, "must be set");
    return _from_compiled_entry;
  }
  
+ address Method::verified_inline_code_entry() {
+   debug_only(NoSafepointVerifier nsv;)
+   assert(_from_compiled_inline_entry != nullptr, "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 != nullptr, "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.

@@ -1286,10 +1347,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();
  
    if (mh->is_continuation_native_intrinsic()) {
      assert(mh->_from_interpreted_entry == nullptr, "initialized incorrectly"); // see link_method
  

@@ -2263,10 +2326,35 @@
    } else {
      return false;
    }
  }
  
+ bool Method::is_scalarized_arg(int idx) const {
+   if (!has_scalarized_args()) {
+     return false;
+   }
+   // Search through signature and check if argument is wrapped in T_METADATA/T_VOID
+   int depth = 0;
+   const GrowableArray<SigEntry>* sig = adapter()->get_sig_cc();
+   for (int i = 0; i < sig->length(); i++) {
+     BasicType bt = sig->at(i)._bt;
+     if (bt == T_METADATA) {
+       depth++;
+     }
+     if (idx == 0) {
+       break; // Argument found
+     }
+     if (bt == T_VOID && (sig->at(i-1)._bt != T_LONG && sig->at(i-1)._bt != T_DOUBLE)) {
+       depth--;
+     }
+     if (depth == 0 && bt != T_LONG && bt != T_DOUBLE) {
+       idx--; // Advance to next argument
+     }
+   }
+   return depth != 0;
+ }
+ 
  #ifndef PRODUCT
  void Method::print_jmethod_ids_count(const ClassLoaderData* loader_data, outputStream* out) {
    out->print("%d", loader_data->jmethod_ids()->count_methods());
  }
  #endif // PRODUCT

@@ -2295,18 +2383,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:         " PTR_FORMAT, p2i(interpreter_entry()));
    st->print(   " - adapters:          ");
    AdapterHandlerEntry* a = ((Method*)this)->adapter();
    if (a == nullptr)
      st->print_cr(PTR_FORMAT, p2i(a));
    else
      a->print_adapter_on(st);
-   st->print_cr(" - compiled entry     " PTR_FORMAT, p2i(from_compiled_entry()));
+   st->print_cr(" - compiled entry           " PTR_FORMAT, p2i(from_compiled_entry()));
+   st->print_cr(" - compiled inline entry    " PTR_FORMAT, p2i(from_compiled_inline_entry()));
+   st->print_cr(" - compiled inline ro entry " PTR_FORMAT, p2i(from_compiled_inline_ro_entry()));
    st->print_cr(" - code size:         %d",   code_size());
    if (code_size() != 0) {
      st->print_cr(" - code start:        " PTR_FORMAT, p2i(code_base()));
      st->print_cr(" - code end (excl):   " PTR_FORMAT, p2i(code_base() + code_size()));
    }

@@ -2372,10 +2466,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 >