Bug 1114580 - Implement ES6 Symbol.toStringTag. r=jorendorff

This commit is contained in:
Tom Schuster 2016-08-31 00:13:10 +02:00
Родитель f3d73221f9
Коммит a62afaf6c1
29 изменённых файлов: 369 добавлений и 81 удалений

Просмотреть файл

@ -151,8 +151,11 @@ GlobalObject::initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, base));
if (!proto)
return false;
if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods))
if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods) ||
!DefineToStringTag(cx, proto, cx->names().MapIterator))
{
return false;
}
global->setReservedSlot(MAP_ITERATOR_PROTO, ObjectValue(*proto));
return true;
}
@ -337,6 +340,10 @@ MapObject::initClass(JSContext* cx, JSObject* obj)
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
return nullptr;
// Define Map.prototype[@@toStringTag].
if (!DefineToStringTag(cx, proto, cx->names().Map))
return nullptr;
}
return proto;
}
@ -893,8 +900,11 @@ GlobalObject::initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, base));
if (!proto)
return false;
if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods))
if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods) ||
!DefineToStringTag(cx, proto, cx->names().SetIterator))
{
return false;
}
global->setReservedSlot(SET_ITERATOR_PROTO, ObjectValue(*proto));
return true;
}
@ -1053,6 +1063,10 @@ SetObject::initClass(JSContext* cx, JSObject* obj)
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
return nullptr;
// Define Set.prototype[@@toStringTag].
if (!DefineToStringTag(cx, proto, cx->names().Set))
return nullptr;
}
return proto;
}

Просмотреть файл

@ -305,63 +305,116 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
}
#endif /* JS_HAS_TOSOURCE */
JSString*
JS_BasicObjectToString(JSContext* cx, HandleObject obj)
{
// Some classes are really common, don't allocate new strings for them.
// The ordering below is based on the measurements in bug 966264.
if (obj->is<PlainObject>())
return cx->names().objectObject;
if (obj->is<StringObject>())
return cx->names().objectString;
if (obj->is<ArrayObject>())
return cx->names().objectArray;
if (obj->is<JSFunction>())
return cx->names().objectFunction;
if (obj->is<NumberObject>())
return cx->names().objectNumber;
const char* className = GetObjectClassName(cx, obj);
if (strcmp(className, "Window") == 0)
return cx->names().objectWindow;
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
!sb.append("]"))
{
return nullptr;
}
return sb.finishString();
}
/* ES5 15.2.4.2. Note steps 1 and 2 are errata. */
// ES6 19.1.3.6
bool
js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Step 1. */
// Step 1.
if (args.thisv().isUndefined()) {
args.rval().setString(cx->names().objectUndefined);
return true;
}
/* Step 2. */
// Step 2.
if (args.thisv().isNull()) {
args.rval().setString(cx->names().objectNull);
return true;
}
/* Step 3. */
// Step 3.
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
/* Steps 4-5. */
JSString* str = JS_BasicObjectToString(cx, obj);
// Step 4.
bool isArray;
if (!IsArray(cx, obj, &isArray))
return false;
// Step 5.
RootedString builtinTag(cx);
if (isArray) {
builtinTag = cx->names().objectArray;
} else {
// Steps 6-13.
ESClass cls;
if (!GetBuiltinClass(cx, obj, &cls))
return false;
switch (cls) {
case ESClass::String:
builtinTag = cx->names().objectString;
break;
case ESClass::Arguments:
builtinTag = cx->names().objectArguments;
break;
case ESClass::Error:
builtinTag = cx->names().objectError;
break;
case ESClass::Boolean:
builtinTag = cx->names().objectBoolean;
break;
case ESClass::Number:
builtinTag = cx->names().objectNumber;
break;
case ESClass::Date:
builtinTag = cx->names().objectDate;
break;
case ESClass::RegExp:
builtinTag = cx->names().objectRegExp;
break;
default:
if (obj->isCallable()) {
// Non-standard: Prevent <object> from showing up as Function.
RootedObject unwrapped(cx, CheckedUnwrap(obj));
if (!unwrapped || !unwrapped->getClass()->isDOMClass())
builtinTag = cx->names().objectFunction;
}
break;
}
}
// Step 14.
// Currently omitted for non-standard fallback.
// Step 15.
RootedValue tag(cx);
RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
if (!GetProperty(cx, obj, obj, toStringTagId, &tag))
return false;
// Step 16.
if (!tag.isString()) {
// Non-standard (bug 1277801): Use ClassName as a fallback in the interim
if (!builtinTag) {
const char* className = GetObjectClassName(cx, obj);
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
!sb.append("]"))
{
return false;
}
builtinTag = sb.finishString();
if (!builtinTag)
return false;
}
args.rval().setString(builtinTag);
return true;
}
// Step 17.
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(tag.toString()) || !sb.append("]"))
return false;
RootedString str(cx, sb.finishString());
if (!str)
return false;
args.rval().setString(str);
return true;
}

