[es6] Implement spec compliant ToName (actually ToPropertyKey).
authorbmeurer <bmeurer@chromium.org>
Fri, 28 Aug 2015 09:46:41 +0000 (02:46 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 28 Aug 2015 09:46:51 +0000 (09:46 +0000)
This adds a %ToName runtime entry that uses the previously introduced
Object::ToName, which is based on the new Object::ToPrimitive method.
Also removes the need to expose ToName in various way via the builtins
and/or context.

Drive-by-fix: Let %HasProperty do the ToName conversion implicitly as
required.

BUG=v8:4307
LOG=n

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

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

src/compiler/js-generic-lowering.cc
src/compiler/linkage.cc
src/contexts.h
src/debug/mirrors.js
src/full-codegen/full-codegen.cc
src/macros.py
src/runtime.js
src/runtime/runtime-object.cc
src/runtime/runtime.h
src/v8natives.js
test/mjsunit/harmony/to-name.js [new file with mode: 0644]

index 3fa66b8..a5f9eee 100644 (file)
@@ -301,7 +301,7 @@ void JSGenericLowering::LowerJSToString(Node* node) {
 
 
 void JSGenericLowering::LowerJSToName(Node* node) {
-  ReplaceWithBuiltinCall(node, Context::TO_NAME_BUILTIN_INDEX, 1);
+  ReplaceWithRuntimeCall(node, Runtime::kToName);
 }
 
 
index 078e5ad..f00c236 100644 (file)
@@ -250,6 +250,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
     case Runtime::kInlineToPrimitive_String:
     case Runtime::kInlineOrdinaryToPrimitive:
     case Runtime::kInlineToNumber:
+    case Runtime::kInlineToName:
       return 1;
     case Runtime::kInlineDeoptimizeNow:
     case Runtime::kInlineThrowNotDateError:
index 1abd6f2..768702a 100644 (file)
@@ -85,7 +85,6 @@ enum BindingFlags {
   V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments)                 \
   V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable)                   \
   V(TO_LENGTH_FUN_INDEX, JSFunction, to_length_fun)                       \
-  V(TO_NAME_INDEX, JSFunction, to_name)                                   \
   V(TO_NUMBER_FUN_INDEX, JSFunction, to_number_fun)                       \
   V(TO_PRIMITIVE_INDEX, JSFunction, to_primitive)                         \
   V(TO_STRING_FUN_INDEX, JSFunction, to_string_fun)
@@ -135,7 +134,6 @@ enum BindingFlags {
   V(STRING_ADD_RIGHT_BUILTIN_INDEX, JSFunction, string_add_right_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_STRING_BUILTIN_INDEX, JSFunction, to_string_builtin)
 
 
index 1b45b93..43f0e02 100644 (file)
@@ -861,7 +861,7 @@ ObjectMirror.prototype.internalProperties = function() {
 
 
 ObjectMirror.prototype.property = function(name) {
-  var details = %DebugGetPropertyDetails(this.value_, builtins.$toName(name));
+  var details = %DebugGetPropertyDetails(this.value_, TO_NAME(name));
   if (details) {
     return new PropertyMirror(this, name, details);
   }
index ee6d958..e270813 100644 (file)
@@ -883,7 +883,7 @@ void FullCodeGenerator::EmitUnwindBeforeReturn() {
 void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property,
                                         BailoutId bailout_id) {
   VisitForStackValue(property->key());
-  __ InvokeBuiltin(Context::TO_NAME_BUILTIN_INDEX, CALL_FUNCTION);
+  __ CallRuntime(Runtime::kToName, 1);
   PrepareForBailoutForId(bailout_id, NO_REGISTERS);
   __ Push(result_register());
 }
index 03c2012..63b0b29 100644 (file)
@@ -156,6 +156,7 @@ 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 TO_NAME(arg) = (%_ToName(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));
index 1ef4e97..72871e6 100644 (file)
@@ -19,7 +19,6 @@ var $sameValue;
 var $sameValueZero;
 var $toInteger;
 var $toLength;
-var $toName;
 var $toNumber;
 var $toPositiveInteger;
 var $toPrimitive;
@@ -434,7 +433,7 @@ function IN(x) {
     }
     return %HasElement(x, this);
   }
-  return %HasProperty(x, %to_name(this));
+  return %HasProperty(x, this);
 }
 
 
@@ -616,12 +615,6 @@ function TO_STRING() {
 }
 
 
-// Convert the receiver to a string or symbol - forward to ToName.
-function TO_NAME() {
-  return %to_name(this);
-}
-
-
 /* -------------------------------------
    - - -   C o n v e r s i o n s   - - -
    -------------------------------------
@@ -690,12 +683,6 @@ function NonStringToString(x) {
 }
 
 
-// ES6 symbols
-function ToName(x) {
-  return IS_SYMBOL(x) ? x : ToString(x);
-}
-
-
 // ECMA-262, section 9.4, page 34.
 function ToInteger(x) {
   if (%_IsSmi(x)) return x;
@@ -833,7 +820,6 @@ $sameValue = SameValue;
 $sameValueZero = SameValueZero;
 $toInteger = ToInteger;
 $toLength = ToLength;
-$toName = ToName;
 $toNumber = ToNumber;
 $toPositiveInteger = ToPositiveInteger;
 $toPrimitive = ToPrimitive;
@@ -877,7 +863,6 @@ $toString = ToString;
   "string_add_right_builtin", STRING_ADD_RIGHT,
   "sub_builtin", SUB,
   "sub_strong_builtin", SUB_STRONG,
-  "to_name_builtin", TO_NAME,
   "to_string_builtin", TO_STRING,
 ]);
 
@@ -887,7 +872,6 @@ $toString = ToString;
   "non_string_to_string", NonStringToString,
   "to_integer_fun", ToInteger,
   "to_length_fun", ToLength,
-  "to_name", ToName,
   "to_number_fun", ToNumber,
   "to_primitive", ToPrimitive,
   "to_string_fun", ToString,
@@ -896,7 +880,6 @@ $toString = ToString;
 utils.Export(function(to) {
   to.ToBoolean = ToBoolean;
   to.ToLength = ToLength;
-  to.ToName = ToName;
   to.ToNumber = ToNumber;
   to.ToPrimitive = ToPrimitive;
   to.ToString = ToString;
index e493118..cb5b3b6 100644 (file)
@@ -756,9 +756,12 @@ RUNTIME_FUNCTION(Runtime_HasProperty) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 2);
   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
 
-  Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+  Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name);
   if (!maybe.IsJust()) return isolate->heap()->exception();
   return isolate->heap()->ToBoolean(maybe.FromJust());
 }
@@ -1481,6 +1484,17 @@ RUNTIME_FUNCTION(Runtime_ToNumber) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_ToName) {
+  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::ToName(isolate, input));
+  return *result;
+}
+
+
 RUNTIME_FUNCTION(Runtime_StrictEquals) {
   SealHandleScope scope(isolate);
   DCHECK_EQ(2, args.length());
index f043254..b3d9283 100644 (file)
@@ -496,6 +496,7 @@ namespace internal {
   F(ToPrimitive_String, 1, 1)                        \
   F(OrdinaryToPrimitive, 2, 1)                       \
   F(ToNumber, 1, 1)                                  \
+  F(ToName, 1, 1)                                    \
   F(StrictEquals, 2, 1)                              \
   F(InstanceOf, 2, 1)                                \
   F(HasInPrototypeChain, 2, 1)
index 7d8b78a..4a9cf54 100644 (file)
@@ -176,7 +176,7 @@ function ObjectValueOf() {
 
 // ECMA-262 - 15.2.4.5
 function ObjectHasOwnProperty(value) {
-  var name = $toName(value);
+  var name = TO_NAME(value);
   var object = TO_OBJECT(this);
 
   if (%_IsJSProxy(object)) {
@@ -200,7 +200,7 @@ function ObjectIsPrototypeOf(V) {
 
 // ECMA-262 - 15.2.4.6
 function ObjectPropertyIsEnumerable(V) {
-  var P = $toName(V);
+  var P = TO_NAME(V);
   if (%_IsJSProxy(this)) {
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(V)) return false;
@@ -225,7 +225,7 @@ function ObjectDefineGetter(name, fun) {
   desc.setGet(fun);
   desc.setEnumerable(true);
   desc.setConfigurable(true);
-  DefineOwnProperty(TO_OBJECT(receiver), $toName(name), desc, false);
+  DefineOwnProperty(TO_OBJECT(receiver), TO_NAME(name), desc, false);
 }
 
 
@@ -234,7 +234,7 @@ function ObjectLookupGetter(name) {
   if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) {
     receiver = %GlobalProxy(ObjectLookupGetter);
   }
-  return %LookupAccessor(TO_OBJECT(receiver), $toName(name), GETTER);
+  return %LookupAccessor(TO_OBJECT(receiver), TO_NAME(name), GETTER);
 }
 
 
@@ -250,7 +250,7 @@ function ObjectDefineSetter(name, fun) {
   desc.setSet(fun);
   desc.setEnumerable(true);
   desc.setConfigurable(true);
-  DefineOwnProperty(TO_OBJECT(receiver), $toName(name), desc, false);
+  DefineOwnProperty(TO_OBJECT(receiver), TO_NAME(name), desc, false);
 }
 
 
@@ -259,7 +259,7 @@ function ObjectLookupSetter(name) {
   if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) {
     receiver = %GlobalProxy(ObjectLookupSetter);
   }
-  return %LookupAccessor(TO_OBJECT(receiver), $toName(name), SETTER);
+  return %LookupAccessor(TO_OBJECT(receiver), TO_NAME(name), SETTER);
 }
 
 
@@ -561,7 +561,7 @@ function CallTrap2(handler, name, defaultTrap, x, y) {
 
 // ES5 section 8.12.1.
 function GetOwnPropertyJS(obj, v) {
-  var p = $toName(v);
+  var p = TO_NAME(v);
   if (%_IsJSProxy(obj)) {
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(v)) return UNDEFINED;
@@ -632,7 +632,7 @@ function DefineProxyProperty(obj, p, attributes, should_throw) {
 
 // ES5 8.12.9.
 function DefineObjectProperty(obj, p, desc, should_throw) {
-  var current_array = %GetOwnProperty(obj, $toName(p));
+  var current_array = %GetOwnProperty(obj, TO_NAME(p));
   var current = ConvertDescriptorArrayToDescriptor(current_array);
   var extensible = %IsExtensible(obj);
 
@@ -906,7 +906,7 @@ function ToNameArray(obj, trap, includeSymbols) {
   var realLength = 0;
   var names = { __proto__: null };  // TODO(rossberg): use sets once ready.
   for (var index = 0; index < n; index++) {
-    var s = $toName(obj[index]);
+    var s = TO_NAME(obj[index]);
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(s) && !includeSymbols) continue;
     if (%HasOwnProperty(names, s)) {
@@ -1032,7 +1032,7 @@ function ObjectDefineProperty(obj, p, attributes) {
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError(kCalledOnNonObject, "Object.defineProperty");
   }
-  var name = $toName(p);
+  var name = TO_NAME(p);
   if (%_IsJSProxy(obj)) {
     // Clone the attributes object for protection.
     // TODO(rossberg): not spec'ed yet, so not sure if this should involve
diff --git a/test/mjsunit/harmony/to-name.js b/test/mjsunit/harmony/to-name.js
new file mode 100644 (file)
index 0000000..c15bfb5
--- /dev/null
@@ -0,0 +1,50 @@
+// 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", %ToName(1));
+assertEquals("1", %_ToName(1));
+
+assertEquals("0.5", %ToName(.5));
+assertEquals("0.5", %_ToName(.5));
+
+assertEquals("null", %ToName(null));
+assertEquals("null", %_ToName(null));
+
+assertEquals("true", %ToName(true));
+assertEquals("true", %_ToName(true));
+
+assertEquals("false", %ToName(false));
+assertEquals("false", %_ToName(false));
+
+assertEquals("undefined", %ToName(undefined));
+assertEquals("undefined", %_ToName(undefined));
+
+assertEquals("random text", %ToName("random text"));
+assertEquals("random text", %_ToName("random text"));
+
+assertEquals(Symbol.toPrimitive, %ToName(Symbol.toPrimitive));
+assertEquals(Symbol.toPrimitive, %_ToName(Symbol.toPrimitive));
+
+var a = { toString: function() { return "xyz" }};
+assertEquals("xyz", %ToName(a));
+assertEquals("xyz", %_ToName(a));
+
+var b = { valueOf: function() { return 42 }};
+assertEquals("[object Object]", %ToName(b));
+assertEquals("[object Object]", %_ToName(b));
+
+var c = {
+  toString: function() { return "x"},
+  valueOf: function() { return 123 }
+};
+assertEquals("x", %ToName(c));
+assertEquals("x", %_ToName(c));
+
+var d = {
+  [Symbol.toPrimitive]: function(hint) { return hint }
+};
+assertEquals("string", %ToName(d));
+assertEquals("string", %_ToName(d));