8143900: OptimizeStringConcat has an opaque dependency on Integer.sizeTable field

Reviewed-by: kvn, thartmann
This commit is contained in:
Yi Yang 2023-03-03 02:00:45 +00:00
parent 35003b5f7b
commit c961a918ad
3 changed files with 80 additions and 137 deletions
src
hotspot/share/opto
java.base/share/classes/java/lang

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023, 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
@ -637,14 +637,6 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn):
assert(OptimizeStringConcat, "shouldn't be here");
size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"),
ciSymbols::int_array_signature(), true);
if (size_table_field == NULL) {
// Something wrong so give up.
assert(false, "why can't we find Integer.sizeTable?");
return;
}
// Collect the types needed to talk about the various slices of memory
byte_adr_idx = C->get_alias_index(TypeAryPtr::BYTES);
@ -1168,144 +1160,105 @@ bool StringConcat::validate_control_flow() {
return !fail;
}
Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) {
const TypeInstPtr* mirror_type = TypeInstPtr::make(field->holder()->java_mirror());
Node* klass_node = __ makecon(mirror_type);
BasicType bt = field->layout_type();
ciType* field_klass = field->type();
const Type *type;
if( bt == T_OBJECT ) {
if (!field->type()->is_loaded()) {
type = TypeInstPtr::BOTTOM;
} else if (field->is_static_constant()) {
// This can happen if the constant oop is non-perm.
ciObject* con = field->constant_value().as_object();
// Do not "join" in the previous type; it doesn't add value,
// and may yield a vacuous result if the field is of interface type.
type = TypeOopPtr::make_from_constant(con, true)->isa_oopptr();
assert(type != NULL, "field singleton type must be consistent");
return __ makecon(type);
} else {
type = TypeOopPtr::make_from_klass(field_klass->as_klass());
}
} else {
type = Type::get_const_basic_type(bt);
}
return kit.make_load(NULL, kit.basic_plus_adr(klass_node, field->offset_in_bytes()),
type, T_OBJECT,
C->get_alias_index(mirror_type->add_offset(field->offset_in_bytes())),
MemNode::unordered);
}
// Mirror of Integer.stringSize() method, return the count of digits in integer,
Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) {
if (arg->is_Con()) {
// Constant integer. Compute constant length using Integer.sizeTable
int arg_val = arg->get_int();
int count = 1;
if (arg_val < 0) {
// Special case for min_jint - it can't be negated.
if (arg_val == min_jint) {
return __ intcon(11);
}
// Constant integer. Compute constant length
jint arg_val = arg->get_int();
jint d = 1;
if (arg_val >= 0) {
d = 0;
arg_val = -arg_val;
count++;
}
ciArray* size_table = (ciArray*)size_table_field->constant_value().as_object();
for (int i = 0; i < size_table->length(); i++) {
if (arg_val <= size_table->element_value(i).as_int()) {
count += i;
break;
jint p = -10;
for (int i = 1; i < 10; i++) {
if (arg_val > p) {
return __ intcon(i + d);
}
p = 10 * p;
}
return __ intcon(count);
return __ intcon(10 + d);
}
RegionNode *final_merge = new RegionNode(3);
// int d = 1;
// if (x >= 0) {
// d = 0;
// x = -x;
// }
RegionNode* sign_merge = new RegionNode(3);
kit.gvn().set_type(sign_merge, Type::CONTROL);
Node* digit_cnt = new PhiNode(sign_merge, TypeInt::INT);
kit.gvn().set_type(digit_cnt, TypeInt::INT);
Node* val = new PhiNode(sign_merge, TypeInt::INT);
kit.gvn().set_type(val, TypeInt::INT);
IfNode* iff = kit.create_and_map_if(kit.control(),
__ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::ge),
PROB_FAIR, COUNT_UNKNOWN);
sign_merge->init_req(1, __ IfTrue(iff));
sign_merge->init_req(2, __ IfFalse(iff));
digit_cnt->init_req(1, __ intcon(0));
digit_cnt->init_req(2, __ intcon(1));
val->init_req(1, __ SubI(__ intcon(0), arg));
val->init_req(2, arg);
kit.set_control(sign_merge);
// int p = -10;
// for (int i = 1; i < 10; i++) {
// if (x > p)
// return i + d;
// p = 10 * p;
// }
RegionNode* final_merge = new RegionNode(3);
kit.gvn().set_type(final_merge, Type::CONTROL);
Node* final_size = new PhiNode(final_merge, TypeInt::INT);
kit.gvn().set_type(final_size, TypeInt::INT);
IfNode* iff = kit.create_and_map_if(kit.control(),
__ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
PROB_FAIR, COUNT_UNKNOWN);
Node* is_min = __ IfFalse(iff);
final_merge->init_req(1, is_min);
final_size->init_req(1, __ intcon(11));
kit.add_empty_predicates();
C->set_has_loops(true);
kit.set_control(__ IfTrue(iff));
if (kit.stopped()) {
final_merge->init_req(2, C->top());
final_size->init_req(2, C->top());
} else {
RegionNode* loop = new RegionNode(3);
kit.gvn().set_type(loop, Type::CONTROL);
Node* index = new PhiNode(loop, TypeInt::INT);
kit.gvn().set_type(index, TypeInt::INT);
Node* temp = new PhiNode(loop, TypeInt::INT);
kit.gvn().set_type(temp, TypeInt::INT);
// int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
RegionNode *r = new RegionNode(3);
kit.gvn().set_type(r, Type::CONTROL);
Node *phi = new PhiNode(r, TypeInt::INT);
kit.gvn().set_type(phi, TypeInt::INT);
Node *size = new PhiNode(r, TypeInt::INT);
kit.gvn().set_type(size, TypeInt::INT);
Node* chk = __ CmpI(arg, __ intcon(0));
Node* p = __ Bool(chk, BoolTest::lt);
IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_FAIR, COUNT_UNKNOWN);
Node* lessthan = __ IfTrue(iff);
Node* greaterequal = __ IfFalse(iff);
r->init_req(1, lessthan);
phi->init_req(1, __ SubI(__ intcon(0), arg));
size->init_req(1, __ intcon(1));
r->init_req(2, greaterequal);
phi->init_req(2, arg);
size->init_req(2, __ intcon(0));
kit.set_control(r);
C->record_for_igvn(r);
C->record_for_igvn(phi);
C->record_for_igvn(size);
loop->init_req(1, kit.control());
index->init_req(1, __ intcon(1));
temp->init_req(1, __ intcon(-10));
kit.set_control(loop);
// for (int i=0; ; i++)
// if (x <= sizeTable[i])
// return i+1;
Node* limit = __ CmpI(index, __ intcon(10));
Node* limitb = __ Bool(limit, BoolTest::lt);
IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN);
Node* limit_less = __ IfTrue(iff2);
kit.set_control(limit_less);
// Add loop predicate first.
kit.add_empty_predicates();
C->set_has_loops(true);
Node* cmp = __ CmpI(val, temp);
Node* cmpb = __ Bool(cmp, BoolTest::gt);
IfNode* iff3 = kit.create_and_map_if(kit.control(), cmpb, PROB_MIN, COUNT_UNKNOWN);
Node* cmp_le = __ IfFalse(iff3);
kit.set_control(cmp_le);
RegionNode *loop = new RegionNode(3);
loop->init_req(1, kit.control());
kit.gvn().set_type(loop, Type::CONTROL);
Node *index = new PhiNode(loop, TypeInt::INT);
index->init_req(1, __ intcon(0));
kit.gvn().set_type(index, TypeInt::INT);
kit.set_control(loop);
Node* sizeTable = fetch_static_field(kit, size_table_field);
Node* value = kit.load_array_element(sizeTable, index, TypeAryPtr::INTS, /* set_ctrl */ false);
C->record_for_igvn(value);
Node* limit = __ CmpI(phi, value);
Node* limitb = __ Bool(limit, BoolTest::le);
IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN);
Node* lessEqual = __ IfTrue(iff2);
Node* greater = __ IfFalse(iff2);
loop->init_req(2, greater);
index->init_req(2, __ AddI(index, __ intcon(1)));
kit.set_control(lessEqual);
C->record_for_igvn(loop);
C->record_for_igvn(index);
final_merge->init_req(2, kit.control());
final_size->init_req(2, __ AddI(__ AddI(index, size), __ intcon(1)));
}
loop->init_req(2, kit.control());
index->init_req(2, __ AddI(index, __ intcon(1)));
temp->init_req(2, __ MulI(temp, __ intcon(10)));
final_merge->init_req(1, __ IfFalse(iff2));
final_merge->init_req(2, __ IfTrue(iff3));
final_size->init_req(1, __ AddI(digit_cnt, __ intcon(10)));
final_size->init_req(2, __ AddI(digit_cnt, index));
kit.set_control(final_merge);
C->record_for_igvn(sign_merge);
C->record_for_igvn(digit_cnt);
C->record_for_igvn(val);
C->record_for_igvn(final_merge);
C->record_for_igvn(final_size);
C->record_for_igvn(loop);
C->record_for_igvn(index);
C->record_for_igvn(temp);
return final_size;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023, 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
@ -43,9 +43,6 @@ class PhaseStringOpts : public Phase {
// Memory slices needed for code gen
int byte_adr_idx;
// Integer.sizeTable - used for int to String conversion
ciField* size_table_field;
// A set for use by various stages
VectorSet _visited;
@ -59,9 +56,6 @@ class PhaseStringOpts : public Phase {
// Replace all the SB calls in concat with an optimization String allocation
void replace_string_concat(StringConcat* concat);
// Load the value of a static field, performing any constant folding.
Node* fetch_static_field(GraphKit& kit, ciField* field);
// Compute the number of characters required to represent the int value
Node* int_stringSize(GraphKit& kit, Node* value);

@ -529,10 +529,6 @@ public final class Integer extends Number
return charPos;
}
// Left here for compatibility reasons, see JDK-8143900.
static final int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
/**
* Returns the string representation size for a given int value.
*