Commit a3d6f6cc authored by bmeurer's avatar bmeurer Committed by Commit bot

[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}
parent 905e008c
...@@ -136,7 +136,63 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 ------------- // ----------- S t a t e -------------
// -- r0 : number of arguments // -- r0 : number of arguments
// -- r1 : constructor function // -- r1 : constructor function
...@@ -145,36 +201,33 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -145,36 +201,33 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// -- sp[argc * 4] : receiver // -- 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). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
__ cmp(r0, Operand(0)); __ sub(r0, r0, Operand(1), SetCC);
__ b(eq, &no_arguments); __ b(lo, &no_arguments);
__ sub(r0, r0, Operand(1)); __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ ldr(r2, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
__ Drop(2); __ Drop(2);
__ b(&done); __ b(&done);
__ bind(&no_arguments); __ bind(&no_arguments);
__ LoadRoot(r2, Heap::kempty_stringRootIndex); __ LoadRoot(r0, Heap::kempty_stringRootIndex);
__ Drop(1); __ Drop(1);
__ bind(&done); __ bind(&done);
} }
// 2. Make sure r2 is a string. // 2. Make sure r0 is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(r2, &convert); __ JumpIfSmi(r0, &convert);
__ CompareObjectType(r2, r3, r3, FIRST_NONSTRING_TYPE); __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
__ b(lo, &done_convert); __ b(lo, &done_convert);
__ bind(&convert); __ bind(&convert);
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
ToStringStub stub(masm->isolate()); ToStringStub stub(masm->isolate());
__ Push(r1); __ Push(r1);
__ Move(r0, r2);
__ CallStub(&stub); __ CallStub(&stub);
__ Move(r2, r0);
__ Pop(r1); __ Pop(r1);
} }
__ bind(&done_convert); __ bind(&done_convert);
...@@ -183,16 +236,17 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -183,16 +236,17 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// 3. Allocate a JSValue wrapper for the string. // 3. Allocate a JSValue wrapper for the string.
{ {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : the first argument
// -- r1 : constructor function // -- r1 : constructor function
// -- r2 : the first argument
// -- lr : return address // -- lr : return address
// ----------------------------------- // -----------------------------------
Label allocate, done_allocate; Label allocate, done_allocate;
__ Move(r2, r0);
__ Allocate(JSValue::kSize, r0, r3, r4, &allocate, TAG_OBJECT); __ Allocate(JSValue::kSize, r0, r3, r4, &allocate, TAG_OBJECT);
__ bind(&done_allocate); __ bind(&done_allocate);
// Initialize the JSValue in eax. // Initialize the JSValue in r0.
__ LoadGlobalFunctionInitialMap(r1, r3, r4); __ LoadGlobalFunctionInitialMap(r1, r3, r4);
__ str(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); __ str(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
__ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex);
......
...@@ -131,7 +131,65 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 ------------- // ----------- S t a t e -------------
// -- x0 : number of arguments // -- x0 : number of arguments
// -- x1 : constructor function // -- x1 : constructor function
...@@ -139,7 +197,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -139,7 +197,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// -- sp[(argc - n - 1) * 8] : arg[n] (zero based) // -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
// -- sp[argc * 8] : receiver // -- 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 // 1. Load the first argument into x2 and get rid of the rest (including the
// receiver). // receiver).
...@@ -147,7 +205,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -147,7 +205,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
Label no_arguments, done; Label no_arguments, done;
__ Cbz(x0, &no_arguments); __ Cbz(x0, &no_arguments);
__ Sub(x0, x0, 1); __ Sub(x0, x0, 1);
__ Drop(x0, kXRegSize); __ Drop(x0);
__ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex)); __ Ldr(x2, MemOperand(jssp, 2 * kPointerSize, PostIndex));
__ B(&done); __ B(&done);
__ Bind(&no_arguments); __ Bind(&no_arguments);
......
...@@ -1118,12 +1118,13 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object, ...@@ -1118,12 +1118,13 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
} }
{ // --- S t r i n g --- { // --- S t r i n g ---
Handle<JSFunction> string_fun = Handle<JSFunction> string_fun = InstallFunction(
InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize, global, "String", JS_VALUE_TYPE, JSValue::kSize,
isolate->initial_object_prototype(), isolate->initial_object_prototype(), Builtins::kStringConstructor);
Builtins::kIllegal); string_fun->shared()->set_construct_stub(isolate->builtins()->builtin(
string_fun->shared()->set_construct_stub( Builtins::kStringConstructor_ConstructStub));
isolate->builtins()->builtin(Builtins::kStringConstructCode)); string_fun->shared()->DontAdaptArguments();
string_fun->shared()->set_length(1);
native_context()->set_string_function(*string_fun); native_context()->set_string_function(*string_fun);
Handle<Map> string_map = Handle<Map> string_map =
......
This diff is collapsed.
...@@ -1260,7 +1260,68 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 ------------- // ----------- S t a t e -------------
// -- eax : number of arguments // -- eax : number of arguments
// -- edi : constructor function // -- edi : constructor function
......
...@@ -141,7 +141,67 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 ------------- // ----------- S t a t e -------------
// -- a0 : number of arguments // -- a0 : number of arguments
// -- a1 : constructor function // -- a1 : constructor function
...@@ -154,7 +214,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -154,7 +214,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// receiver). // receiver).
{ {
Label no_arguments, done; 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)); __ Subu(a0, a0, Operand(1));
__ sll(a0, a0, kPointerSizeLog2); __ sll(a0, a0, kPointerSizeLog2);
__ Addu(sp, a0, sp); __ Addu(sp, a0, sp);
...@@ -204,9 +264,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -204,9 +264,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
__ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex); __ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex);
__ sw(a3, FieldMemOperand(v0, JSObject::kPropertiesOffset)); __ sw(a3, FieldMemOperand(v0, JSObject::kPropertiesOffset));
__ sw(a3, FieldMemOperand(v0, JSObject::kElementsOffset)); __ sw(a3, FieldMemOperand(v0, JSObject::kElementsOffset));
__ Ret(USE_DELAY_SLOT);
__ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset)); __ sw(a0, FieldMemOperand(v0, JSValue::kValueOffset));
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
// Fallback to the runtime to allocate in new space. // Fallback to the runtime to allocate in new space.
__ bind(&allocate); __ bind(&allocate);
......
...@@ -140,7 +140,66 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 ------------- // ----------- S t a t e -------------
// -- a0 : number of arguments // -- a0 : number of arguments
// -- a1 : constructor function // -- a1 : constructor function
...@@ -153,7 +212,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { ...@@ -153,7 +212,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// receiver). // receiver).
{ {
Label no_arguments, done; 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)); __ Dsubu(a0, a0, Operand(1));
__ dsll(a0, a0, kPointerSizeLog2); __ dsll(a0, a0, kPointerSizeLog2);
__ Daddu(sp, a0, sp); __ Daddu(sp, a0, sp);
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
#include "src/runtime/runtime-utils.h" #include "src/runtime/runtime-utils.h"
#include "src/arguments.h" #include "src/arguments.h"
#include "src/isolate-inl.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/string-builder.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -38,6 +40,22 @@ RUNTIME_FUNCTION(Runtime_SymbolDescription) { ...@@ -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<String> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.Finish());
return *result;
}
RUNTIME_FUNCTION(Runtime_SymbolRegistry) { RUNTIME_FUNCTION(Runtime_SymbolRegistry) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 0); DCHECK(args.length() == 0);
......
...@@ -926,6 +926,7 @@ namespace internal { ...@@ -926,6 +926,7 @@ namespace internal {
F(CreateSymbol, 1, 1) \ F(CreateSymbol, 1, 1) \
F(CreatePrivateSymbol, 1, 1) \ F(CreatePrivateSymbol, 1, 1) \
F(SymbolDescription, 1, 1) \ F(SymbolDescription, 1, 1) \
F(SymbolDescriptiveString, 1, 1) \
F(SymbolRegistry, 0, 1) \ F(SymbolRegistry, 0, 1) \
F(SymbolIsPrivate, 1, 1) F(SymbolIsPrivate, 1, 1)
......
...@@ -18,7 +18,6 @@ var InternalPackedArray = utils.InternalPackedArray; ...@@ -18,7 +18,6 @@ var InternalPackedArray = utils.InternalPackedArray;
var RegExpExec; var RegExpExec;
var RegExpExecNoTests; var RegExpExecNoTests;
var RegExpLastMatchInfo; var RegExpLastMatchInfo;
var SymbolToString;
var ToNumber; var ToNumber;
var ToString; var ToString;
...@@ -28,26 +27,12 @@ utils.Import(function(from) { ...@@ -28,26 +27,12 @@ utils.Import(function(from) {
RegExpExec = from.RegExpExec; RegExpExec = from.RegExpExec;
RegExpExecNoTests = from.RegExpExecNoTests; RegExpExecNoTests = from.RegExpExecNoTests;
RegExpLastMatchInfo = from.RegExpLastMatchInfo; RegExpLastMatchInfo = from.RegExpLastMatchInfo;
SymbolToString = from.SymbolToString;
ToNumber = from.ToNumber; ToNumber = from.ToNumber;
ToString = from.ToString; 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 // ECMA-262 section 15.5.4.2
function StringToString() { function StringToString() {
if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) { if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
...@@ -1151,7 +1136,6 @@ function StringRaw(callSite) { ...@@ -1151,7 +1136,6 @@ function StringRaw(callSite) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Set the String function and constructor. // Set the String function and constructor.
%SetCode(GlobalString, StringConstructor);
%FunctionSetPrototype(GlobalString, new GlobalString()); %FunctionSetPrototype(GlobalString, new GlobalString());
// Set up the constructor property on the String prototype object. // Set up the constructor property on the String prototype object.
......
...@@ -53,8 +53,7 @@ function SymbolToString() { ...@@ -53,8 +53,7 @@ function SymbolToString() {
throw MakeTypeError(kIncompatibleMethodReceiver, throw MakeTypeError(kIncompatibleMethodReceiver,
"Symbol.prototype.toString", this); "Symbol.prototype.toString", this);
} }
var description = %SymbolDescription(%_ValueOf(this)); return %SymbolDescriptiveString(%_ValueOf(this));
return "Symbol(" + (IS_UNDEFINED(description) ? "" : description) + ")";
} }
......
...@@ -1314,7 +1314,69 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -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 ------------- // ----------- S t a t e -------------
// -- rax : number of arguments // -- rax : number of arguments
// -- rdi : constructor function // -- rdi : constructor function
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment