[es6] Implement spec compliant ToPrimitive in the runtime.
authorbmeurer <bmeurer@chromium.org>
Fri, 28 Aug 2015 09:21:23 +0000 (02:21 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 28 Aug 2015 09:21:43 +0000 (09:21 +0000)
This is the first step towards a spec compliant ToPrimitive
implementation (and therefore spec compliant ToNumber, ToString,
ToName, and friends).  It adds support for the @@toPrimitive
symbol that was introduced with ES2015, and also adds the new
Symbol.prototype[@@toPrimitive] and Date.prototype[@@toPrimitive]
initial properties.

There are now runtime functions for %ToPrimitive, %ToNumber and
%ToString, which do the right thing and should be used as fallbacks
instead of the hairy runtime.js implementations.  I will do the
same for the other conversion operations mentioned by the spec in
follow up CLs.  Once everything is in place we can look into
optimizing things further, so that we don't always call into the
runtime.

Also fixed Date.prototype.toJSON to be spec compliant.

R=mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:4307
LOG=y

Review URL: https://codereview.chromium.org/1306303003

Cr-Commit-Position: refs/heads/master@{#30434}

42 files changed:
src/accessors.cc
src/api.cc
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/compiler/linkage.cc
src/contexts.h
src/date.js
src/debug/debug.cc
src/execution.cc
src/execution.h
src/full-codegen/arm/full-codegen-arm.cc
src/full-codegen/arm64/full-codegen-arm64.cc
src/full-codegen/ia32/full-codegen-ia32.cc
src/full-codegen/mips/full-codegen-mips.cc
src/full-codegen/mips64/full-codegen-mips64.cc
src/full-codegen/ppc/full-codegen-ppc.cc
src/full-codegen/x64/full-codegen-x64.cc
src/full-codegen/x87/full-codegen-x87.cc
src/heap/heap.h
src/ia32/code-stubs-ia32.cc
src/json-stringifier.h
src/macros.py
src/messages.cc
src/messages.h
src/mips/code-stubs-mips.cc
src/mips64/code-stubs-mips64.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/ppc/code-stubs-ppc.cc
src/runtime.js
src/runtime/runtime-i18n.cc
src/runtime/runtime-numbers.cc
src/runtime/runtime-object.cc
src/runtime/runtime-scopes.cc
src/runtime/runtime.h
src/symbol.js
src/x64/code-stubs-x64.cc
src/x87/code-stubs-x87.cc
test/cctest/test-heap.cc
test/mjsunit/harmony/to-number.js [new file with mode: 0644]
test/mjsunit/harmony/to-primitive.js [new file with mode: 0644]

index b18cd9967b69d6af7e8de83d65004fea70442ef4..c1951b9622bbfd2c5107a43e87ded643825c0e88 100644 (file)
@@ -216,7 +216,7 @@ void Accessors::ArrayLengthSetter(
     }
 
     Handle<Object> number_v;
     }
 
     Handle<Object> number_v;
-    if (!Execution::ToNumber(isolate, length_obj).ToHandle(&number_v)) {
+    if (!Object::ToNumber(isolate, length_obj).ToHandle(&number_v)) {
       isolate->OptionalRescheduleException(false);
       return;
     }
       isolate->OptionalRescheduleException(false);
       return;
     }
index 0fb4154b6ed18d952ef5425ac285a3da0ab47c19..42a887582723524f4773847d51cdb2da5f58827a 100644 (file)
@@ -2854,7 +2854,7 @@ MaybeLocal<String> Value::ToString(Local<Context> context) const {
   PREPARE_FOR_EXECUTION(context, "ToString", String);
   Local<String> result;
   has_pending_exception =
   PREPARE_FOR_EXECUTION(context, "ToString", String);
   Local<String> result;
   has_pending_exception =
-      !ToLocal<String>(i::Execution::ToString(isolate, obj), &result);
+      !ToLocal<String>(i::Object::ToString(isolate, obj), &result);
   RETURN_ON_FAILED_EXECUTION(String);
   RETURN_ESCAPED(result);
 }
   RETURN_ON_FAILED_EXECUTION(String);
   RETURN_ESCAPED(result);
 }
@@ -2920,7 +2920,7 @@ MaybeLocal<Number> Value::ToNumber(Local<Context> context) const {
   PREPARE_FOR_EXECUTION(context, "ToNumber", Number);
   Local<Number> result;
   has_pending_exception =
   PREPARE_FOR_EXECUTION(context, "ToNumber", Number);
   Local<Number> result;
   has_pending_exception =
-      !ToLocal<Number>(i::Execution::ToNumber(isolate, obj), &result);
+      !ToLocal<Number>(i::Object::ToNumber(isolate, obj), &result);
   RETURN_ON_FAILED_EXECUTION(Number);
   RETURN_ESCAPED(result);
 }
   RETURN_ON_FAILED_EXECUTION(Number);
   RETURN_ESCAPED(result);
 }
@@ -3244,7 +3244,7 @@ Maybe<double> Value::NumberValue(Local<Context> context) const {
   if (obj->IsNumber()) return Just(obj->Number());
   PREPARE_FOR_EXECUTION_PRIMITIVE(context, "NumberValue", double);
   i::Handle<i::Object> num;
   if (obj->IsNumber()) return Just(obj->Number());
   PREPARE_FOR_EXECUTION_PRIMITIVE(context, "NumberValue", double);
   i::Handle<i::Object> num;
-  has_pending_exception = !i::Execution::ToNumber(isolate, obj).ToHandle(&num);
+  has_pending_exception = !i::Object::ToNumber(isolate, obj).ToHandle(&num);
   RETURN_ON_FAILED_EXECUTION_PRIMITIVE(double);
   return Just(num->Number());
 }
   RETURN_ON_FAILED_EXECUTION_PRIMITIVE(double);
   return Just(num->Number());
 }
@@ -3334,7 +3334,7 @@ MaybeLocal<Uint32> Value::ToArrayIndex(Local<Context> context) const {
   PREPARE_FOR_EXECUTION(context, "ToArrayIndex", Uint32);
   i::Handle<i::Object> string_obj;
   has_pending_exception =
   PREPARE_FOR_EXECUTION(context, "ToArrayIndex", Uint32);
   i::Handle<i::Object> string_obj;
   has_pending_exception =
-      !i::Execution::ToString(isolate, self).ToHandle(&string_obj);
+      !i::Object::ToString(isolate, self).ToHandle(&string_obj);
   RETURN_ON_FAILED_EXECUTION(Uint32);
   i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
   uint32_t index;
   RETURN_ON_FAILED_EXECUTION(Uint32);
   i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
   uint32_t index;
@@ -3614,8 +3614,8 @@ Maybe<PropertyAttribute> v8::Object::GetPropertyAttributes(
   auto self = Utils::OpenHandle(this);
   auto key_obj = Utils::OpenHandle(*key);
   if (!key_obj->IsName()) {
   auto self = Utils::OpenHandle(this);
   auto key_obj = Utils::OpenHandle(*key);
   if (!key_obj->IsName()) {
-    has_pending_exception = !i::Execution::ToString(
-        isolate, key_obj).ToHandle(&key_obj);
+    has_pending_exception =
+        !i::Object::ToString(isolate, key_obj).ToHandle(&key_obj);
     RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
   }
   auto key_name = i::Handle<i::Name>::cast(key_obj);
     RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
   }
   auto key_name = i::Handle<i::Name>::cast(key_obj);
index 5bd40084833cd1a1de41042d0ac52f121621761c..695bf33dc95637dc20f4ce02c78300c8143d1402 100644 (file)
@@ -3264,7 +3264,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ bind(&not_oddball);
 
   __ push(r0);  // Push argument.
   __ bind(&not_oddball);
 
   __ push(r0);  // Push argument.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index 4bd582ff23d31e09e2723c9f4e35a45b7683997b..4555a81c5eaa7947b6849d0ed67da08dd147619c 100644 (file)
@@ -3995,7 +3995,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ Bind(&not_oddball);
 
   __ Push(x0);  // Push argument.
   __ Bind(&not_oddball);
 
   __ Push(x0);  // Push argument.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index 93112be1af9a995e48ee434292967d977f7ce24c..078e5adf993e04de5ad404867cc7c054dcd29be7 100644 (file)
@@ -245,6 +245,11 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
     case Runtime::kInlineGetPrototype:
     case Runtime::kInlineRegExpExec:
     case Runtime::kInlineToObject:
     case Runtime::kInlineGetPrototype:
     case Runtime::kInlineRegExpExec:
     case Runtime::kInlineToObject:
+    case Runtime::kInlineToPrimitive:
+    case Runtime::kInlineToPrimitive_Number:
+    case Runtime::kInlineToPrimitive_String:
+    case Runtime::kInlineOrdinaryToPrimitive:
+    case Runtime::kInlineToNumber:
       return 1;
     case Runtime::kInlineDeoptimizeNow:
     case Runtime::kInlineThrowNotDateError:
       return 1;
     case Runtime::kInlineDeoptimizeNow:
     case Runtime::kInlineThrowNotDateError:
index 7c4ebc0c2b39da083e4690e248e8caf5d8033a1a..1abd6f2df6053125903ce84c18f104e3a9d150ca 100644 (file)
@@ -136,7 +136,6 @@ enum BindingFlags {
   V(SUB_BUILTIN_INDEX, JSFunction, sub_builtin)                             \
   V(SUB_STRONG_BUILTIN_INDEX, JSFunction, sub_strong_builtin)               \
   V(TO_NAME_BUILTIN_INDEX, JSFunction, to_name_builtin)                     \
   V(SUB_BUILTIN_INDEX, JSFunction, sub_builtin)                             \
   V(SUB_STRONG_BUILTIN_INDEX, JSFunction, sub_strong_builtin)               \
   V(TO_NAME_BUILTIN_INDEX, JSFunction, to_name_builtin)                     \
-  V(TO_NUMBER_BUILTIN_INDEX, JSFunction, to_number_builtin)                 \
   V(TO_STRING_BUILTIN_INDEX, JSFunction, to_string_builtin)
 
 
   V(TO_STRING_BUILTIN_INDEX, JSFunction, to_string_builtin)
 
 
index 2be8bcb220a7f3ed91ea1fb6943fa79398d5e4a7..44d2f4df1639044f19958d914c858bdc87760508 100644 (file)
@@ -364,6 +364,21 @@ function DateToLocaleTimeString() {
 }
 
 
 }
 
 
+// 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
+function DateToPrimitive(hint) {
+  if (!IS_SPEC_OBJECT(this)) {
+    throw MakeTypeError(kIncompatibleMethodReceiver,
+                        "Date.prototype [ @@toPrimitive ]", this);
+  }
+  if (hint === "default") {
+    hint = "string";
+  } else if (hint !== "number" && hint !== "string") {
+    throw MakeTypeError(kInvalidHint, hint);
+  }
+  return %OrdinaryToPrimitive(this, hint);
+}
+
+
 // ECMA 262 - 15.9.5.8
 function DateValueOf() {
   CHECK_DATE(this);
 // ECMA 262 - 15.9.5.8
 function DateValueOf() {
   CHECK_DATE(this);
@@ -777,9 +792,10 @@ function DateToISOString() {
 }
 
 
 }
 
 
+// 20.3.4.37 Date.prototype.toJSON ( key )
 function DateToJSON(key) {
   var o = TO_OBJECT(this);
 function DateToJSON(key) {
   var o = TO_OBJECT(this);
-  var tv = $defaultNumber(o);
+  var tv = TO_PRIMITIVE_NUMBER(o);
   if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
     return null;
   }
   if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
     return null;
   }
@@ -831,6 +847,9 @@ utils.InstallFunctions(GlobalDate, DONT_ENUM, [
 
 // Set up non-enumerable constructor property of the Date prototype object.
 %AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
 
 // Set up non-enumerable constructor property of the Date prototype object.
 %AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
+utils.SetFunctionName(DateToPrimitive, symbolToPrimitive);
+%AddNamedProperty(GlobalDate.prototype, symbolToPrimitive, DateToPrimitive,
+                  DONT_ENUM | READ_ONLY);
 
 // Set up non-enumerable functions of the Date prototype object and
 // set their names.
 
 // Set up non-enumerable functions of the Date prototype object and
 // set their names.
index 99036d71e7e7c6df559e192591ff1d36598e35ef..de7cc2315d02397e85f54388772acf6f4da68b67 100644 (file)
@@ -2148,7 +2148,7 @@ void Debug::NotifyMessageHandler(v8::DebugEvent event,
       Handle<Object> exception;
       if (!maybe_exception.ToHandle(&exception)) break;
       Handle<Object> result;
       Handle<Object> exception;
       if (!maybe_exception.ToHandle(&exception)) break;
       Handle<Object> result;
-      if (!Execution::ToString(isolate_, exception).ToHandle(&result)) break;
+      if (!Object::ToString(isolate_, exception).ToHandle(&result)) break;
       answer = Handle<String>::cast(result);
     }
 
       answer = Handle<String>::cast(result);
     }
 
index 4ab2403e56f0a0cc9d9345e51e0a233a260ff21c..64e5e39f9aa13471c675482bbf22220ada71b292 100644 (file)
@@ -544,18 +544,6 @@ void StackGuard::InitThread(const ExecutionAccess& lock) {
   } while (false)
 
 
   } while (false)
 
 
-MaybeHandle<Object> Execution::ToNumber(
-    Isolate* isolate, Handle<Object> obj) {
-  RETURN_NATIVE_CALL(to_number, { obj });
-}
-
-
-MaybeHandle<Object> Execution::ToString(
-    Isolate* isolate, Handle<Object> obj) {
-  RETURN_NATIVE_CALL(to_string, { obj });
-}
-
-
 MaybeHandle<Object> Execution::ToDetailString(
     Isolate* isolate, Handle<Object> obj) {
   RETURN_NATIVE_CALL(to_detail_string, { obj });
 MaybeHandle<Object> Execution::ToDetailString(
     Isolate* isolate, Handle<Object> obj) {
   RETURN_NATIVE_CALL(to_detail_string, { obj });
@@ -584,7 +572,7 @@ MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
 
 
 MaybeHandle<Object> Execution::ToInt32(Isolate* isolate, Handle<Object> obj) {
 
 
 MaybeHandle<Object> Execution::ToInt32(Isolate* isolate, Handle<Object> obj) {
-  ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToNumber(isolate, obj),
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(isolate, obj),
                              Object);
   return isolate->factory()->NewNumberFromInt(DoubleToInt32(obj->Number()));
 }
                              Object);
   return isolate->factory()->NewNumberFromInt(DoubleToInt32(obj->Number()));
 }
@@ -601,7 +589,7 @@ MaybeHandle<Object> Execution::ToObject(Isolate* isolate, Handle<Object> obj) {
 
 
 MaybeHandle<Object> Execution::ToUint32(Isolate* isolate, Handle<Object> obj) {
 
 
 MaybeHandle<Object> Execution::ToUint32(Isolate* isolate, Handle<Object> obj) {
-  ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToNumber(isolate, obj),
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(isolate, obj),
                              Object);
   return isolate->factory()->NewNumberFromUint(DoubleToUint32(obj->Number()));
 }
                              Object);
   return isolate->factory()->NewNumberFromUint(DoubleToUint32(obj->Number()));
 }
index 2c07a64aaecc5409064ba1bc5eaf2f2edcf73880..d7996d1904b3098d3727d230275535f43fb9b354 100644 (file)
@@ -59,10 +59,6 @@ class Execution final : public AllStatic {
                                      Handle<Object> argv[],
                                      MaybeHandle<Object>* exception_out = NULL);
 
                                      Handle<Object> argv[],
                                      MaybeHandle<Object>* exception_out = NULL);
 
-  // ECMA-262 9.3
-  MUST_USE_RESULT static MaybeHandle<Object> ToNumber(
-      Isolate* isolate, Handle<Object> obj);
-
   // ECMA-262 9.4
   MUST_USE_RESULT static MaybeHandle<Object> ToInteger(
       Isolate* isolate, Handle<Object> obj);
   // ECMA-262 9.4
   MUST_USE_RESULT static MaybeHandle<Object> ToInteger(
       Isolate* isolate, Handle<Object> obj);
@@ -80,10 +76,6 @@ class Execution final : public AllStatic {
   MUST_USE_RESULT static MaybeHandle<Object> ToLength(
       Isolate* isolate, Handle<Object> obj);
 
   MUST_USE_RESULT static MaybeHandle<Object> ToLength(
       Isolate* isolate, Handle<Object> obj);
 
-  // ECMA-262 9.8
-  MUST_USE_RESULT static MaybeHandle<Object> ToString(
-      Isolate* isolate, Handle<Object> obj);
-
   // ECMA-262 9.8
   MUST_USE_RESULT static MaybeHandle<Object> ToDetailString(
       Isolate* isolate, Handle<Object> obj);
   // ECMA-262 9.8
   MUST_USE_RESULT static MaybeHandle<Object> ToDetailString(
       Isolate* isolate, Handle<Object> obj);
index ef65b31c541f4b93ff5273a2f941e4580811f520..ca25d6ea554d94811cb7146501b7c5713a513a9c 100644 (file)
@@ -3468,7 +3468,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   // string "valueOf" the result is false.
   // The use of ip to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
   // string "valueOf" the result is false.
   // The use of ip to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
-  __ mov(ip, Operand(isolate()->factory()->value_of_string()));
+  __ LoadRoot(ip, Heap::kvalueOf_stringRootIndex);
   __ jmp(&entry);
   __ bind(&loop);
   __ ldr(r3, MemOperand(r4, 0));
   __ jmp(&entry);
   __ bind(&loop);
   __ ldr(r3, MemOperand(r4, 0));
index a9ec2aa3bfb9d09bc80a82c97cccc2f4ff0e9533..55ac3f5f9185b52e23d46e75460d66546e2aa0db 100644 (file)
@@ -3169,7 +3169,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   // string "valueOf" the result is false.
   Register valueof_string = x1;
   int descriptor_size = DescriptorArray::kDescriptorSize * kPointerSize;
   // string "valueOf" the result is false.
   Register valueof_string = x1;
   int descriptor_size = DescriptorArray::kDescriptorSize * kPointerSize;
-  __ Mov(valueof_string, Operand(isolate()->factory()->value_of_string()));
+  __ LoadRoot(valueof_string, Heap::kvalueOf_stringRootIndex);
   __ Bind(&loop);
   __ Ldr(x15, MemOperand(descriptors, descriptor_size, PostIndex));
   __ Cmp(x15, valueof_string);
   __ Bind(&loop);
   __ Ldr(x15, MemOperand(descriptors, descriptor_size, PostIndex));
   __ Cmp(x15, valueof_string);
index 8bdd8d456db402fa668d09b7ed138e931d50bd71..1cf1416bd1a9bfafdcb7de37872de0deeb91071d 100644 (file)
@@ -3363,7 +3363,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   __ jmp(&entry);
   __ bind(&loop);
   __ mov(edx, FieldOperand(ebx, 0));
   __ jmp(&entry);
   __ bind(&loop);
   __ mov(edx, FieldOperand(ebx, 0));
-  __ cmp(edx, isolate()->factory()->value_of_string());
+  __ cmp(edx, isolate()->factory()->valueOf_string());
   __ j(equal, if_false);
   __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
   __ bind(&entry);
   __ j(equal, if_false);
   __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
   __ bind(&entry);
index 7486896240b5c945c44cbdd7e520adbf5dbf8919..9baeff034af1f70dc7ff548c141747333deb61ac 100644 (file)
@@ -3462,7 +3462,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   // string "valueOf" the result is false.
   // The use of t2 to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
   // string "valueOf" the result is false.
   // The use of t2 to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
-  __ li(t2, Operand(isolate()->factory()->value_of_string()));
+  __ LoadRoot(t2, Heap::kvalueOf_stringRootIndex);
   __ jmp(&entry);
   __ bind(&loop);
   __ lw(a3, MemOperand(t0, 0));
   __ jmp(&entry);
   __ bind(&loop);
   __ lw(a3, MemOperand(t0, 0));
index c4b924bf126dfd1ed97282926c42741d5ffd2bfe..10e4580411ee9ae4802476306556a17d82516131 100644 (file)
@@ -3464,7 +3464,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   // string "valueOf" the result is false.
   // The use of a6 to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
   // string "valueOf" the result is false.
   // The use of a6 to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
-  __ li(a6, Operand(isolate()->factory()->value_of_string()));
+  __ LoadRoot(a6, Heap::kvalueOf_stringRootIndex);
   __ jmp(&entry);
   __ bind(&loop);
   __ ld(a3, MemOperand(a4, 0));
   __ jmp(&entry);
   __ bind(&loop);
   __ ld(a3, MemOperand(a4, 0));
index 634ccdbd2c578e18a16f164f16ba939e91a9e51b..c9b11ba4cb1debebae95c721d5251741c139538b 100644 (file)
@@ -3461,7 +3461,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   // string "valueOf" the result is false.
   // The use of ip to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
   // string "valueOf" the result is false.
   // The use of ip to store the valueOf string assumes that it is not otherwise
   // used in the loop below.
-  __ mov(ip, Operand(isolate()->factory()->value_of_string()));
+  __ LoadRoot(ip, Heap::kvalueOf_stringRootIndex);
   __ b(&entry);
   __ bind(&loop);
   __ LoadP(r6, MemOperand(r7, 0));
   __ b(&entry);
   __ bind(&loop);
   __ LoadP(r6, MemOperand(r7, 0));
index 9ef1faea3139ff6a20f8e42c1a73247e645fd604..d521fcd97c98c709ca3da5c06f492f51945d5c3c 100644 (file)
@@ -3353,7 +3353,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   __ jmp(&entry);
   __ bind(&loop);
   __ movp(rdx, FieldOperand(r8, 0));
   __ jmp(&entry);
   __ bind(&loop);
   __ movp(rdx, FieldOperand(r8, 0));
-  __ Cmp(rdx, isolate()->factory()->value_of_string());
+  __ CompareRoot(rdx, Heap::kvalueOf_stringRootIndex);
   __ j(equal, if_false);
   __ addp(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
   __ bind(&entry);
   __ j(equal, if_false);
   __ addp(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
   __ bind(&entry);
index 9e2d95cbff09bbd7deda3f20eb38e48044da5822..82e754e6a9272a300faec573f5486d299b07f5b8 100644 (file)
@@ -3354,7 +3354,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
   __ jmp(&entry);
   __ bind(&loop);
   __ mov(edx, FieldOperand(ebx, 0));
   __ jmp(&entry);
   __ bind(&loop);
   __ mov(edx, FieldOperand(ebx, 0));
-  __ cmp(edx, isolate()->factory()->value_of_string());
+  __ cmp(edx, isolate()->factory()->valueOf_string());
   __ j(equal, if_false);
   __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
   __ bind(&entry);
   __ j(equal, if_false);
   __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
   __ bind(&entry);
index 97d32bbe9c5b417c9060fcf287f85aaef33a82cb..826933dd9e2364bdec93be9e889e1a96ff1e9714 100644 (file)
@@ -218,6 +218,7 @@ namespace internal {
   V(Boolean_string, "Boolean")                                 \
   V(callee_string, "callee")                                   \
   V(constructor_string, "constructor")                         \
   V(Boolean_string, "Boolean")                                 \
   V(callee_string, "callee")                                   \
   V(constructor_string, "constructor")                         \
+  V(default_string, "default")                                 \
   V(dot_result_string, ".result")                              \
   V(eval_string, "eval")                                       \
   V(float32x4_string, "float32x4")                             \
   V(dot_result_string, ".result")                              \
   V(eval_string, "eval")                                       \
   V(float32x4_string, "float32x4")                             \
@@ -278,8 +279,9 @@ namespace internal {
   V(Date_string, "Date")                                       \
   V(char_at_string, "CharAt")                                  \
   V(undefined_string, "undefined")                             \
   V(Date_string, "Date")                                       \
   V(char_at_string, "CharAt")                                  \
   V(undefined_string, "undefined")                             \
-  V(value_of_string, "valueOf")                                \
+  V(valueOf_string, "valueOf")                                 \
   V(stack_string, "stack")                                     \
   V(stack_string, "stack")                                     \
+  V(toString_string, "toString")                               \
   V(toJSON_string, "toJSON")                                   \
   V(KeyedLoadMonomorphic_string, "KeyedLoadMonomorphic")       \
   V(KeyedStoreMonomorphic_string, "KeyedStoreMonomorphic")     \
   V(toJSON_string, "toJSON")                                   \
   V(KeyedLoadMonomorphic_string, "KeyedLoadMonomorphic")       \
   V(KeyedStoreMonomorphic_string, "KeyedStoreMonomorphic")     \
@@ -353,6 +355,7 @@ namespace internal {
     Symbol.isConcatSpreadable)                                   \
   V(is_regexp_symbol, symbolIsRegExp, Symbol.isRegExp)           \
   V(iterator_symbol, symbolIterator, Symbol.iterator)            \
     Symbol.isConcatSpreadable)                                   \
   V(is_regexp_symbol, symbolIsRegExp, Symbol.isRegExp)           \
   V(iterator_symbol, symbolIterator, Symbol.iterator)            \
+  V(to_primitive_symbol, symbolToPrimitive, Symbol.toPrimitive)  \
   V(to_string_tag_symbol, symbolToStringTag, Symbol.toStringTag) \
   V(unscopables_symbol, symbolUnscopables, Symbol.unscopables)
 
   V(to_string_tag_symbol, symbolToStringTag, Symbol.toStringTag) \
   V(unscopables_symbol, symbolUnscopables, Symbol.unscopables)
 
index 0590ab8f5928c488d418530ab954a6eaefcfb9c0..bfabb1f7847dde97e966a9fcc4b5f445cfbb769b 100644 (file)
@@ -3271,7 +3271,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ pop(ecx);   // Pop return address.
   __ push(eax);  // Push argument.
   __ push(ecx);  // Push return address.
   __ pop(ecx);   // Pop return address.
   __ push(eax);  // Push argument.
   __ push(ecx);  // Push return address.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index fb6b80dde4ec4c5ffe2a4c8cdff26795384794af..3744ea78d9c7a95524179265b39a871cabf7021b 100644 (file)
@@ -382,12 +382,12 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
   if (class_name == isolate_->heap()->String_string()) {
     Handle<Object> value;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   if (class_name == isolate_->heap()->String_string()) {
     Handle<Object> value;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-        isolate_, value, Execution::ToString(isolate_, object), EXCEPTION);
+        isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
     SerializeString(Handle<String>::cast(value));
   } else if (class_name == isolate_->heap()->Number_string()) {
     Handle<Object> value;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     SerializeString(Handle<String>::cast(value));
   } else if (class_name == isolate_->heap()->Number_string()) {
     Handle<Object> value;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-        isolate_, value, Execution::ToNumber(isolate_, object), EXCEPTION);
+        isolate_, value, Object::ToNumber(isolate_, object), EXCEPTION);
     if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
     SerializeHeapNumber(Handle<HeapNumber>::cast(value));
   } else if (class_name == isolate_->heap()->Boolean_string()) {
     if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
     SerializeHeapNumber(Handle<HeapNumber>::cast(value));
   } else if (class_name == isolate_->heap()->Boolean_string()) {
index b0228da9a59de5c1f22a384cb02205f9a69e6a27..03c2012593346e4cb0021e84ae74489fe71a16e0 100644 (file)
@@ -153,6 +153,9 @@ macro TO_UINT32(arg) = (arg >>> 0);
 macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : $nonStringToString(arg));
 macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : $nonNumberToNumber(arg));
 macro TO_OBJECT(arg) = (%_ToObject(arg));
 macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : $nonStringToString(arg));
 macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : $nonNumberToNumber(arg));
 macro TO_OBJECT(arg) = (%_ToObject(arg));
