зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1155700 - Change Map/Set to use ClassSpec. r=arai
This commit is contained in:
Родитель
01e395e4ac
Коммит
4a506eb986
|
@ -85,6 +85,11 @@ function MapForEach(callbackfn, thisArg = undefined) {
|
|||
}
|
||||
}
|
||||
|
||||
function MapEntries() {
|
||||
return callFunction(std_Map_iterator, this);
|
||||
}
|
||||
_SetCanonicalName(MapEntries, "entries");
|
||||
|
||||
var iteratorTemp = { mapIterationResultPair : null };
|
||||
|
||||
function MapIteratorNext() {
|
||||
|
|
|
@ -257,6 +257,30 @@ MapIteratorObject::createResultPair(JSContext* cx)
|
|||
|
||||
/*** Map *****************************************************************************************/
|
||||
|
||||
static const ClassSpec MapObjectProtoClassSpec = {
|
||||
DELEGATED_CLASSSPEC(MapObject::class_.spec),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
ClassSpec::IsDelegated
|
||||
};
|
||||
|
||||
static const Class MapObjectProtoClass = {
|
||||
js_Object_str,
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
|
||||
JS_NULL_CLASS_OPS,
|
||||
&MapObjectProtoClassSpec
|
||||
};
|
||||
|
||||
static JSObject*
|
||||
CreatMapPrototype(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
return cx->global()->createBlankPrototype(cx, &MapObjectProtoClass);
|
||||
}
|
||||
|
||||
const ClassOps MapObject::classOps_ = {
|
||||
nullptr, // addProperty
|
||||
nullptr, // delProperty
|
||||
|
@ -272,17 +296,28 @@ const ClassOps MapObject::classOps_ = {
|
|||
mark
|
||||
};
|
||||
|
||||
const ClassSpec MapObject::classSpec_ = {
|
||||
GenericCreateConstructor<MapObject::construct, 0, gc::AllocKind::FUNCTION>,
|
||||
CreatMapPrototype,
|
||||
nullptr,
|
||||
MapObject::staticProperties,
|
||||
MapObject::methods,
|
||||
MapObject::properties,
|
||||
};
|
||||
|
||||
const Class MapObject::class_ = {
|
||||
"Map",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(MapObject::SlotCount) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Map) |
|
||||
JSCLASS_FOREGROUND_FINALIZE,
|
||||
&MapObject::classOps_
|
||||
&MapObject::classOps_,
|
||||
&MapObject::classSpec_
|
||||
};
|
||||
|
||||
const JSPropertySpec MapObject::properties[] = {
|
||||
JS_PSG("size", size, 0),
|
||||
JS_STRING_SYM_PS(toStringTag, "Map", JSPROP_READONLY),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
|
@ -295,6 +330,10 @@ const JSFunctionSpec MapObject::methods[] = {
|
|||
JS_FN("values", values, 0, 0),
|
||||
JS_FN("clear", clear, 0, 0),
|
||||
JS_SELF_HOSTED_FN("forEach", "MapForEach", 2, 0),
|
||||
// MapEntries only exists to preseve the equal identity of
|
||||
// entries and @@iterator.
|
||||
JS_SELF_HOSTED_FN("entries", "MapEntries", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "MapEntries", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -303,53 +342,6 @@ const JSPropertySpec MapObject::staticProperties[] = {
|
|||
JS_PS_END
|
||||
};
|
||||
|
||||
static JSObject*
|
||||
InitClass(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp, JSProtoKey key, Native construct,
|
||||
const JSPropertySpec* properties, const JSFunctionSpec* methods,
|
||||
const JSPropertySpec* staticProperties)
|
||||
{
|
||||
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 0));
|
||||
if (!ctor ||
|
||||
!JS_DefineProperties(cx, ctor, staticProperties) ||
|
||||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
|
||||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
|
||||
!GlobalObject::initBuiltinConstructor(cx, global, key, ctor, proto))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MapObject::initClass(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||
RootedObject proto(cx,
|
||||
InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods,
|
||||
staticProperties));
|
||||
if (proto) {
|
||||
// Define the "entries" method.
|
||||
JSFunction* fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
|
||||
if (!fun)
|
||||
return nullptr;
|
||||
|
||||
// Define its alias.
|
||||
RootedValue funval(cx, ObjectValue(*fun));
|
||||
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;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
static void
|
||||
MarkKey(Range& r, const HashableValue& key, JSTracer* trc)
|
||||
|
@ -852,12 +844,6 @@ MapObject::clear(JSContext* cx, HandleObject obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::InitMapClass(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
return MapObject::initClass(cx, obj);
|
||||
}
|
||||
|
||||
|
||||
/*** SetIterator *********************************************************************************/
|
||||
|
||||
|
@ -1000,6 +986,30 @@ SetIteratorObject::createResult(JSContext* cx)
|
|||
|
||||
/*** Set *****************************************************************************************/
|
||||
|
||||
static const ClassSpec SetObjectProtoClassSpec = {
|
||||
DELEGATED_CLASSSPEC(SetObject::class_.spec),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
ClassSpec::IsDelegated
|
||||
};
|
||||
|
||||
static const Class SetObjectProtoClass = {
|
||||
js_Object_str,
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
|
||||
JS_NULL_CLASS_OPS,
|
||||
&SetObjectProtoClassSpec
|
||||
};
|
||||
|
||||
static JSObject*
|
||||
CreateSetPrototype(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
return cx->global()->createBlankPrototype(cx, &SetObjectProtoClass);
|
||||
}
|
||||
|
||||
const ClassOps SetObject::classOps_ = {
|
||||
nullptr, // addProperty
|
||||
nullptr, // delProperty
|
||||
|
@ -1015,17 +1025,28 @@ const ClassOps SetObject::classOps_ = {
|
|||
mark
|
||||
};
|
||||
|
||||
const ClassSpec SetObject::classSpec_ = {
|
||||
GenericCreateConstructor<SetObject::construct, 0, gc::AllocKind::FUNCTION>,
|
||||
CreateSetPrototype,
|
||||
nullptr,
|
||||
SetObject::staticProperties,
|
||||
SetObject::methods,
|
||||
SetObject::properties,
|
||||
};
|
||||
|
||||
const Class SetObject::class_ = {
|
||||
"Set",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(SetObject::SlotCount) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Set) |
|
||||
JSCLASS_FOREGROUND_FINALIZE,
|
||||
&SetObject::classOps_
|
||||
&SetObject::classOps_,
|
||||
&SetObject::classSpec_,
|
||||
};
|
||||
|
||||
const JSPropertySpec SetObject::properties[] = {
|
||||
JS_PSG("size", size, 0),
|
||||
JS_STRING_SYM_PS(toStringTag, "Set", JSPROP_READONLY),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
|
@ -1036,6 +1057,11 @@ const JSFunctionSpec SetObject::methods[] = {
|
|||
JS_FN("entries", entries, 0, 0),
|
||||
JS_FN("clear", clear, 0, 0),
|
||||
JS_SELF_HOSTED_FN("forEach", "SetForEach", 2, 0),
|
||||
// SetValues only exists to preseve the equal identity of
|
||||
// values, keys and @@iterator.
|
||||
JS_SELF_HOSTED_FN("values", "SetValues", 0, 0),
|
||||
JS_SELF_HOSTED_FN("keys", "SetValues", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "SetValues", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -1044,36 +1070,6 @@ const JSPropertySpec SetObject::staticProperties[] = {
|
|||
JS_PS_END
|
||||
};
|
||||
|
||||
JSObject*
|
||||
SetObject::initClass(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||
RootedObject proto(cx,
|
||||
InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods,
|
||||
staticProperties));
|
||||
if (proto) {
|
||||
// Define the "values" method.
|
||||
JSFunction* fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
|
||||
if (!fun)
|
||||
return nullptr;
|
||||
|
||||
// Define its aliases.
|
||||
RootedValue funval(cx, ObjectValue(*fun));
|
||||
if (!JS_DefineProperty(cx, proto, "keys", funval, 0))
|
||||
return nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SetObject::keys(JSContext* cx, HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> keys)
|
||||
{
|
||||
|
@ -1440,12 +1436,6 @@ SetObject::clear(JSContext* cx, unsigned argc, Value* vp)
|
|||
return CallNonGenericMethod(cx, is, clear_impl, args);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::InitSetClass(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
return SetObject::initClass(cx, obj);
|
||||
}
|
||||
|
||||
/*** JS static utility functions *********************************************/
|
||||
|
||||
static bool
|
||||
|
|
|
@ -93,7 +93,6 @@ class MapObject : public NativeObject {
|
|||
"IteratorKind Entries must match self-hosting define for item kind "
|
||||
"key-and-value.");
|
||||
|
||||
static JSObject* initClass(JSContext* cx, JSObject* obj);
|
||||
static const Class class_;
|
||||
|
||||
enum { NurseryKeysSlot, SlotCount };
|
||||
|
@ -124,6 +123,7 @@ class MapObject : public NativeObject {
|
|||
friend class OrderedHashTableRef<MapObject>;
|
||||
|
||||
private:
|
||||
static const ClassSpec classSpec_;
|
||||
static const ClassOps classOps_;
|
||||
|
||||
static const JSPropertySpec properties[];
|
||||
|
@ -199,7 +199,6 @@ class SetObject : public NativeObject {
|
|||
"IteratorKind Entries must match self-hosting define for item kind "
|
||||
"key-and-value.");
|
||||
|
||||
static JSObject* initClass(JSContext* cx, JSObject* obj);
|
||||
static const Class class_;
|
||||
|
||||
enum { NurseryKeysSlot, SlotCount };
|
||||
|
@ -224,6 +223,7 @@ class SetObject : public NativeObject {
|
|||
friend class OrderedHashTableRef<SetObject>;
|
||||
|
||||
private:
|
||||
static const ClassSpec classSpec_;
|
||||
static const ClassOps classOps_;
|
||||
|
||||
static const JSPropertySpec properties[];
|
||||
|
@ -328,12 +328,6 @@ IsOptimizableInitForSet(JSContext* cx, HandleObject setObject, HandleValue itera
|
|||
return stubChain->tryOptimizeArray(cx, array.as<ArrayObject>(), optimized);
|
||||
}
|
||||
|
||||
extern JSObject*
|
||||
InitMapClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
extern JSObject*
|
||||
InitSetClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* builtin_MapObject_h */
|
||||
|
|
|
@ -79,6 +79,11 @@ function SetForEach(callbackfn, thisArg = undefined) {
|
|||
}
|
||||
}
|
||||
|
||||
function SetValues() {
|
||||
return callFunction(std_Set_iterator, this);
|
||||
}
|
||||
_SetCanonicalName(SetValues, "values");
|
||||
|
||||
// ES6 final draft 23.2.2.2.
|
||||
function SetSpecies() {
|
||||
// Step 1.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Make sure the real class name is not exposed by Errors.
|
||||
function assertThrowsObjectError(f) {
|
||||
try {
|
||||
f();
|
||||
assertEq(true, false);
|
||||
} catch (e) {
|
||||
assertEq(e instanceof TypeError, true);
|
||||
assertEq(e.message.includes("called on incompatible Object"), true);
|
||||
}
|
||||
}
|
||||
|
||||
assertThrowsObjectError(() => Map.prototype.has(0));
|
||||
assertThrowsObjectError(() => Set.prototype.has(0));
|
||||
assertThrowsObjectError(() => WeakMap.prototype.has({}));
|
||||
assertThrowsObjectError(() => WeakSet.prototype.has({}));
|
||||
assertThrowsObjectError(() => Date.prototype.getSeconds());
|
|
@ -0,0 +1,12 @@
|
|||
const prototypes = [
|
||||
Map.prototype,
|
||||
Set.prototype,
|
||||
WeakMap.prototype,
|
||||
WeakSet.prototype,
|
||||
Date.prototype,
|
||||
];
|
||||
|
||||
for (const prototype of prototypes) {
|
||||
delete prototype[Symbol.toStringTag];
|
||||
assertEq(Object.prototype.toString.call(prototype), "[object Object]");
|
||||
}
|
|
@ -104,8 +104,8 @@
|
|||
real(Uint8ClampedArray, 33, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
||||
real(Proxy, 34, InitProxyClass, js::ProxyClassPtr) \
|
||||
real(WeakMap, 35, InitWeakMapClass, OCLASP(WeakMap)) \
|
||||
real(Map, 36, InitMapClass, OCLASP(Map)) \
|
||||
real(Set, 37, InitSetClass, OCLASP(Set)) \
|
||||
real(Map, 36, InitViaClassSpec, OCLASP(Map)) \
|
||||
real(Set, 37, InitViaClassSpec, OCLASP(Set)) \
|
||||
real(DataView, 38, InitDataViewClass, OCLASP(DataView)) \
|
||||
real(Symbol, 39, InitSymbolClass, OCLASP(Symbol)) \
|
||||
IF_SAB(real,imaginary)(SharedArrayBuffer, 40, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче