From: dslomov@chromium.org Date: Wed, 22 Jan 2014 12:15:57 +0000 (+0000) Subject: ES6: Implement Object.setPrototypeOf X-Git-Tag: upstream/4.7.83~11063 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=33d7e64b510c8459188d9e60861deed08b961c21;p=platform%2Fupstream%2Fv8.git ES6: Implement Object.setPrototypeOf This reverts commit bdc89ae76c15f3ef2626f8849744500248aec3ba. This is a revert of the revert with test/webkit updated as needed. Original CL Description: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.setprototypeof This just exposes the internal %SetPrototype and adds all the required type checks as specified. BUG=v8:2675 LOG=Y R=dslomov@chromium.org, rossberg@chromium.org Review URL: https://codereview.chromium.org/144193005 Patch from Erik Arvidsson . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18739 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/macros.py b/src/macros.py index 0ba5427..1722c6c 100644 --- a/src/macros.py +++ b/src/macros.py @@ -139,6 +139,10 @@ macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg)); # we cannot handle those anyway. macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function'); +# Macro for ES6 CheckObjectCoercible +# Will throw a TypeError of the form "[functionName] called on null or undefined". +macro CHECK_OBJECT_COERCIBLE(arg, functionName) = if (IS_NULL_OR_UNDEFINED(arg) && !IS_UNDETECTABLE(arg)) throw MakeTypeError('called_on_null_or_undefined', [functionName]); + # Indices in bound function info retrieved by %BoundFunctionGetBindings(...). const kBoundFunctionIndex = 0; const kBoundThisIndex = 1; diff --git a/src/messages.js b/src/messages.js index 20d5f99..6cc9ad2 100644 --- a/src/messages.js +++ b/src/messages.js @@ -78,7 +78,7 @@ var kMessages = { getter_must_be_callable: ["Getter must be a function: ", "%0"], setter_must_be_callable: ["Setter must be a function: ", "%0"], value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"], - proto_object_or_null: ["Object prototype may only be an Object or null"], + proto_object_or_null: ["Object prototype may only be an Object or null: ", "%0"], property_desc_object: ["Property description must be an object: ", "%0"], redefine_disallowed: ["Cannot redefine property: ", "%0"], define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."], diff --git a/src/string.js b/src/string.js index dd5115d..8e4b896 100644 --- a/src/string.js +++ b/src/string.js @@ -61,10 +61,8 @@ function StringValueOf() { // ECMA-262, section 15.5.4.4 function StringCharAt(pos) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.charAt"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.charAt"); + var result = %_StringCharAt(this, pos); if (%_IsSmi(result)) { result = %_StringCharAt(TO_STRING_INLINE(this), TO_INTEGER(pos)); @@ -75,10 +73,8 @@ function StringCharAt(pos) { // ECMA-262 section 15.5.4.5 function StringCharCodeAt(pos) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.charCodeAt"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.charCodeAt"); + var result = %_StringCharCodeAt(this, pos); if (!%_IsSmi(result)) { result = %_StringCharCodeAt(TO_STRING_INLINE(this), TO_INTEGER(pos)); @@ -89,10 +85,8 @@ function StringCharCodeAt(pos) { // ECMA-262, section 15.5.4.6 function StringConcat() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.concat"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat"); + var len = %_ArgumentsLength(); var this_as_string = TO_STRING_INLINE(this); if (len === 1) { @@ -113,10 +107,8 @@ function StringConcat() { // ECMA-262 section 15.5.4.7 function StringIndexOf(pattern /* position */) { // length == 1 - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.indexOf"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.indexOf"); + var subject = TO_STRING_INLINE(this); pattern = TO_STRING_INLINE(pattern); var index = 0; @@ -132,10 +124,8 @@ function StringIndexOf(pattern /* position */) { // length == 1 // ECMA-262 section 15.5.4.8 function StringLastIndexOf(pat /* position */) { // length == 1 - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.lastIndexOf"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.lastIndexOf"); + var sub = TO_STRING_INLINE(this); var subLength = sub.length; var pat = TO_STRING_INLINE(pat); @@ -165,10 +155,8 @@ function StringLastIndexOf(pat /* position */) { // length == 1 // This function is implementation specific. For now, we do not // do anything locale specific. function StringLocaleCompare(other) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.localeCompare"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.localeCompare"); + return %StringLocaleCompare(TO_STRING_INLINE(this), TO_STRING_INLINE(other)); } @@ -176,10 +164,8 @@ function StringLocaleCompare(other) { // ECMA-262 section 15.5.4.10 function StringMatch(regexp) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.match"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.match"); + var subject = TO_STRING_INLINE(this); if (IS_REGEXP(regexp)) { // Emulate RegExp.prototype.exec's side effect in step 5, even though @@ -210,10 +196,8 @@ var reusableMatchInfo = [2, "", "", -1, -1]; // ECMA-262, section 15.5.4.11 function StringReplace(search, replace) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.replace"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.replace"); + var subject = TO_STRING_INLINE(this); // Decision tree for dispatch @@ -543,10 +527,8 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { // ECMA-262 section 15.5.4.12 function StringSearch(re) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.search"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.search"); + var regexp; if (IS_STRING(re)) { regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re); @@ -565,10 +547,8 @@ function StringSearch(re) { // ECMA-262 section 15.5.4.13 function StringSlice(start, end) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.slice"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.slice"); + var s = TO_STRING_INLINE(this); var s_len = s.length; var start_i = TO_INTEGER(start); @@ -609,10 +589,8 @@ function StringSlice(start, end) { // ECMA-262 section 15.5.4.14 function StringSplit(separator, limit) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.split"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.split"); + var subject = TO_STRING_INLINE(this); limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); @@ -709,10 +687,8 @@ function StringSplitOnRegExp(subject, separator, limit, length) { // ECMA-262 section 15.5.4.15 function StringSubstring(start, end) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.subString"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.subString"); + var s = TO_STRING_INLINE(this); var s_len = s.length; @@ -744,10 +720,8 @@ function StringSubstring(start, end) { // This is not a part of ECMA-262. function StringSubstr(start, n) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.substr"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.substr"); + var s = TO_STRING_INLINE(this); var len; @@ -786,65 +760,51 @@ function StringSubstr(start, n) { // ECMA-262, 15.5.4.16 function StringToLowerCase() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.toLowerCase"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase"); + return %StringToLowerCase(TO_STRING_INLINE(this)); } // ECMA-262, 15.5.4.17 function StringToLocaleLowerCase() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.toLocaleLowerCase"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase"); + return %StringToLowerCase(TO_STRING_INLINE(this)); } // ECMA-262, 15.5.4.18 function StringToUpperCase() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.toUpperCase"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase"); + return %StringToUpperCase(TO_STRING_INLINE(this)); } // ECMA-262, 15.5.4.19 function StringToLocaleUpperCase() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.toLocaleUpperCase"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase"); + return %StringToUpperCase(TO_STRING_INLINE(this)); } // ES5, 15.5.4.20 function StringTrim() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.trim"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.trim"); + return %StringTrim(TO_STRING_INLINE(this), true, true); } function StringTrimLeft() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.trimLeft"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.trimLeft"); + return %StringTrim(TO_STRING_INLINE(this), true, false); } function StringTrimRight() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["String.prototype.trimRight"]); - } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.trimRight"); + return %StringTrim(TO_STRING_INLINE(this), false, true); } diff --git a/src/v8natives.js b/src/v8natives.js index e987baf..b0b66e7 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -1015,6 +1015,21 @@ function ObjectGetPrototypeOf(obj) { return %GetPrototype(obj); } +// ES6 section 19.1.2.19. +function ObjectSetPrototypeOf(obj, proto) { + CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf"); + + if (proto !== null && !IS_SPEC_OBJECT(proto)) { + throw MakeTypeError("proto_object_or_null", [proto]); + } + + if (IS_SPEC_OBJECT(obj)) { + %SetPrototype(obj, proto); + } + + return obj; +} + // ES5 section 15.2.3.3 function ObjectGetOwnPropertyDescriptor(obj, p) { @@ -1443,6 +1458,7 @@ function SetUpObject() { "defineProperties", ObjectDefineProperties, "freeze", ObjectFreeze, "getPrototypeOf", ObjectGetPrototypeOf, + "setPrototypeOf", ObjectSetPrototypeOf, "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, "getOwnPropertyNames", ObjectGetOwnPropertyNames, // getOwnPropertySymbols is added in symbol.js. diff --git a/test/mjsunit/set-prototype-of.js b/test/mjsunit/set-prototype-of.js new file mode 100644 index 0000000..02bd5e2 --- /dev/null +++ b/test/mjsunit/set-prototype-of.js @@ -0,0 +1,170 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-symbols + + +function getObjects() { + function func() {} + return [ + func, + new func(), + {x: 5}, + /regexp/, + ['array'], + // new Error(), + new Date(), + new Number(1), + new Boolean(true), + new String('str'), + Object(Symbol()) + ]; +} + + +var coercibleValues = [ + 1, + true, + 'string', + Symbol() +]; + + +var nonCoercibleValues = [ + undefined, + null +]; + + +var valuesWithoutNull = coercibleValues.concat(undefined); + + +function TestSetPrototypeOfCoercibleValues() { + for (var i = 0; i < coercibleValues.length; i++) { + var value = coercibleValues[i]; + assertThrows(function() { + Object.getPrototypeOf(value); + }, TypeError); + + assertEquals(Object.setPrototypeOf(value, {}), value); + + assertThrows(function() { + Object.getPrototypeOf(value); + }, TypeError); + } +} +TestSetPrototypeOfCoercibleValues(); + + +function TestSetPrototypeOfNonCoercibleValues() { + for (var i = 0; i < nonCoercibleValues.length; i++) { + var value = nonCoercibleValues[i]; + assertThrows(function() { + Object.setPrototypeOf(value, {}); + }, TypeError); + } +} +TestSetPrototypeOfNonCoercibleValues(); + + +function TestSetPrototypeToNonObject(proto) { + var objects = getObjects(); + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + for (var j = 0; j < valuesWithoutNull.length; j++) { + var proto = valuesWithoutNull[j]; + assertThrows(function() { + Object.setPrototypeOf(object, proto); + }, TypeError); + } + } +} +TestSetPrototypeToNonObject(); + + +function TestSetPrototypeOf(object, proto) { + assertEquals(Object.setPrototypeOf(object, proto), object); + assertEquals(Object.getPrototypeOf(object), proto); +} + + +function TestSetPrototypeOfForObjects() { + var objects1 = getObjects(); + var objects2 = getObjects(); + for (var i = 0; i < objects1.length; i++) { + for (var j = 0; j < objects2.length; j++) { + TestSetPrototypeOf(objects1[i], objects2[j]); + } + } +} +TestSetPrototypeOfForObjects(); + + +function TestSetPrototypeToNull() { + var objects = getObjects(); + for (var i = 0; i < objects.length; i++) { + TestSetPrototypeOf(objects[i], null); + } +} +TestSetPrototypeToNull(); + + +function TestSetPrototypeOfNonExtensibleObject() { + var objects = getObjects(); + var proto = {}; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + Object.preventExtensions(object); + assertThrows(function() { + Object.setPrototypeOf(object, proto); + }, TypeError); + } +} +TestSetPrototypeOfNonExtensibleObject(); + + +function TestLookup() { + var object = {}; + assertFalse('x' in object); + assertFalse('y' in object); + + var oldProto = { + x: 'old x', + y: 'old y' + }; + Object.setPrototypeOf(object, oldProto); + assertEquals(object.x, 'old x'); + assertEquals(object.y, 'old y'); + + var newProto = { + x: 'new x' + }; + Object.setPrototypeOf(object, newProto); + assertEquals(object.x, 'new x'); + assertFalse('y' in object); +} +TestLookup(); diff --git a/test/webkit/Object-create-expected.txt b/test/webkit/Object-create-expected.txt index 519cfb4..ff31544 100644 --- a/test/webkit/Object-create-expected.txt +++ b/test/webkit/Object-create-expected.txt @@ -26,8 +26,8 @@ Test to ensure correct behaviour of Object.defineProperties On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS Object.create() threw exception TypeError: Object prototype may only be an Object or null. -PASS Object.create('a string') threw exception TypeError: Object prototype may only be an Object or null. +PASS Object.create() threw exception TypeError: Object prototype may only be an Object or null: undefined. +PASS Object.create('a string') threw exception TypeError: Object prototype may only be an Object or null: a string. PASS Object.create({}, 'a string') threw exception TypeError: Property description must be an object: a. PASS Object.create(null, 'a string') threw exception TypeError: Property description must be an object: a. PASS JSON.stringify(Object.create(null,{property:{value:'foo', enumerable:true}, property2:{value:'foo', enumerable:true}})) is '{"property":"foo","property2":"foo"}' diff --git a/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt b/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt index 36bc6f6..560be18 100644 --- a/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt +++ b/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt @@ -63,7 +63,7 @@ FAIL getSortedOwnPropertyNames(decodeURI) should be length,name. Was arguments,c FAIL getSortedOwnPropertyNames(decodeURIComponent) should be length,name. Was arguments,caller,length,name. FAIL getSortedOwnPropertyNames(encodeURI) should be length,name. Was arguments,caller,length,name. FAIL getSortedOwnPropertyNames(encodeURIComponent) should be length,name. Was arguments,caller,length,name. -FAIL getSortedOwnPropertyNames(Object) should be create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal. Was arguments,caller,create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,is,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal. +FAIL getSortedOwnPropertyNames(Object) should be create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf. Was arguments,caller,create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,is,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf. PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'] FAIL getSortedOwnPropertyNames(Function) should be length,name,prototype. Was arguments,caller,length,name,prototype. FAIL getSortedOwnPropertyNames(Function.prototype) should be apply,bind,call,constructor,length,name,toString. Was apply,arguments,bind,call,caller,constructor,length,name,toString. diff --git a/test/webkit/fast/js/Object-getOwnPropertyNames.js b/test/webkit/fast/js/Object-getOwnPropertyNames.js index 4f3334a..97ab6ad 100644 --- a/test/webkit/fast/js/Object-getOwnPropertyNames.js +++ b/test/webkit/fast/js/Object-getOwnPropertyNames.js @@ -71,7 +71,7 @@ var expectedPropertyNamesSet = { "encodeURI": "['length', 'name']", "encodeURIComponent": "['length', 'name']", // Built-in ECMA objects - "Object": "['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']", + "Object": "['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal', 'setPrototypeOf']", "Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']", "Function": "['length', 'name', 'prototype']", "Function.prototype": "['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']",