< prev index next >
src/share/vm/opto/stringopts.cpp
Print this page
*** 596,606 ****
assert(false, "why can't we find Integer.sizeTable?");
return;
}
// Collect the types needed to talk about the various slices of memory
! char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS);
// For each locally allocated StringBuffer see if the usages can be
// collapsed into a single String construction.
// Run through the list of allocation looking for SB.toString to see
--- 596,606 ----
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);
// For each locally allocated StringBuffer see if the usages can be
// collapsed into a single String construction.
// Run through the list of allocation looking for SB.toString to see
*** 1126,1135 ****
--- 1126,1154 ----
C->get_alias_index(mirror_type->add_offset(field->offset_in_bytes())),
MemNode::unordered);
}
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) {
+ 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;
+ }
+ }
+ return __ intcon(count);
+ }
+
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);
*** 1210,1275 ****
C->record_for_igvn(final_size);
return final_size;
}
! void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) {
! RegionNode *final_merge = new RegionNode(4);
! kit.gvn().set_type(final_merge, Type::CONTROL);
! Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
! kit.gvn().set_type(final_mem, Type::MEMORY);
!
! // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive
! {
! // i == MIN_VALUE
! IfNode* iff = kit.create_and_map_if(kit.control(),
! __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
! PROB_FAIR, COUNT_UNKNOWN);
!
! Node* old_mem = kit.memory(char_adr_idx);
!
! kit.set_control(__ IfFalse(iff));
! if (kit.stopped()) {
! // Statically not equal to MIN_VALUE so this path is dead
! final_merge->init_req(3, kit.control());
! } else {
! copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())),
! char_array, start);
! final_merge->init_req(3, kit.control());
! final_mem->init_req(3, kit.memory(char_adr_idx));
! }
!
! kit.set_control(__ IfTrue(iff));
! kit.set_memory(old_mem, char_adr_idx);
! }
!
!
! // Simplified version of Integer.getChars
!
! // int q, r;
! // int charPos = index;
! Node* charPos = end;
!
! // char sign = 0;
!
! Node* i = arg;
! Node* sign = __ intcon(0);
!
// if (i < 0) {
// sign = '-';
// i = -i;
// }
! {
! IfNode* iff = kit.create_and_map_if(kit.control(),
! __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt),
PROB_FAIR, COUNT_UNKNOWN);
! RegionNode *merge = new RegionNode(3);
kit.gvn().set_type(merge, Type::CONTROL);
! i = new PhiNode(merge, TypeInt::INT);
kit.gvn().set_type(i, TypeInt::INT);
! sign = new PhiNode(merge, TypeInt::INT);
kit.gvn().set_type(sign, TypeInt::INT);
merge->init_req(1, __ IfTrue(iff));
i->init_req(1, __ SubI(__ intcon(0), arg));
sign->init_req(1, __ intcon('-'));
--- 1229,1252 ----
C->record_for_igvn(final_size);
return final_size;
}
! // Simplified version of Integer.getChars
! void PhaseStringOpts::getChars(GraphKit& kit, Node* arg, Node* dst_array, BasicType bt, Node* end, Node* final_merge, Node* final_mem, int merge_index) {
// if (i < 0) {
// sign = '-';
// i = -i;
// }
! IfNode* iff = kit.create_and_map_if(kit.control(), __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt),
PROB_FAIR, COUNT_UNKNOWN);
! RegionNode* merge = new RegionNode(3);
kit.gvn().set_type(merge, Type::CONTROL);
! Node* i = new PhiNode(merge, TypeInt::INT);
kit.gvn().set_type(i, TypeInt::INT);
! Node* sign = new PhiNode(merge, TypeInt::INT);
kit.gvn().set_type(sign, TypeInt::INT);
merge->init_req(1, __ IfTrue(iff));
i->init_req(1, __ SubI(__ intcon(0), arg));
sign->init_req(1, __ intcon('-'));
*** 1280,1419 ****
kit.set_control(merge);
C->record_for_igvn(merge);
C->record_for_igvn(i);
C->record_for_igvn(sign);
- }
// for (;;) {
// q = i / 10;
// r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
// buf [--charPos] = digits [r];
// i = q;
// if (i == 0) break;
// }
- {
// Add loop predicate first.
kit.add_predicate();
! RegionNode *head = new RegionNode(3);
head->init_req(1, kit.control());
kit.gvn().set_type(head, Type::CONTROL);
! Node *i_phi = new PhiNode(head, TypeInt::INT);
i_phi->init_req(1, i);
kit.gvn().set_type(i_phi, TypeInt::INT);
! charPos = PhiNode::make(head, charPos);
kit.gvn().set_type(charPos, TypeInt::INT);
! Node *mem = PhiNode::make(head, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS);
kit.gvn().set_type(mem, Type::MEMORY);
kit.set_control(head);
! kit.set_memory(mem, char_adr_idx);
! Node* q = __ DivI(NULL, i_phi, __ intcon(10));
Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)),
__ LShiftI(q, __ intcon(1))));
! Node* m1 = __ SubI(charPos, __ intcon(1));
Node* ch = __ AddI(r, __ intcon('0'));
! Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR),
! ch, T_CHAR, char_adr_idx, MemNode::unordered);
!
!
! IfNode* iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne),
PROB_FAIR, COUNT_UNKNOWN);
Node* ne = __ IfTrue(iff);
Node* eq = __ IfFalse(iff);
head->init_req(2, ne);
mem->init_req(2, st);
- i_phi->init_req(2, q);
- charPos->init_req(2, m1);
! charPos = m1;
kit.set_control(eq);
! kit.set_memory(st, char_adr_idx);
C->record_for_igvn(head);
C->record_for_igvn(mem);
C->record_for_igvn(i_phi);
C->record_for_igvn(charPos);
- }
- {
// if (sign != 0) {
// buf [--charPos] = sign;
// }
! IfNode* iff = kit.create_and_map_if(kit.control(),
! __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne),
PROB_FAIR, COUNT_UNKNOWN);
! final_merge->init_req(2, __ IfFalse(iff));
! final_mem->init_req(2, kit.memory(char_adr_idx));
kit.set_control(__ IfTrue(iff));
if (kit.stopped()) {
! final_merge->init_req(1, C->top());
! final_mem->init_req(1, C->top());
} else {
! Node* m1 = __ SubI(charPos, __ intcon(1));
! Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR),
! sign, T_CHAR, char_adr_idx, MemNode::unordered);
! final_merge->init_req(1, kit.control());
! final_mem->init_req(1, st);
}
kit.set_control(final_merge);
! kit.set_memory(final_mem, char_adr_idx);
C->record_for_igvn(final_merge);
C->record_for_igvn(final_mem);
}
}
! Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start) {
! Node* string = str;
! Node* offset = kit.load_String_offset(kit.control(), string);
! Node* count = kit.load_String_length(kit.control(), string);
! Node* value = kit.load_String_value (kit.control(), string);
- // copy the contents
- if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) {
// For small constant strings just emit individual stores.
// A length of 6 seems like a good space/speed tradeof.
! int c = count->get_int();
! int o = offset->get_int();
! const TypeOopPtr* t = kit.gvn().type(value)->isa_oopptr();
! ciTypeArray* value_array = t->const_oop()->as_type_array();
! for (int e = 0; e < c; e++) {
! __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
! __ intcon(value_array->char_at(o + e)), T_CHAR, char_adr_idx,
! MemNode::unordered);
! start = __ AddI(start, __ intcon(1));
}
} else {
! Node* src_ptr = kit.array_element_address(value, offset, T_CHAR);
! Node* dst_ptr = kit.array_element_address(char_array, start, T_CHAR);
! Node* c = count;
! Node* extra = NULL;
! #ifdef _LP64
! c = __ ConvI2L(c);
! extra = C->top();
! #endif
! Node* call = kit.make_runtime_call(GraphKit::RC_LEAF|GraphKit::RC_NO_FP,
! OptoRuntime::fast_arraycopy_Type(),
! CAST_FROM_FN_PTR(address, StubRoutines::jshort_disjoint_arraycopy()),
! "jshort_disjoint_arraycopy", TypeAryPtr::CHARS,
! src_ptr, dst_ptr, c, extra);
! start = __ AddI(start, count);
}
! return start;
}
void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// Log a little info about the transformation
sc->maybe_log_transform();
--- 1257,1678 ----
kit.set_control(merge);
C->record_for_igvn(merge);
C->record_for_igvn(i);
C->record_for_igvn(sign);
// for (;;) {
// q = i / 10;
// r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
// buf [--charPos] = digits [r];
// i = q;
// if (i == 0) break;
// }
// Add loop predicate first.
kit.add_predicate();
! RegionNode* head = new RegionNode(3);
head->init_req(1, kit.control());
+
kit.gvn().set_type(head, Type::CONTROL);
! Node* i_phi = new PhiNode(head, TypeInt::INT);
i_phi->init_req(1, i);
kit.gvn().set_type(i_phi, TypeInt::INT);
! Node* charPos = new PhiNode(head, TypeInt::INT);
! charPos->init_req(1, end);
kit.gvn().set_type(charPos, TypeInt::INT);
! Node* mem = PhiNode::make(head, kit.memory(byte_adr_idx), Type::MEMORY, TypeAryPtr::BYTES);
kit.gvn().set_type(mem, Type::MEMORY);
+
kit.set_control(head);
! kit.set_memory(mem, byte_adr_idx);
! Node* q = __ DivI(kit.null(), i_phi, __ intcon(10));
Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)),
__ LShiftI(q, __ intcon(1))));
! Node* index = __ SubI(charPos, __ intcon((bt == T_BYTE) ? 1 : 2));
Node* ch = __ AddI(r, __ intcon('0'));
+ Node* st = __ store_to_memory(kit.control(), kit.array_element_address(dst_array, index, T_BYTE),
+ ch, bt, byte_adr_idx, MemNode::unordered);
! iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne),
PROB_FAIR, COUNT_UNKNOWN);
Node* ne = __ IfTrue(iff);
Node* eq = __ IfFalse(iff);
head->init_req(2, ne);
mem->init_req(2, st);
! i_phi->init_req(2, q);
! charPos->init_req(2, index);
! charPos = index;
kit.set_control(eq);
! kit.set_memory(st, byte_adr_idx);
C->record_for_igvn(head);
C->record_for_igvn(mem);
C->record_for_igvn(i_phi);
C->record_for_igvn(charPos);
// if (sign != 0) {
// buf [--charPos] = sign;
// }
! iff = kit.create_and_map_if(kit.control(), __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne),
PROB_FAIR, COUNT_UNKNOWN);
! final_merge->init_req(merge_index + 2, __ IfFalse(iff));
! final_mem->init_req(merge_index + 2, kit.memory(byte_adr_idx));
kit.set_control(__ IfTrue(iff));
if (kit.stopped()) {
! final_merge->init_req(merge_index + 1, C->top());
! final_mem->init_req(merge_index + 1, C->top());
} else {
! Node* index = __ SubI(charPos, __ intcon((bt == T_BYTE) ? 1 : 2));
! st = __ store_to_memory(kit.control(), kit.array_element_address(dst_array, index, T_BYTE),
! sign, bt, byte_adr_idx, MemNode::unordered);
! final_merge->init_req(merge_index + 1, kit.control());
! final_mem->init_req(merge_index + 1, st);
}
+ }
+
+ // Copy the characters representing arg into dst_array starting at start
+ Node* PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* dst_array, Node* dst_coder, Node* start, Node* size) {
+ bool dcon = dst_coder->is_Con();
+ bool dbyte = dcon ? (dst_coder->get_int() == java_lang_String::CODER_LATIN1) : false;
+ Node* end = __ AddI(start, __ LShiftI(size, dst_coder));
+
+ // The final_merge node has 4 entries in case the encoding is known:
+ // (0) Control, (1) result w/ sign, (2) result w/o sign, (3) result for Integer.min_value
+ // or 6 entries in case the encoding is not known:
+ // (0) Control, (1) Latin1 w/ sign, (2) Latin1 w/o sign, (3) min_value, (4) UTF16 w/ sign, (5) UTF16 w/o sign
+ RegionNode* final_merge = new RegionNode(dcon ? 4 : 6);
+ kit.gvn().set_type(final_merge, Type::CONTROL);
+
+ Node* final_mem = PhiNode::make(final_merge, kit.memory(byte_adr_idx), Type::MEMORY, TypeAryPtr::BYTES);
+ kit.gvn().set_type(final_mem, Type::MEMORY);
+
+ // need to handle arg == Integer.MIN_VALUE specially because negating doesn't make it positive
+ IfNode* iff = kit.create_and_map_if(kit.control(), __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne),
+ PROB_FAIR, COUNT_UNKNOWN);
+ Node* old_mem = kit.memory(byte_adr_idx);
+
+ kit.set_control(__ IfFalse(iff));
+ if (kit.stopped()) {
+ // Statically not equal to MIN_VALUE so this path is dead
+ final_merge->init_req(3, kit.control());
+ } else {
+ copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())),
+ dst_array, dst_coder, start);
+ final_merge->init_req(3, kit.control());
+ final_mem->init_req(3, kit.memory(byte_adr_idx));
+ }
+
+ kit.set_control(__ IfTrue(iff));
+ kit.set_memory(old_mem, byte_adr_idx);
+
+ if (!dcon) {
+ // Check encoding of destination
+ iff = kit.create_and_map_if(kit.control(), __ Bool(__ CmpI(dst_coder, __ intcon(0)), BoolTest::eq),
+ PROB_FAIR, COUNT_UNKNOWN);
+ old_mem = kit.memory(byte_adr_idx);
+ }
+ if (!dcon || dbyte) {
+ // Destination is Latin1,
+ if (!dcon) {
+ kit.set_control(__ IfTrue(iff));
+ }
+ getChars(kit, arg, dst_array, T_BYTE, end, final_merge, final_mem);
+ }
+ if (!dcon || !dbyte) {
+ // Destination is UTF16
+ int merge_index = 0;
+ if (!dcon) {
+ kit.set_control(__ IfFalse(iff));
+ kit.set_memory(old_mem, byte_adr_idx);
+ merge_index = 3; // Account for Latin1 case
+ }
+ getChars(kit, arg, dst_array, T_CHAR, end, final_merge, final_mem, merge_index);
+ }
+
+ // Final merge point for Latin1 and UTF16 case
kit.set_control(final_merge);
! kit.set_memory(final_mem, byte_adr_idx);
C->record_for_igvn(final_merge);
C->record_for_igvn(final_mem);
+ return end;
+ }
+
+ // Copy 'count' bytes/chars from src_array to dst_array starting at index start
+ void PhaseStringOpts::arraycopy(GraphKit& kit, IdealKit& ideal, Node* src_array, Node* dst_array, BasicType elembt, Node* start, Node* count) {
+ assert(elembt == T_BYTE || elembt == T_CHAR, "Invalid type for arraycopy");
+
+ if (elembt == T_CHAR) {
+ // Get number of chars
+ count = __ RShiftI(count, __ intcon(1));
+ }
+
+ Node* extra = NULL;
+ #ifdef _LP64
+ count = __ ConvI2L(count);
+ extra = C->top();
+ #endif
+
+ Node* src_ptr = __ array_element_address(src_array, __ intcon(0), T_BYTE);
+ Node* dst_ptr = __ array_element_address(dst_array, start, T_BYTE);
+ // Check if destination address is aligned to HeapWordSize
+ const TypeInt* tdst = __ gvn().type(start)->is_int();
+ bool aligned = tdst->is_con() && ((tdst->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0);
+ // Figure out which arraycopy runtime method to call (disjoint, uninitialized).
+ const char* copyfunc_name = "arraycopy";
+ address copyfunc_addr = StubRoutines::select_arraycopy_function(elembt, aligned, true, copyfunc_name, true);
+ ideal.make_leaf_call_no_fp(OptoRuntime::fast_arraycopy_Type(), copyfunc_addr, copyfunc_name,
+ TypeAryPtr::BYTES, src_ptr, dst_ptr, count, extra);
+ }
+
+ #undef __
+ #define __ ideal.
+
+ // Copy contents of a Latin1 encoded string from src_array to dst_array
+ void PhaseStringOpts::copy_latin1_string(GraphKit& kit, IdealKit& ideal, Node* src_array, IdealVariable& count,
+ Node* dst_array, Node* dst_coder, Node* start) {
+ bool dcon = dst_coder->is_Con();
+ bool dbyte = dcon ? (dst_coder->get_int() == java_lang_String::CODER_LATIN1) : false;
+
+ if (!dcon) {
+ __ if_then(dst_coder, BoolTest::eq, __ ConI(java_lang_String::CODER_LATIN1));
+ }
+ if (!dcon || dbyte) {
+ // Destination is Latin1. Simply emit a byte arraycopy.
+ arraycopy(kit, ideal, src_array, dst_array, T_BYTE, start, __ value(count));
+ }
+ if (!dcon) {
+ __ else_();
+ }
+ if (!dcon || !dbyte) {
+ // Destination is UTF16. Inflate src_array into dst_array.
+ kit.sync_kit(ideal);
+ if (Matcher::match_rule_supported(Op_StrInflatedCopy)) {
+ // Use fast intrinsic
+ Node* src = kit.array_element_address(src_array, kit.intcon(0), T_BYTE);
+ Node* dst = kit.array_element_address(dst_array, start, T_BYTE);
+ kit.inflate_string(src, dst, __ value(count));
+ } else {
+ // No intrinsic available, use slow method
+ kit.inflate_string_slow(src_array, dst_array, start, __ value(count));
+ }
+ ideal.sync_kit(&kit);
+ // Multiply count by two since we now need two bytes per char
+ __ set(count, __ LShiftI(__ value(count), __ ConI(1)));
+ }
+ if (!dcon) {
+ __ end_if();
}
}
+ // Read two bytes from index and index+1 and convert them to a char
+ static jchar readChar(ciTypeArray* array, int index) {
+ int shift_high, shift_low;
+ #ifdef VM_LITTLE_ENDIAN
+ shift_high = 0;
+ shift_low = 8;
+ #else
+ shift_high = 8;
+ shift_low = 0;
+ #endif
+
+ jchar b1 = ((jchar) array->byte_at(index)) & 0xff;
+ jchar b2 = ((jchar) array->byte_at(index+1)) & 0xff;
+ return (b1 << shift_high) | (b2 << shift_low);
+ }
! // Copy contents of constant src_array to dst_array by emitting individual stores
! void PhaseStringOpts::copy_constant_string(GraphKit& kit, IdealKit& ideal, ciTypeArray* src_array, IdealVariable& count,
! bool src_is_byte, Node* dst_array, Node* dst_coder, Node* start) {
! bool dcon = dst_coder->is_Con();
! bool dbyte = dcon ? (dst_coder->get_int() == java_lang_String::CODER_LATIN1) : false;
! int length = src_array->length();
!
! if (!dcon) {
! __ if_then(dst_coder, BoolTest::eq, __ ConI(java_lang_String::CODER_LATIN1));
! }
! if (!dcon || dbyte) {
! // Destination is Latin1. Copy each byte of src_array into dst_array.
! Node* index = start;
! for (int i = 0; i < length; i++) {
! Node* adr = kit.array_element_address(dst_array, index, T_BYTE);
! Node* val = __ ConI(src_array->byte_at(i));
! __ store(__ ctrl(), adr, val, T_BYTE, byte_adr_idx, MemNode::unordered);
! index = __ AddI(index, __ ConI(1));
! }
! }
! if (!dcon) {
! __ else_();
! }
! if (!dcon || !dbyte) {
! // Destination is UTF16. Copy each char of src_array into dst_array.
! Node* index = start;
! for (int i = 0; i < length; i++) {
! Node* adr = kit.array_element_address(dst_array, index, T_BYTE);
! jchar val;
! if (src_is_byte) {
! val = src_array->byte_at(i);
! } else {
! val = readChar(src_array, i++);
! }
! __ store(__ ctrl(), adr, __ ConI(val), T_CHAR, byte_adr_idx, MemNode::unordered);
! index = __ AddI(index, __ ConI(2));
! }
! if (src_is_byte) {
! // Multiply count by two since we now need two bytes per char
! __ set(count, __ ConI(2 * length));
! }
! }
! if (!dcon) {
! __ end_if();
! }
! }
!
! // Compress copy contents of the byte/char String str into dst_array starting at index start.
! Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* dst_array, Node* dst_coder, Node* start) {
! Node* src_array = kit.load_String_value(kit.control(), str);
!
! IdealKit ideal(&kit, true, true);
! IdealVariable count(ideal); __ declarations_done();
!
! if (str->is_Con()) {
! // Constant source string
! const TypeOopPtr* t = kit.gvn().type(src_array)->isa_oopptr();
! ciTypeArray* src_array_type = t->const_oop()->as_type_array();
!
! // Check encoding of constant string
! bool src_is_byte = (get_constant_coder(kit, str) == java_lang_String::CODER_LATIN1);
// For small constant strings just emit individual stores.
// A length of 6 seems like a good space/speed tradeof.
! __ set(count, __ ConI(src_array_type->length()));
! int src_len = src_array_type->length() / (src_is_byte ? 1 : 2);
! if (src_len < unroll_string_copy_length) {
! // Small constant string
! copy_constant_string(kit, ideal, src_array_type, count, src_is_byte, dst_array, dst_coder, start);
! } else if (src_is_byte) {
! // Source is Latin1
! copy_latin1_string(kit, ideal, src_array, count, dst_array, dst_coder, start);
! } else {
! // Source is UTF16 (destination too). Simply emit a char arraycopy.
! arraycopy(kit, ideal, src_array, dst_array, T_CHAR, start, __ value(count));
}
} else {
! Node* size = kit.load_array_length(src_array);
! __ set(count, size);
! // Non-constant source string
! if (CompactStrings) {
! // Emit runtime check for coder
! Node* coder = kit.load_String_coder(__ ctrl(), str);
! __ if_then(coder, BoolTest::eq, __ ConI(java_lang_String::CODER_LATIN1)); {
! // Source is Latin1
! copy_latin1_string(kit, ideal, src_array, count, dst_array, dst_coder, start);
! } __ else_();
! }
! // Source is UTF16 (destination too). Simply emit a char arraycopy.
! arraycopy(kit, ideal, src_array, dst_array, T_CHAR, start, __ value(count));
!
! if (CompactStrings) {
! __ end_if();
! }
! }
!
! // Finally sync IdealKit and GraphKit.
! kit.sync_kit(ideal);
! return __ AddI(start, __ value(count));
! }
!
! // Compress copy the char into dst_array at index start.
! Node* PhaseStringOpts::copy_char(GraphKit& kit, Node* val, Node* dst_array, Node* dst_coder, Node* start) {
! bool dcon = (dst_coder != NULL) && dst_coder->is_Con();
! bool dbyte = dcon ? (dst_coder->get_int() == java_lang_String::CODER_LATIN1) : false;
!
! IdealKit ideal(&kit, true, true);
! IdealVariable end(ideal); __ declarations_done();
! Node* adr = kit.array_element_address(dst_array, start, T_BYTE);
! if (!dcon){
! __ if_then(dst_coder, BoolTest::eq, __ ConI(java_lang_String::CODER_LATIN1));
! }
! if (!dcon || dbyte) {
! // Destination is Latin1. Store a byte.
! __ store(__ ctrl(), adr, val, T_BYTE, byte_adr_idx, MemNode::unordered);
! __ set(end, __ AddI(start, __ ConI(1)));
! }
! if (!dcon) {
! __ else_();
! }
! if (!dcon || !dbyte) {
! // Destination is UTF16. Store a char.
! __ store(__ ctrl(), adr, val, T_CHAR, byte_adr_idx, MemNode::unordered);
! __ set(end, __ AddI(start, __ ConI(2)));
! }
! if (!dcon) {
! __ end_if();
! }
! // Finally sync IdealKit and GraphKit.
! kit.sync_kit(ideal);
! return __ value(end);
! }
!
! #undef __
! #define __ kit.
!
! // Allocate a byte array of specified length.
! Node* PhaseStringOpts::allocate_byte_array(GraphKit& kit, IdealKit* ideal, Node* length) {
! if (ideal != NULL) {
! // Sync IdealKit and graphKit.
! kit.sync_kit(*ideal);
! }
! Node* byte_array = 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
! // reexecution. If we deoptimize in the slow path the bytecode
! // will be reexecuted and the char[] allocation will be thrown away.
! kit.jvms()->set_should_reexecute(true);
! byte_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_BYTE))),
! length, 1);
! }
!
! // Mark the allocation so that zeroing is skipped since the code
! // below will overwrite the entire array
! AllocateArrayNode* byte_alloc = AllocateArrayNode::Ideal_array_allocation(byte_array, _gvn);
! byte_alloc->maybe_set_complete(_gvn);
!
! if (ideal != NULL) {
! // Sync IdealKit and graphKit.
! ideal->sync_kit(&kit);
}
! return byte_array;
}
+ jbyte PhaseStringOpts::get_constant_coder(GraphKit& kit, Node* str) {
+ assert(str->is_Con(), "String must be constant");
+ const TypeOopPtr* str_type = kit.gvn().type(str)->isa_oopptr();
+ ciInstance* str_instance = str_type->const_oop()->as_instance();
+ jbyte coder = str_instance->field_value_by_offset(java_lang_String::coder_offset_in_bytes()).as_byte();
+ assert(CompactStrings || (coder == java_lang_String::CODER_UTF16), "Strings must be UTF16 encoded");
+ return coder;
+ }
+
+ int PhaseStringOpts::get_constant_length(GraphKit& kit, Node* str) {
+ assert(str->is_Con(), "String must be constant");
+ Node* src_array = kit.load_String_value(kit.control(), str);
+ const TypeOopPtr* t = kit.gvn().type(src_array)->isa_oopptr();
+ return t->const_oop()->as_type_array()->length();
+ }
void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// Log a little info about the transformation
sc->maybe_log_transform();
*** 1443,1453 ****
}
jvms->set_map(map);
map->ensure_stack(jvms, jvms->method()->max_stack());
-
// disconnect all the old StringBuilder calls from the graph
sc->eliminate_unneeded_control();
// At this point all the old work has been completely removed from
// the graph and the saved JVMState exists at the point where the
--- 1702,1711 ----
*** 1471,1481 ****
--- 1729,1749 ----
// Create a hook node to hold onto the individual sizes since they
// are need for the copying phase.
Node* string_sizes = new Node(args);
+ Node* coder = __ intcon(0);
Node* length = __ intcon(0);
+ // If at least one argument is UTF16 encoded, we can fix the encoding.
+ bool coder_fixed = false;
+
+ if (!CompactStrings) {
+ // Fix encoding of result string to UTF16
+ coder_fixed = true;
+ coder = __ intcon(java_lang_String::CODER_UTF16);
+ }
+
for (int argi = 0; argi < sc->num_arguments(); argi++) {
Node* arg = sc->argument(argi);
switch (sc->mode(argi)) {
case StringConcat::IntMode: {
Node* string_size = int_stringSize(kit, arg);
*** 1489,1499 ****
}
case StringConcat::StringNullCheckMode: {
const Type* type = kit.gvn().type(arg);
assert(type != TypePtr::NULL_PTR, "missing check");
if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
! // Null check with uncommont trap since
// StringBuilder(null) throws exception.
// Use special uncommon trap instead of
// calling normal do_null_check().
Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne);
IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN);
--- 1757,1767 ----
}
case StringConcat::StringNullCheckMode: {
const Type* type = kit.gvn().type(arg);
assert(type != TypePtr::NULL_PTR, "missing check");
if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
! // Null check with uncommon trap since
// StringBuilder(null) throws exception.
// Use special uncommon trap instead of
// calling normal do_null_check().
Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne);
IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN);
*** 1507,1521 ****
--- 1775,1791 ----
// Fallthrough to add string length.
}
case StringConcat::StringMode: {
const Type* type = kit.gvn().type(arg);
Node* count = NULL;
+ Node* arg_coder = NULL;
if (type == TypePtr::NULL_PTR) {
// replace the argument with the null checked version
arg = null_string;
sc->set_argument(argi, arg);
count = kit.load_String_length(kit.control(), arg);
+ arg_coder = kit.load_String_coder(kit.control(), arg);
} else if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
// s = s != null ? s : "null";
// length = length + (s.count - s.offset);
RegionNode *r = new RegionNode(3);
kit.gvn().set_type(r, Type::CONTROL);
*** 1535,1556 ****
--- 1805,1875 ----
C->record_for_igvn(phi);
// replace the argument with the null checked version
arg = phi;
sc->set_argument(argi, arg);
count = kit.load_String_length(kit.control(), arg);
+ arg_coder = kit.load_String_coder(kit.control(), arg);
} else {
// A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP
// kit.control might be a different test, that can be hoisted above the actual nullcheck
// in case, that the control input is not null, Ideal_common_DU_postCCP will not look for a nullcheck.
count = kit.load_String_length(NULL, arg);
+ arg_coder = kit.load_String_coder(NULL, arg);
+ }
+ if (arg->is_Con()) {
+ // Constant string. Get constant coder and length.
+ jbyte const_coder = get_constant_coder(kit, arg);
+ int const_length = get_constant_length(kit, arg);
+ if (const_coder == java_lang_String::CODER_LATIN1) {
+ // Can be latin1 encoded
+ arg_coder = __ intcon(const_coder);
+ count = __ intcon(const_length);
+ } else {
+ // Found UTF16 encoded string. Fix result array encoding to UTF16.
+ coder_fixed = true;
+ coder = __ intcon(const_coder);
+ count = __ intcon(const_length / 2);
+ }
+ }
+
+ if (!coder_fixed) {
+ coder = __ OrI(coder, arg_coder);
}
length = __ AddI(length, count);
string_sizes->init_req(argi, NULL);
break;
}
case StringConcat::CharMode: {
// one character only
+ const TypeInt* t = kit.gvn().type(arg)->is_int();
+ if (!coder_fixed && t->is_con()) {
+ // Constant char
+ if (t->get_con() <= 255) {
+ // Can be latin1 encoded
+ coder = __ OrI(coder, __ intcon(java_lang_String::CODER_LATIN1));
+ } else {
+ // Must be UTF16 encoded. Fix result array encoding to UTF16.
+ coder_fixed = true;
+ coder = __ intcon(java_lang_String::CODER_UTF16);
+ }
+ } else if (!coder_fixed) {
+ // Not constant
+ #undef __
+ #define __ ideal.
+ IdealKit ideal(&kit, true, true);
+ IdealVariable char_coder(ideal); __ declarations_done();
+ // Check if character can be latin1 encoded
+ __ if_then(arg, BoolTest::le, __ ConI(0xFF));
+ __ set(char_coder, __ ConI(java_lang_String::CODER_LATIN1));
+ __ else_();
+ __ set(char_coder, __ ConI(java_lang_String::CODER_UTF16));
+ __ end_if();
+ kit.sync_kit(ideal);
+ coder = __ OrI(coder, __ value(char_coder));
+ #undef __
+ #define __ kit.
+ }
length = __ AddI(length, __ intcon(1));
break;
}
default:
ShouldNotReachHere();
*** 1574,1630 ****
Deoptimization::Action_make_not_entrant);
}
Node* result;
if (!kit.stopped()) {
! Node* char_array = NULL;
if (sc->num_arguments() == 1 &&
(sc->mode(0) == StringConcat::StringMode ||
sc->mode(0) == StringConcat::StringNullCheckMode)) {
// Handle the case when there is only a single String argument.
// In this case, we can just pull the value from the String itself.
! char_array = kit.load_String_value(kit.control(), sc->argument(0));
} else {
! // length now contains the number of characters needed for the
! // char[] so create a new AllocateArray for the char[]
! {
! PreserveReexecuteState preexecs(&kit);
! // The original jvms is for an allocation of either a String or
! // StringBuffer so no stack adjustment is necessary for proper
! // reexecution. If we deoptimize in the slow path the bytecode
! // will be reexecuted and the char[] allocation will be thrown away.
! kit.jvms()->set_should_reexecute(true);
! char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))),
! length, 1);
! }
! // Mark the allocation so that zeroing is skipped since the code
! // below will overwrite the entire array
! AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn);
! char_alloc->maybe_set_complete(_gvn);
!
! // Now copy the string representations into the final char[]
Node* start = __ intcon(0);
for (int argi = 0; argi < sc->num_arguments(); argi++) {
Node* arg = sc->argument(argi);
switch (sc->mode(argi)) {
case StringConcat::IntMode: {
! Node* end = __ AddI(start, string_sizes->in(argi));
! // getChars words backwards so pass the ending point as well as the start
! int_getChars(kit, arg, char_array, start, end);
! start = end;
break;
}
case StringConcat::StringNullCheckMode:
case StringConcat::StringMode: {
! start = copy_string(kit, arg, char_array, start);
break;
}
case StringConcat::CharMode: {
! __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
! arg, T_CHAR, char_adr_idx, MemNode::unordered);
! start = __ AddI(start, __ intcon(1));
break;
}
default:
ShouldNotReachHere();
}
--- 1893,1932 ----
Deoptimization::Action_make_not_entrant);
}
Node* result;
if (!kit.stopped()) {
! assert(CompactStrings || (coder->is_Con() && coder->get_int() == java_lang_String::CODER_UTF16),
! "Result string must be UTF16 encoded if CompactStrings is disabled");
!
! Node* dst_array = NULL;
if (sc->num_arguments() == 1 &&
(sc->mode(0) == StringConcat::StringMode ||
sc->mode(0) == StringConcat::StringNullCheckMode)) {
// Handle the case when there is only a single String argument.
// In this case, we can just pull the value from the String itself.
! dst_array = kit.load_String_value(kit.control(), sc->argument(0));
} else {
! // Allocate destination byte array according to coder
! dst_array = allocate_byte_array(kit, NULL, __ LShiftI(length, coder));
! // Now copy the string representations into the final byte[]
Node* start = __ intcon(0);
for (int argi = 0; argi < sc->num_arguments(); argi++) {
Node* arg = sc->argument(argi);
switch (sc->mode(argi)) {
case StringConcat::IntMode: {
! start = int_getChars(kit, arg, dst_array, coder, start, string_sizes->in(argi));
break;
}
case StringConcat::StringNullCheckMode:
case StringConcat::StringMode: {
! start = copy_string(kit, arg, dst_array, coder, start);
break;
}
case StringConcat::CharMode: {
! start = copy_char(kit, arg, dst_array, coder, start);
break;
}
default:
ShouldNotReachHere();
}
*** 1640,1655 ****
// reexecution.
kit.jvms()->set_should_reexecute(true);
result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass())));
}
! // Intialize the string
! if (java_lang_String::has_offset_field()) {
! kit.store_String_offset(kit.control(), result, __ intcon(0));
! kit.store_String_length(kit.control(), result, length);
! }
! kit.store_String_value(kit.control(), result, char_array);
} else {
result = C->top();
}
// hook up the outgoing control and result
kit.replace_call(sc->end(), result);
--- 1942,1954 ----
// reexecution.
kit.jvms()->set_should_reexecute(true);
result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass())));
}
! // Initialize the string
! kit.store_String_value(kit.control(), result, dst_array);
! kit.store_String_coder(kit.control(), result, coder);
} else {
result = C->top();
}
// hook up the outgoing control and result
kit.replace_call(sc->end(), result);
< prev index next >