Bug 1055472 - Part 9: Make the Map constructor properly subclassable. (r=Waldo)
authorEric Faust <efaustbmo@gmail.com>
Fri, 13 Nov 2015 18:22:21 -0800
changeset 309838 ed1209c6d7e3f2e7dcdc430c53b1d83c323c47a7
parent 309837 e38d42f7ba2bee86e49b7dab94f6951c1752efa0
child 309839 57cf6353c9fb31f250c26a93b8a460140359e572
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1055472
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1055472 - Part 9: Make the Map constructor properly subclassable. (r=Waldo)
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -216,17 +216,17 @@ MapIteratorObject::next(JSContext* cx, H
     return false;
 }
 
 
 /*** Map *****************************************************************************************/
 
 const Class MapObject::class_ = {
     "Map",
-    JSCLASS_HAS_PRIVATE | 
+    JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
     nullptr, // addProperty
     nullptr, // delProperty
     nullptr, // getProperty
     nullptr, // setProperty
     nullptr, // enumerate
     nullptr, // resolve
     nullptr, // mayResolve
@@ -407,31 +407,30 @@ MapObject::set(JSContext* cx, HandleObje
         ReportOutOfMemory(cx);
         return false;
     }
     WriteBarrierPost(cx->runtime(), map, key.value());
     return true;
 }
 
 MapObject*
-MapObject::create(JSContext* cx)
+MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
 {
-    Rooted<MapObject*> obj(cx, NewBuiltinClassInstance<MapObject>(cx));
-    if (!obj)
-        return nullptr;
-
-    ValueMap* map = cx->new_<ValueMap>(cx->runtime());
+    auto map = cx->make_unique<ValueMap>(cx->runtime());
     if (!map || !map->init()) {
-        js_delete(map);
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    obj->setPrivate(map);
-    return obj;
+    MapObject* mapObj = NewObjectWithClassProto<MapObject>(cx,  proto);
+    if (!mapObj)
+        return nullptr;
+
+    mapObj->setPrivate(map.release());
+    return mapObj;
 }
 
 void
 MapObject::finalize(FreeOp* fop, JSObject* obj)
 {
     if (ValueMap* map = obj->as<MapObject>().getData())
         fop->delete_(map);
 }
@@ -439,17 +438,22 @@ MapObject::finalize(FreeOp* fop, JSObjec
 bool
 MapObject::construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (!ThrowIfNotConstructing(cx, args, "Map"))
         return false;
 
-    Rooted<MapObject*> obj(cx, MapObject::create(cx));
+    RootedObject proto(cx);
+    RootedObject newTarget(cx, &args.newTarget().toObject());
+    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+        return false;
+
+    Rooted<MapObject*> obj(cx, MapObject::create(cx, proto));
     if (!obj)
         return false;
 
     if (!args.get(0).isNullOrUndefined()) {
         RootedValue adderVal(cx);
         if (!GetProperty(cx, obj, obj, cx->names().set, &adderVal))
             return false;
 
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -87,17 +87,17 @@ class MapObject : public NativeObject {
 
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
     static bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
                                             JS::AutoValueVector* entries);
     static bool entries(JSContext* cx, unsigned argc, Value* vp);
     static bool has(JSContext* cx, unsigned argc, Value* vp);
-    static MapObject* create(JSContext* cx);
+    static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
 
     // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
     // interfaces, etc.)
     static uint32_t size(JSContext *cx, HandleObject obj);
     static bool get(JSContext *cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
     static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
     static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
 
--- a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
+++ b/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
@@ -27,16 +27,17 @@ testBuiltin(TypeError);
 testBuiltin(URIError);
 testBuiltin(Number);
 testBuiltin(Date);
 testBuiltin(Date, 5);
 testBuiltin(Date, 5, 10);
 testBuiltin(RegExp);
 testBuiltin(RegExp, /Regexp Argument/);
 testBuiltin(RegExp, "String Argument");
+testBuiltin(Map);
 
 `;
 
 if (classesEnabled())
     eval(test);
 
 if (typeof reportCompare === 'function')
     reportCompare(0,0,"OK");