| Index: src/x64/builtins-x64.cc
|
| diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
|
| index 685701ef740161dd4fa32f653c55c9f6a40438b4..a244c98558732f9a1b762332886e828050c1bfbb 100644
|
| --- a/src/x64/builtins-x64.cc
|
| +++ b/src/x64/builtins-x64.cc
|
| @@ -1312,121 +1312,75 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
|
| // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
|
| // -- rsp[(argc + 1) * 8] : receiver
|
| // -----------------------------------
|
| - Counters* counters = masm->isolate()->counters();
|
| - __ IncrementCounter(counters->string_ctor_calls(), 1);
|
| -
|
| - if (FLAG_debug_code) {
|
| - __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, rcx);
|
| - __ cmpp(rdi, rcx);
|
| - __ Assert(equal, kUnexpectedStringFunction);
|
| - }
|
| -
|
| - // Load the first argument into rax and get rid of the rest
|
| - // (including the receiver).
|
| - StackArgumentsAccessor args(rsp, rax);
|
| - Label no_arguments;
|
| - __ testp(rax, rax);
|
| - __ j(zero, &no_arguments);
|
| - __ movp(rbx, args.GetArgumentOperand(1));
|
| - __ PopReturnAddressTo(rcx);
|
| - __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
|
| - __ PushReturnAddressFrom(rcx);
|
| - __ movp(rax, rbx);
|
| -
|
| - // Lookup the argument in the number to string cache.
|
| - Label not_cached, argument_is_string;
|
| - __ LookupNumberStringCache(rax, // Input.
|
| - rbx, // Result.
|
| - rcx, // Scratch 1.
|
| - rdx, // Scratch 2.
|
| - ¬_cached);
|
| - __ IncrementCounter(counters->string_ctor_cached_number(), 1);
|
| - __ bind(&argument_is_string);
|
| -
|
| - // ----------- S t a t e -------------
|
| - // -- rbx : argument converted to string
|
| - // -- rdi : constructor function
|
| - // -- rsp[0] : return address
|
| - // -----------------------------------
|
|
|
| - // Allocate a JSValue and put the tagged pointer into rax.
|
| - Label gc_required;
|
| - __ Allocate(JSValue::kSize,
|
| - rax, // Result.
|
| - rcx, // New allocation top (we ignore it).
|
| - no_reg,
|
| - &gc_required,
|
| - TAG_OBJECT);
|
| -
|
| - // Set the map.
|
| - __ LoadGlobalFunctionInitialMap(rdi, rcx);
|
| - if (FLAG_debug_code) {
|
| - __ cmpb(FieldOperand(rcx, Map::kInstanceSizeOffset),
|
| - Immediate(JSValue::kSize >> kPointerSizeLog2));
|
| - __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
|
| - __ cmpb(FieldOperand(rcx, Map::kUnusedPropertyFieldsOffset), Immediate(0));
|
| - __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
|
| + // 1. Load the first argument into rbx and get rid of the rest (including the
|
| + // receiver).
|
| + {
|
| + StackArgumentsAccessor args(rsp, rax);
|
| + Label no_arguments, done;
|
| + __ testp(rax, rax);
|
| + __ j(zero, &no_arguments, Label::kNear);
|
| + __ movp(rbx, args.GetArgumentOperand(1));
|
| + __ jmp(&done, Label::kNear);
|
| + __ bind(&no_arguments);
|
| + __ LoadRoot(rbx, Heap::kempty_stringRootIndex);
|
| + __ bind(&done);
|
| + __ PopReturnAddressTo(rcx);
|
| + __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
|
| + __ PushReturnAddressFrom(rcx);
|
| }
|
| - __ movp(FieldOperand(rax, HeapObject::kMapOffset), rcx);
|
| -
|
| - // Set properties and elements.
|
| - __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
|
| - __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rcx);
|
| - __ movp(FieldOperand(rax, JSObject::kElementsOffset), rcx);
|
| -
|
| - // Set the value.
|
| - __ movp(FieldOperand(rax, JSValue::kValueOffset), rbx);
|
|
|
| - // Ensure the object is fully initialized.
|
| - STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
|
| -
|
| - // We're done. Return.
|
| - __ ret(0);
|
| -
|
| - // 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);
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - __ JumpIfSmi(rax, &convert_argument);
|
| - Condition is_string = masm->IsObjectStringType(rax, rbx, rcx);
|
| - __ j(NegateCondition(is_string), &convert_argument);
|
| - __ movp(rbx, rax);
|
| - __ IncrementCounter(counters->string_ctor_string_value(), 1);
|
| - __ jmp(&argument_is_string);
|
| -
|
| - // Invoke the conversion builtin and put the result into rbx.
|
| - __ bind(&convert_argument);
|
| - __ IncrementCounter(counters->string_ctor_conversions(), 1);
|
| + // 2. Make sure rbx is a string.
|
| {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - __ Push(rdi); // Preserve the function.
|
| - ToStringStub stub(masm->isolate());
|
| - __ CallStub(&stub);
|
| - __ Pop(rdi);
|
| + Label convert, done_convert;
|
| + __ JumpIfSmi(rbx, &convert, Label::kNear);
|
| + __ CmpObjectType(rbx, FIRST_NONSTRING_TYPE, rdx);
|
| + __ j(below, &done_convert);
|
| + __ bind(&convert);
|
| + {
|
| + FrameScope scope(masm, StackFrame::INTERNAL);
|
| + ToStringStub stub(masm->isolate());
|
| + __ Move(rax, rbx);
|
| + __ CallStub(&stub);
|
| + __ Move(rbx, rax);
|
| + }
|
| + __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, rdi);
|
| + __ bind(&done_convert);
|
| }
|
| - __ movp(rbx, rax);
|
| - __ jmp(&argument_is_string);
|
|
|
| - // Load the empty string into rbx, remove the receiver from the
|
| - // stack, and jump back to the case where the argument is a string.
|
| - __ bind(&no_arguments);
|
| - __ LoadRoot(rbx, Heap::kempty_stringRootIndex);
|
| - __ PopReturnAddressTo(rcx);
|
| - __ leap(rsp, Operand(rsp, kPointerSize));
|
| - __ PushReturnAddressFrom(rcx);
|
| - __ jmp(&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);
|
| + // 3. Allocate a JSValue wrapper for the string.
|
| {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - __ Push(rbx);
|
| - __ CallRuntime(Runtime::kNewStringWrapper, 1);
|
| + // ----------- S t a t e -------------
|
| + // -- rbx : the first argument
|
| + // -- rdi : constructor function
|
| + // -----------------------------------
|
| +
|
| + Label allocate, done_allocate;
|
| + __ Allocate(JSValue::kSize, rax, rcx, no_reg, &allocate, TAG_OBJECT);
|
| + __ bind(&done_allocate);
|
| +
|
| + // Initialize the JSValue in rax.
|
| + __ LoadGlobalFunctionInitialMap(rdi, rcx);
|
| + __ movp(FieldOperand(rax, HeapObject::kMapOffset), rcx);
|
| + __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
|
| + __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rcx);
|
| + __ movp(FieldOperand(rax, JSObject::kElementsOffset), rcx);
|
| + __ movp(FieldOperand(rax, JSValue::kValueOffset), rbx);
|
| + STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
|
| + __ Ret();
|
| +
|
| + // Fallback to the runtime to allocate in new space.
|
| + __ bind(&allocate);
|
| + {
|
| + FrameScope scope(masm, StackFrame::INTERNAL);
|
| + __ Push(rbx);
|
| + __ Push(Smi::FromInt(JSValue::kSize));
|
| + __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
| + __ Pop(rbx);
|
| + }
|
| + __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, rdi);
|
| + __ jmp(&done_allocate);
|
| }
|
| - __ ret(0);
|
| }
|
|
|
|
|
|
|