Index: runtime/vm/flow_graph_optimizer.cc |
=================================================================== |
--- runtime/vm/flow_graph_optimizer.cc (revision 31282) |
+++ runtime/vm/flow_graph_optimizer.cc (working copy) |
@@ -1481,6 +1481,122 @@ |
} |
+static bool IsStringFromCharCode(Definition* d) { |
+ return (d->IsStringCharCode() && |
+ (d->AsStringCharCode()->kind() == StringCharCodeInstr::kFromCharCode)); |
+} |
+ |
+ |
+// Return true if d is a string of length one (a constant or result from |
+// from string-from-char-code instruction. |
+static bool IsLengthOneString(Definition* d) { |
+ if (d->IsConstant()) { |
+ const Object& obj = d->AsConstant()->value(); |
+ if (obj.IsString()) { |
+ return String::Cast(obj).Length() == 1; |
+ } else { |
+ return false; |
+ } |
+ } else { |
+ return IsStringFromCharCode(d); |
+ } |
+} |
+ |
+ |
+// Returns true if the string comparison was converted into char-code |
+// comparison. Conversion is only possible for strings of length one. |
+// E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
+// TODO(srdjan): Expand for two-byte and external strings. |
+bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
+ Token::Kind op_kind) { |
+ ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
+ // Check that left and right are length one strings (either string constants |
+ // or results of string-from-char-code. |
+ Definition* left = call->ArgumentAt(0); |
+ Definition* right = call->ArgumentAt(1); |
+ Value* left_val = NULL; |
+ Definition* to_remove_left = NULL; |
+ if (IsLengthOneString(right)) { |
+ // Swap, since we know that both arguments are strings |
+ Definition* temp = left; |
+ left = right; |
+ right = temp; |
+ } |
+ if (IsLengthOneString(left)) { |
+ // Optimize if left is a string with length one (either constant or |
+ // result of string-from-char-code. |
+ if (left->IsConstant()) { |
+ ConstantInstr* left_const = left->AsConstant(); |
+ const String& str = String::Cast(left_const->value()); |
+ ASSERT(str.Length() == 1); |
+ ConstantInstr* char_code_left = |
+ new ConstantInstr(Smi::ZoneHandle(Smi::New(str.CharAt(0)))); |
Florian Schneider
2013/12/20 09:29:12
Use flow_graph()->GetConstant(Smi::Handle(Smi::New
srdjan
2013/12/20 19:48:03
Done, and using ZoneHandle since the handle escape
|
+ InsertBefore(call, char_code_left, NULL, Definition::kValue); |
+ left_val = new Value(char_code_left); |
+ } else if (IsStringFromCharCode(left)) { |
+ // Use input of string-from-charcode as left value. |
+ StringCharCodeInstr* instr = left->AsStringCharCode(); |
+ left_val = new Value(instr->char_code()->definition()); |
+ to_remove_left = instr; |
+ } else { |
+ // IsLengthOneString(left) should have been false. |
+ UNREACHABLE(); |
+ } |
+ |
+ Definition* to_remove_right = NULL; |
+ Value* right_val = NULL; |
+ if (IsStringFromCharCode(right)) { |
+ // Skip string-from-char-code, and use its input as right value. |
+ StringCharCodeInstr* right_instr = right->AsStringCharCode(); |
+ right_val = new Value(right_instr->char_code()->definition()); |
+ to_remove_right = right_instr; |
+ } else { |
+ const ICData& unary_checks_1 = |
+ ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
+ AddCheckClass(right, |
+ unary_checks_1, |
+ call->deopt_id(), |
+ call->env(), |
+ call); |
+ // String-to-char-code instructions returns -1 (illegal charcode) if |
+ // string is not of length one. |
+ StringCharCodeInstr* char_code_right = new StringCharCodeInstr( |
+ new Value(right), |
+ kOneByteStringCid, |
+ StringCharCodeInstr::kToCharCode); |
+ InsertBefore(call, char_code_right, call->env(), Definition::kValue); |
+ right_val = new Value(char_code_right); |
+ } |
+ |
+ // Comparing char-codes instead of strings. |
+ EqualityCompareInstr* comp = |
+ new EqualityCompareInstr(call->token_pos(), |
+ op_kind, |
+ left_val, |
+ right_val, |
+ kSmiCid, |
+ call->deopt_id()); |
+ ReplaceCall(call, comp); |
+ |
+ // Remove dead instructions. |
+ if ((to_remove_left != NULL) && |
+ (to_remove_left->input_use_list() == NULL)) { |
+ ConstantInstr* null = new ConstantInstr(Instance::ZoneHandle()); |
Florian Schneider
2013/12/20 09:29:12
Use flow_grah()->constant_null().
srdjan
2013/12/20 19:48:03
Done.
|
+ to_remove_left->ReplaceUsesWith(null); |
+ to_remove_left->RemoveFromGraph(); |
+ } |
+ if ((to_remove_right != NULL) && |
+ (to_remove_right->input_use_list() == NULL)) { |
+ ConstantInstr* null = new ConstantInstr(Instance::ZoneHandle()); |
Florian Schneider
2013/12/20 09:29:12
Use flow_grah()->constant_null().
srdjan
2013/12/20 19:48:03
Done.
|
+ to_remove_right->ReplaceUsesWith(null); |
+ to_remove_right->RemoveFromGraph(); |
+ } |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+ |
static bool SmiFitsInDouble() { return kSmiBits < 53; } |
bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
@@ -1493,7 +1609,13 @@ |
Definition* right = call->ArgumentAt(1); |
intptr_t cid = kIllegalCid; |
- if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
+ if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
+ if (TryStringLengthOneEquality(call, op_kind)) { |
+ return true; |
+ } else { |
+ return false; |
+ } |
+ } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
InsertBefore(call, |
new CheckSmiInstr(new Value(left), call->deopt_id()), |
call->env(), |
@@ -2355,9 +2477,10 @@ |
LoadIndexedInstr* load_char_code = |
BuildStringCodeUnitAt(call, class_ids[0]); |
InsertBefore(call, load_char_code, NULL, Definition::kValue); |
- StringFromCharCodeInstr* char_at = |
- new StringFromCharCodeInstr(new Value(load_char_code), |
- kOneByteStringCid); |
+ StringCharCodeInstr* char_at = |
+ new StringCharCodeInstr(new Value(load_char_code), |
+ kOneByteStringCid, |
+ StringCharCodeInstr::kFromCharCode); |
ReplaceCall(call, char_at); |
return true; |
} |
@@ -6661,9 +6784,32 @@ |
} |
-void ConstantPropagator::VisitStringFromCharCode( |
- StringFromCharCodeInstr* instr) { |
- SetValue(instr, non_constant_); |
+void ConstantPropagator::VisitStringCharCode(StringCharCodeInstr* instr) { |
+ if (instr->kind() == StringCharCodeInstr::kFromCharCode) { |
+ const Object& o = instr->char_code()->definition()->constant_value(); |
+ if (IsNonConstant(o)) { |
+ SetValue(instr, non_constant_); |
+ } else if (IsConstant(o)) { |
+ const intptr_t ch_code = Smi::Cast(o).Value(); |
+ ASSERT(ch_code >= 0); |
+ if (ch_code < Symbols::kMaxOneCharCodeSymbol) { |
+ RawString** table = Symbols::PredefinedAddress(); |
+ SetValue(instr, String::ZoneHandle(table[ch_code])); |
+ } else { |
+ SetValue(instr, non_constant_); |
+ } |
+ } |
+ } else { |
+ ASSERT(instr->kind() == StringCharCodeInstr::kToCharCode); |
+ const Object& o = instr->str()->definition()->constant_value(); |
+ if (IsNonConstant(o)) { |
+ SetValue(instr, non_constant_); |
+ } else if (IsConstant(o)) { |
+ const String& str = String::Cast(o); |
+ const intptr_t result = (str.Length() == 1) ? str.CharAt(0) : -1; |
Florian Schneider
2013/12/20 09:29:12
Can the case of Length() > 1 occur at all?
srdjan
2013/12/20 19:48:03
Yes, length 0 as well. StringToCharCode has as its
|
+ SetValue(instr, Smi::ZoneHandle(Smi::New(result))); |
+ } |
+ } |
} |