8143900: OptimizeStringConcat has an opaque dependency on Integer.sizeTable field
Reviewed-by: kvn, thartmann
This commit is contained in:
parent
35003b5f7b
commit
c961a918ad
src
@ -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.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user