Просмотреть файл

@ -79,6 +79,7 @@ SymbolObject::initClass(JSContext* cx, HandleObject obj)
if (!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
!DefineToStringTag(cx, proto, cx->names().Symbol) ||
!DefinePropertiesAndFunctions(cx, ctor, nullptr, staticMethods) ||
!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Symbol, ctor, proto))
{

Просмотреть файл

@ -1438,6 +1438,21 @@ function TypedArraySpecies() {
return this;
}
// ES 2017 draft June 2, 2016 22.2.3.32
function TypedArrayToStringTag() {
// Step 1.
var O = this;
// Steps 2-3.
if (!IsObject(O) || !IsTypedArray(O))
return undefined;
// Steps 4-6.
// Modified to retrieve the [[TypedArrayName]] from the constructor.
return _NameForTypedArray(O);
}
_SetCanonicalName(TypedArrayToStringTag, "get [Symbol.toStringTag]");
// ES 2016 draft Mar 25, 2016 24.1.4.3.
function ArrayBufferSlice(start, end) {
// Step 1.

Просмотреть файл

@ -435,6 +435,8 @@ InitWeakMapClass(JSContext* cx, HandleObject obj, bool defineMembers)
if (defineMembers) {
if (!DefinePropertiesAndFunctions(cx, proto, nullptr, weak_map_methods))
return nullptr;
if (!DefineToStringTag(cx, proto, cx->names().WeakMap))
return nullptr;
}
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakMap, ctor, proto))

Просмотреть файл