+macro TO_PRIMITIVE(arg) = (%_ToPrimitive(arg));
+macro TO_PRIMITIVE_NUMBER(arg) = (%_ToPrimitive_Number(arg));
+macro TO_PRIMITIVE_STRING(arg) = (%_ToPrimitive_String(arg));
 macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
 macro HAS_OWN_PROPERTY(arg, index) = (%_CallFunction(arg, index, ObjectHasOwnProperty));
 macro SHOULD_CREATE_WRAPPER(functionName, receiver) = (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(functionName));
 macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
 macro HAS_OWN_PROPERTY(arg, index) = (%_CallFunction(arg, index, ObjectHasOwnProperty));
 macro SHOULD_CREATE_WRAPPER(functionName, receiver) = (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(functionName));
index a8afa3f5a75067c76c173d301c3d41b0a789a4bc..4dcac50bf2d63a56b3a1fb86f74a85272b381dd2 100644 (file)
@@ -471,7 +471,7 @@ MaybeHandle<String> ErrorToStringHelper::GetStringifiedProperty(
                              String);
   if (obj->IsUndefined()) return default_value;
   if (!obj->IsString()) {
                              String);
   if (obj->IsUndefined()) return default_value;
   if (!obj->IsString()) {
-    ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToString(isolate, obj),
+    ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToString(isolate, obj),
                                String);
   }
   return Handle<String>::cast(obj);
                                String);
   }
   return Handle<String>::cast(obj);
