From c403ede42ab9ab8e1c6e6788de5c140b16502746 Mon Sep 17 00:00:00 2001 From: bmeurer Date: Fri, 28 Aug 2015 02:46:41 -0700 Subject: [PATCH] [es6] Implement spec compliant ToName (actually ToPropertyKey). 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 | 2 +- src/compiler/linkage.cc | 1 + src/contexts.h | 2 -- src/debug/mirrors.js | 2 +- src/full-codegen/full-codegen.cc | 2 +- src/macros.py | 1 + src/runtime.js | 19 +---------- src/runtime/runtime-object.cc | 18 +++++++++-- src/runtime/runtime.h | 1 + src/v8natives.js | 20 ++++++------ test/mjsunit/harmony/to-name.js | 50 +++++++++++++++++++++++++++++ 11 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 test/mjsunit/harmony/to-name.js diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 3fa66b856..a5f9eeec7 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -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); } diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc index 078e5adf9..f00c236fd 100644 --- a/src/compiler/linkage.cc +++ b/src/compiler/linkage.cc @@ -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: diff --git a/src/contexts.h b/src/contexts.h index 1abd6f2df..768702a96 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -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) diff --git a/src/debug/mirrors.js b/src/debug/mirrors.js index 1b45b93d8..43f0e029a 100644 --- a/src/debug/mirrors.js +++ b/src/debug/mirrors.js @@ -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); } diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc index ee6d9580c..e27081315 100644 --- a/src/full-codegen/full-codegen.cc +++ b/src/full-codegen/full-codegen.cc @@ -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()); } diff --git a/src/macros.py b/src/macros.py index 03c201259..63b0b2948 100644 --- a/src/macros.py +++ b/src/macros.py @@ -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)); diff --git a/src/runtime.js b/src/runtime.js index 1ef4e973f..72871e60c 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -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; diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index e493118ae..cb5b3b685 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -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 maybe = JSReceiver::HasProperty(receiver, key); + Handle name; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, + Object::ToName(isolate, key)); + Maybe 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 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()); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index f04325442..b3d928308 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -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) diff --git a/src/v8natives.js b/src/v8natives.js index 7d8b78a6b..4a9cf5471 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -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 index 000000000..c15bfb5d2 --- /dev/null +++ b/test/mjsunit/harmony/to-name.js @@ -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)); -- 2.34.1