@ -51,6 +51,7 @@ WeakSetObject::initClass(JSContext* cx, JSObject* obj)
if (!ctor ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
!DefineToStringTag(cx, proto, cx->names().WeakSet) ||
!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakSet, ctor, proto))
{
return nullptr;

Просмотреть файл

@ -13,11 +13,7 @@ assertEq(Map.length, 0);
assertEq(Map.name, "Map");
assertEq(Object.getPrototypeOf(Map.prototype), Object.prototype);
assertEq("toStringTag" in Symbol, false,
"if this fails, congratulations! implement " +
"Map.prototype[Symbol.toStringTag] = 'Map' in SpiderMonkey and make " +
"the next test check for '[object Map]' again");
assertEq(Object.prototype.toString.call(Map.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(Map.prototype), "[object Map]");
assertEq(Object.prototype.toString.call(new Map()), "[object Map]");
assertEq(Object.keys(Map.prototype).join(), "");
assertEq(Map.prototype.constructor, Map);

Просмотреть файл

@ -13,11 +13,7 @@ assertEq(Set.length, 0);
assertEq(Set.name, "Set");
assertEq(Object.getPrototypeOf(Set.prototype), Object.prototype);
assertEq("toStringTag" in Symbol, false,
"if this fails, congratulations! implement " +
"Set.prototype[Symbol.toStringTag] = 'Set' in SpiderMonkey and make " +
"the next test check for '[object Set]' again");
assertEq(Object.prototype.toString.call(Set.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(Set.prototype), "[object Set]");
assertEq(Object.prototype.toString.call(new Set()), "[object Set]");
assertEq(Object.keys(Set.prototype).join(), "");
assertEq(Set.prototype.constructor, Set);

Просмотреть файл

@ -11,7 +11,7 @@ assertEq(WeakMap.length, 0);
assertEq(WeakMap.name, "WeakMap");
assertEq(Object.getPrototypeOf(WeakMap.prototype), Object.prototype);
assertEq(Object.prototype.toString.call(WeakMap.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(WeakMap.prototype), "[object WeakMap]");
assertEq(Object.prototype.toString.call(new WeakMap()), "[object WeakMap]");
assertEq(Object.keys(WeakMap.prototype).join(), "");
assertEq(WeakMap.prototype.constructor, WeakMap);

Просмотреть файл

@ -11,7 +11,7 @@ assertEq(WeakSet.length, 0);
assertEq(WeakSet.name, "WeakSet");
assertEq(Object.getPrototypeOf(WeakSet.prototype), Object.prototype);
assertEq(Object.prototype.toString.call(WeakSet.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(WeakSet.prototype), "[object WeakSet]");
assertEq(Object.prototype.toString.call(new WeakSet), "[object WeakSet]");
assertEq(Object.keys(WeakSet.prototype).length, 0);
assertEq(WeakSet.prototype.constructor, WeakSet);

Просмотреть файл

@ -9,13 +9,9 @@ function test(constructor) {
var iter = new constructor()[Symbol.iterator]();
assertDeepEq(Reflect.ownKeys(iter), []);
// Iterator prototypes only have a .next property.
// At least until we support @@toStringTag.
// Iterator prototypes only have a .next and @@toStringTag property.
var proto1 = Object.getPrototypeOf(iter);
var names = Reflect.ownKeys(proto1);
names.sort();
assertDeepEq(Reflect.ownKeys(proto1), ['next']);
assertDeepEq(Reflect.ownKeys(proto1), ['next', Symbol.toStringTag]);
var desc = Object.getOwnPropertyDescriptor(proto1, 'next');
assertEq(desc.configurable, true);

Просмотреть файл

@ -12,7 +12,7 @@ dbg.onDebuggerStatement = function (frame) {
assertEq(arr[3].class, "Date");
assertEq(arr[4].class, "Object");
assertEq(arr[5].class, "Function");
assertEq(arr[6].class, "Date");
assertEq(arr[6].class, "Object");
hits++;
};
g.f(Object.prototype, [], eval, new Date,

Просмотреть файл

@ -11,8 +11,8 @@ var p2 = r2.proxy;
assertThrowsInstanceOf(() => ({} instanceof p), TypeError);
assertThrowsInstanceOf(() => ({} instanceof p2), TypeError);
assertEq(Object.prototype.toString.call(p), "[object Object]");
assertEq(Object.prototype.toString.call(p2), "[object Function]");
assertThrowsInstanceOf(() => Object.prototype.toString.call(p), TypeError);
assertThrowsInstanceOf(() => Object.prototype.toString.call(p2), TypeError);
assertThrowsInstanceOf(() => RegExp.prototype.exec.call(p, ""), TypeError);
assertThrowsInstanceOf(() => RegExp.prototype.exec.call(p2, ""), TypeError);

Просмотреть файл

@ -4967,6 +4967,7 @@ GetSymbolDescription(HandleSymbol symbol);
macro(hasInstance) \
macro(split) \
macro(toPrimitive) \
macro(toStringTag) \
macro(unscopables)
enum class SymbolCode : uint32_t {

Просмотреть файл

@ -1495,8 +1495,12 @@ GlobalObject::initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global
const Class* cls = &ArrayIteratorPrototypeClass;
RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto));
if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods))
if (!proto ||
!DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods) ||
!DefineToStringTag(cx, proto, cx->names().ArrayIterator))
{
return false;
}
global->setReservedSlot(ARRAY_ITERATOR_PROTO, ObjectValue(*proto));
return true;
@ -1514,8 +1518,12 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> globa
const Class* cls = &StringIteratorPrototypeClass;
RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto));
if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods))
if (!proto ||
!DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods) ||
!DefineToStringTag(cx, proto, cx->names().StringIterator))
{
return false;
}
global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
return true;

