Exemplo n.º 1
0
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
                 JSWatchPointHandler handler, void *closure)
{
    JSAtom *atom;
    jsid propid;
    JSObject *pobj;
    JSScopeProperty *sprop;
    JSRuntime *rt;
    JSWatchPoint *wp;
    JSPropertyOp watcher;

    if (!OBJ_IS_NATIVE(obj)) {
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
                             OBJ_GET_CLASS(cx, obj)->name);
        return JS_FALSE;
    }

    if (JSVAL_IS_INT(id)) {
        propid = (jsid)id;
        atom = NULL;
    } else {
        atom = js_ValueToStringAtom(cx, id);
        if (!atom)
            return JS_FALSE;
        propid = (jsid)atom;
    }

    if (!js_LookupProperty(cx, obj, propid, &pobj, (JSProperty **)&sprop))
        return JS_FALSE;
    rt = cx->runtime;
    if (!sprop) {
        /* Check for a deleted symbol watchpoint, which holds its property. */
        sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
        if (!sprop) {
            /* Make a new property in obj so we can watch for the first set. */
            if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
                                   NULL, NULL, JSPROP_ENUMERATE,
                                   (JSProperty **)&sprop)) {
                sprop = NULL;
            }
        }
    } else if (pobj != obj) {
        /* Clone the prototype property so we can watch the right object. */
        jsval value;
        JSPropertyOp getter, setter;
        uintN attrs;

        if (OBJ_IS_NATIVE(pobj)) {
            value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
                    ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
                    : JSVAL_VOID;
            getter = sprop->getter;
            setter = sprop->setter;
            attrs = sprop->attrs;
        } else {
            if (!OBJ_GET_PROPERTY(cx, pobj, id, &value)) {
                OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
                return JS_FALSE;
            }
            getter = setter = JS_PropertyStub;
            attrs = JSPROP_ENUMERATE;
        }
        OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);

        if (!js_DefineProperty(cx, obj, propid, value, getter, setter, attrs,
                               (JSProperty **)&sprop)) {
            sprop = NULL;
        }
    }
    if (!sprop)
        return JS_FALSE;

    wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
    if (!wp) {
        watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
        if (!watcher)
            return JS_FALSE;

        wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
        if (!wp)
            return JS_FALSE;
        wp->handler = NULL;
        wp->closure = NULL;
        if (!js_AddRoot(cx, &wp->closure, "wp->closure")) {
            JS_free(cx, wp);
            return JS_FALSE;
        }
        JS_APPEND_LINK(&wp->links, &rt->watchPointList);
        wp->object = obj;
        wp->sprop = sprop;
        JS_ASSERT(sprop->setter != js_watch_set);
        wp->setter = sprop->setter;
        wp->nrefs = 1;
        sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
                                             sprop->getter, watcher);
        if (!sprop)
            return DropWatchPoint(cx, wp);
    }
    wp->handler = handler;
    wp->closure = closure;
    OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);
    return JS_TRUE;
}
Exemplo n.º 2
0
static JSBool
obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    JSFunction *fun;
    jsval userid, symid, propid, value;
    JSAtom *atom;
    JSRuntime *rt;
    JSBool ok;
    JSProperty *prop;
    JSPropertyOp getter, setter;
    JSClass *clasp;

    fun = JS_ValueToFunction(cx, argv[1]);
    if (!fun)
	return JS_FALSE;
    argv[1] = OBJECT_TO_JSVAL(fun->object);

    /*
     * Lock the world while we look in obj.  Be sure to return via goto out
     * on error, so we unlock.
     */
    rt = cx->runtime;
    JS_LOCK_RUNTIME(rt);

    /* Compute the unique int/atom symbol id needed by js_LookupProperty. */
    userid = argv[0];
    if (JSVAL_IS_INT(userid)) {
	symid = userid;
	atom = NULL;
    } else {
	atom = js_ValueToStringAtom(cx, userid);
	if (!atom) {
	    ok = JS_FALSE;
	    goto out;
	}
	symid = (jsval)atom;
    }

    ok = js_LookupProperty(cx, obj, symid, &obj, &prop);
    if (atom)
	js_DropAtom(cx, atom);
    if (!ok)
	goto out;

    /* Set propid from the property, in case it has a tinyid. */
    if (prop) {
	propid = prop->id;
	getter = prop->getter;
	setter = prop->setter;
	value = prop->object->slots[prop->slot];
    } else {
	propid = userid;
	clasp = obj->map->clasp;
	getter = clasp->getProperty;
	setter = clasp->setProperty;
	value = JSVAL_VOID;
    }

    /*
     * Security policy is implemented in getters and setters, so we have to
     * call get and set here to let the JS API client check for a watchpoint
     * that crosses a trust boundary.
     * XXX assumes get and set are idempotent, should use a clasp->watch hook
     */
    ok = getter(cx, obj, propid, &value) && setter(cx, obj, propid, &value);
    if (!ok)
	goto out;

    /* Finally, call into jsdbgapi.c to set the watchpoint on userid. */
    ok = JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, fun->object);

out:
    JS_UNLOCK_RUNTIME(rt);
    return ok;
}