index f08135bb16e17c5db3d713a3514a418f12b44536..532db92471a77780644c419d19ef4cd3bee5f3aa 100644 (file)
@@ -257,6 +257,7 @@ class CallSite {
     "Offset is outside the bounds of the DataView")                            \
   T(InvalidDataViewLength, "Invalid data view length")                         \
   T(InvalidDataViewOffset, "Start offset is outside the bounds of the buffer") \
     "Offset is outside the bounds of the DataView")                            \
   T(InvalidDataViewLength, "Invalid data view length")                         \
   T(InvalidDataViewOffset, "Start offset is outside the bounds of the buffer") \
+  T(InvalidHint, "Invalid hint: %")                                            \
   T(InvalidLanguageTag, "Invalid language tag: %")                             \
   T(InvalidWeakMapKey, "Invalid value used as weak map key")                   \
   T(InvalidWeakSetValue, "Invalid value used in weak set")                     \
   T(InvalidLanguageTag, "Invalid language tag: %")                             \
   T(InvalidWeakMapKey, "Invalid value used as weak map key")                   \
   T(InvalidWeakSetValue, "Invalid value used in weak set")                     \
index b34cbf1d85dadc24e3b4894b514b3fa8432fbaa3..039268dcbc8325d7c640571f04167e20ddf76047 100644 (file)
@@ -3413,7 +3413,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ bind(&not_oddball);
 
   __ push(a0);  // Push argument.
   __ bind(&not_oddball);
 
   __ push(a0);  // Push argument.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index 3c53d3651bec9f9020afb1a0972826d1658162e1..bff8717d48dfdbf5ff35d814a98e5fafb8e765c4 100644 (file)
@@ -3445,7 +3445,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ bind(&not_oddball);
 
   __ push(a0);  // Push argument.
   __ bind(&not_oddball);
 
   __ push(a0);  // Push argument.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index 57750c3459187f53f3bf43bda562d0bf3baeeaac..a37fcd58369c83a7fcb4be93efa62cd8eb658656 100644 (file)
@@ -1132,6 +1132,7 @@ bool Object::FitsRepresentation(Representation representation) {
 }
 
 
 }
 
 
+// static
 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
                                          Handle<Object> object) {
   return ToObject(
 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
                                          Handle<Object> object) {
   return ToObject(
@@ -1139,6 +1140,21 @@ MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
 }
 
 
 }
 
 
+// static
+MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) {
+  if (input->IsName()) return Handle<Name>::cast(input);
+  return ToString(isolate, input);
+}
+
+
+// static
+MaybeHandle<Object> Object::ToPrimitive(Handle<Object> input,
+                                        ToPrimitiveHint hint) {
+  if (input->IsPrimitive()) return input;
+  return JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), hint);
+}
+
+
 bool Object::HasSpecificClassOf(String* name) {
   return this->IsJSObject() && (JSObject::cast(this)->class_name() == name);
 }
 bool Object::HasSpecificClassOf(String* name) {
   return this->IsJSObject() && (JSObject::cast(this)->class_name() == name);
 }
index fc461887cf0bc6e85263fd082b019abb5e20d7f2..260a64b91d2b436c796b61493770445f6e9b154f 100644 (file)
@@ -90,14 +90,57 @@ MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
 }
 
 
 }
 
 
-MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> object) {
-  if (object->IsName()) {
-    return Handle<Name>::cast(object);
-  } else {
-    Handle<Object> converted;
-    ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
-                               Execution::ToString(isolate, object), Name);
-    return Handle<Name>::cast(converted);
+// static
+MaybeHandle<Object> Object::ToNumber(Isolate* isolate, Handle<Object> input) {
+  while (true) {
+    if (input->IsNumber()) {
+      return input;
+    }
+    if (input->IsOddball()) {
+      return handle(Handle<Oddball>::cast(input)->to_number(), isolate);
+    }
+    if (input->IsString()) {
+      return String::ToNumber(Handle<String>::cast(input));
+    }
+    if (input->IsSymbol()) {
+      THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
+                      Object);
+    }
+    if (input->IsSimd128Value()) {
+      THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
+                      Object);
+    }
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
+                                                ToPrimitiveHint::kNumber),
+        Object);
+  }
+}
+
+
+// static
+MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
+  while (true) {
+    if (input->IsString()) {
+      return Handle<String>::cast(input);
+    }
+    if (input->IsOddball()) {
+      return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
+    }
+    if (input->IsNumber()) {
+      return isolate->factory()->NumberToString(input);
+    }
+    if (input->IsSymbol()) {
+      THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
+                      String);
+    }
+    if (input->IsSimd128Value()) {
+      return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
+    }
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
+                                                ToPrimitiveHint::kString),
+        String);
   }
 }
 
   }
 }
 
@@ -109,7 +152,6 @@ bool Object::BooleanValue() {
   if (IsUndetectableObject()) return false;   // Undetectable object is false.
   if (IsString()) return String::cast(this)->length() != 0;
   if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
   if (IsUndetectableObject()) return false;   // Undetectable object is false.
   if (IsString()) return String::cast(this)->length() != 0;
   if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
-  if (IsSimd128Value()) return true;  // Simd value types evaluate to true.
   return true;
 }
 
   return true;
 }
 
@@ -157,6 +199,26 @@ bool Object::IsPromise(Handle<Object> object) {
 }
 
 
 }
 
 