Просмотреть файл

@ -1388,6 +1388,8 @@ js::InitMathClass(JSContext* cx, HandleObject obj)
return nullptr;
if (!JS_DefineConstDoubles(cx, Math, math_constants))
return nullptr;
if (!DefineToStringTag(cx, Math, cx->names().Math))
return nullptr;
obj->as<GlobalObject>().setConstructor(JSProto_Math, ObjectValue(*Math));

Просмотреть файл

@ -990,6 +990,9 @@ js::InitJSONClass(JSContext* cx, HandleObject obj)
if (!JS_DefineFunctions(cx, JSON, json_static_methods))
return nullptr;
if (!DefineToStringTag(cx, JSON, cx->names().JSON))
return nullptr;
global->setConstructor(JSProto_JSON, ObjectValue(*JSON));
return JSON;

Просмотреть файл

@ -1253,12 +1253,9 @@ const char*
ScriptedProxyHandler::className(JSContext* cx, HandleObject proxy) const
{
// Right now the caller is not prepared to handle failures.
RootedObject target(cx, proxy->as<ProxyObject>().target());
if (!target)
return BaseProxyHandler::className(cx, proxy);
return GetObjectClassName(cx, target);
return BaseProxyHandler::className(cx, proxy);
}
JSString*
ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
{

Просмотреть файл

@ -74,9 +74,7 @@ function TestGeneratorObjectPrototype() {
found_property_names.sort();
assertDeepEq(found_property_names, expected_property_names);
// No symbol properties, at least until we have @@toStringTag.
assertEq(Object.getOwnPropertySymbols(GeneratorObjectPrototype).length, 0);
assertDeepEq(Object.getOwnPropertySymbols(GeneratorObjectPrototype), [Symbol.toStringTag]);
}
TestGeneratorObjectPrototype();

Просмотреть файл

@ -0,0 +1,153 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// ES6 19.1.3.6 Object.prototype.toString ( )
function testToString() {
var tests = [
[undefined, "[object Undefined]"],
[null, "[object Null]"],
[[], "[object Array]"],
[new String("abc"), "[object String]"],
[(function () {return arguments;})(), "[object Arguments]"],
[(function () {"use strict"; return arguments;})(), "[object Arguments]"],
[function() {}, "[object Function]"],
[new Error("abc"), "[object Error]"],
[true, "[object Boolean]"],
[5, "[object Number]"],
[new Date(), "[object Date]"],
[/regexp/, "[object RegExp]"],
[{[Symbol.toStringTag]: "abc"}, "[object abc]"],
[Object.create(JSON), "[object JSON]"],
[Object.create(new Number), "[object Object]"],
[Object.create(new Number, {[Symbol.toStringTag]: {value: "abc"}}), "[object abc]"],
[(function() { var x = new Number(); x[Symbol.toStringTag] = "abc"; return x; })(), "[object abc]"],
[[], "[object Array]"]
];
// Testing if the values are obtained the right way.
for (let [value, expected] of tests) {
let result = Object.prototype.toString.call(value);
assertEq(result, expected);
}
}
testToString();
function testProxy() {
var count = 0;
var metaHandler = new Proxy({}, {
get(target, property, receiver) {
assertEq(property, "get");
return function(target, property, receiver) {
assertEq(property, Symbol.toStringTag);
count++;
return undefined;
}
}
});
assertEq(Object.prototype.toString.call(new Proxy({}, metaHandler)), "[object Object]")
assertEq(Object.prototype.toString.call(new Proxy(new Date, metaHandler)), "[object Object]")
assertEq(Object.prototype.toString.call(new Proxy([], metaHandler)), "[object Array]")
assertEq(Object.prototype.toString.call(new Proxy(function() {}, metaHandler)), "[object Function]")
var {proxy, revoke} = Proxy.revocable({}, metaHandler);
revoke();
assertThrowsInstanceOf(() => Object.prototype.toString.call(proxy), TypeError);
assertEq(count, 4);
}
testProxy();
// Tests the passed objects toStringTag values and ensures it's
// desc is writable: false, enumerable: false, configurable: true
function testDefault(object, expected) {
let desc = Object.getOwnPropertyDescriptor(object, Symbol.toStringTag);
assertEq(desc.value, expected);
assertEq(desc.writable, false);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
}
// ES6 19.4.3.5 Symbol.prototype [ @@toStringTag ]
testDefault(Symbol.prototype, "Symbol");
// ES6 20.2.1.9 Math [ @@toStringTag ]
testDefault(Math, "Math");
// ES6 21.1.5.2.2 %StringIteratorPrototype% [ @@toStringTag ]
testDefault(""[Symbol.iterator]().__proto__, "String Iterator")
// ES6 22.1.5.2.2 %ArrayIteratorPrototype% [ @@toStringTag ]
testDefault([][Symbol.iterator]().__proto__, "Array Iterator")
// ES6 22.2.3.31 get %TypedArray%.prototype [ @@toStringTag ]
function testTypedArray() {
let ta = (new Uint8Array(0)).__proto__.__proto__;
let desc = Object.getOwnPropertyDescriptor(ta, Symbol.toStringTag);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertEq(desc.set, undefined);
let get = desc.get;
assertEq(get.name, "get [Symbol.toStringTag]");
assertEq(get.call(3.14), undefined);
assertEq(get.call({}), undefined);
assertEq(get.call(ta), undefined);
let types = [
Int8Array,
Uint8Array,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];
for (let type of types) {
let array = new type(0);
assertEq(get.call(array), type.name);
assertEq(Object.prototype.toString.call(array), `[object ${type.name}]`);
}
}
testTypedArray();
// ES6 23.1.3.13 Map.prototype [ @@toStringTag ]
testDefault(Map.prototype, "Map");
// ES6 23.1.5.2.2 %MapIteratorPrototype% [ @@toStringTag ]
testDefault(new Map()[Symbol.iterator]().__proto__, "Map Iterator")
// ES6 23.2.3.12 Set.prototype [ @@toStringTag ]
testDefault(Set.prototype, "Set");
// ES6 23.2.5.2.2 %SetIteratorPrototype% [ @@toStringTag ]
testDefault(new Set()[Symbol.iterator]().__proto__, "Set Iterator")
// ES6 23.3.3.6 WeakMap.prototype [ @@toStringTag ]
testDefault(WeakMap.prototype, "WeakMap");
// ES6 23.4.3.5 WeakSet.prototype [ @@toStringTag ]
testDefault(WeakSet.prototype, "WeakSet");
// ES6 24.1.4.4 ArrayBuffer.prototype [ @@toStringTag ]
testDefault(ArrayBuffer.prototype, "ArrayBuffer");
// ES6 24.2.4.21 DataView.prototype[ @@toStringTag ]
testDefault(DataView.prototype, "DataView");
// ES6 24.3.3 JSON [ @@toStringTag ]
testDefault(JSON, "JSON");
// ES6 25.2.3.3 GeneratorFunction.prototype [ @@toStringTag ]
testDefault(function* () {}.constructor.prototype, "GeneratorFunction");
// ES6 25.3.1.5 Generator.prototype [ @@toStringTag ]
testDefault(function* () {}().__proto__.__proto__, "Generator");
// ES6 25.4.5.4 Promise.prototype [ @@toStringTag ]
// testDefault(Promise.prototype, "Promise");
// Promise is not yet implemented.
reportCompare(true, true);

Просмотреть файл

@ -99,7 +99,8 @@ if (typeof assertDeepEq === 'undefined') {
assertSameValue(ac, bc, msg);
switch (ac) {
case "[object Function]":
assertSameValue(Function_toString(a), Function_toString(b), msg);
if (typeof isProxy !== "undefined" && !isProxy(a) && !isProxy(b))
assertSameValue(Function_toString(a), Function_toString(b), msg);
}
}

Просмотреть файл

@ -1532,7 +1532,7 @@ function test() {
assertEq(Object.prototype.toString.apply(new Float32Array(0)), "[object Float32Array]");
assertEq(Object.prototype.toString.apply(new ArrayBuffer()), "[object ArrayBuffer]");
assertEq(Object.prototype.toString.apply(new DataView(view.buffer)), "[object DataView]");
assertEq(Object.prototype.toString.apply(DataView.prototype), "[object DataViewPrototype]");
assertEq(Object.prototype.toString.apply(DataView.prototype), "[object DataView]");
// Technically the spec requires these throw a TypeError -- right now. It's
// not clear this is desirable. Once we implement @@toStringTag we can see

Просмотреть файл

@ -1771,6 +1771,9 @@ js::InitArrayBufferClass(JSContext* cx, HandleObject obj)
if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs))
return nullptr;
if (!DefineToStringTag(cx, arrayBufferProto, cx->names().ArrayBuffer))
return nullptr;
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer,
ctor, arrayBufferProto))
{

Просмотреть файл

@ -20,6 +20,7 @@
macro(arguments, arguments, "arguments") \
macro(as, as, "as") \
macro(ArrayBufferSpecies, ArrayBufferSpecies, "ArrayBufferSpecies") \
macro(ArrayIterator, ArrayIterator, "Array Iterator") \
macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
macro(ArraySpecies, ArraySpecies, "ArraySpecies") \
macro(ArraySpeciesCreate, ArraySpeciesCreate, "ArraySpeciesCreate") \
@ -121,6 +122,7 @@
macro(futexNotEqual, futexNotEqual, "not-equal") \
macro(futexTimedOut, futexTimedOut, "timed-out") \
macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
macro(Generator, Generator, "Generator") \
macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
macro(get, get, "get") \
macro(getPrefix, getPrefix, "get ") \
@ -175,6 +177,7 @@
macro(locale, locale, "locale") \
macro(lookupGetter, lookupGetter, "__lookupGetter__") \
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
macro(MapIterator, MapIterator, "Map Iterator") \
macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
macro(message, message, "message") \
@ -203,15 +206,18 @@
macro(NumberFormat, NumberFormat, "NumberFormat") \
macro(NumberFormatFormatGet, NumberFormatFormatGet, "Intl_NumberFormat_format_get") \
macro(numeric, numeric, "numeric") \
macro(objectArray, objectArray, "[object Array]") \
macro(objectFunction, objectFunction, "[object Function]") \
macro(objectNull, objectNull, "[object Null]") \
macro(objectNumber, objectNumber, "[object Number]") \
macro(objectObject, objectObject, "[object Object]") \
macro(objects, objects, "objects") \
macro(objectString, objectString, "[object String]") \
macro(objectUndefined, objectUndefined, "[object Undefined]") \
macro(objectWindow, objectWindow, "[object Window]") \
macro(objectNull, objectNull, "[object Null]") \
macro(objectArray, objectArray, "[object Array]") \
macro(objectString, objectString, "[object String]") \
macro(objectArguments, objectArguments, "[object Arguments]") \
macro(objectFunction, objectFunction, "[object Function]") \
macro(objectError, objectError, "[object Error]") \
macro(objectBoolean, objectBoolean, "[object Boolean]") \
macro(objectNumber, objectNumber, "[object Number]") \
macro(objectDate, objectDate, "[object Date]") \
macro(objectRegExp, objectRegExp, "[object RegExp]") \
macro(objects, objects, "objects") \
macro(of, of, "of") \
macro(offset, offset, "offset") \
macro(optimizedOut, optimizedOut, "optimizedOut") \
@ -223,6 +229,7 @@
macro(pattern, pattern, "pattern") \
macro(preventExtensions, preventExtensions, "preventExtensions") \
macro(promise, promise, "promise") \
macro(SetIterator, SetIterator, "Set Iterator") \
macro(state, state, "state") \
macro(pending, pending, "pending") \
macro(fulfillHandler, fulfillHandler, "fulfillHandler") \
@ -260,6 +267,7 @@
macro(static, static_, "static") \
macro(sticky, sticky, "sticky") \
macro(strings, strings, "strings") \
macro(StringIterator, StringIterator, "String Iterator") \
macro(StructType, StructType, "StructType") \
macro(style, style, "style") \
macro(super, super, "super") \

Просмотреть файл

@ -300,14 +300,20 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
iteratorProto));
if (!genObjectProto)
return false;
if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods))
if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods) ||
!DefineToStringTag(cx, genObjectProto, cx->names().Generator))
{
return false;
}
RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
if (!genFunctionProto || !genFunctionProto->setDelegate(cx))
return false;
if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto))
if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) ||
!DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
{
return false;
}
RootedValue function(cx, global->getConstructor(JSProto_Function));
if (!function.toObjectOrNull())

