mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-19 09:57:49 +00:00
8283541: Add Statical counters and some comments in PhaseStringOpts
Reviewed-by: thartmann, kvn
This commit is contained in:
parent
15ce8c6195
commit
cb16e41089
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user