< prev index next >

src/hotspot/share/opto/doCall.cpp

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
--- 1,7 ---
  /*
!  * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.

*** 23,22 ***
--- 23,25 ---
   */
  
  #include "ci/ciCallSite.hpp"
  #include "ci/ciMethodHandle.hpp"
  #include "ci/ciSymbols.hpp"
+ #include "classfile/vmIntrinsics.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "compiler/compileBroker.hpp"
  #include "compiler/compileLog.hpp"
  #include "interpreter/linkResolver.hpp"
+ #include "jvm_io.h"
  #include "logging/log.hpp"
  #include "logging/logLevel.hpp"
  #include "logging/logMessage.hpp"
  #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"

*** 612,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()) {
      ciInstanceKlass* calling_klass = method()->holder();
      ciInstanceKlass* sender_klass = calling_klass;
      if (sender_klass->is_interface()) {
        receiver_constraint = sender_klass;
      }
--- 615,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_constructor()) {
      ciInstanceKlass* calling_klass = method()->holder();
      ciInstanceKlass* sender_klass = calling_klass;
      if (sender_klass->is_interface()) {
        receiver_constraint = sender_klass;
      }

*** 654,10 ***
--- 657,14 ---
    // ---------------------
    // Decide call tactic.
    // This call checks with CHA, the interpreter profile, intrinsics table, etc.
    // It decides whether inlining is desirable or not.
    CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type);
+   if (failing()) {
+     return;
+   }
+   assert(cg != nullptr, "must find a CallGenerator for callee %s", callee->name()->as_utf8());
  
    // NOTE:  Don't use orig_callee and callee after this point!  Use cg->method() instead.
    orig_callee = callee = nullptr;
  
    // ---------------------

*** 740,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.
            // 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.
--- 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.
            // 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.

*** 798,10 ***
--- 805,31 ---
      }
      BasicType ct = ctype->basic_type();
      if (is_reference_type(ct)) {
        record_profiled_return_for_speculation();
      }
+ 
+     if (!rtype->is_void()) {
+       Node* retnode = peek();
+       const Type* rettype = gvn().type(retnode);
+       if (rettype->is_inlinetypeptr() && !retnode->is_InlineType()) {
+         retnode = InlineTypeNode::make_from_oop(this, retnode, rettype->inline_klass());
+         dec_sp(1);
+         push(retnode);
+       }
+     }
+ 
+     if (cg->method()->is_object_constructor() && receiver != nullptr && gvn().type(receiver)->is_inlinetypeptr()) {
+       InlineTypeNode* non_larval = InlineTypeNode::make_from_oop(this, receiver, gvn().type(receiver)->inline_klass());
+       // Relinquish the oop input, we will delay the allocation to the point it is needed, see the
+       // comments in InlineTypeNode::Ideal for more details
+       non_larval = non_larval->clone_if_required(&gvn(), nullptr);
+       non_larval->set_oop(gvn(), null());
+       non_larval->set_is_buffered(gvn(), false);
+       non_larval = gvn().transform(non_larval)->as_InlineType();
+       map()->replace_edge(receiver, non_larval);
+     }
    }
  
    // Restart record of parsing work after possible inlining of call
  #ifndef PRODUCT
    parse_histogram()->set_initial_state(bc());
< prev index next >