js/src/jsweakmap.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jsweakmap.h"
michael@0 8
michael@0 9 #include <string.h>
michael@0 10
michael@0 11 #include "jsapi.h"
michael@0 12 #include "jscntxt.h"
michael@0 13 #include "jsfriendapi.h"
michael@0 14 #include "jsobj.h"
michael@0 15 #include "jswrapper.h"
michael@0 16
michael@0 17 #include "vm/GlobalObject.h"
michael@0 18 #include "vm/WeakMapObject.h"
michael@0 19
michael@0 20 #include "jsobjinlines.h"
michael@0 21
michael@0 22 using namespace js;
michael@0 23
michael@0 24 WeakMapBase::WeakMapBase(JSObject *memOf, JSCompartment *c)
michael@0 25 : memberOf(memOf),
michael@0 26 compartment(c),
michael@0 27 next(WeakMapNotInList)
michael@0 28 {
michael@0 29 JS_ASSERT_IF(memberOf, memberOf->compartment() == c);
michael@0 30 }
michael@0 31
michael@0 32 WeakMapBase::~WeakMapBase()
michael@0 33 {
michael@0 34 JS_ASSERT(next == WeakMapNotInList);
michael@0 35 }
michael@0 36
michael@0 37 bool
michael@0 38 WeakMapBase::markCompartmentIteratively(JSCompartment *c, JSTracer *tracer)
michael@0 39 {
michael@0 40 bool markedAny = false;
michael@0 41 for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next) {
michael@0 42 if (m->markIteratively(tracer))
michael@0 43 markedAny = true;
michael@0 44 }
michael@0 45 return markedAny;
michael@0 46 }
michael@0 47
michael@0 48 void
michael@0 49 WeakMapBase::sweepCompartment(JSCompartment *c)
michael@0 50 {
michael@0 51 for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next)
michael@0 52 m->sweep();
michael@0 53 }
michael@0 54
michael@0 55 void
michael@0 56 WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
michael@0 57 {
michael@0 58 JSRuntime *rt = tracer->runtime;
michael@0 59 for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
michael@0 60 for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next)
michael@0 61 m->traceMappings(tracer);
michael@0 62 }
michael@0 63 }
michael@0 64
michael@0 65 void
michael@0 66 WeakMapBase::resetCompartmentWeakMapList(JSCompartment *c)
michael@0 67 {
michael@0 68 JS_ASSERT(WeakMapNotInList != nullptr);
michael@0 69
michael@0 70 WeakMapBase *m = c->gcWeakMapList;
michael@0 71 c->gcWeakMapList = nullptr;
michael@0 72 while (m) {
michael@0 73 WeakMapBase *n = m->next;
michael@0 74 m->next = WeakMapNotInList;
michael@0 75 m = n;
michael@0 76 }
michael@0 77 }
michael@0 78
michael@0 79 bool
michael@0 80 WeakMapBase::saveCompartmentWeakMapList(JSCompartment *c, WeakMapVector &vector)
michael@0 81 {
michael@0 82 WeakMapBase *m = c->gcWeakMapList;
michael@0 83 while (m) {
michael@0 84 if (!vector.append(m))
michael@0 85 return false;
michael@0 86 m = m->next;
michael@0 87 }
michael@0 88 return true;
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 WeakMapBase::restoreCompartmentWeakMapLists(WeakMapVector &vector)
michael@0 93 {
michael@0 94 for (WeakMapBase **p = vector.begin(); p != vector.end(); p++) {
michael@0 95 WeakMapBase *m = *p;
michael@0 96 JS_ASSERT(m->next == WeakMapNotInList);
michael@0 97 JSCompartment *c = m->compartment;
michael@0 98 m->next = c->gcWeakMapList;
michael@0 99 c->gcWeakMapList = m;
michael@0 100 }
michael@0 101 }
michael@0 102
michael@0 103 void
michael@0 104 WeakMapBase::removeWeakMapFromList(WeakMapBase *weakmap)
michael@0 105 {
michael@0 106 JSCompartment *c = weakmap->compartment;
michael@0 107 for (WeakMapBase **p = &c->gcWeakMapList; *p; p = &(*p)->next) {
michael@0 108 if (*p == weakmap) {
michael@0 109 *p = (*p)->next;
michael@0 110 weakmap->next = WeakMapNotInList;
michael@0 111 break;
michael@0 112 }
michael@0 113 }
michael@0 114 }
michael@0 115
michael@0 116 static JSObject *
michael@0 117 GetKeyArg(JSContext *cx, CallArgs &args)
michael@0 118 {
michael@0 119 if (args[0].isPrimitive()) {
michael@0 120 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
michael@0 121 return nullptr;
michael@0 122 }
michael@0 123 return &args[0].toObject();
michael@0 124 }
michael@0 125
michael@0 126 MOZ_ALWAYS_INLINE bool
michael@0 127 IsWeakMap(HandleValue v)
michael@0 128 {
michael@0 129 return v.isObject() && v.toObject().is<WeakMapObject>();
michael@0 130 }
michael@0 131
michael@0 132 MOZ_ALWAYS_INLINE bool
michael@0 133 WeakMap_has_impl(JSContext *cx, CallArgs args)
michael@0 134 {
michael@0 135 JS_ASSERT(IsWeakMap(args.thisv()));
michael@0 136
michael@0 137 if (args.length() < 1) {
michael@0 138 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
michael@0 139 "WeakMap.has", "0", "s");
michael@0 140 return false;
michael@0 141 }
michael@0 142 JSObject *key = GetKeyArg(cx, args);
michael@0 143 if (!key)
michael@0 144 return false;
michael@0 145
michael@0 146 if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
michael@0 147 if (map->has(key)) {
michael@0 148 args.rval().setBoolean(true);
michael@0 149 return true;
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 args.rval().setBoolean(false);
michael@0 154 return true;
michael@0 155 }
michael@0 156
michael@0 157 static bool
michael@0 158 WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
michael@0 159 {
michael@0 160 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 161 return CallNonGenericMethod<IsWeakMap, WeakMap_has_impl>(cx, args);
michael@0 162 }
michael@0 163
michael@0 164 MOZ_ALWAYS_INLINE bool
michael@0 165 WeakMap_clear_impl(JSContext *cx, CallArgs args)
michael@0 166 {
michael@0 167 JS_ASSERT(IsWeakMap(args.thisv()));
michael@0 168
michael@0 169 // We can't js_delete the weakmap because the data gathered during GC
michael@0 170 // is used by the Cycle Collector
michael@0 171 if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap())
michael@0 172 map->clear();
michael@0 173
michael@0 174 args.rval().setUndefined();
michael@0 175 return true;
michael@0 176 }
michael@0 177
michael@0 178 static bool
michael@0 179 WeakMap_clear(JSContext *cx, unsigned argc, Value *vp)
michael@0 180 {
michael@0 181 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 182 return CallNonGenericMethod<IsWeakMap, WeakMap_clear_impl>(cx, args);
michael@0 183 }
michael@0 184
michael@0 185 MOZ_ALWAYS_INLINE bool
michael@0 186 WeakMap_get_impl(JSContext *cx, CallArgs args)
michael@0 187 {
michael@0 188 JS_ASSERT(IsWeakMap(args.thisv()));
michael@0 189
michael@0 190 if (args.length() < 1) {
michael@0 191 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
michael@0 192 "WeakMap.get", "0", "s");
michael@0 193 return false;
michael@0 194 }
michael@0 195 JSObject *key = GetKeyArg(cx, args);
michael@0 196 if (!key)
michael@0 197 return false;
michael@0 198
michael@0 199 if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
michael@0 200 if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
michael@0 201 // Read barrier to prevent an incorrectly gray value from escaping the
michael@0 202 // weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp
michael@0 203 ExposeValueToActiveJS(ptr->value().get());
michael@0 204
michael@0 205 args.rval().set(ptr->value());
michael@0 206 return true;
michael@0 207 }
michael@0 208 }
michael@0 209
michael@0 210 args.rval().set((args.length() > 1) ? args[1] : UndefinedValue());
michael@0 211 return true;
michael@0 212 }
michael@0 213
michael@0 214 static bool
michael@0 215 WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
michael@0 216 {
michael@0 217 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 218 return CallNonGenericMethod<IsWeakMap, WeakMap_get_impl>(cx, args);
michael@0 219 }
michael@0 220
michael@0 221 MOZ_ALWAYS_INLINE bool
michael@0 222 WeakMap_delete_impl(JSContext *cx, CallArgs args)
michael@0 223 {
michael@0 224 JS_ASSERT(IsWeakMap(args.thisv()));
michael@0 225
michael@0 226 if (args.length() < 1) {
michael@0 227 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
michael@0 228 "WeakMap.delete", "0", "s");
michael@0 229 return false;
michael@0 230 }
michael@0 231 JSObject *key = GetKeyArg(cx, args);
michael@0 232 if (!key)
michael@0 233 return false;
michael@0 234
michael@0 235 if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
michael@0 236 if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
michael@0 237 map->remove(ptr);
michael@0 238 args.rval().setBoolean(true);
michael@0 239 return true;
michael@0 240 }
michael@0 241 }
michael@0 242
michael@0 243 args.rval().setBoolean(false);
michael@0 244 return true;
michael@0 245 }
michael@0 246
michael@0 247 static bool
michael@0 248 WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
michael@0 249 {
michael@0 250 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 251 return CallNonGenericMethod<IsWeakMap, WeakMap_delete_impl>(cx, args);
michael@0 252 }
michael@0 253
michael@0 254 static bool
michael@0 255 TryPreserveReflector(JSContext *cx, HandleObject obj)
michael@0 256 {
michael@0 257 if (obj->getClass()->ext.isWrappedNative ||
michael@0 258 (obj->getClass()->flags & JSCLASS_IS_DOMJSCLASS) ||
michael@0 259 (obj->is<ProxyObject>() &&
michael@0 260 obj->as<ProxyObject>().handler()->family() == GetDOMProxyHandlerFamily()))
michael@0 261 {
michael@0 262 JS_ASSERT(cx->runtime()->preserveWrapperCallback);
michael@0 263 if (!cx->runtime()->preserveWrapperCallback(cx, obj)) {
michael@0 264 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_WEAKMAP_KEY);
michael@0 265 return false;
michael@0 266 }
michael@0 267 }
michael@0 268 return true;
michael@0 269 }
michael@0 270
michael@0 271 static inline void
michael@0 272 WeakMapPostWriteBarrier(JSRuntime *rt, ObjectValueMap *weakMap, JSObject *key)
michael@0 273 {
michael@0 274 #ifdef JSGC_GENERATIONAL
michael@0 275 /*
michael@0 276 * Strip the barriers from the type before inserting into the store buffer.
michael@0 277 * This will automatically ensure that barriers do not fire during GC.
michael@0 278 *
michael@0 279 * Some compilers complain about instantiating the WeakMap class for
michael@0 280 * unbarriered type arguments, so we cast to a HashMap instead. Because of
michael@0 281 * WeakMap's multiple inheritace, We need to do this in two stages, first to
michael@0 282 * the HashMap base class and then to the unbarriered version.
michael@0 283 */
michael@0 284 ObjectValueMap::Base *baseHashMap = static_cast<ObjectValueMap::Base *>(weakMap);
michael@0 285
michael@0 286 typedef HashMap<JSObject *, Value> UnbarrieredMap;
michael@0 287 UnbarrieredMap *unbarrieredMap = reinterpret_cast<UnbarrieredMap *>(baseHashMap);
michael@0 288
michael@0 289 typedef gc::HashKeyRef<UnbarrieredMap, JSObject *> Ref;
michael@0 290 if (key && IsInsideNursery(rt, key))
michael@0 291 rt->gcStoreBuffer.putGeneric(Ref((unbarrieredMap), key));
michael@0 292 #endif
michael@0 293 }
michael@0 294
michael@0 295 MOZ_ALWAYS_INLINE bool
michael@0 296 SetWeakMapEntryInternal(JSContext *cx, Handle<WeakMapObject*> mapObj,
michael@0 297 HandleObject key, HandleValue value)
michael@0 298 {
michael@0 299 ObjectValueMap *map = mapObj->getMap();
michael@0 300 if (!map) {
michael@0 301 map = cx->new_<ObjectValueMap>(cx, mapObj.get());
michael@0 302 if (!map)
michael@0 303 return false;
michael@0 304 if (!map->init()) {
michael@0 305 js_delete(map);
michael@0 306 JS_ReportOutOfMemory(cx);
michael@0 307 return false;
michael@0 308 }
michael@0 309 mapObj->setPrivate(map);
michael@0 310 }
michael@0 311
michael@0 312 // Preserve wrapped native keys to prevent wrapper optimization.
michael@0 313 if (!TryPreserveReflector(cx, key))
michael@0 314 return false;
michael@0 315
michael@0 316 if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) {
michael@0 317 RootedObject delegate(cx, op(key));
michael@0 318 if (delegate && !TryPreserveReflector(cx, delegate))
michael@0 319 return false;
michael@0 320 }
michael@0 321
michael@0 322 JS_ASSERT(key->compartment() == mapObj->compartment());
michael@0 323 JS_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment());
michael@0 324 if (!map->put(key, value)) {
michael@0 325 JS_ReportOutOfMemory(cx);
michael@0 326 return false;
michael@0 327 }
michael@0 328 WeakMapPostWriteBarrier(cx->runtime(), map, key.get());
michael@0 329 return true;
michael@0 330 }
michael@0 331
michael@0 332 MOZ_ALWAYS_INLINE bool
michael@0 333 WeakMap_set_impl(JSContext *cx, CallArgs args)
michael@0 334 {
michael@0 335 JS_ASSERT(IsWeakMap(args.thisv()));
michael@0 336
michael@0 337 if (args.length() < 1) {
michael@0 338 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
michael@0 339 "WeakMap.set", "0", "s");
michael@0 340 return false;
michael@0 341 }
michael@0 342 RootedObject key(cx, GetKeyArg(cx, args));
michael@0 343 if (!key)
michael@0 344 return false;
michael@0 345
michael@0 346 RootedValue value(cx, (args.length() > 1) ? args[1] : UndefinedValue());
michael@0 347 Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
michael@0 348 Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());
michael@0 349
michael@0 350 args.rval().setUndefined();
michael@0 351 return SetWeakMapEntryInternal(cx, map, key, value);
michael@0 352 }
michael@0 353
michael@0 354 static bool
michael@0 355 WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
michael@0 356 {
michael@0 357 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 358 return CallNonGenericMethod<IsWeakMap, WeakMap_set_impl>(cx, args);
michael@0 359 }
michael@0 360
michael@0 361 JS_FRIEND_API(bool)
michael@0 362 JS_NondeterministicGetWeakMapKeys(JSContext *cx, HandleObject objArg, MutableHandleObject ret)
michael@0 363 {
michael@0 364 RootedObject obj(cx, objArg);
michael@0 365 obj = UncheckedUnwrap(obj);
michael@0 366 if (!obj || !obj->is<WeakMapObject>()) {
michael@0 367 ret.set(nullptr);
michael@0 368 return true;
michael@0 369 }
michael@0 370 RootedObject arr(cx, NewDenseEmptyArray(cx));
michael@0 371 if (!arr)
michael@0 372 return false;
michael@0 373 ObjectValueMap *map = obj->as<WeakMapObject>().getMap();
michael@0 374 if (map) {
michael@0 375 // Prevent GC from mutating the weakmap while iterating.
michael@0 376 gc::AutoSuppressGC suppress(cx);
michael@0 377 for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
michael@0 378 RootedObject key(cx, r.front().key());
michael@0 379 if (!cx->compartment()->wrap(cx, &key))
michael@0 380 return false;
michael@0 381 if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
michael@0 382 return false;
michael@0 383 }
michael@0 384 }
michael@0 385 ret.set(arr);
michael@0 386 return true;
michael@0 387 }
michael@0 388
michael@0 389 static void
michael@0 390 WeakMap_mark(JSTracer *trc, JSObject *obj)
michael@0 391 {
michael@0 392 if (ObjectValueMap *map = obj->as<WeakMapObject>().getMap())
michael@0 393 map->trace(trc);
michael@0 394 }
michael@0 395
michael@0 396 static void
michael@0 397 WeakMap_finalize(FreeOp *fop, JSObject *obj)
michael@0 398 {
michael@0 399 if (ObjectValueMap *map = obj->as<WeakMapObject>().getMap()) {
michael@0 400 map->check();
michael@0 401 #ifdef DEBUG
michael@0 402 map->~ObjectValueMap();
michael@0 403 memset(static_cast<void *>(map), 0xdc, sizeof(*map));
michael@0 404 fop->free_(map);
michael@0 405 #else
michael@0 406 fop->delete_(map);
michael@0 407 #endif
michael@0 408 }
michael@0 409 }
michael@0 410
michael@0 411 JS_PUBLIC_API(JSObject*)
michael@0 412 JS::NewWeakMapObject(JSContext *cx)
michael@0 413 {
michael@0 414 return NewBuiltinClassInstance(cx, &WeakMapObject::class_);
michael@0 415 }
michael@0 416
michael@0 417 JS_PUBLIC_API(bool)
michael@0 418 JS::IsWeakMapObject(JSObject *obj)
michael@0 419 {
michael@0 420 return obj->is<WeakMapObject>();
michael@0 421 }
michael@0 422
michael@0 423 JS_PUBLIC_API(bool)
michael@0 424 JS::GetWeakMapEntry(JSContext *cx, HandleObject mapObj, HandleObject key,
michael@0 425 MutableHandleValue rval)
michael@0 426 {
michael@0 427 CHECK_REQUEST(cx);
michael@0 428 assertSameCompartment(cx, key);
michael@0 429 rval.setUndefined();
michael@0 430 ObjectValueMap *map = mapObj->as<WeakMapObject>().getMap();
michael@0 431 if (!map)
michael@0 432 return true;
michael@0 433 if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
michael@0 434 // Read barrier to prevent an incorrectly gray value from escaping the
michael@0 435 // weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp
michael@0 436 ExposeValueToActiveJS(ptr->value().get());
michael@0 437 rval.set(ptr->value());
michael@0 438 }
michael@0 439 return true;
michael@0 440 }
michael@0 441
michael@0 442 JS_PUBLIC_API(bool)
michael@0 443 JS::SetWeakMapEntry(JSContext *cx, HandleObject mapObj, HandleObject key,
michael@0 444 HandleValue val)
michael@0 445 {
michael@0 446 CHECK_REQUEST(cx);
michael@0 447 assertSameCompartment(cx, key, val);
michael@0 448 Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
michael@0 449 return SetWeakMapEntryInternal(cx, rootedMap, key, val);
michael@0 450 }
michael@0 451
michael@0 452 static bool
michael@0 453 WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
michael@0 454 {
michael@0 455 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 456 JSObject *obj = NewBuiltinClassInstance(cx, &WeakMapObject::class_);
michael@0 457 if (!obj)
michael@0 458 return false;
michael@0 459
michael@0 460 args.rval().setObject(*obj);
michael@0 461 return true;
michael@0 462 }
michael@0 463
michael@0 464 const Class WeakMapObject::class_ = {
michael@0 465 "WeakMap",
michael@0 466 JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
michael@0 467 JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap),
michael@0 468 JS_PropertyStub, /* addProperty */
michael@0 469 JS_DeletePropertyStub, /* delProperty */
michael@0 470 JS_PropertyStub, /* getProperty */
michael@0 471 JS_StrictPropertyStub, /* setProperty */
michael@0 472 JS_EnumerateStub,
michael@0 473 JS_ResolveStub,
michael@0 474 JS_ConvertStub,
michael@0 475 WeakMap_finalize,
michael@0 476 nullptr, /* call */
michael@0 477 nullptr, /* construct */
michael@0 478 nullptr, /* xdrObject */
michael@0 479 WeakMap_mark
michael@0 480 };
michael@0 481
michael@0 482 static const JSFunctionSpec weak_map_methods[] = {
michael@0 483 JS_FN("has", WeakMap_has, 1, 0),
michael@0 484 JS_FN("get", WeakMap_get, 2, 0),
michael@0 485 JS_FN("delete", WeakMap_delete, 1, 0),
michael@0 486 JS_FN("set", WeakMap_set, 2, 0),
michael@0 487 JS_FN("clear", WeakMap_clear, 0, 0),
michael@0 488 JS_FS_END
michael@0 489 };
michael@0 490
michael@0 491 JSObject *
michael@0 492 js_InitWeakMapClass(JSContext *cx, HandleObject obj)
michael@0 493 {
michael@0 494 JS_ASSERT(obj->isNative());
michael@0 495
michael@0 496 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
michael@0 497
michael@0 498 RootedObject weakMapProto(cx, global->createBlankPrototype(cx, &WeakMapObject::class_));
michael@0 499 if (!weakMapProto)
michael@0 500 return nullptr;
michael@0 501
michael@0 502 RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct,
michael@0 503 cx->names().WeakMap, 0));
michael@0 504 if (!ctor)
michael@0 505 return nullptr;
michael@0 506
michael@0 507 if (!LinkConstructorAndPrototype(cx, ctor, weakMapProto))
michael@0 508 return nullptr;
michael@0 509
michael@0 510 if (!DefinePropertiesAndBrand(cx, weakMapProto, nullptr, weak_map_methods))
michael@0 511 return nullptr;
michael@0 512
michael@0 513 if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakMap, ctor, weakMapProto))
michael@0 514 return nullptr;
michael@0 515 return weakMapProto;
michael@0 516 }
michael@0 517

mercurial