Bug 1155700 - Change Map/Set to use ClassSpec. r=arai

This commit is contained in:
Tom Schuster 2016-11-19 01:17:53 +01:00
Родитель 01e395e4ac
Коммит 4a506eb986
7 изменённых файлов: 123 добавлений и 101 удалений

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

@ -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)) \