+// static
+MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
+                                      Handle<Name> name) {
+  Handle<Object> func;
+  Isolate* isolate = receiver->GetIsolate();
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
+                             JSReceiver::GetProperty(receiver, name), Object);
+  if (func->IsNull() || func->IsUndefined()) {
+    return isolate->factory()->undefined_value();
+  }
+  if (!func->IsCallable()) {
+    // TODO(bmeurer): Better error message here?
+    THROW_NEW_ERROR(isolate,
+                    NewTypeError(MessageTemplate::kCalledNonCallable, func),
+                    Object);
+  }
+  return func;
+}
+
+
 MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
                                         LanguageMode language_mode) {
   for (; it->IsFound(); it->Next()) {
 MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
                                         LanguageMode language_mode) {
   for (; it->IsFound(); it->Next()) {
@@ -1485,6 +1547,73 @@ void HeapNumber::HeapNumberPrint(std::ostream& os) {  // NOLINT
   (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
 
 
   (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
 
 
+// static
+Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
+#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
+  if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
+  SIMD128_TYPES(SIMD128_TYPE)
+#undef SIMD128_TYPE
+  UNREACHABLE();
+  return Handle<String>::null();
+}
+
+
+// static
+Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
+  Isolate* const isolate = input->GetIsolate();
+  char arr[100];
+  Vector<char> buffer(arr, arraysize(arr));
+  std::ostringstream os;
+  os << "SIMD.Float32x4("
+     << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
+     << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
+     << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
+     << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
+  return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
+}
+
+
+#define SIMD128_BOOL_TO_STRING(Type, lane_count)                            \
+  Handle<String> Type::ToString(Handle<Type> input) {                       \
+    Isolate* const isolate = input->GetIsolate();                           \
+    std::ostringstream os;                                                  \
+    os << "SIMD." #Type "(";                                                \
+    os << (input->get_lane(0) ? "true" : "false");                          \
+    for (int i = 1; i < lane_count; i++) {                                  \
+      os << ", " << (input->get_lane(i) ? "true" : "false");                \
+    }                                                                       \
+    os << ")";                                                              \
+    return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
+  }
+SIMD128_BOOL_TO_STRING(Bool32x4, 4)
+SIMD128_BOOL_TO_STRING(Bool16x8, 8)
+SIMD128_BOOL_TO_STRING(Bool8x16, 16)
+#undef SIMD128_BOOL_TO_STRING
+
+
+#define SIMD128_INT_TO_STRING(Type, lane_count)                             \
+  Handle<String> Type::ToString(Handle<Type> input) {                       \
+    Isolate* const isolate = input->GetIsolate();                           \
+    char arr[100];                                                          \
+    Vector<char> buffer(arr, arraysize(arr));                               \
+    std::ostringstream os;                                                  \
+    os << "SIMD." #Type "(";                                                \
+    os << IntToCString(input->get_lane(0), buffer);                         \
+    for (int i = 1; i < lane_count; i++) {                                  \
+      os << ", " << IntToCString(input->get_lane(i), buffer);               \
+    }                                                                       \
+    os << ")";                                                              \
+    return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
+  }
+SIMD128_INT_TO_STRING(Int32x4, 4)
+SIMD128_INT_TO_STRING(Uint32x4, 4)
+SIMD128_INT_TO_STRING(Int16x8, 8)
+SIMD128_INT_TO_STRING(Uint16x8, 8)
+SIMD128_INT_TO_STRING(Int8x16, 16)
+SIMD128_INT_TO_STRING(Uint8x16, 16)
+#undef SIMD128_INT_TO_STRING
+
+
 bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
   return READ_INT64_FIELD(this, kValueOffset) ==
              READ_INT64_FIELD(other, kValueOffset) &&
 bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
   return READ_INT64_FIELD(this, kValueOffset) ==
              READ_INT64_FIELD(other, kValueOffset) &&
@@ -3279,7 +3408,7 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
   if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
     if (!value->IsNumber() && !value->IsUndefined()) {
       ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), to_assign,
   if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
     if (!value->IsNumber() && !value->IsUndefined()) {
       ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), to_assign,
-                                 Execution::ToNumber(it->isolate(), value),
+                                 Object::ToNumber(it->isolate(), value),
                                  Object);
       // ToNumber above might modify the receiver, causing the cached
       // holder_map to mismatch the actual holder->map() after this point.
                                  Object);
       // ToNumber above might modify the receiver, causing the cached
       // holder_map to mismatch the actual holder->map() after this point.
@@ -5881,6 +6010,75 @@ MaybeHandle<JSObject> JSObject::DeepCopy(
 }
 
 
 }
 
 
+// static
+MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
+                                            ToPrimitiveHint hint) {
+  Isolate* const isolate = receiver->GetIsolate();
+  Handle<Object> exotic_to_prim;
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, exotic_to_prim,
+      GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
+  if (!exotic_to_prim->IsUndefined()) {
+    Handle<Object> hint_string;
+    switch (hint) {
+      case ToPrimitiveHint::kDefault:
+        hint_string = isolate->factory()->default_string();
+        break;
+      case ToPrimitiveHint::kNumber:
+        hint_string = isolate->factory()->number_string();
+        break;
+      case ToPrimitiveHint::kString:
+        hint_string = isolate->factory()->string_string();
+        break;
+    }
+    Handle<Object> result;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, result,
+        Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
+        Object);
+    if (result->IsPrimitive()) return result;
+    THROW_NEW_ERROR(isolate,
+                    NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
+                    Object);
+  }
+  return OrdinaryToPrimitive(receiver,
+                             (hint == ToPrimitiveHint::kString)
+                                 ? isolate->factory()->string_string()
+                                 : isolate->factory()->number_string());
+}
+
+
+// static
+MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(Handle<JSReceiver> receiver,
+                                                    Handle<String> hint) {
+  Isolate* const isolate = receiver->GetIsolate();
+  Handle<String> method_names[2];
+  if (hint.is_identical_to(isolate->factory()->number_string())) {
+    method_names[0] = isolate->factory()->valueOf_string();
+    method_names[1] = isolate->factory()->toString_string();
+  } else {
+    DCHECK(hint.is_identical_to(isolate->factory()->string_string()));
+    method_names[0] = isolate->factory()->toString_string();
+    method_names[1] = isolate->factory()->valueOf_string();
+  }
+  for (Handle<String> name : method_names) {
+    Handle<Object> method;
+    ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
+                               JSReceiver::GetProperty(receiver, name), Object);
+    if (method->IsCallable()) {
+      Handle<Object> result;
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
+          Object);
+      if (result->IsPrimitive()) return result;
+    }
+  }
+  THROW_NEW_ERROR(isolate,
+                  NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
+                  Object);
+}
+
+
 // Tests for the fast common case for property enumeration:
 // - This object and all prototypes has an enum cache (which means that
 //   it is no proxy, has no interceptors and needs no access checks).
 // Tests for the fast common case for property enumeration:
 // - This object and all prototypes has an enum cache (which means that
 //   it is no proxy, has no interceptors and needs no access checks).
@@ -8152,6 +8350,95 @@ bool String::LooksValid() {
 }
 
 
 }
 
 
