зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1114580 - Implement ES6 Symbol.toStringTag. r=jorendorff
This commit is contained in:
Родитель
f3d73221f9
Коммит
a62afaf6c1
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче