stringopts.cpp revision 3712
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * This code is free software; you can redistribute it and/or modify it
843e19887f64dde75055cf8842fc4db2171eff45johnlev * under the terms of the GNU General Public License version 2 only, as
843e19887f64dde75055cf8842fc4db2171eff45johnlev * published by the Free Software Foundation.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * This code is distributed in the hope that it will be useful, but WITHOUT
843e19887f64dde75055cf8842fc4db2171eff45johnlev * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
843e19887f64dde75055cf8842fc4db2171eff45johnlev * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
843e19887f64dde75055cf8842fc4db2171eff45johnlev * version 2 for more details (a copy is included in the LICENSE file that
843e19887f64dde75055cf8842fc4db2171eff45johnlev * accompanied this code).
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You should have received a copy of the GNU General Public License version
843e19887f64dde75055cf8842fc4db2171eff45johnlev * 2 along with this work; if not, write to the Free Software Foundation,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
843e19887f64dde75055cf8842fc4db2171eff45johnlev * or visit www.oracle.com if you need additional information or have any
843e19887f64dde75055cf8842fc4db2171eff45johnlev * questions.
843e19887f64dde75055cf8842fc4db2171eff45johnlev AllocateNode* _begin; // The allocation the begins the pattern
843e19887f64dde75055cf8842fc4db2171eff45johnlev CallStaticJavaNode* _end; // The final call of the pattern. Will either be
843e19887f64dde75055cf8842fc4db2171eff45johnlev // SB.toString or or String.<init>(SB.toString)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bool _multiple; // indicates this is a fusion of two or more
843e19887f64dde75055cf8842fc4db2171eff45johnlev // separate StringBuilders
843e19887f64dde75055cf8842fc4db2171eff45johnlev Node* _arguments; // The list of arguments to be concatenated
843e19887f64dde75055cf8842fc4db2171eff45johnlev GrowableArray<int> _mode; // into a String along with a mode flag
843e19887f64dde75055cf8842fc4db2171eff45johnlev // indicating how to treat the value.
843e19887f64dde75055cf8842fc4db2171eff45johnlev Node_List _control; // List of control nodes that will be deleted
843e19887f64dde75055cf8842fc4db2171eff45johnlev Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten
843e19887f64dde75055cf8842fc4db2171eff45johnlev // to restart at the initial JVMState.
843e19887f64dde75055cf8842fc4db2171eff45johnlev // Mode for converting arguments to Strings
843e19887f64dde75055cf8842fc4db2171eff45johnlev StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end):
843e19887f64dde75055cf8842fc4db2171eff45johnlev // XXX This is place holder code for reusing an existing String
843e19887f64dde75055cf8842fc4db2171eff45johnlev // allocation but the logic for checking the state safety is
843e19887f64dde75055cf8842fc4db2171eff45johnlev // probably inadequate at the moment.
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev CallStaticJavaNode *use = i.get()->isa_CallStaticJava();
843e19887f64dde75055cf8842fc4db2171eff45johnlev use->method()->intrinsic_id() == vmIntrinsics::_String_String &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev // Found useless new String(sb.toString()) so reuse the newly allocated String
843e19887f64dde75055cf8842fc4db2171eff45johnlev // when creating the result instead of allocating a new one.
843e19887f64dde75055cf8842fc4db2171eff45johnlev StringConcat* merge(StringConcat* other, Node* arg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev int mode(int i) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'",
193974072f41a843678abf5f61979c748687e66bSherry Moore while (p != NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method()));
843e19887f64dde75055cf8842fc4db2171eff45johnlev void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) {
193974072f41a843678abf5f61979c748687e66bSherry Moore for (uint u = 0; u < _uncommon_traps.size(); u++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // Build a new call using the jvms state of the allocate
843e19887f64dde75055cf8842fc4db2171eff45johnlev address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point();
843e19887f64dde75055cf8842fc4db2171eff45johnlev const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type();
843e19887f64dde75055cf8842fc4db2171eff45johnlev CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap",
843e19887f64dde75055cf8842fc4db2171eff45johnlev // Set the trap request to record intrinsic failure if this trap
843e19887f64dde75055cf8842fc4db2171eff45johnlev // is taken too many times. Ideally we would handle then traps by
843e19887f64dde75055cf8842fc4db2171eff45johnlev // doing the original bookkeeping in the MDO so that if it caused
843e19887f64dde75055cf8842fc4db2171eff45johnlev // the code to be thrown out we could still recompile and use the
843e19887f64dde75055cf8842fc4db2171eff45johnlev // optimization. Failing the uncommon traps doesn't really mean
843e19887f64dde75055cf8842fc4db2171eff45johnlev // that the optimization is a bad idea but there's no other way to
843e19887f64dde75055cf8842fc4db2171eff45johnlev // do the MDO updates currently.
843e19887f64dde75055cf8842fc4db2171eff45johnlev int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic,
843e19887f64dde75055cf8842fc4db2171eff45johnlev call->init_req(TypeFunc::Parms, __ intcon(trap_request));
void cleanup() {
if (n->is_Call()) {
if (n != _end) {
} else if (n->is_IfTrue()) {
if (n->is_Call()) {
if (n->is_Call()) {
for (int x = 0; x < num_arguments(); x++) {
return result;
if (m != NULL &&
return string_calls;
return NULL;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
while (cnode) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
return NULL;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
return sc;
return NULL;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
return NULL;
false, NULL, 0);
const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes());
const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes());
const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes());
// Run through the list of allocation looking for SB.toString to see
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
goto restart;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
switch (opc) {
case Op_Region: {
if (m->is_Phi()) {
case Op_AddP:
case Op_CreateEx: {
if (m->is_AddP()) {
case Op_Phi:
int null_check_count = 0;
if (n->is_Allocate()) {
if (n->is_Call()) {
bool fail = false;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
b->dump();
fail = true;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
fail = true;
if (!fail) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
fail = true;
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
#ifndef PRODUCT
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
fail = true;
#ifndef PRODUCT
for (int i = 0; i < num_arguments(); i++) {
return !fail;
C->record_for_igvn(r);
return final_size;
void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) {
Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
C->record_for_igvn(i);
if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) {
#ifdef _LP64
return start;
// length = length + (s.count - s.offset);
C->record_for_igvn(r);
Node* count = kit.make_load(kit.control(), kit.basic_plus_adr(arg, arg, java_lang_String::count_offset_in_bytes()),
if (argi > 0) {
kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::offset_offset_in_bytes()),
kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::count_offset_in_bytes()),