Bug 990290 - Expose JSAPI functions for creating and manipulating scripted WeakMaps. r=terrence

This commit is contained in:
Bobby Holley 2014-04-11 07:59:46 -07:00
parent 506d2f07ec
commit 77804e57dd
2 changed files with 100 additions and 34 deletions

View File

@ -4365,10 +4365,28 @@ CreateTypeError(JSContext *cx, HandleString stack, HandleString fileName,
uint32_t lineNumber, uint32_t columnNumber, JSErrorReport *report,
HandleString message, MutableHandleValue rval);
} /* namespace JS */
/************************************************************************/
/*
* Weak Maps.
*/
extern JS_PUBLIC_API(JSObject *)
NewWeakMapObject(JSContext *cx);
extern JS_PUBLIC_API(bool)
IsWeakMapObject(JSObject *obj);
extern JS_PUBLIC_API(bool)
GetWeakMapEntry(JSContext *cx, JS::HandleObject mapObj, JS::HandleObject key,
JS::MutableHandleValue val);
extern JS_PUBLIC_API(bool)
SetWeakMapEntry(JSContext *cx, JS::HandleObject mapObj, JS::HandleObject key,
JS::HandleValue val);
} /* namespace JS */
/*
* Dates.
*/

View File

@ -292,6 +292,43 @@ WeakMapPostWriteBarrier(JSRuntime *rt, ObjectValueMap *weakMap, JSObject *key)
#endif
}
MOZ_ALWAYS_INLINE bool
SetWeakMapEntryInternal(JSContext *cx, Handle<WeakMapObject*> mapObj,
HandleObject key, HandleValue value)
{
ObjectValueMap *map = mapObj->getMap();
if (!map) {
map = cx->new_<ObjectValueMap>(cx, mapObj.get());
if (!map)
return false;
if (!map->init()) {
js_delete(map);
JS_ReportOutOfMemory(cx);
return false;
}
mapObj->setPrivate(map);
}
// Preserve wrapped native keys to prevent wrapper optimization.
if (!TryPreserveReflector(cx, key))
return false;
if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) {
RootedObject delegate(cx, op(key));
if (delegate && !TryPreserveReflector(cx, delegate))
return false;
}
JS_ASSERT(key->compartment() == mapObj->compartment());
JS_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment());
if (!map->put(key, value)) {
JS_ReportOutOfMemory(cx);
return false;
}
WeakMapPostWriteBarrier(cx->runtime(), map, key.get());
return true;
}
MOZ_ALWAYS_INLINE bool
WeakMap_set_impl(JSContext *cx, CallArgs args)
{
@ -307,41 +344,11 @@ WeakMap_set_impl(JSContext *cx, CallArgs args)
return false;
RootedValue value(cx, (args.length() > 1) ? args[1] : UndefinedValue());
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
ObjectValueMap *map = thisObj->as<WeakMapObject>().getMap();
if (!map) {
map = cx->new_<ObjectValueMap>(cx, thisObj.get());
if (!map)
return false;
if (!map->init()) {
js_delete(map);
JS_ReportOutOfMemory(cx);
return false;
}
thisObj->setPrivate(map);
}
// Preserve wrapped native keys to prevent wrapper optimization.
if (!TryPreserveReflector(cx, key))
return false;
if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) {
RootedObject delegate(cx, op(key));
if (delegate && !TryPreserveReflector(cx, delegate))
return false;
}
JS_ASSERT(key->compartment() == thisObj->compartment());
JS_ASSERT_IF(value.isObject(), value.toObject().compartment() == thisObj->compartment());
if (!map->put(key, value)) {
JS_ReportOutOfMemory(cx);
return false;
}
WeakMapPostWriteBarrier(cx->runtime(), map, key.get());
Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());
args.rval().setUndefined();
return true;
return SetWeakMapEntryInternal(cx, map, key, value);
}
static bool
@ -401,6 +408,47 @@ WeakMap_finalize(FreeOp *fop, JSObject *obj)
}
}
JS_PUBLIC_API(JSObject*)
JS::NewWeakMapObject(JSContext *cx)
{
return NewBuiltinClassInstance(cx, &WeakMapObject::class_);
}
JS_PUBLIC_API(bool)
JS::IsWeakMapObject(JSObject *obj)
{
return obj->is<WeakMapObject>();
}
JS_PUBLIC_API(bool)
JS::GetWeakMapEntry(JSContext *cx, HandleObject mapObj, HandleObject key,
MutableHandleValue rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, key);
rval.setUndefined();
ObjectValueMap *map = mapObj->as<WeakMapObject>().getMap();
if (!map)
return true;
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
// Read barrier to prevent an incorrectly gray value from escaping the
// weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp
ExposeValueToActiveJS(ptr->value().get());
rval.set(ptr->value());
}
return true;
}
JS_PUBLIC_API(bool)
JS::SetWeakMapEntry(JSContext *cx, HandleObject mapObj, HandleObject key,
HandleValue val)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, key, val);
Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
return SetWeakMapEntryInternal(cx, rootedMap, key, val);
}
static bool
WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
{