Chromium Code Reviews| Index: src/arm/builtins-arm.cc |
| diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc |
| index c29c65662bfa2999b202f40e84cf34ca5b21f772..b01424e996eeb90a9ade1a9770da01e491431c3f 100644 |
| --- a/src/arm/builtins-arm.cc |
| +++ b/src/arm/builtins-arm.cc |
| @@ -144,121 +144,74 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { |
| // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) |
| // -- sp[argc * 4] : receiver |
| // ----------------------------------- |
| - Counters* counters = masm->isolate()->counters(); |
| - __ IncrementCounter(counters->string_ctor_calls(), 1, r2, r3); |
| - Register function = r1; |
| - if (FLAG_debug_code) { |
| - __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r2); |
| - __ cmp(function, Operand(r2)); |
| - __ Assert(eq, kUnexpectedStringFunction); |
| + // 1. Load the first argument into r2 and get rid of the rest (including the |
| + // receiver). |
| + { |
| + Label no_arguments, done; |
| + __ cmp(r0, Operand(0)); |
| + __ b(eq, &no_arguments); |
| + __ sub(r0, r0, Operand(1)); |
| + __ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); |
| + __ Drop(2); |
| + __ b(&done); |
| + __ bind(&no_arguments); |
| + __ LoadRoot(r2, Heap::kempty_stringRootIndex); |
| + __ Drop(1); |
| + __ bind(&done); |
| } |
| - // Load the first arguments in r0 and get rid of the rest. |
| - Label no_arguments; |
| - __ cmp(r0, Operand::Zero()); |
| - __ b(eq, &no_arguments); |
| - // First args = sp[(argc - 1) * 4]. |
| - __ sub(r0, r0, Operand(1)); |
| - __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); |
| - // sp now point to args[0], drop args[0] + receiver. |
| - __ Drop(2); |
| - |
| - Register argument = r2; |
| - Label not_cached, argument_is_string; |
| - __ LookupNumberStringCache(r0, // Input. |
| - argument, // Result. |
| - r3, // Scratch. |
| - r4, // Scratch. |
| - r5, // Scratch. |
| - ¬_cached); |
| - __ IncrementCounter(counters->string_ctor_cached_number(), 1, r3, r4); |
| - __ bind(&argument_is_string); |
| - |
| - // ----------- S t a t e ------------- |
| - // -- r2 : argument converted to string |
| - // -- r1 : constructor function |
| - // -- lr : return address |
| - // ----------------------------------- |
| - |
| - Label gc_required; |
| - __ Allocate(JSValue::kSize, |
| - r0, // Result. |
| - r3, // Scratch. |
| - r4, // Scratch. |
| - &gc_required, |
| - TAG_OBJECT); |
| - |
| - // Initialising the String Object. |
| - Register map = r3; |
| - __ LoadGlobalFunctionInitialMap(function, map, r4); |
| - if (FLAG_debug_code) { |
| - __ ldrb(r4, FieldMemOperand(map, Map::kInstanceSizeOffset)); |
| - __ cmp(r4, Operand(JSValue::kSize >> kPointerSizeLog2)); |
| - __ Assert(eq, kUnexpectedStringWrapperInstanceSize); |
| - __ ldrb(r4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset)); |
| - __ cmp(r4, Operand::Zero()); |
| - __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper); |
| + // 2. Make sure r2 is a string. |
| + { |
| + Label convert, done_convert; |
| + __ JumpIfSmi(r2, &convert); |
| + __ CompareObjectType(r2, r3, r3, FIRST_NONSTRING_TYPE); |
| + __ b(lo, &done_convert); |
| + __ bind(&convert); |
| + { |
| + FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| + ToStringStub stub(masm->isolate()); |
| + __ Move(r0, r2); |
| + __ CallStub(&stub); |
| + __ Move(r2, r0); |
| + } |
| + __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r1); |
|
Jarin
2015/09/14 07:11:40
Maybe some comment about the incoming r1 being the
Benedikt Meurer
2015/09/14 07:26:39
Done.
|
| + __ bind(&done_convert); |
| } |
| - __ str(map, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| - __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); |
| - __ str(r3, FieldMemOperand(r0, JSObject::kPropertiesOffset)); |
| - __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset)); |
| - |
| - __ str(argument, FieldMemOperand(r0, JSValue::kValueOffset)); |
| - |
| - // Ensure the object is fully initialized. |
| - STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); |
| + // 3. Allocate a JSValue wrapper for the string. |
| + { |
| + // ----------- S t a t e ------------- |
| + // -- r1 : constructor function |
| + // -- r2 : the first argument |
| + // -- lr : return address |
| + // ----------------------------------- |
| - __ Ret(); |
| + Label allocate, done_allocate; |
| + __ Allocate(JSValue::kSize, r0, r3, r4, &allocate, TAG_OBJECT); |
| + __ bind(&done_allocate); |
| + |
| + // Initialize the JSValue in eax. |
| + __ LoadGlobalFunctionInitialMap(r1, r3, r4); |
| + __ str(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| + __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); |
| + __ str(r3, FieldMemOperand(r0, JSObject::kPropertiesOffset)); |
| + __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset)); |
| + __ str(r2, FieldMemOperand(r0, JSValue::kValueOffset)); |
| + STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); |
| + __ Ret(); |
| - // The argument was not found in the number to string cache. Check |
| - // if it's a string already before calling the conversion builtin. |
| - Label convert_argument; |
| - __ bind(¬_cached); |
| - __ JumpIfSmi(r0, &convert_argument); |
| - |
| - // Is it a String? |
| - __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| - __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| - STATIC_ASSERT(kNotStringTag != 0); |
| - __ tst(r3, Operand(kIsNotStringMask)); |
| - __ b(ne, &convert_argument); |
| - __ mov(argument, r0); |
| - __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4); |
| - __ b(&argument_is_string); |
| - |
| - // Invoke the conversion builtin and put the result into r2. |
| - __ bind(&convert_argument); |
| - __ push(function); // Preserve the function. |
| - __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4); |
| - { |
| - FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| - ToStringStub stub(masm->isolate()); |
| - __ CallStub(&stub); |
| - } |
| - __ pop(function); |
| - __ mov(argument, r0); |
| - __ b(&argument_is_string); |
| - |
| - // Load the empty string into r2, remove the receiver from the |
| - // stack, and jump back to the case where the argument is a string. |
| - __ bind(&no_arguments); |
| - __ LoadRoot(argument, Heap::kempty_stringRootIndex); |
| - __ Drop(1); |
| - __ b(&argument_is_string); |
| - |
| - // At this point the argument is already a string. Call runtime to |
| - // create a string wrapper. |
| - __ bind(&gc_required); |
| - __ IncrementCounter(counters->string_ctor_gc_required(), 1, r3, r4); |
| - { |
| - FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| - __ push(argument); |
| - __ CallRuntime(Runtime::kNewStringWrapper, 1); |
| + // Fallback to the runtime to allocate in new space. |
| + __ bind(&allocate); |
| + { |
| + FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| + __ Move(r3, Smi::FromInt(JSValue::kSize)); |
| + __ Push(r1, r2, r3); |
| + __ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
| + __ Pop(r1, r2); |
| + } |
| + __ b(&done_allocate); |
| } |
| - __ Ret(); |
| } |