8284198: Undo JDK-8261137: Optimization of Box nodes in uncommon_trap

Reviewed-by: kvn, thartmann
This commit is contained in:
Wu Yan 2022-04-11 06:23:09 +00:00 committed by Fei Yang
parent eb3ead96b3
commit 0c04bf8e59
10 changed files with 29 additions and 207 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@ -28,7 +28,6 @@
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciUtilities.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
@ -281,31 +280,6 @@ bool ciInstanceKlass::is_boxed_value_offset(int offset) const {
(offset == java_lang_boxing_object::value_offset(bt));
}
static bool is_klass_initialized(Symbol* klass_name) {
VM_ENTRY_MARK;
InstanceKlass* ik = SystemDictionary::find_instance_klass(klass_name, Handle(), Handle());
return ik != nullptr && ik->is_initialized();
}
bool ciInstanceKlass::is_box_cache_valid() const {
BasicType box_type = box_klass_type();
if (box_type != T_OBJECT) {
switch(box_type) {
case T_INT: return is_klass_initialized(java_lang_Integer_IntegerCache::symbol());
case T_CHAR: return is_klass_initialized(java_lang_Character_CharacterCache::symbol());
case T_SHORT: return is_klass_initialized(java_lang_Short_ShortCache::symbol());
case T_BYTE: return is_klass_initialized(java_lang_Byte_ByteCache::symbol());
case T_LONG: return is_klass_initialized(java_lang_Long_LongCache::symbol());
case T_BOOLEAN:
case T_FLOAT:
case T_DOUBLE: return true;
default:;
}
}
return false;
}
// ------------------------------------------------------------------
// ciInstanceKlass::is_in_package
//

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@ -265,7 +265,6 @@ public:
BasicType box_klass_type() const;
bool is_box_klass() const;
bool is_boxed_value_offset(int offset) const;
bool is_box_cache_valid() const;
// Is this klass in the given package?
bool is_in_package(const char* packagename) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -582,62 +582,6 @@ void LateInlineVirtualCallGenerator::do_late_inline() {
CallGenerator::do_late_inline_helper();
}
static bool has_non_debug_usages(Node* n) {
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* m = n->fast_out(i);
if (!m->is_SafePoint()
|| (m->is_Call() && m->as_Call()->has_non_debug_use(n))) {
return true;
}
}
return false;
}
static bool is_box_cache_valid(CallNode* call) {
ciInstanceKlass* klass = call->as_CallStaticJava()->method()->holder();
return klass->is_box_cache_valid();
}
// delay box in runtime, treat box as a scalarized object
static void scalarize_debug_usages(CallNode* call, Node* resproj) {
GraphKit kit(call->jvms());
PhaseGVN& gvn = kit.gvn();
ProjNode* res = resproj->as_Proj();
ciInstanceKlass* klass = call->as_CallStaticJava()->method()->holder();
int n_fields = klass->nof_nonstatic_fields();
assert(n_fields == 1, "the klass must be an auto-boxing klass");
for (DUIterator_Last imin, i = res->last_outs(imin); i >= imin;) {
SafePointNode* sfpt = res->last_out(i)->as_SafePoint();
uint first_ind = sfpt->req() - sfpt->jvms()->scloff();
Node* sobj = new SafePointScalarObjectNode(gvn.type(res)->isa_oopptr(),
#ifdef ASSERT
call,
#endif // ASSERT
first_ind, n_fields, true);
sobj->init_req(0, kit.root());
sfpt->add_req(call->in(TypeFunc::Parms));
sobj = gvn.transform(sobj);
JVMState* jvms = sfpt->jvms();
jvms->set_endoff(sfpt->req());
int start = jvms->debug_start();
int end = jvms->debug_end();
int num_edges = sfpt->replace_edges_in_range(res, sobj, start, end, &gvn);
i -= num_edges;
}
assert(res->outcnt() == 0, "the box must have no use after replace");
#ifndef PRODUCT
if (PrintEliminateAllocations) {
tty->print("++++ Eliminated: %d ", call->_idx);
call->as_CallStaticJava()->method()->print_short_name(tty);
tty->cr();
}
#endif
}
void CallGenerator::do_late_inline_helper() {
assert(is_late_inline(), "only late inline allowed");
@ -687,24 +631,11 @@ void CallGenerator::do_late_inline_helper() {
C->remove_macro_node(call);
}
bool result_not_used = false;
// The call is marked as pure (no important side effects), but result isn't used.
// It's safe to remove the call.
bool result_not_used = (callprojs.resproj == NULL || callprojs.resproj->outcnt() == 0);
if (is_pure_call()) {
// Disabled due to JDK-8276112
if (false && is_boxing_late_inline() && callprojs.resproj != nullptr) {
// replace box node to scalar node only in case it is directly referenced by debug info
assert(call->as_CallStaticJava()->is_boxing_method(), "sanity");
if (!has_non_debug_usages(callprojs.resproj) && is_box_cache_valid(call)) {
scalarize_debug_usages(call, callprojs.resproj);
}
}
// The call is marked as pure (no important side effects), but result isn't used.
// It's safe to remove the call.
result_not_used = (callprojs.resproj == NULL || callprojs.resproj->outcnt() == 0);
}
if (result_not_used) {
if (is_pure_call() && result_not_used) {
GraphKit kit(call->jvms());
kit.replace_call(call, C->top(), true);
} else {
@ -832,8 +763,6 @@ class LateInlineBoxingCallGenerator : public LateInlineCallGenerator {
return new_jvms;
}
virtual bool is_boxing_late_inline() const { return true; }
virtual CallGenerator* with_call_node(CallNode* call) {
LateInlineBoxingCallGenerator* cg = new LateInlineBoxingCallGenerator(method(), _inline_cg);
cg->set_call_node(call->as_CallStaticJava());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -74,7 +74,6 @@ class CallGenerator : public ResourceObj {
virtual bool is_late_inline() const { return false; }
// same but for method handle calls
virtual bool is_mh_late_inline() const { return false; }
virtual bool is_boxing_late_inline() const { return false; }
virtual bool is_string_late_inline() const { return false; }
virtual bool is_virtual_late_inline() const { return false; }

View File

@ -1567,20 +1567,17 @@ SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp,
Node* alloc,
#endif
uint first_index,
uint n_fields,
bool is_auto_box) :
uint n_fields) :
TypeNode(tp, 1), // 1 control input -- seems required. Get from root.
_first_index(first_index),
_n_fields(n_fields),
_is_auto_box(is_auto_box)
_n_fields(n_fields)
#ifdef ASSERT
, _alloc(alloc)
#endif
{
#ifdef ASSERT
if (!alloc->is_Allocate()
&& !(alloc->Opcode() == Op_VectorBox)
&& (!alloc->is_CallStaticJava() || !alloc->as_CallStaticJava()->is_boxing_method())) {
&& !(alloc->Opcode() == Op_VectorBox)) {
alloc->dump();
assert(false, "unexpected call node");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@ -512,7 +512,6 @@ class SafePointScalarObjectNode: public TypeNode {
// states of the scalarized object fields are collected.
// It is relative to the last (youngest) jvms->_scloff.
uint _n_fields; // Number of non-static fields of the scalarized object.
bool _is_auto_box; // True if the scalarized object is an auto box.
DEBUG_ONLY(Node* _alloc;)
virtual uint hash() const ; // { return NO_HASH; }
@ -525,7 +524,7 @@ public:
#ifdef ASSERT
Node* alloc,
#endif
uint first_index, uint n_fields, bool is_auto_box = false);
uint first_index, uint n_fields);
virtual int Opcode() const;
virtual uint ideal_reg() const;
virtual const RegMask &in_RegMask(uint) const;
@ -538,7 +537,6 @@ public:
}
uint n_fields() const { return _n_fields; }
bool is_auto_box() const { return _is_auto_box; }
#ifdef ASSERT
Node* alloc() const { return _alloc; }
#endif

View File

@ -819,9 +819,8 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local,
ciKlass* cik = t->is_oopptr()->klass();
assert(cik->is_instance_klass() ||
cik->is_array_klass(), "Not supported allocation.");
ScopeValue* klass_sv = new ConstantOopWriteValue(cik->java_mirror()->constant_encoding());
sv = spobj->is_auto_box() ? new AutoBoxObjectValue(spobj->_idx, klass_sv)
: new ObjectValue(spobj->_idx, klass_sv);
sv = new ObjectValue(spobj->_idx,
new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()));
set_sv_for_object_node(objs, sv);
uint first_ind = spobj->first_index(sfpt->jvms());
@ -1093,9 +1092,8 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) {
ciKlass* cik = t->is_oopptr()->klass();
assert(cik->is_instance_klass() ||
cik->is_array_klass(), "Not supported allocation.");
ScopeValue* klass_sv = new ConstantOopWriteValue(cik->java_mirror()->constant_encoding());
ObjectValue* sv = spobj->is_auto_box() ? new AutoBoxObjectValue(spobj->_idx, klass_sv)
: new ObjectValue(spobj->_idx, klass_sv);
ObjectValue* sv = new ObjectValue(spobj->_idx,
new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()));
PhaseOutput::set_sv_for_object_node(objs, sv);
uint first_ind = spobj->first_index(youngest_jvms);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@ -926,7 +926,7 @@ void Deoptimization::deoptimize_all_marked(nmethod* nmethod_only) {
Deoptimization::DeoptAction Deoptimization::_unloaded_action
= Deoptimization::Action_reinterpret;
#if COMPILER2_OR_JVMCI
#if INCLUDE_JVMCI
template<typename CacheType>
class BoxCacheBase : public CHeapObj<mtCompiler> {
protected:
@ -1054,7 +1054,9 @@ oop Deoptimization::get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMa
}
return NULL;
}
#endif // INCLUDE_JVMCI
#if COMPILER2_OR_JVMCI
bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, TRAPS) {
Handle pending_exception(THREAD, thread->pending_exception());
const char* exception_file = thread->exception_file();
@ -1071,7 +1073,9 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap*
oop obj = NULL;
if (k->is_instance_klass()) {
if (sv->is_auto_box()) {
#if INCLUDE_JVMCI
CompiledMethod* cm = fr->cb()->as_compiled_method_or_null();
if (cm->is_compiled_by_jvmci() && sv->is_auto_box()) {
AutoBoxObjectValue* abv = (AutoBoxObjectValue*) sv;
obj = get_cached_box(abv, fr, reg_map, THREAD);
if (obj != NULL) {
@ -1079,6 +1083,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap*
abv->set_cached(true);
}
}
#endif // INCLUDE_JVMCI
InstanceKlass* ik = InstanceKlass::cast(k);
if (obj == NULL) {
@ -1425,10 +1430,12 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr
continue;
}
#if INCLUDE_JVMCI
// Don't reassign fields of boxes that came from a cache. Caches may be in CDS.
if (sv->is_auto_box() && ((AutoBoxObjectValue*) sv)->is_cached()) {
continue;
}
#endif // INCLUDE_JVMCI
#ifdef COMPILER2
if (EnableVectorSupport && VectorSupport::is_vector(k)) {
assert(sv->field_size() == 1, "%s not a vector", k->name()->as_C_string());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@ -160,9 +160,8 @@ class Deoptimization : AllStatic {
#if INCLUDE_JVMCI
static address deoptimize_for_missing_exception_handler(CompiledMethod* cm);
#endif
static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, TRAPS);
#endif
private:
// Does the actual work for deoptimizing a single frame

View File

@ -1,78 +0,0 @@
/*
* Copyright (c) 2021, Huawei Technologies Co., Ltd. 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8261137
* @requires vm.flagless
* @requires vm.debug == true & vm.compiler2.enabled
* @summary Verify that box object is scalarized in case it is directly referenced by debug info.
* @library /test/lib
*
* @run driver compiler.eliminateAutobox.TestEliminateBoxInDebugInfo
*/
package compiler.eliminateAutobox;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class TestEliminateBoxInDebugInfo {
public static void runTest() throws Exception {
String[] arguments = {
"-XX:CompileCommand=compileonly,compiler/eliminateAutobox/TestEliminateBoxInDebugInfo$Test.foo",
"-XX:CompileCommand=dontinline,compiler/eliminateAutobox/TestEliminateBoxInDebugInfo$Test.black",
"-Xbatch",
"-XX:+PrintEliminateAllocations",
Test.class.getName()
};
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0)
.stdoutShouldContain("++++ Eliminated: ");
}
public static void main(String[] args) throws Exception {
runTest();
}
static class Test {
public static void main(String[] args) throws Exception {
// warmup
for (int i = 0; i < 100000; i++) {
foo(1000 + (i % 1000));
}
}
public static int foo(int value) {
Integer ii = Integer.valueOf(value);
int sum = 0;
if (value > 999) {
sum += ii.intValue();
}
black();
return sum;
}
public static void black() {}
}
}