Просмотреть файл

@ -657,6 +657,14 @@ js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
return true;
}
bool
js::DefineToStringTag(JSContext *cx, HandleObject obj, JSAtom* tag)
{
RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
RootedValue tagString(cx, StringValue(tag));
return DefineProperty(cx, obj, toStringTagId, tagString, nullptr, nullptr, JSPROP_READONLY);
}
static void
GlobalDebuggees_finalize(FreeOp* fop, JSObject* obj)
{

Просмотреть файл

@ -953,6 +953,9 @@ DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
typedef HashSet<GlobalObject*, DefaultHasher<GlobalObject*>, SystemAllocPolicy> GlobalObjectSet;
extern bool
DefineToStringTag(JSContext *cx, HandleObject obj, JSAtom* tag);
/*
* Convenience templates to generic constructor and prototype creation functions
* for ClassSpecs.

Просмотреть файл

@ -46,6 +46,7 @@
#include "vm/TypedArrayCommon.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"
#include "jsfuninlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
@ -1970,6 +1971,23 @@ intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_NameForTypedArray(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
RootedObject object(cx, &args[0].toObject());
MOZ_ASSERT(object->is<TypedArrayObject>());
JSProtoKey protoKey = StandardProtoKeyOrNull(object);
MOZ_ASSERT(protoKey);
args.rval().setString(ClassName(protoKey, cx));
return true;
}
/**
* Returns an object created in the embedding-provided incumbent global.
*
@ -2292,6 +2310,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0),
JS_FN("MakeDefaultConstructor", intrinsic_MakeDefaultConstructor, 2,0),
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1,0),
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 4,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),

Просмотреть файл

@ -1339,6 +1339,7 @@ TypedArrayObject::protoAccessors[] = {
JS_PSG("buffer", TypedArray_bufferGetter, 0),
JS_PSG("byteLength", TypedArray_byteLengthGetter, 0),
JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
JS_SELF_HOSTED_SYM_GET(toStringTag, "TypedArrayToStringTag", 0),
JS_PS_END
};
@ -2732,6 +2733,9 @@ DataViewObject::initClass(JSContext* cx)
if (!JS_DefineFunctions(cx, proto, DataViewObject::jsfuncs))
return false;
if (!DefineToStringTag(cx, proto, cx->names().DataView))
return false;
/*
* Create a helper function to implement the craziness of
* |new DataView(new otherWindow.ArrayBuffer())|, and install it in the