< prev index next > src/hotspot/share/opto/doCall.cpp
Print this page
#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"
// 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();
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;
}
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
// 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.
}
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 >