| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 99eb21fa2e698caee89005ea9655542832cc5bbe..b93b40813379fbf8b0e0b39d08ad1b24f73250c1 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -1990,6 +1990,7 @@ const char* TRBinaryOpIC::GetName(TypeInfo type_info) {
|
| case INT32: return "Int32s";
|
| case HEAP_NUMBER: return "HeapNumbers";
|
| case ODDBALL: return "Oddball";
|
| + case BOTH_STRING: return "BothStrings";
|
| case STRING: return "Strings";
|
| case GENERIC: return "Generic";
|
| default: return "Invalid";
|
| @@ -2005,6 +2006,7 @@ TRBinaryOpIC::State TRBinaryOpIC::ToState(TypeInfo type_info) {
|
| case INT32:
|
| case HEAP_NUMBER:
|
| case ODDBALL:
|
| + case BOTH_STRING:
|
| case STRING:
|
| return MONOMORPHIC;
|
| case GENERIC:
|
| @@ -2019,12 +2021,17 @@ TRBinaryOpIC::TypeInfo TRBinaryOpIC::JoinTypes(TRBinaryOpIC::TypeInfo x,
|
| TRBinaryOpIC::TypeInfo y) {
|
| if (x == UNINITIALIZED) return y;
|
| if (y == UNINITIALIZED) return x;
|
| - if (x == STRING && y == STRING) return STRING;
|
| - if (x == STRING || y == STRING) return GENERIC;
|
| - if (x >= y) return x;
|
| + if (x == y) return x;
|
| + if (x == BOTH_STRING && y == STRING) return STRING;
|
| + if (x == STRING && y == BOTH_STRING) return STRING;
|
| + if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) {
|
| + return GENERIC;
|
| + }
|
| + if (x > y) return x;
|
| return y;
|
| }
|
|
|
| +
|
| TRBinaryOpIC::TypeInfo TRBinaryOpIC::GetTypeInfo(Handle<Object> left,
|
| Handle<Object> right) {
|
| ::v8::internal::TypeInfo left_type =
|
| @@ -2046,9 +2053,11 @@ TRBinaryOpIC::TypeInfo TRBinaryOpIC::GetTypeInfo(Handle<Object> left,
|
| return HEAP_NUMBER;
|
| }
|
|
|
| - if (left_type.IsString() || right_type.IsString()) {
|
| - // Patching for fast string ADD makes sense even if only one of the
|
| - // arguments is a string.
|
| + // Patching for fast string ADD makes sense even if only one of the
|
| + // arguments is a string.
|
| + if (left_type.IsString()) {
|
| + return right_type.IsString() ? BOTH_STRING : STRING;
|
| + } else if (right_type.IsString()) {
|
| return STRING;
|
| }
|
|
|
| @@ -2081,11 +2090,11 @@ RUNTIME_FUNCTION(MaybeObject*, TypeRecordingBinaryOp_Patch) {
|
| TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right);
|
| type = TRBinaryOpIC::JoinTypes(type, previous_type);
|
| TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED;
|
| - if (type == TRBinaryOpIC::STRING && op != Token::ADD) {
|
| + if ((type == TRBinaryOpIC::STRING || type == TRBinaryOpIC::BOTH_STRING) &&
|
| + op != Token::ADD) {
|
| type = TRBinaryOpIC::GENERIC;
|
| }
|
| - if (type == TRBinaryOpIC::SMI &&
|
| - previous_type == TRBinaryOpIC::SMI) {
|
| + if (type == TRBinaryOpIC::SMI && previous_type == TRBinaryOpIC::SMI) {
|
| if (op == Token::DIV || op == Token::MUL || kSmiValueSize == 32) {
|
| // Arithmetic on two Smi inputs has yielded a heap number.
|
| // That is the only way to get here from the Smi stub.
|
| @@ -2097,8 +2106,7 @@ RUNTIME_FUNCTION(MaybeObject*, TypeRecordingBinaryOp_Patch) {
|
| result_type = TRBinaryOpIC::INT32;
|
| }
|
| }
|
| - if (type == TRBinaryOpIC::INT32 &&
|
| - previous_type == TRBinaryOpIC::INT32) {
|
| + if (type == TRBinaryOpIC::INT32 && previous_type == TRBinaryOpIC::INT32) {
|
| // We must be here because an operation on two INT32 types overflowed.
|
| result_type = TRBinaryOpIC::HEAP_NUMBER;
|
| }
|
|
|