< prev index next >

src/hotspot/share/opto/doCall.cpp

Print this page
@@ -36,10 +36,11 @@
  #include "logging/logStream.hpp"
  #include "opto/addnode.hpp"
  #include "opto/callGenerator.hpp"
  #include "opto/castnode.hpp"
  #include "opto/cfgnode.hpp"
+ #include "opto/inlinetypenode.hpp"
  #include "opto/mulnode.hpp"
  #include "opto/parse.hpp"
  #include "opto/rootnode.hpp"
  #include "opto/runtime.hpp"
  #include "opto/subnode.hpp"

@@ -575,10 +576,30 @@
    // Try to get the most accurate receiver type
    ciMethod* callee             = orig_callee;
    int       vtable_index       = Method::invalid_vtable_index;
    bool      call_does_dispatch = false;
  
+   // Detect the call to the object or abstract class constructor at the end of a value constructor to know when we are done initializing the larval
+   if (orig_callee->is_object_constructor() && (orig_callee->holder()->is_abstract() || orig_callee->holder()->is_java_lang_Object()) && stack(sp() - nargs)->is_InlineType()) {
+     assert(method()->is_object_constructor() && (method()->holder()->is_inlinetype() || method()->holder()->is_abstract()), "Unexpected caller");
+     InlineTypeNode* receiver = stack(sp() - nargs)->as_InlineType();
+     // TODO 8325106 re-enable the assert and add the same check for the receiver in the caller map
+     //assert(receiver->is_larval(), "must be larval");
+     InlineTypeNode* clone = receiver->clone_if_required(&_gvn, _map);
+     clone->set_is_larval(false);
+     clone = _gvn.transform(clone)->as_InlineType();
+     replace_in_map(receiver, clone);
+ 
+     if (_caller->has_method()) {
+       // Get receiver from the caller map and update it in the exit map now that we are done initializing it
+       SafePointNode* map = _caller->map();
+       Node* receiver_in_caller = map->argument(_caller, 0)->as_InlineType();
+       assert(receiver_in_caller->bottom_type()->inline_klass() == receiver->bottom_type()->inline_klass(), "Receiver type mismatch");
+       _exits.map()->replace_edge(receiver_in_caller, clone, &_gvn);
+     }
+   }
+ 
    // Speculative type of the receiver if any
    ciKlass* speculative_receiver_type = nullptr;
    if (is_virtual_or_interface) {
      Node* receiver_node             = stack(sp() - nargs);
      const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr();

@@ -595,11 +616,11 @@
      speculative_receiver_type = receiver_type != nullptr ? receiver_type->speculative_type() : nullptr;
    }
  
    // Additional receiver subtype checks for interface calls via invokespecial or invokeinterface.
    ciKlass* receiver_constraint = nullptr;
-   if (iter().cur_bc_raw() == Bytecodes::_invokespecial && !orig_callee->is_object_initializer()) {
+   if (iter().cur_bc_raw() == Bytecodes::_invokespecial && !orig_callee->is_object_constructor()) {
      ciInstanceKlass* calling_klass = method()->holder();
      ciInstanceKlass* sender_klass = calling_klass;
      if (sender_klass->is_interface()) {
        receiver_constraint = sender_klass;
      }

@@ -662,10 +683,11 @@
    assert(jvms == this->jvms(), "still operating on the right JVMS");
    assert(jvms_in_sync(),       "jvms must carry full info into CG");
  
    // save across call, for a subsequent cast_not_null.
    Node* receiver = has_receiver ? argument(0) : nullptr;
+   Node* receiver_in_caller = local(0);
  
    // The extra CheckCastPPs for speculative types mess with PhaseStringOpts
    if (receiver != nullptr && !call_does_dispatch && !cg->is_string_late_inline()) {
      // Feed profiling data for a single receiver to the type system so
      // it can propagate it as a speculative type

@@ -725,11 +747,11 @@
        // Be careful here with return types.
        if (ctype != rtype) {
          BasicType rt = rtype->basic_type();
          BasicType ct = ctype->basic_type();
          if (ct == T_VOID) {
-           // It's OK for a method  to return a value that is discarded.
+           // It's OK for a method to return a value that is discarded.
            // The discarding does not require any special action from the caller.
            // The Java code knows this, at VerifyType.isNullConversion.
            pop_node(rt);  // whatever it was, pop it
          } else if (rt == T_INT || is_subword_type(rt)) {
            // Nothing.  These cases are handled in lambda form bytecode.

@@ -783,10 +805,25 @@
      }
      BasicType ct = ctype->basic_type();
      if (is_reference_type(ct)) {
        record_profiled_return_for_speculation();
      }
+     if (rtype->is_inlinetype() && !peek()->is_InlineType()) {
+       Node* retnode = pop();
+       retnode = InlineTypeNode::make_from_oop(this, retnode, rtype->as_inline_klass(), !gvn().type(retnode)->maybe_null());
+       push_node(T_OBJECT, retnode);
+     }
+   }
+ 
+   // Did we inline a value class constructor from another value class constructor?
+   if (cg->is_inline() && cg->method()->is_object_constructor() && cg->method()->holder()->is_inlinetype() &&
+       _method->is_object_constructor() && cg->method()->holder()->is_inlinetype() && receiver_in_caller == receiver) {
+     // Update the receiver in the exit map because the constructor call updated it.
+     // MethodLiveness::BasicBlock::compute_gen_kill_single ensures that the receiver in local(0) is live.
+     assert(local(0)->is_InlineType(), "Unexpected receiver");
+     assert(receiver->bottom_type()->inline_klass() == local(0)->bottom_type()->inline_klass(), "Receiver type mismatch");
+     _exits.map()->replace_edge(receiver, local(0), &_gvn);
    }
  
    // Restart record of parsing work after possible inlining of call
  #ifndef PRODUCT
    parse_histogram()->set_initial_state(bc());
< prev index next >