8283541: Add Statical counters and some comments in PhaseStringOpts

Reviewed-by: thartmann, kvn
This commit is contained in:
Xin Liu 2022-04-20 17:38:24 +00:00
parent 15ce8c6195
commit cb16e41089
3 changed files with 57 additions and 45 deletions

View File

@ -248,6 +248,7 @@ void Compile::print_statistics() {
{ ttyLocker ttyl;
if (xtty != NULL) xtty->head("statistics type='opto'");
Parse::print_statistics();
PhaseStringOpts::print_statistics();
PhaseCCP::print_statistics();
PhaseRegAlloc::print_statistics();
PhaseOutput::print_statistics();
@ -1836,7 +1837,7 @@ void Compile::inline_string_calls(bool parse_time) {
{
ResourceMark rm;
print_method(PHASE_BEFORE_STRINGOPTS, 3);
PhaseStringOpts pso(initial_gvn(), for_igvn());
PhaseStringOpts pso(initial_gvn());
print_method(PHASE_AFTER_STRINGOPTS, 3);
}

View File

@ -26,17 +26,13 @@
#include "ci/ciSymbols.hpp"
#include "classfile/javaClasses.hpp"
#include "compiler/compileLog.hpp"
#include "opto/addnode.hpp"
#include "opto/callGenerator.hpp"
#include "opto/callnode.hpp"
#include "opto/divnode.hpp"
#include "opto/graphKit.hpp"
#include "opto/idealKit.hpp"
#include "opto/rootnode.hpp"
#include "opto/runtime.hpp"
#include "opto/stringopts.hpp"
#include "opto/subnode.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/atomic.hpp"
#include "runtime/stubRoutines.hpp"
#define __ kit.
@ -44,7 +40,6 @@
class StringConcat : public ResourceObj {
private:
PhaseStringOpts* _stringopts;
Node* _string_alloc;
AllocateNode* _begin; // The allocation the begins the pattern
CallStaticJavaNode* _end; // The final call of the pattern. Will either be
// SB.toString or or String.<init>(SB.toString)
@ -71,7 +66,6 @@ class StringConcat : public ResourceObj {
StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end):
_stringopts(stringopts),
_string_alloc(NULL),
_begin(NULL),
_end(end),
_multiple(false) {
@ -82,29 +76,6 @@ class StringConcat : public ResourceObj {
bool validate_mem_flow();
bool validate_control_flow();
void merge_add() {
#if 0
// XXX This is place holder code for reusing an existing String
// allocation but the logic for checking the state safety is
// probably inadequate at the moment.
CallProjections endprojs;
sc->end()->extract_projections(&endprojs, false);
if (endprojs.resproj != NULL) {
for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) {
CallStaticJavaNode *use = i.get()->isa_CallStaticJava();
if (use != NULL && use->method() != NULL &&
use->method()->intrinsic_id() == vmIntrinsics::_String_String &&
use->in(TypeFunc::Parms + 1) == endprojs.resproj) {
// Found useless new String(sb.toString()) so reuse the newly allocated String
// when creating the result instead of allocating a new one.
sc->set_string_alloc(use->in(TypeFunc::Parms));
sc->set_end(use);
}
}
}
#endif
}
StringConcat* merge(StringConcat* other, Node* arg);
void set_allocation(AllocateNode* alloc) {
@ -209,7 +180,6 @@ class StringConcat : public ResourceObj {
}
CallStaticJavaNode* end() { return _end; }
AllocateNode* begin() { return _begin; }
Node* string_alloc() { return _string_alloc; }
void eliminate_unneeded_control();
void eliminate_initialize(InitializeNode* init);
@ -218,10 +188,7 @@ class StringConcat : public ResourceObj {
void maybe_log_transform() {
CompileLog* log = _stringopts->C->log();
if (log != NULL) {
log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'",
num_arguments(),
_string_alloc != NULL,
_multiple);
log->head("replace_string_concat arguments='%d' multiple='%d'", num_arguments(), _multiple);
JVMState* p = _begin->jvms();
while (p != NULL) {
log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
@ -414,11 +381,13 @@ Node_List PhaseStringOpts::collect_toString_calls() {
}
}
uint encountered = 0;
while (worklist.size() > 0) {
Node* ctrl = worklist.pop();
if (StringConcat::is_SB_toString(ctrl)) {
CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
string_calls.push(csj);
encountered++;
}
if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
worklist.push(ctrl->in(0));
@ -431,10 +400,34 @@ Node_List PhaseStringOpts::collect_toString_calls() {
}
}
}
#ifndef PRODUCT
Atomic::add(&_stropts_total, encountered);
#endif
return string_calls;
}
// Recognize a fluent-chain of StringBuilder/Buffer. They are either explicit usages
// of them or the legacy bytecodes of string concatenation prior to JEP-280. eg.
//
// String result = new StringBuilder()
// .append("foo")
// .append("bar")
// .append(123)
// .toString(); // "foobar123"
//
// PS: Only a certain subset of constructor and append methods are acceptable.
// The criterion is that the length of argument is easy to work out in this phrase.
// It will drop complex cases such as Object.
//
// Since it walks along the receivers of fluent-chain, it will give up if the codeshape is
// not "fluent" enough. eg.
// StringBuilder sb = new StringBuilder();
// sb.append("foo");
// sb.toString();
//
// The receiver of toString method is the result of Allocation Node(CheckCastPP).
// The append method is overlooked. It will fail at validate_control_flow() test.
//
StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
ciMethod* m = call->method();
ciSymbol* string_sig;
@ -459,9 +452,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
#endif
StringConcat* sc = new StringConcat(this, call);
AllocateNode* alloc = NULL;
InitializeNode* init = NULL;
// possible opportunity for StringBuilder fusion
CallStaticJavaNode* cnode = call;
@ -638,7 +629,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
}
PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn):
Phase(StringOpts),
_gvn(gvn) {
@ -691,6 +682,7 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
StringConcat* merged = sc->merge(other, arg);
if (merged->validate_control_flow() && merged->validate_mem_flow()) {
#ifndef PRODUCT
Atomic::inc(&_stropts_merged);
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would succeed");
}
@ -2031,9 +2023,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
}
}
// If we're not reusing an existing String allocation then allocate one here.
result = sc->string_alloc();
if (result == NULL) {
{
PreserveReexecuteState preexecs(&kit);
// The original jvms is for an allocation of either a String or
// StringBuffer so no stack adjustment is necessary for proper
@ -2060,4 +2050,17 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// Unhook any hook nodes
string_sizes->disconnect_inputs(C);
sc->cleanup();
#ifndef PRODUCT
Atomic::inc(&_stropts_replaced);
#endif
}
#ifndef PRODUCT
uint PhaseStringOpts::_stropts_replaced = 0;
uint PhaseStringOpts::_stropts_merged = 0;
uint PhaseStringOpts::_stropts_total = 0;
void PhaseStringOpts::print_statistics() {
tty->print_cr("StringConcat: %4d/%4d/%4d(replaced/merged/total)", _stropts_replaced, _stropts_merged, _stropts_total);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 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
@ -112,7 +112,15 @@ class PhaseStringOpts : public Phase {
};
public:
PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List* worklist);
PhaseStringOpts(PhaseGVN* gvn);
#ifndef PRODUCT
static void print_statistics();
private:
static uint _stropts_replaced;
static uint _stropts_merged;
static uint _stropts_total;
#endif
};
#endif // SHARE_OPTO_STRINGOPTS_HPP