From: bmeurer Date: Wed, 16 Sep 2015 10:44:36 +0000 (-0700) Subject: [builtins] Unify the String constructor. X-Git-Tag: upstream/4.7.83~281 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a3d6f6cce317dbe1d31079eb81e15e49f3fb687a;p=platform%2Fupstream%2Fv8.git [builtins] Unify the String constructor. Implement the String constructor completely as native builtin, avoiding the need to do gymnastics in JavaScript builtin to properly detect the no argument case (which is different from the undefined argument case) and also allowing to just tailcall through to ToString or SymbolDescriptiveString for the common case. Also the JavaScript builtin was misleading since the case for construct call was unused, but could be triggered in a wrong way once we support tail calls from constructor functions. This refactoring allows us to properly implement subclassing for String builtins, once we have the correct initial_map on derived classes (it's merely a matter of using NewTarget instead of the target register now). This introduces a new %SymbolDescriptiveString runtime entry, which is also used by Symbol.toString() now. R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1344893002 Cr-Commit-Position: refs/heads/master@{#30759} --- diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index 62e25a8fa..c210be554 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -136,7 +136,63 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } -void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { +// static +void Builtins::Generate_StringConstructor(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- r0 : number of arguments + // -- r1 : constructor function + // -- lr : return address + // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) + // -- sp[argc * 4] : receiver + // ----------------------------------- + + // 1. Load the first argument into r0 and get rid of the rest (including the + // receiver). + Label no_arguments; + { + __ sub(r0, r0, Operand(1), SetCC); + __ b(lo, &no_arguments); + __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); + __ Drop(2); + } + + // 2a. At least one argument, return r0 if it's a string, otherwise + // dispatch to appropriate conversion. + Label to_string, symbol_descriptive_string; + { + __ JumpIfSmi(r0, &to_string); + STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); + __ CompareObjectType(r0, r1, r1, FIRST_NONSTRING_TYPE); + __ b(hi, &to_string); + __ b(eq, &symbol_descriptive_string); + __ Ret(); + } + + // 2b. No arguments, return the empty string (and pop the receiver). + __ bind(&no_arguments); + { + __ LoadRoot(r0, Heap::kempty_stringRootIndex); + __ Ret(1); + } + + // 3a. Convert r0 to a string. + __ bind(&to_string); + { + ToStringStub stub(masm->isolate()); + __ TailCallStub(&stub); + } + + // 3b. Convert symbol in r0 to a string. + __ bind(&symbol_descriptive_string); + { + __ Push(r0); + __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1); + } +} + + +// static +void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : number of arguments // -- r1 : constructor function @@ -145,36 +201,33 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // -- sp[argc * 4] : receiver // ----------------------------------- - // 1. Load the first argument into r2 and get rid of the rest (including the + // 1. Load the first argument into r0 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)); + __ sub(r0, r0, Operand(1), SetCC); + __ b(lo, &no_arguments); + __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex)); __ Drop(2); __ b(&done); __ bind(&no_arguments); - __ LoadRoot(r2, Heap::kempty_stringRootIndex); + __ LoadRoot(r0, Heap::kempty_stringRootIndex); __ Drop(1); __ bind(&done); } - // 2. Make sure r2 is a string. + // 2. Make sure r0 is a string. { Label convert, done_convert; - __ JumpIfSmi(r2, &convert); - __ CompareObjectType(r2, r3, r3, FIRST_NONSTRING_TYPE); + __ JumpIfSmi(r0, &convert); + __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE); __ b(lo, &done_convert); __ bind(&convert); { FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); ToStringStub stub(masm->isolate()); __ Push(r1); - __ Move(r0, r2); __ CallStub(&stub); - __ Move(r2, r0); __ Pop(r1); } __ bind(&done_convert); @@ -183,16 +236,17 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // 3. Allocate a JSValue wrapper for the string. { // ----------- S t a t e ------------- + // -- r0 : the first argument // -- r1 : constructor function - // -- r2 : the first argument // -- lr : return address // ----------------------------------- Label allocate, done_allocate; + __ Move(r2, r0); __ Allocate(JSValue::kSize, r0, r3, r4, &allocate, TAG_OBJECT); __ bind(&done_allocate); - // Initialize the JSValue in eax. + // Initialize the JSValue in r0. __ LoadGlobalFunctionInitialMap(r1, r3, r4); __ str(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc index c2b1ec2c3..9cd7cc6c3 100644 --- a/src/arm64/builtins-arm64.cc +++ b/src/arm64/builtins-arm64.cc @@ -131,7 +131,65 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } -void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { +// static +void Builtins::Generate_StringConstructor(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- x0 : number of arguments + // -- x1 : constructor function + // -- lr : return address + // -- sp[(argc - n - 1) * 8] : arg[n] (zero based) + // -- sp[argc * 8] : receiver + // ----------------------------------- + ASM_LOCATION("Builtins::Generate_StringConstructor"); + + // 1. Load the first argument into x0 and get rid of the rest (including the + // receiver). + Label no_arguments; + { + __ Cbz(x0, &no_arguments); + __ Sub(x0, x0, 1); + __ Drop(x0); + __ Ldr(x0, MemOperand(jssp, 2 * kPointerSize, PostIndex)); + } + + // 2a. At least one argument, return x0 if it's a string, otherwise + // dispatch to appropriate conversion. + Label to_string, symbol_descriptive_string; + { + __ JumpIfSmi(x0, &to_string); + STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); + __ CompareObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE); + __ B(hi, &to_string); + __ B(eq, &symbol_descriptive_string); + __ Ret(); + } + + // 2b. No arguments, return the empty string (and pop the receiver). + __ Bind(&no_arguments); + { + __ LoadRoot(x0, Heap::kempty_stringRootIndex); + __ Drop(1); + __ Ret(); + } + + // 3a. Convert x0 to a string. + __ Bind(&to_string); + { + ToStringStub stub(masm->isolate()); + __ TailCallStub(&stub); + } + + // 3b. Convert symbol in x0 to a string. + __ Bind(&symbol_descriptive_string); + { + __ Push(x0); + __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1); + } +} + + +// static +void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- x0 : number of arguments // -- x1 : constructor function @@ -139,7 +197,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // -- sp[(argc - n - 1) * 8] : arg[n] (zero based) // -- sp[argc * 8] : receiver // ----------------------------------- - ASM_LOCATION("Builtins::Generate_StringConstructCode"); + ASM_LOCATION("Builtins::Generate_StringConstructor_ConstructStub"); // 1. Load the first argument into x2 and get rid of the rest (including the // receiver). @@ -147,7 +205,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { Label no_arguments, done; __ Cbz(x0, &no_arguments); __ Sub(x0, x0, 1); - __ Drop(x0, kXRegSize); + __ Drop(x0); __ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex)); __ B(&done); __ Bind(&no_arguments); diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 5d91247e9..0346c8c52 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1118,12 +1118,13 @@ void Genesis::InitializeGlobal(Handle global_object, } { // --- S t r i n g --- - Handle string_fun = - InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize, - isolate->initial_object_prototype(), - Builtins::kIllegal); - string_fun->shared()->set_construct_stub( - isolate->builtins()->builtin(Builtins::kStringConstructCode)); + Handle string_fun = InstallFunction( + global, "String", JS_VALUE_TYPE, JSValue::kSize, + isolate->initial_object_prototype(), Builtins::kStringConstructor); + string_fun->shared()->set_construct_stub(isolate->builtins()->builtin( + Builtins::kStringConstructor_ConstructStub)); + string_fun->shared()->DontAdaptArguments(); + string_fun->shared()->set_length(1); native_context()->set_string_function(*string_fun); Handle string_map = diff --git a/src/builtins.h b/src/builtins.h index 8a55eaa45..aff47f259 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -68,74 +68,75 @@ enum BuiltinExtraArguments { V(RestrictedStrictArgumentsPropertiesThrower, NO_EXTRA_ARGUMENTS) // Define list of builtins implemented in assembly. -#define BUILTIN_LIST_A(V) \ - V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(CallFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(Call, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(PushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(InOptimizationQueue, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(JSConstructStubApi, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(InterpreterEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(InterpreterExitTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(CompileLazy, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(CompileOptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(CompileOptimizedConcurrent, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(NotifySoftDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(NotifyStubFailure, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(NotifyStubFailureSaveDoubles, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(LoadIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(StoreIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, kNoExtraICState) \ - V(KeyedLoadIC_Megamorphic, KEYED_LOAD_IC, MEGAMORPHIC, kNoExtraICState) \ - \ - V(KeyedLoadIC_Megamorphic_Strong, KEYED_LOAD_IC, MEGAMORPHIC, \ - LoadICState::kStrongModeState) \ - \ - V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, \ - StoreICState::kStrictModeState) \ - \ - V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, kNoExtraICState) \ - V(KeyedStoreIC_PreMonomorphic, KEYED_STORE_IC, PREMONOMORPHIC, \ - kNoExtraICState) \ - V(KeyedStoreIC_Megamorphic, KEYED_STORE_IC, MEGAMORPHIC, kNoExtraICState) \ - \ - V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED, \ - StoreICState::kStrictModeState) \ - V(KeyedStoreIC_PreMonomorphic_Strict, KEYED_STORE_IC, PREMONOMORPHIC, \ - StoreICState::kStrictModeState) \ - V(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \ - StoreICState::kStrictModeState) \ - \ - V(FunctionCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(FunctionApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(ReflectApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(ReflectConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(InternalArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(ArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(StringConstructCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(OnStackReplacement, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(InterruptCheck, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(OsrAfterStackCheck, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(StackCheck, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - \ - V(MarkCodeAsToBeExecutedOnce, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(MarkCodeAsExecutedOnce, BUILTIN, UNINITIALIZED, kNoExtraICState) \ - V(MarkCodeAsExecutedTwice, BUILTIN, UNINITIALIZED, kNoExtraICState) \ +#define BUILTIN_LIST_A(V) \ + V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(CallFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(Call, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(PushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(InOptimizationQueue, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(JSConstructStubApi, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(InterpreterEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(InterpreterExitTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(CompileLazy, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(CompileOptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(CompileOptimizedConcurrent, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(NotifySoftDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(NotifyStubFailure, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(NotifyStubFailureSaveDoubles, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(LoadIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(StoreIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, kNoExtraICState) \ + V(KeyedLoadIC_Megamorphic, KEYED_LOAD_IC, MEGAMORPHIC, kNoExtraICState) \ + \ + V(KeyedLoadIC_Megamorphic_Strong, KEYED_LOAD_IC, MEGAMORPHIC, \ + LoadICState::kStrongModeState) \ + \ + V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, \ + StoreICState::kStrictModeState) \ + \ + V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, kNoExtraICState) \ + V(KeyedStoreIC_PreMonomorphic, KEYED_STORE_IC, PREMONOMORPHIC, \ + kNoExtraICState) \ + V(KeyedStoreIC_Megamorphic, KEYED_STORE_IC, MEGAMORPHIC, kNoExtraICState) \ + \ + V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED, \ + StoreICState::kStrictModeState) \ + V(KeyedStoreIC_PreMonomorphic_Strict, KEYED_STORE_IC, PREMONOMORPHIC, \ + StoreICState::kStrictModeState) \ + V(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \ + StoreICState::kStrictModeState) \ + \ + V(FunctionCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(FunctionApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(ReflectApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(ReflectConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(InternalArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(ArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(StringConstructor, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(StringConstructor_ConstructStub, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(OnStackReplacement, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(InterruptCheck, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(OsrAfterStackCheck, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(StackCheck, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + \ + V(MarkCodeAsToBeExecutedOnce, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(MarkCodeAsExecutedOnce, BUILTIN, UNINITIALIZED, kNoExtraICState) \ + V(MarkCodeAsExecutedTwice, BUILTIN, UNINITIALIZED, kNoExtraICState) \ CODE_AGE_LIST_WITH_ARG(DECLARE_CODE_AGE_BUILTIN, V) // Define list of builtin handlers implemented in assembly. @@ -282,7 +283,8 @@ class Builtins { static void Generate_InternalArrayCode(MacroAssembler* masm); static void Generate_ArrayCode(MacroAssembler* masm); - static void Generate_StringConstructCode(MacroAssembler* masm); + static void Generate_StringConstructor(MacroAssembler* masm); + static void Generate_StringConstructor_ConstructStub(MacroAssembler* masm); static void Generate_OnStackReplacement(MacroAssembler* masm); static void Generate_OsrAfterStackCheck(MacroAssembler* masm); static void Generate_InterruptCheck(MacroAssembler* masm); diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 707e8446d..2f111935e 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -1260,7 +1260,68 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } -void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { +// static +void Builtins::Generate_StringConstructor(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : number of arguments + // -- edi : constructor function + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- esp[(argc + 1) * 4] : receiver + // ----------------------------------- + + // 1. Load the first argument into eax and get rid of the rest (including the + // receiver). + Label no_arguments; + { + __ test(eax, eax); + __ j(zero, &no_arguments, Label::kNear); + __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); + __ PopReturnAddressTo(ecx); + __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); + __ PushReturnAddressFrom(ecx); + __ mov(eax, ebx); + } + + // 2a. At least one argument, return eax if it's a string, otherwise + // dispatch to appropriate conversion. + Label to_string, symbol_descriptive_string; + { + __ JumpIfSmi(eax, &to_string, Label::kNear); + STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); + __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); + __ j(above, &to_string, Label::kNear); + __ j(equal, &symbol_descriptive_string, Label::kNear); + __ Ret(); + } + + // 2b. No arguments, return the empty string (and pop the receiver). + __ bind(&no_arguments); + { + __ LoadRoot(eax, Heap::kempty_stringRootIndex); + __ ret(1 * kPointerSize); + } + + // 3a. Convert eax to a string. + __ bind(&to_string); + { + ToStringStub stub(masm->isolate()); + __ TailCallStub(&stub); + } + + // 3b. Convert symbol in eax to a string. + __ bind(&symbol_descriptive_string); + { + __ PopReturnAddressTo(ecx); + __ Push(eax); + __ PushReturnAddressFrom(ecx); + __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1); + } +} + + +// static +void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax : number of arguments // -- edi : constructor function diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc index 9b33341f8..2e6795b03 100644 --- a/src/mips/builtins-mips.cc +++ b/src/mips/builtins-mips.cc @@ -141,7 +141,67 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } -void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { +// static +void Builtins::Generate_StringConstructor(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- a0 : number of arguments + // -- a1 : constructor function + // -- ra : return address + // -- sp[(argc - n - 1) * 4] : arg[n] (zero based) + // -- sp[argc * 4] : receiver + // ----------------------------------- + + // 1. Load the first argument into a0 and get rid of the rest (including the + // receiver). + Label no_arguments; + { + __ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg)); + __ Subu(a0, a0, Operand(1)); + __ sll(a0, a0, kPointerSizeLog2); + __ Addu(sp, a0, sp); + __ lw(a0, MemOperand(sp)); + __ Drop(2); + } + + // 2a. At least one argument, return a0 if it's a string, otherwise + // dispatch to appropriate conversion. + Label to_string, symbol_descriptive_string; + { + __ JumpIfSmi(a0, &to_string); + __ GetObjectType(a0, a1, a1); + STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); + __ Subu(a1, a1, Operand(FIRST_NONSTRING_TYPE)); + __ Branch(&symbol_descriptive_string, eq, a1, Operand(zero_reg)); + __ Branch(&to_string, gt, a1, Operand(zero_reg)); + __ Ret(USE_DELAY_SLOT); + __ mov(v0, a0); + } + + // 2b. No arguments, return the empty string (and pop the receiver). + __ bind(&no_arguments); + { + __ LoadRoot(v0, Heap::kempty_stringRootIndex); + __ DropAndRet(1); + } + + // 3a. Convert a0 to a string. + __ bind(&to_string); + { + ToStringStub stub(masm->isolate()); + __ TailCallStub(&stub); + } + + // 3b. Convert symbol in a0 to a string. + __ bind(&symbol_descriptive_string); + { + __ Push(a0); + __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1); + } +} + + +// static +void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- a0 : number of arguments // -- a1 : constructor function @@ -154,7 +214,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // receiver). { Label no_arguments, done; - __ Branch(&no_arguments, eq, a0, Operand(zero_reg)); + __ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg)); __ Subu(a0, a0, Operand(1)); __ sll(a0, a0, kPointerSizeLog2); __ Addu(sp, a0, sp); @@ -204,9 +264,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { __ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex); __ sw(a3, FieldMemOperand(v0, JSObject::kPropertiesOffset)); __ sw(a3, FieldMemOperand(v0, JSObject::kElementsOffset)); + __ Ret(USE_DELAY_SLOT); __ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); - __ Ret(); // Fallback to the runtime to allocate in new space. __ bind(&allocate); diff --git a/src/mips64/builtins-mips64.cc b/src/mips64/builtins-mips64.cc index 0480d3334..99e38f6f1 100644 --- a/src/mips64/builtins-mips64.cc +++ b/src/mips64/builtins-mips64.cc @@ -140,7 +140,66 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } -void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { +// static +void Builtins::Generate_StringConstructor(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- a0 : number of arguments + // -- a1 : constructor function + // -- ra : return address + // -- sp[(argc - n - 1) * 8] : arg[n] (zero based) + // -- sp[argc * 8] : receiver + // ----------------------------------- + + // 1. Load the first argument into a0 and get rid of the rest (including the + // receiver). + Label no_arguments; + { + __ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg)); + __ Dsubu(a0, a0, Operand(1)); + __ dsll(a0, a0, kPointerSizeLog2); + __ Daddu(sp, a0, sp); + __ ld(a0, MemOperand(sp)); + __ Drop(2); + } + + // 2a. At least one argument, return a0 if it's a string, otherwise + // dispatch to appropriate conversion. + Label to_string, symbol_descriptive_string; + { + __ JumpIfSmi(a0, &to_string); + __ GetObjectType(a0, a1, a1); + STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); + __ Subu(a1, a1, Operand(FIRST_NONSTRING_TYPE)); + __ Branch(&symbol_descriptive_string, eq, a1, Operand(zero_reg)); + __ Branch(&to_string, gt, a1, Operand(zero_reg)); + __ Ret(USE_DELAY_SLOT); + __ mov(v0, a0); + } + + // 2b. No arguments, return the empty string (and pop the receiver). + __ bind(&no_arguments); + { + __ LoadRoot(v0, Heap::kempty_stringRootIndex); + __ DropAndRet(1); + } + + // 3a. Convert a0 to a string. + __ bind(&to_string); + { + ToStringStub stub(masm->isolate()); + __ TailCallStub(&stub); + } + + // 3b. Convert symbol in a0 to a string. + __ bind(&symbol_descriptive_string); + { + __ Push(a0); + __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1); + } +} + + +void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- a0 : number of arguments // -- a1 : constructor function @@ -153,7 +212,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // receiver). { Label no_arguments, done; - __ Branch(&no_arguments, eq, a0, Operand(zero_reg)); + __ Branch(USE_DELAY_SLOT, &no_arguments, eq, a0, Operand(zero_reg)); __ Dsubu(a0, a0, Operand(1)); __ dsll(a0, a0, kPointerSizeLog2); __ Daddu(sp, a0, sp); diff --git a/src/runtime/runtime-symbol.cc b/src/runtime/runtime-symbol.cc index 03bd76ce2..778c24170 100644 --- a/src/runtime/runtime-symbol.cc +++ b/src/runtime/runtime-symbol.cc @@ -5,7 +5,9 @@ #include "src/runtime/runtime-utils.h" #include "src/arguments.h" +#include "src/isolate-inl.h" #include "src/objects-inl.h" +#include "src/string-builder.h" namespace v8 { namespace internal { @@ -38,6 +40,22 @@ RUNTIME_FUNCTION(Runtime_SymbolDescription) { } +RUNTIME_FUNCTION(Runtime_SymbolDescriptiveString) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); + IncrementalStringBuilder builder(isolate); + builder.AppendCString("Symbol("); + if (symbol->name()->IsString()) { + builder.AppendString(handle(String::cast(symbol->name()), isolate)); + } + builder.AppendCharacter(')'); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.Finish()); + return *result; +} + + RUNTIME_FUNCTION(Runtime_SymbolRegistry) { HandleScope scope(isolate); DCHECK(args.length() == 0); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 4774073d4..f20e1ab5f 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -926,6 +926,7 @@ namespace internal { F(CreateSymbol, 1, 1) \ F(CreatePrivateSymbol, 1, 1) \ F(SymbolDescription, 1, 1) \ + F(SymbolDescriptiveString, 1, 1) \ F(SymbolRegistry, 0, 1) \ F(SymbolIsPrivate, 1, 1) diff --git a/src/string.js b/src/string.js index e6671eec1..039a2b8d5 100644 --- a/src/string.js +++ b/src/string.js @@ -18,7 +18,6 @@ var InternalPackedArray = utils.InternalPackedArray; var RegExpExec; var RegExpExecNoTests; var RegExpLastMatchInfo; -var SymbolToString; var ToNumber; var ToString; @@ -28,26 +27,12 @@ utils.Import(function(from) { RegExpExec = from.RegExpExec; RegExpExecNoTests = from.RegExpExecNoTests; RegExpLastMatchInfo = from.RegExpLastMatchInfo; - SymbolToString = from.SymbolToString; ToNumber = from.ToNumber; ToString = from.ToString; }); //------------------------------------------------------------------- -function StringConstructor(x) { - // TODO(bmeurer): Move this to toplevel. - "use strict"; - if (%_ArgumentsLength() == 0) x = ''; - if (%_IsConstructCall()) { - %_SetValueOf(this, TO_STRING_INLINE(x)); - } else { - return IS_SYMBOL(x) ? - %_CallFunction(x, SymbolToString) : TO_STRING_INLINE(x); - } -} - - // ECMA-262 section 15.5.4.2 function StringToString() { if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) { @@ -1151,7 +1136,6 @@ function StringRaw(callSite) { // ------------------------------------------------------------------- // Set the String function and constructor. -%SetCode(GlobalString, StringConstructor); %FunctionSetPrototype(GlobalString, new GlobalString()); // Set up the constructor property on the String prototype object. diff --git a/src/symbol.js b/src/symbol.js index 2f68eff24..c65cda7c4 100644 --- a/src/symbol.js +++ b/src/symbol.js @@ -53,8 +53,7 @@ function SymbolToString() { throw MakeTypeError(kIncompatibleMethodReceiver, "Symbol.prototype.toString", this); } - var description = %SymbolDescription(%_ValueOf(this)); - return "Symbol(" + (IS_UNDEFINED(description) ? "" : description) + ")"; + return %SymbolDescriptiveString(%_ValueOf(this)); } diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index a9a0a8f42..630eda61b 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -1314,7 +1314,69 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } -void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { +// static +void Builtins::Generate_StringConstructor(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- rax : number of arguments + // -- rdi : constructor function + // -- rsp[0] : return address + // -- rsp[(argc - n) * 8] : arg[n] (zero-based) + // -- rsp[(argc + 1) * 8] : receiver + // ----------------------------------- + + // 1. Load the first argument into rax and get rid of the rest (including the + // receiver). + Label no_arguments; + { + StackArgumentsAccessor args(rsp, rax); + __ testp(rax, rax); + __ j(zero, &no_arguments, Label::kNear); + __ movp(rbx, args.GetArgumentOperand(1)); + __ PopReturnAddressTo(rcx); + __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize)); + __ PushReturnAddressFrom(rcx); + __ movp(rax, rbx); + } + + // 2a. At least one argument, return rax if it's a string, otherwise + // dispatch to appropriate conversion. + Label to_string, symbol_descriptive_string; + { + __ JumpIfSmi(rax, &to_string, Label::kNear); + STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); + __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx); + __ j(above, &to_string, Label::kNear); + __ j(equal, &symbol_descriptive_string, Label::kNear); + __ Ret(); + } + + // 2b. No arguments, return the empty string (and pop the receiver). + __ bind(&no_arguments); + { + __ LoadRoot(rax, Heap::kempty_stringRootIndex); + __ ret(1 * kPointerSize); + } + + // 3a. Convert rax to a string. + __ bind(&to_string); + { + ToStringStub stub(masm->isolate()); + __ TailCallStub(&stub); + } + + // 3b. Convert symbol in rax to a string. + __ bind(&symbol_descriptive_string); + { + __ PopReturnAddressTo(rcx); + __ Push(rax); + __ PushReturnAddressFrom(rcx); + __ TailCallRuntime(Runtime::kSymbolDescriptiveString, 1, 1); + } +} + + +// static +void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- rax : number of arguments // -- rdi : constructor function