+namespace {
+
+bool AreDigits(const uint8_t* s, int from, int to) {
+  for (int i = from; i < to; i++) {
+    if (s[i] < '0' || s[i] > '9') return false;
+  }
+
+  return true;
+}
+
+
+int ParseDecimalInteger(const uint8_t* s, int from, int to) {
+  DCHECK(to - from < 10);  // Overflow is not possible.
+  DCHECK(from < to);
+  int d = s[from] - '0';
+
+  for (int i = from + 1; i < to; i++) {
+    d = 10 * d + (s[i] - '0');
+  }
+
+  return d;
+}
+
+}  // namespace
+
+
+// static
+Handle<Object> String::ToNumber(Handle<String> subject) {
+  Isolate* const isolate = subject->GetIsolate();
+
+  // Flatten {subject} string first.
+  subject = String::Flatten(subject);
+
+  // Fast array index case.
+  uint32_t index;
+  if (subject->AsArrayIndex(&index)) {
+    return isolate->factory()->NewNumberFromUint(index);
+  }
+
+  // Fast case: short integer or some sorts of junk values.
+  if (subject->IsSeqOneByteString()) {
+    int len = subject->length();
+    if (len == 0) return handle(Smi::FromInt(0), isolate);
+
+    DisallowHeapAllocation no_gc;
+    uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
+    bool minus = (data[0] == '-');
+    int start_pos = (minus ? 1 : 0);
+
+    if (start_pos == len) {
+      return isolate->factory()->nan_value();
+    } else if (data[start_pos] > '9') {
+      // Fast check for a junk value. A valid string may start from a
+      // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
+      // or the 'I' character ('Infinity'). All of that have codes not greater
+      // than '9' except 'I' and &nbsp;.
+      if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
+        return isolate->factory()->nan_value();
+      }
+    } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
+      // The maximal/minimal smi has 10 digits. If the string has less digits
+      // we know it will fit into the smi-data type.
+      int d = ParseDecimalInteger(data, start_pos, len);
+      if (minus) {
+        if (d == 0) return isolate->factory()->minus_zero_value();
+        d = -d;
+      } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
+                 (len == 1 || data[0] != '0')) {
+        // String hash is not calculated yet but all the data are present.
+        // Update the hash field to speed up sequential convertions.
+        uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
+#ifdef DEBUG
+        subject->Hash();  // Force hash calculation.
+        DCHECK_EQ(static_cast<int>(subject->hash_field()),
+                  static_cast<int>(hash));
+#endif
+        subject->set_hash_field(hash);
+      }
+      return handle(Smi::FromInt(d), isolate);
+    }
+  }
+
+  // Slower case.
+  int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
+  return isolate->factory()->NewNumber(
+      StringToDouble(isolate->unicode_cache(), subject, flags));
+}
+
+
 String::FlatContent String::GetFlatContent() {
   DCHECK(!AllowHeapAllocation::IsAllowed());
   int length = this->length();
 String::FlatContent String::GetFlatContent() {
   DCHECK(!AllowHeapAllocation::IsAllowed());
   int length = this->length();
index f7492ebb04dd2da57172af281cd396a77360dadd..f7aea06f9510966644b8235f3ba394fa765b3a74 100644 (file)
@@ -168,6 +168,11 @@ enum KeyedAccessStoreMode {
 };
 
 
 };
 
 
+// Valid hints for the abstract operation ToPrimitive,
+// implemented according to ES6, section 7.1.1.
+enum class ToPrimitiveHint { kDefault, kNumber, kString };
+
+
 enum TypeofMode { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
 
 
 enum TypeofMode { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
 
 
@@ -1077,9 +1082,25 @@ class Object {
   MUST_USE_RESULT static MaybeHandle<JSReceiver> ToObject(
       Isolate* isolate, Handle<Object> object, Handle<Context> context);
 
   MUST_USE_RESULT static MaybeHandle<JSReceiver> ToObject(
       Isolate* isolate, Handle<Object> object, Handle<Context> context);
 
-  // Convert to a Name if needed.
-  MUST_USE_RESULT static MaybeHandle<Name> ToName(Isolate* isolate,
-                                                  Handle<Object> object);
+  // ES6 section 7.1.14 ToPropertyKey
+  MUST_USE_RESULT static inline MaybeHandle<Name> ToName(Isolate* isolate,
+                                                         Handle<Object> input);
+
+  // ES6 section 7.1.1 ToPrimitive
+  MUST_USE_RESULT static inline MaybeHandle<Object> ToPrimitive(
+      Handle<Object> input, ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
+
+  // ES6 section 7.1.3 ToNumber
+  MUST_USE_RESULT static MaybeHandle<Object> ToNumber(Isolate* isolate,
+                                                      Handle<Object> input);
+
+  // ES6 section 7.1.12 ToString
+  MUST_USE_RESULT static MaybeHandle<String> ToString(Isolate* isolate,
+                                                      Handle<Object> input);
+
+  // ES6 section 7.3.9 GetMethod
+  MUST_USE_RESULT static MaybeHandle<Object> GetMethod(
+      Handle<JSReceiver> receiver, Handle<Name> name);
 
   MUST_USE_RESULT static MaybeHandle<Object> GetProperty(
       LookupIterator* it, LanguageMode language_mode = SLOPPY);
 
   MUST_USE_RESULT static MaybeHandle<Object> GetProperty(
       LookupIterator* it, LanguageMode language_mode = SLOPPY);
@@ -1578,6 +1599,8 @@ class Simd128Value : public HeapObject {
   DECLARE_PRINTER(Simd128Value)
   DECLARE_VERIFIER(Simd128Value)
 
   DECLARE_PRINTER(Simd128Value)
   DECLARE_VERIFIER(Simd128Value)
 
+  static Handle<String> ToString(Handle<Simd128Value> input);
+
   // Equality operations.
   inline bool Equals(Simd128Value* that);
 
   // Equality operations.
   inline bool Equals(Simd128Value* that);
 
@@ -1620,6 +1643,8 @@ class Simd128Value : public HeapObject {
                                                                      \
     DECLARE_PRINTER(Type)                                            \
                                                                      \
                                                                      \
     DECLARE_PRINTER(Type)                                            \
                                                                      \
+    static Handle<String> ToString(Handle<Type> input);              \
+                                                                     \
     inline bool Equals(Type* that);                                  \
                                                                      \
    private:                                                          \
     inline bool Equals(Type* that);                                  \
                                                                      \
    private:                                                          \
@@ -1649,6 +1674,13 @@ class JSReceiver: public HeapObject {
  public:
   DECLARE_CAST(JSReceiver)
 
  public:
   DECLARE_CAST(JSReceiver)
 
+  // ES6 section 7.1.1 ToPrimitive
+  MUST_USE_RESULT static MaybeHandle<Object> ToPrimitive(
+      Handle<JSReceiver> receiver,
+      ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
+  MUST_USE_RESULT static MaybeHandle<Object> OrdinaryToPrimitive(
+      Handle<JSReceiver> receiver, Handle<String> hint);
+
   // Implementation of [[HasProperty]], ECMA-262 5th edition, section 8.12.6.
   MUST_USE_RESULT static inline Maybe<bool> HasProperty(
       Handle<JSReceiver> object, Handle<Name> name);
   // Implementation of [[HasProperty]], ECMA-262 5th edition, section 8.12.6.
   MUST_USE_RESULT static inline Maybe<bool> HasProperty(
       Handle<JSReceiver> object, Handle<Name> name);
@@ -8346,6 +8378,9 @@ class String: public Name {
   // to this method are not efficient unless the string is flat.
   INLINE(uint16_t Get(int index));
 
   // to this method are not efficient unless the string is flat.
   INLINE(uint16_t Get(int index));
 
+  // ES6 section 7.1.3.1 ToNumber Applied to the String Type
+  static Handle<Object> ToNumber(Handle<String> subject);
+
   // Flattens the string.  Checks first inline to see if it is
   // necessary.  Does nothing if the string is not a cons string.
   // Flattening allocates a sequential string with the same data as
   // Flattens the string.  Checks first inline to see if it is
   // necessary.  Does nothing if the string is not a cons string.
   // Flattening allocates a sequential string with the same data as
index 896dd6c1df6b0b5a31da9dae50f154a9439ff1af..50e8b7f6fab357fefe7af797a961b23a20c0b712 100644 (file)
@@ -3433,7 +3433,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ bind(&not_oddball);
 
   __ push(r3);  // Push argument.
   __ bind(&not_oddball);
 
   __ push(r3);  // Push argument.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index 1503373d4a3fc6c78cc2630b039800f30c338b08..1ef4e973fdc8dd1baff155916e15b1e75155cc88 100644 (file)
@@ -11,7 +11,6 @@
 
 // The following declarations are shared with other native JS files.
 // They are all declared at this one spot to avoid redeclaration errors.
 
 // The following declarations are shared with other native JS files.
 // They are all declared at this one spot to avoid redeclaration errors.
-var $defaultNumber;
 var $defaultString;
 var $NaN;
 var $nonNumberToNumber;
 var $defaultString;
 var $NaN;
 var $nonNumberToNumber;
@@ -826,7 +825,6 @@ function ToPositiveInteger(x, rangeErrorIndex) {
 // ----------------------------------------------------------------------------
 // Exports
 
 // ----------------------------------------------------------------------------
 // Exports
 
-$defaultNumber = DefaultNumber;
 $defaultString = DefaultString;
 $NaN = %GetRootNaN();
 $nonNumberToNumber = NonNumberToNumber;
 $defaultString = DefaultString;
 $NaN = %GetRootNaN();
 $nonNumberToNumber = NonNumberToNumber;
@@ -880,7 +878,6 @@ $toString = ToString;
   "sub_builtin", SUB,
   "sub_strong_builtin", SUB_STRONG,
   "to_name_builtin", TO_NAME,
   "sub_builtin", SUB,
   "sub_strong_builtin", SUB_STRONG,
   "to_name_builtin", TO_NAME,
-  "to_number_builtin", TO_NUMBER,
   "to_string_builtin", TO_STRING,
 ]);
 
   "to_string_builtin", TO_STRING,
 ]);
 
index 73d511074abd13cd6a4b700c4f329959fffda829..290c228c24d36eae8976955f93d484194582dd8a 100644 (file)
@@ -352,7 +352,7 @@ RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
 
   Handle<Object> value;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
 
   Handle<Object> value;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
-                                     Execution::ToNumber(isolate, date));
+                                     Object::ToNumber(isolate, date));
 
   icu::SimpleDateFormat* date_format =
       DateFormat::UnpackDateFormat(isolate, date_format_holder);
 
   icu::SimpleDateFormat* date_format =
       DateFormat::UnpackDateFormat(isolate, date_format_holder);
@@ -446,7 +446,7 @@ RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
 
   Handle<Object> value;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
 
   Handle<Object> value;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
-                                     Execution::ToNumber(isolate, number));
+                                     Object::ToNumber(isolate, number));
 
   icu::DecimalFormat* number_format =
       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
 
   icu::DecimalFormat* number_format =
       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
index 49734ba8ddeac904827be4299b216fc1e74e712f..d99d5fc548bbec0d95f8b5f560e29964d3a2f436 100644 (file)
@@ -112,81 +112,11 @@ RUNTIME_FUNCTION(Runtime_IsValidSmi) {
 }
 
 
 }
 
 
-static bool AreDigits(const uint8_t* s, int from, int to) {
-  for (int i = from; i < to; i++) {
-    if (s[i] < '0' || s[i] > '9') return false;
-  }
-
-  return true;
-}
-
-
-static int ParseDecimalInteger(const uint8_t* s, int from, int to) {
-  DCHECK(to - from < 10);  // Overflow is not possible.
-  DCHECK(from < to);
-  int d = s[from] - '0';
-
-  for (int i = from + 1; i < to; i++) {
-    d = 10 * d + (s[i] - '0');
-  }
-
-  return d;
-}
-
-
 RUNTIME_FUNCTION(Runtime_StringToNumber) {
   HandleScope handle_scope(isolate);
 RUNTIME_FUNCTION(Runtime_StringToNumber) {
   HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 1);
+  DCHECK_EQ(1, args.length());
   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  subject = String::Flatten(subject);
-
-  // Fast case: short integer or some sorts of junk values.
-  if (subject->IsSeqOneByteString()) {
-    int len = subject->length();
-    if (len == 0) return Smi::FromInt(0);
-
-    DisallowHeapAllocation no_gc;
-    uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
-    bool minus = (data[0] == '-');
-    int start_pos = (minus ? 1 : 0);
-
-    if (start_pos == len) {
-      return isolate->heap()->nan_value();
-    } else if (data[start_pos] > '9') {
-      // Fast check for a junk value. A valid string may start from a
-      // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
-      // or the 'I' character ('Infinity'). All of that have codes not greater
-      // than '9' except 'I' and &nbsp;.
-      if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
-        return isolate->heap()->nan_value();
-      }
-    } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
-      // The maximal/minimal smi has 10 digits. If the string has less digits
-      // we know it will fit into the smi-data type.
-      int d = ParseDecimalInteger(data, start_pos, len);
-      if (minus) {
-        if (d == 0) return isolate->heap()->minus_zero_value();
-        d = -d;
-      } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
-                 (len == 1 || data[0] != '0')) {
-        // String hash is not calculated yet but all the data are present.
-        // Update the hash field to speed up sequential convertions.
-        uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
-#ifdef DEBUG
-        subject->Hash();  // Force hash calculation.
-        DCHECK_EQ(static_cast<int>(subject->hash_field()),
-                  static_cast<int>(hash));
-#endif
-        subject->set_hash_field(hash);
-      }
-      return Smi::FromInt(d);
-    }
-  }
-
-  // Slower case.
-  int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
-  return *isolate->factory()->NewNumber(
-      StringToDouble(isolate->unicode_cache(), subject, flags));
+  return *String::ToNumber(subject);
 }
 
 
 }
 
 
