| Index: src/arm/code-stubs-arm.cc
|
| ===================================================================
|
| --- src/arm/code-stubs-arm.cc (revision 6823)
|
| +++ src/arm/code-stubs-arm.cc (working copy)
|
| @@ -2961,22 +2961,26 @@
|
|
|
| Register left = r1;
|
| Register right = r0;
|
| - Label call_runtime;
|
| + Label left_not_string, call_runtime;
|
|
|
| - // Check if first argument is a string.
|
| - __ JumpIfSmi(left, &call_runtime);
|
| + // Check if left argument is a string.
|
| + __ JumpIfSmi(left, &left_not_string);
|
| __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE);
|
| - __ b(ge, &call_runtime);
|
| + __ b(ge, &left_not_string);
|
|
|
| - // First argument is a a string, test second.
|
| + StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
|
| + GenerateRegisterArgsPush(masm);
|
| + __ TailCallStub(&string_add_left_stub);
|
| +
|
| + // Left operand is not a string, test right.
|
| + __ bind(&left_not_string);
|
| __ JumpIfSmi(right, &call_runtime);
|
| __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE);
|
| __ b(ge, &call_runtime);
|
|
|
| - // First and second argument are strings.
|
| - StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
|
| + StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
|
| GenerateRegisterArgsPush(masm);
|
| - __ TailCallStub(&string_add_stub);
|
| + __ TailCallStub(&string_add_right_stub);
|
|
|
| // At least one argument is not a string.
|
| __ bind(&call_runtime);
|
| @@ -5442,18 +5446,19 @@
|
|
|
|
|
| void StringAddStub::Generate(MacroAssembler* masm) {
|
| - Label string_add_runtime;
|
| + Label string_add_runtime, call_builtin;
|
| + Builtins::JavaScript builtin_id = Builtins::ADD;
|
| +
|
| // Stack on entry:
|
| - // sp[0]: second argument.
|
| - // sp[4]: first argument.
|
| + // sp[0]: second argument (right).
|
| + // sp[4]: first argument (left).
|
|
|
| // Load the two arguments.
|
| __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument.
|
| __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
|
|
|
| // Make sure that both arguments are strings if not known in advance.
|
| - if (string_check_) {
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| + if (flags_ == NO_STRING_ADD_FLAGS) {
|
| __ JumpIfEitherSmi(r0, r1, &string_add_runtime);
|
| // Load instance types.
|
| __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| @@ -5465,13 +5470,27 @@
|
| __ tst(r4, Operand(kIsNotStringMask));
|
| __ tst(r5, Operand(kIsNotStringMask), eq);
|
| __ b(ne, &string_add_runtime);
|
| + } else {
|
| + // Here at least one of the arguments is definitely a string.
|
| + // We convert the one that is not known to be a string.
|
| + if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
|
| + ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
|
| + GenerateConvertArgument(
|
| + masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin);
|
| + builtin_id = Builtins::STRING_ADD_RIGHT;
|
| + } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
|
| + ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
|
| + GenerateConvertArgument(
|
| + masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin);
|
| + builtin_id = Builtins::STRING_ADD_LEFT;
|
| + }
|
| }
|
|
|
| // Both arguments are strings.
|
| // r0: first string
|
| // r1: second string
|
| - // r4: first string instance type (if string_check_)
|
| - // r5: second string instance type (if string_check_)
|
| + // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| + // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| {
|
| Label strings_not_empty;
|
| // Check if either of the strings are empty. In that case return the other.
|
| @@ -5499,8 +5518,8 @@
|
| // r1: second string
|
| // r2: length of first string
|
| // r3: length of second string
|
| - // r4: first string instance type (if string_check_)
|
| - // r5: second string instance type (if string_check_)
|
| + // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| + // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| // Look at the length of the result of adding the two strings.
|
| Label string_add_flat_result, longer_than_two;
|
| // Adding two lengths can't overflow.
|
| @@ -5512,7 +5531,7 @@
|
| __ b(ne, &longer_than_two);
|
|
|
| // Check that both strings are non-external ascii strings.
|
| - if (!string_check_) {
|
| + if (flags_ != NO_STRING_ADD_FLAGS) {
|
| __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
|
| __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
|
| @@ -5560,7 +5579,7 @@
|
|
|
| // If result is not supposed to be flat, allocate a cons string object.
|
| // If both strings are ascii the result is an ascii cons string.
|
| - if (!string_check_) {
|
| + if (flags_ != NO_STRING_ADD_FLAGS) {
|
| __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
|
| __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
|
| @@ -5608,11 +5627,11 @@
|
| // r1: second string
|
| // r2: length of first string
|
| // r3: length of second string
|
| - // r4: first string instance type (if string_check_)
|
| - // r5: second string instance type (if string_check_)
|
| + // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| + // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
|
| // r6: sum of lengths.
|
| __ bind(&string_add_flat_result);
|
| - if (!string_check_) {
|
| + if (flags_ != NO_STRING_ADD_FLAGS) {
|
| __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
|
| __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
|
| @@ -5710,9 +5729,63 @@
|
| // Just jump to runtime to add the two strings.
|
| __ bind(&string_add_runtime);
|
| __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
|
| +
|
| + if (call_builtin.is_linked()) {
|
| + __ bind(&call_builtin);
|
| + __ InvokeBuiltin(builtin_id, JUMP_JS);
|
| + }
|
| }
|
|
|
|
|
| +void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
|
| + int stack_offset,
|
| + Register arg,
|
| + Register scratch1,
|
| + Register scratch2,
|
| + Register scratch3,
|
| + Register scratch4,
|
| + Label* slow) {
|
| + // First check if the argument is already a string.
|
| + Label not_string, done;
|
| + __ JumpIfSmi(arg, ¬_string);
|
| + __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE);
|
| + __ b(lt, &done);
|
| +
|
| + // Check the number to string cache.
|
| + Label not_cached;
|
| + __ bind(¬_string);
|
| + // Puts the cached result into scratch1.
|
| + NumberToStringStub::GenerateLookupNumberStringCache(masm,
|
| + arg,
|
| + scratch1,
|
| + scratch2,
|
| + scratch3,
|
| + scratch4,
|
| + false,
|
| + ¬_cached);
|
| + __ mov(arg, scratch1);
|
| + __ str(arg, MemOperand(sp, stack_offset));
|
| + __ jmp(&done);
|
| +
|
| + // Check if the argument is a safe string wrapper.
|
| + __ bind(¬_cached);
|
| + __ JumpIfSmi(arg, slow);
|
| + __ CompareObjectType(
|
| + arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1.
|
| + __ b(ne, slow);
|
| + __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
|
| + __ and_(scratch2,
|
| + scratch2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
|
| + __ cmp(scratch2,
|
| + Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
|
| + __ b(ne, slow);
|
| + __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset));
|
| + __ str(arg, MemOperand(sp, stack_offset));
|
| +
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| void StringCharAtStub::Generate(MacroAssembler* masm) {
|
| // Expects two arguments (object, index) on the stack:
|
| // lr: return address
|
|
|