JS_SetWatchPoint(JSContext *cx, JSObject *obj_, jsid id_, JSWatchPointHandler handler, JSObject *closure_) { assertSameCompartment(cx, obj_); RootedId id(cx, id_); RootedObject origobj(cx, obj_), closure(cx, closure_); RootedObject obj(cx, GetInnerObject(cx, origobj)); if (!obj) return false; RootedValue v(cx); unsigned attrs; RootedId propid(cx); if (JSID_IS_INT(id)) { propid = id; } else if (JSID_IS_OBJECT(id)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH_PROP); return false; } else { RootedValue val(cx, IdToValue(id)); if (!ValueToId<CanGC>(cx, val, &propid)) return false; } /* * If, by unwrapping and innerizing, we changed the object, check * again to make sure that we're allowed to set a watch point. */ if (origobj != obj && !CheckAccess(cx, obj, propid, JSACC_WATCH, &v, &attrs)) return false; if (!obj->isNative()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH, obj->getClass()->name); return false; } /* * Use sparse indexes for watched objects, as dense elements can be written * to without checking the watchpoint map. */ if (!JSObject::sparsifyDenseElements(cx, obj)) return false; types::MarkTypePropertyConfigured(cx, obj, propid); WatchpointMap *wpmap = cx->compartment()->watchpointMap; if (!wpmap) { wpmap = cx->runtime()->new_<WatchpointMap>(); if (!wpmap || !wpmap->init()) { js_ReportOutOfMemory(cx); return false; } cx->compartment()->watchpointMap = wpmap; } return wpmap->watch(cx, obj, propid, handler, closure); }
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler handler, JSObject *closure) { assertSameCompartment(cx, obj); id = js_CheckForStringIndex(id); JSObject *origobj; Value v; uintN attrs; jsid propid; origobj = obj; OBJ_TO_INNER_OBJECT(cx, obj); if (!obj) return false; AutoValueRooter idroot(cx); if (JSID_IS_INT(id)) { propid = id; } else if (JSID_IS_OBJECT(id)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH_PROP); return false; } else { if (!js_ValueToStringId(cx, IdToValue(id), &propid)) return false; propid = js_CheckForStringIndex(propid); idroot.set(IdToValue(propid)); } /* * If, by unwrapping and innerizing, we changed the object, check * again to make sure that we're allowed to set a watch point. */ if (origobj != obj && !CheckAccess(cx, obj, propid, JSACC_WATCH, &v, &attrs)) return false; if (!obj->isNative()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, obj->getClass()->name); return false; } types::MarkTypePropertyConfigured(cx, obj, propid); WatchpointMap *wpmap = cx->compartment->watchpointMap; if (!wpmap) { wpmap = cx->runtime->new_<WatchpointMap>(); if (!wpmap || !wpmap->init()) { js_ReportOutOfMemory(cx); return false; } cx->compartment->watchpointMap = wpmap; } return wpmap->watch(cx, obj, propid, handler, closure); }
JS_SetWatchPoint(JSContext *cx, JSObject *obj_, jsid id, JSWatchPointHandler handler, JSObject *closure_) { assertSameCompartment(cx, obj_); RootedObject obj(cx, obj_), closure(cx, closure_); JSObject *origobj = obj; obj = GetInnerObject(cx, obj); if (!obj) return false; RootedValue v(cx); unsigned attrs; RootedId propid(cx); if (JSID_IS_INT(id)) { propid = id; } else if (JSID_IS_OBJECT(id)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH_PROP); return false; } else { if (!ValueToId(cx, IdToValue(id), propid.address())) return false; } /* * If, by unwrapping and innerizing, we changed the object, check * again to make sure that we're allowed to set a watch point. */ if (origobj != obj && !CheckAccess(cx, obj, propid, JSACC_WATCH, &v, &attrs)) return false; if (!obj->isNative()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, obj->getClass()->name); return false; } types::MarkTypePropertyConfigured(cx, obj, propid); WatchpointMap *wpmap = cx->compartment->watchpointMap; if (!wpmap) { wpmap = cx->runtime->new_<WatchpointMap>(); if (!wpmap || !wpmap->init()) { js_ReportOutOfMemory(cx); return false; } cx->compartment->watchpointMap = wpmap; } return wpmap->watch(cx, obj, propid, handler, closure); }
JS_SetWatchPoint(JSContext *cx, JSObject *obj_, jsid id_, JSWatchPointHandler handler, JSObject *closure_) { assertSameCompartment(cx, obj_); RootedId id(cx, id_); RootedObject origobj(cx, obj_), closure(cx, closure_); RootedObject obj(cx, GetInnerObject(cx, origobj)); if (!obj) return false; RootedId propid(cx); if (JSID_IS_INT(id)) { propid = id; } else if (JSID_IS_OBJECT(id)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH_PROP); return false; } else { RootedValue val(cx, IdToValue(id)); if (!ValueToId<CanGC>(cx, val, &propid)) return false; } if (!obj->isNative()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH, obj->getClass()->name); return false; } /* * Use sparse indexes for watched objects, as dense elements can be written * to without checking the watchpoint map. */ if (!JSObject::sparsifyDenseElements(cx, obj)) return false; types::MarkTypePropertyNonData(cx, obj, propid); WatchpointMap *wpmap = cx->compartment()->watchpointMap; if (!wpmap) { wpmap = cx->runtime()->new_<WatchpointMap>(); if (!wpmap || !wpmap->init()) { js_ReportOutOfMemory(cx); return false; } cx->compartment()->watchpointMap = wpmap; } return wpmap->watch(cx, obj, propid, handler, closure); }
bool WatchpointMap::markAllIteratively(JSTracer *trc) { JSRuntime *rt = trc->context->runtime; if (rt->gcCurrentCompartment) { WatchpointMap *wpmap = rt->gcCurrentCompartment->watchpointMap; return wpmap && wpmap->markIteratively(trc); } bool mutated = false; for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { if ((*c)->watchpointMap) mutated |= (*c)->watchpointMap->markIteratively(trc); } return mutated; }