index 2dd5db86e127cb228572ca1d9f3c8865340abcfc..e493118ae097b0670488b78b4a743a1b17d70cec 100644 (file)
@@ -1425,6 +1425,62 @@ RUNTIME_FUNCTION(Runtime_ToObject) {
 }
 
 
 }
 
 
+RUNTIME_FUNCTION(Runtime_ToPrimitive) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(1, args.length());
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     Object::ToPrimitive(input));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(1, args.length());
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Object::ToPrimitive(input, ToPrimitiveHint::kNumber));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToPrimitive_String) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(1, args.length());
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Object::ToPrimitive(input, ToPrimitiveHint::kString));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_OrdinaryToPrimitive) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, hint, 1);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, JSReceiver::OrdinaryToPrimitive(receiver, hint));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToNumber) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(1, args.length());
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     Object::ToNumber(isolate, input));
+  return *result;
+}
+
+
 RUNTIME_FUNCTION(Runtime_StrictEquals) {
   SealHandleScope scope(isolate);
   DCHECK_EQ(2, args.length());
 RUNTIME_FUNCTION(Runtime_StrictEquals) {
   SealHandleScope scope(isolate);
   DCHECK_EQ(2, args.length());
index fa8f7a811a8d96c91eb2fa30e9627f278df0df34..3839a2724efcee1030b9ae4b154ea5257ef73f88 100644 (file)
@@ -1139,7 +1139,7 @@ RUNTIME_FUNCTION(Runtime_Arguments) {
   // Convert the key to a string.
   Handle<Object> converted;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
   // Convert the key to a string.
   Handle<Object> converted;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
-                                     Execution::ToString(isolate, raw_key));
+                                     Object::ToString(isolate, raw_key));
   Handle<String> key = Handle<String>::cast(converted);
 
   // Try to convert the string key into an array index.
   Handle<String> key = Handle<String>::cast(converted);
 
   // Try to convert the string key into an array index.
index 18faeb8741da6f3a757de254aef325cd9167bcb0..f04325442a87a1f81a18cc3192b4c30257618e8e 100644 (file)
@@ -491,6 +491,11 @@ namespace internal {
   F(DefineGetterPropertyUnchecked, 4, 1)             \
   F(DefineSetterPropertyUnchecked, 4, 1)             \
   F(ToObject, 1, 1)                                  \
   F(DefineGetterPropertyUnchecked, 4, 1)             \
   F(DefineSetterPropertyUnchecked, 4, 1)             \
   F(ToObject, 1, 1)                                  \
+  F(ToPrimitive, 1, 1)                               \
+  F(ToPrimitive_Number, 1, 1)                        \
+  F(ToPrimitive_String, 1, 1)                        \
+  F(OrdinaryToPrimitive, 2, 1)                       \
+  F(ToNumber, 1, 1)                                  \
   F(StrictEquals, 2, 1)                              \
   F(InstanceOf, 2, 1)                                \
   F(HasInPrototypeChain, 2, 1)
   F(StrictEquals, 2, 1)                              \
   F(InstanceOf, 2, 1)                                \
   F(HasInPrototypeChain, 2, 1)
index 8cac2c56a2f69cfa8397c6c13bb0d07ef9f33f1f..3f6e281777086cb9317071a730767db99c9db157 100644 (file)
@@ -7,6 +7,7 @@
 // - symbolIsConcatSpreadable
 // - symbolIsRegExp
 // - symbolIterator
 // - symbolIsConcatSpreadable
 // - symbolIsRegExp
 // - symbolIterator
+// - symbolToPrimitive
 // - symbolToStringTag
 // - symbolUnscopables
 
 // - symbolToStringTag
 // - symbolUnscopables
 
@@ -40,6 +41,16 @@ function SymbolConstructor(x) {
 }
 
 
 }
 
 
+// 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
+function SymbolToPrimitive(hint) {
+  if (!(IS_SYMBOL(this) || IS_SYMBOL_WRAPPER(this))) {
+    throw MakeTypeError(kIncompatibleMethodReceiver,
+                        "Symbol.prototype [ @@toPrimitive ]", this);
+  }
+  return %_ValueOf(this);
+}
+
+
 function SymbolToString() {
   if (!(IS_SYMBOL(this) || IS_SYMBOL_WRAPPER(this))) {
     throw MakeTypeError(kIncompatibleMethodReceiver,
 function SymbolToString() {
   if (!(IS_SYMBOL(this) || IS_SYMBOL_WRAPPER(this))) {
     throw MakeTypeError(kIncompatibleMethodReceiver,
@@ -97,6 +108,7 @@ utils.InstallConstants(GlobalSymbol, [
   // "isConcatSpreadable", symbolIsConcatSpreadable,
   // "isRegExp", symbolIsRegExp,
   "iterator", symbolIterator,
   // "isConcatSpreadable", symbolIsConcatSpreadable,
   // "isRegExp", symbolIsRegExp,
   "iterator", symbolIterator,
+  "toPrimitive", symbolToPrimitive,
   // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
   // Move here when shipping
   // "toStringTag", symbolToStringTag,
   // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
   // Move here when shipping
   // "toStringTag", symbolToStringTag,
@@ -110,6 +122,10 @@ utils.InstallFunctions(GlobalSymbol, DONT_ENUM, [
 
 %AddNamedProperty(
     GlobalSymbol.prototype, "constructor", GlobalSymbol, DONT_ENUM);
 
 %AddNamedProperty(
     GlobalSymbol.prototype, "constructor", GlobalSymbol, DONT_ENUM);
+utils.SetFunctionName(SymbolToPrimitive, symbolToPrimitive);
+%AddNamedProperty(
+    GlobalSymbol.prototype, symbolToPrimitive, SymbolToPrimitive,
+    DONT_ENUM | READ_ONLY);
 %AddNamedProperty(
     GlobalSymbol.prototype, symbolToStringTag, "Symbol", DONT_ENUM | READ_ONLY);
 
 %AddNamedProperty(
     GlobalSymbol.prototype, symbolToStringTag, "Symbol", DONT_ENUM | READ_ONLY);
 
index a3db777404a1208d3d6d0f264a056f360e6d8bbc..aca21a12749594f86a0dc9a000cb1b6f2a32209d 100644 (file)
@@ -3224,7 +3224,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ PopReturnAddressTo(rcx);     // Pop return address.
   __ Push(rax);                   // Push argument.
   __ PushReturnAddressFrom(rcx);  // Push return address.
   __ PopReturnAddressTo(rcx);     // Pop return address.
   __ Push(rax);                   // Push argument.
   __ PushReturnAddressFrom(rcx);  // Push return address.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index aa57534844088b3994b40402f4983206aaec445b..ff05f4d763af4032802c1d7977e29d4841152534 100644 (file)
@@ -2981,7 +2981,7 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
   __ pop(ecx);   // Pop return address.
   __ push(eax);  // Push argument.
   __ push(ecx);  // Push return address.
   __ pop(ecx);   // Pop return address.
   __ push(eax);  // Push argument.
   __ push(ecx);  // Push return address.
-  __ InvokeBuiltin(Context::TO_NUMBER_BUILTIN_INDEX, JUMP_FUNCTION);
+  __ TailCallRuntime(Runtime::kToNumber, 1, 1);
 }
 
 
 }
 
 
index 3dff7efaf6056e5d663bb64277521b87c9b1dbe2..2c85596090bd6e4f858336be88b464ed766ef64b 100644 (file)
@@ -74,16 +74,14 @@ TEST(HeapMaps) {
 static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
   CHECK(obj->IsOddball());
   Handle<Object> handle(obj, isolate);
 static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
   CHECK(obj->IsOddball());
   Handle<Object> handle(obj, isolate);
-  Object* print_string =
-      *Execution::ToString(isolate, handle).ToHandleChecked();
+  Object* print_string = *Object::ToString(isolate, handle).ToHandleChecked();
   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
 }
 
 
 static void CheckSmi(Isolate* isolate, int value, const char* string) {
   Handle<Object> handle(Smi::FromInt(value), isolate);
   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
 }
 
 
 static void CheckSmi(Isolate* isolate, int value, const char* string) {
   Handle<Object> handle(Smi::FromInt(value), isolate);
-  Object* print_string =
-      *Execution::ToString(isolate, handle).ToHandleChecked();
+  Object* print_string = *Object::ToString(isolate, handle).ToHandleChecked();
   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
 }
 
   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
 }
 
@@ -92,7 +90,7 @@ static void CheckNumber(Isolate* isolate, double value, const char* string) {
   Handle<Object> number = isolate->factory()->NewNumber(value);
   CHECK(number->IsNumber());
   Handle<Object> print_string =
   Handle<Object> number = isolate->factory()->NewNumber(value);
   CHECK(number->IsNumber());
   Handle<Object> print_string =
-      Execution::ToString(isolate, number).ToHandleChecked();
+      Object::ToString(isolate, number).ToHandleChecked();
   CHECK(String::cast(*print_string)->IsUtf8EqualTo(CStrVector(string)));
 }
 
   CHECK(String::cast(*print_string)->IsUtf8EqualTo(CStrVector(string)));
 }
 
diff --git a/test/mjsunit/harmony/to-number.js b/test/mjsunit/harmony/to-number.js
new file mode 100644 (file)
index 0000000..7125766
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+assertEquals(1, %ToNumber(1));
+assertEquals(1, %_ToNumber(1));
+
+assertEquals(.5, %ToNumber(.5));
+assertEquals(.5, %_ToNumber(.5));
+
+assertEquals(0, %ToNumber(null));
+assertEquals(0, %_ToNumber(null));
+
+assertEquals(1, %ToNumber(true));
+assertEquals(1, %_ToNumber(true));
+
+assertEquals(0, %ToNumber(false));
+assertEquals(0, %_ToNumber(false));
+
+assertEquals(NaN, %ToNumber(undefined));
+assertEquals(NaN, %_ToNumber(undefined));
+
+assertEquals(-1, %ToNumber("-1"));
+assertEquals(-1, %_ToNumber("-1"));
+assertEquals(123, %ToNumber("123"));
+assertEquals(123, %_ToNumber("123"));
+assertEquals(NaN, %ToNumber("random text"));
+assertEquals(NaN, %_ToNumber("random text"));
+
+assertThrows(function() { %ToNumber(Symbol.toPrimitive) }, TypeError);
+assertThrows(function() { %_ToNumber(Symbol.toPrimitive) }, TypeError);
+
+var a = { toString: function() { return 54321 }};
+assertEquals(54321, %ToNumber(a));
+assertEquals(54321, %_ToNumber(a));
+
+var b = { valueOf: function() { return 42 }};
+assertEquals(42, %ToNumber(b));
+assertEquals(42, %_ToNumber(b));
+
+var c = {
+  toString: function() { return "x"},
+  valueOf: function() { return 123 }
+};
+assertEquals(123, %ToNumber(c));
+assertEquals(123, %_ToNumber(c));
+
+var d = {
+  [Symbol.toPrimitive]: function(hint) {
+    assertEquals("number", hint);
+    return 987654321;
+  }
+};
+assertEquals(987654321, %ToNumber(d));
+assertEquals(987654321, %_ToNumber(d));
diff --git a/test/mjsunit/harmony/to-primitive.js b/test/mjsunit/harmony/to-primitive.js
new file mode 100644 (file)
index 0000000..7557425
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+assertEquals(1, %ToPrimitive(1));
+assertEquals(1, %ToPrimitive_Number(1));
+assertEquals(1, %ToPrimitive_String(1));
+assertEquals(1, %_ToPrimitive(1));
+assertEquals(1, %_ToPrimitive_Number(1));
+assertEquals(1, %_ToPrimitive_String(1));
+
+assertEquals(.5, %ToPrimitive(.5));
+assertEquals(.5, %ToPrimitive_Number(.5));
+assertEquals(.5, %ToPrimitive_String(.5));
+assertEquals(.5, %_ToPrimitive(.5));
+assertEquals(.5, %_ToPrimitive_Number(.5));
+assertEquals(.5, %_ToPrimitive_String(.5));
+
+assertEquals(null, %ToPrimitive(null));
+assertEquals(null, %ToPrimitive_Number(null));
+assertEquals(null, %ToPrimitive_String(null));
+assertEquals(null, %_ToPrimitive(null));
+assertEquals(null, %_ToPrimitive_Number(null));
+assertEquals(null, %_ToPrimitive_String(null));
+
+assertEquals(true, %ToPrimitive(true));
+assertEquals(true, %ToPrimitive_Number(true));
+assertEquals(true, %ToPrimitive_String(true));
+assertEquals(true, %_ToPrimitive(true));
+assertEquals(true, %_ToPrimitive_Number(true));
+assertEquals(true, %_ToPrimitive_String(true));
+
+assertEquals(false, %ToPrimitive(false));
+assertEquals(false, %ToPrimitive_Number(false));
+assertEquals(false, %ToPrimitive_String(false));
+assertEquals(false, %_ToPrimitive(false));
+assertEquals(false, %_ToPrimitive_Number(false));
+assertEquals(false, %_ToPrimitive_String(false));
+
+assertEquals(undefined, %ToPrimitive(undefined));
+assertEquals(undefined, %ToPrimitive_Number(undefined));
+assertEquals(undefined, %ToPrimitive_String(undefined));
+assertEquals(undefined, %_ToPrimitive(undefined));
+assertEquals(undefined, %_ToPrimitive_Number(undefined));
+assertEquals(undefined, %_ToPrimitive_String(undefined));
+
+assertEquals("random text", %ToPrimitive("random text"));
+assertEquals("random text", %ToPrimitive_Number("random text"));
+assertEquals("random text", %ToPrimitive_String("random text"));
+assertEquals("random text", %_ToPrimitive("random text"));
+assertEquals("random text", %_ToPrimitive_Number("random text"));
+assertEquals("random text", %_ToPrimitive_String("random text"));
+
+assertEquals(Symbol.toPrimitive, %ToPrimitive(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %ToPrimitive_Number(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %ToPrimitive_String(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToPrimitive(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToPrimitive_Number(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToPrimitive_String(Symbol.toPrimitive));
+
+var a = { toString: function() { return "xyz" }};
+assertEquals("xyz", %ToPrimitive(a));
+assertEquals("xyz", %ToPrimitive_Number(a));
+assertEquals("xyz", %ToPrimitive_String(a));
+assertEquals("xyz", %_ToPrimitive(a));
+assertEquals("xyz", %_ToPrimitive_Number(a));
+assertEquals("xyz", %_ToPrimitive_String(a));
+assertEquals("xyz", %OrdinaryToPrimitive(a, "number"));
+assertEquals("xyz", %OrdinaryToPrimitive(a, "string"));
+assertEquals("xyz", %_OrdinaryToPrimitive(a, "number"));
+assertEquals("xyz", %_OrdinaryToPrimitive(a, "string"));
+
+var b = { valueOf: function() { return 42 }};
+assertEquals(42, %ToPrimitive(b));
+assertEquals(42, %ToPrimitive_Number(b));
+assertEquals("[object Object]", %ToPrimitive_String(b));
+assertEquals(42, %_ToPrimitive(b));
+assertEquals(42, %_ToPrimitive_Number(b));
+assertEquals("[object Object]", %_ToPrimitive_String(b));
+assertEquals(42, %OrdinaryToPrimitive(b, "number"));
+assertEquals("[object Object]", %OrdinaryToPrimitive(b, "string"));
+assertEquals(42, %_OrdinaryToPrimitive(b, "number"));
+assertEquals("[object Object]", %_OrdinaryToPrimitive(b, "string"));
+
+var c = {
+  toString: function() { return "x"},
+  valueOf: function() { return 123 }
+};
+assertEquals(123, %ToPrimitive(c));
+assertEquals(123, %ToPrimitive_Number(c));
+assertEquals("x", %ToPrimitive_String(c));
+assertEquals(123, %_ToPrimitive(c));
+assertEquals(123, %_ToPrimitive_Number(c));
+assertEquals("x", %_ToPrimitive_String(c));
+assertEquals(123, %OrdinaryToPrimitive(c, "number"));
+assertEquals("x", %OrdinaryToPrimitive(c, "string"));
+assertEquals(123, %_OrdinaryToPrimitive(c, "number"));
+assertEquals("x", %_OrdinaryToPrimitive(c, "string"));
+
+var d = {
+  [Symbol.toPrimitive]: function(hint) { return hint }
+};
+assertEquals("default", %ToPrimitive(d));
+assertEquals("number", %ToPrimitive_Number(d));
+assertEquals("string", %ToPrimitive_String(d));
+assertEquals("default", %_ToPrimitive(d));
+assertEquals("number", %_ToPrimitive_Number(d));
+assertEquals("string", %_ToPrimitive_String(d));