Bug 822385 - Add getter, setter and method with jitinfo to the shell. r=bz
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 20 Dec 2012 15:27:54 +0100
changeset 125735 91dae828764356a04eda7c4a41bef0c28d01944d
parent 125734 1e2283f6856c629369358bbbe4f9b6f53192ba0f
child 125736 e7efeccbef31c3887d967e4938c780681ffd0e22
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs822385
milestone20.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 822385 - Add getter, setter and method with jitinfo to the shell. r=bz
js/src/jit-test/tests/basic/test-jitinfo.js
js/src/shell/js.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/test-jitinfo.js
@@ -0,0 +1,20 @@
+// Test for the shell's FakeDOMObject constructor. This test
+// ensures the fuzzers know about this object.
+function f() {
+    var res = 0;
+    var d = new FakeDOMObject();
+    assertEq(d !== new FakeDOMObject(), true);
+
+    for (var i=0; i<100; i++) {
+	var x = d.x;
+	assertEq(typeof x, "number");
+
+	d.x = 10;
+	d.x = undefined;
+
+	assertEq(d.doFoo(), 0);
+	assertEq(d.doFoo(1), 1);
+	assertEq(d.doFoo(1, 2), 2);
+    }
+}
+f();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4612,16 +4612,229 @@ static JSClass env_class = {
     "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub,  JS_PropertyStub,
     JS_PropertyStub,  env_setProperty,
     env_enumerate, (JSResolveOp) env_resolve,
     JS_ConvertStub
 };
 
 /*
+ * Define a FakeDOMObject constructor. It returns an object with a getter,
+ * setter and method with attached JitInfo. This object can be used to test
+ * IonMonkey DOM optimizations in the shell.
+ */
+static uint32_t DOM_OBJECT_SLOT = 0;
+
+static JSBool
+dom_genericGetter(JSContext* cx, unsigned argc, JS::Value *vp);
+
+static JSBool
+dom_genericSetter(JSContext* cx, unsigned argc, JS::Value *vp);
+
+static JSBool
+dom_genericMethod(JSContext *cx, unsigned argc, JS::Value *vp);
+
+#ifdef DEBUG
+static JSClass *GetDomClass();
+#endif
+
+static bool
+dom_get_x(JSContext* cx, JSHandleObject obj, void *self, JS::Value *vp)
+{
+    JS_ASSERT(JS_GetClass(obj) == GetDomClass());
+    JS_ASSERT(self == (void *)0x1234);
+    *vp = JS_NumberValue(double(3.14));
+    return true;
+}
+
+static bool
+dom_set_x(JSContext* cx, JSHandleObject obj, void *self, JS::Value *argv)
+{
+    JS_ASSERT(JS_GetClass(obj) == GetDomClass());
+    JS_ASSERT(self == (void *)0x1234);
+    return true;
+}
+
+static bool
+dom_doFoo(JSContext* cx, JSHandleObject obj, void *self, unsigned argc, JS::Value *vp)
+{
+    JS_ASSERT(JS_GetClass(obj) == GetDomClass());
+    JS_ASSERT(self == (void *)0x1234);
+
+    /* Just return argc. */
+    CallArgs args = CallArgsFromVp(argc, vp);
+    args.rval().setInt32(argc);
+    return true;
+}
+
+const JSJitInfo dom_x_getterinfo = {
+    (JSJitPropertyOp)dom_get_x,
+    0,        /* protoID */
+    0,        /* depth */
+    JSJitInfo::Getter,
+    true,     /* isInfallible. False in setters. */
+    true      /* isConstant. Only relevant for getters. */
+};
+
+const JSJitInfo dom_x_setterinfo = {
+    (JSJitPropertyOp)dom_set_x,
+    0,        /* protoID */
+    0,        /* depth */
+    JSJitInfo::Setter,
+    false,    /* isInfallible. False in setters. */
+    false     /* isConstant. Only relevant for getters. */
+};
+
+const JSJitInfo doFoo_methodinfo = {
+    (JSJitPropertyOp)dom_doFoo,
+    0,        /* protoID */
+    0,        /* depth */
+    JSJitInfo::Method,
+    false,    /* isInfallible. False in setters. */
+    false     /* isConstant. Only relevant for getters. */
+};
+
+static JSPropertySpec dom_props[] = {
+    {"x", 0,
+     JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS,
+     { (JSPropertyOp)dom_genericGetter, &dom_x_getterinfo },
+     { (JSStrictPropertyOp)dom_genericSetter, &dom_x_setterinfo }
+    },
+    {NULL,0,0,JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}
+};
+
+static JSFunctionSpec dom_methods[] = {
+    JS_FNINFO("doFoo", dom_genericMethod, &doFoo_methodinfo, 3, JSPROP_ENUMERATE),
+    JS_FS_END
+};
+
+static JSClass dom_class = {
+    "FakeDOMObject", JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub,       /* addProperty */
+    JS_PropertyStub,       /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    NULL,                  /* finalize */
+    NULL,                  /* checkAccess */
+    NULL,                  /* call */
+    NULL,                  /* hasInstance */
+    NULL,                  /* construct */
+    NULL,                  /* trace */
+    JSCLASS_NO_INTERNAL_MEMBERS
+};
+
+#ifdef DEBUG
+static JSClass *GetDomClass() {
+    return &dom_class;
+}
+#endif
+
+static JSBool
+dom_genericGetter(JSContext *cx, unsigned argc, JS::Value *vp)
+{
+    js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+    if (!obj)
+        return false;
+
+    if (JS_GetClass(obj) != &dom_class) {
+        *vp = JSVAL_VOID;
+        return true;
+    }
+
+    JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+
+    const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
+    MOZ_ASSERT(info->type == JSJitInfo::Getter);
+    JSJitPropertyOp getter = info->op;
+    return getter(cx, obj, val.toPrivate(), vp);
+}
+
+static JSBool
+dom_genericSetter(JSContext* cx, unsigned argc, JS::Value* vp)
+{
+    js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+    if (!obj)
+        return false;
+
+    JS_ASSERT(argc == 1);
+
+    if (JS_GetClass(obj) != &dom_class) {
+        *vp = JSVAL_VOID;
+        return true;
+    }
+
+    JS::Value* argv = JS_ARGV(cx, vp);
+    JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+
+    const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
+    MOZ_ASSERT(info->type == JSJitInfo::Setter);
+    JSJitPropertyOp setter = info->op;
+    if (!setter(cx, obj, val.toPrivate(), argv))
+        return false;
+    *vp = JSVAL_VOID;
+    return true;
+}
+
+static JSBool
+dom_genericMethod(JSContext* cx, unsigned argc, JS::Value *vp)
+{
+    js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+    if (!obj)
+        return false;
+
+    if (JS_GetClass(obj) != &dom_class) {
+        *vp = JSVAL_VOID;
+        return true;
+    }
+
+    JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+
+    const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
+    MOZ_ASSERT(info->type == JSJitInfo::Method);
+    JSJitMethodOp method = (JSJitMethodOp)info->op;
+    return method(cx, obj, val.toPrivate(), argc, vp);
+}
+
+static JSBool
+dom_constructor(JSContext* cx, unsigned argc, JS::Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject callee(cx, &args.callee());
+    RootedValue protov(cx);
+    if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &protov))
+        return false;
+
+    if (!protov.isObject()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "FakeDOMObject");
+        return false;
+    }
+
+    RootedObject domObj(cx, JS_NewObject(cx, &dom_class, &protov.toObject(), NULL));
+    if (!domObj)
+        return false;
+
+    /* Fow now just initialize to a constant we can check. */
+    SetReservedSlot(domObj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL((void *)0x1234));
+
+    args.rval().setObject(*domObj);
+    return true;
+}
+
+static JSBool
+InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID, uint32_t depth)
+{
+    /* There's only a single (fake) DOM object in the shell, so just return true. */
+    return true;
+}
+
+/*
  * Avoid a reentrancy hazard.
  *
  * The non-JS_THREADSAFE shell uses a signal handler to implement timeout().
  * The JS engine is not really reentrant, but JS_TriggerAllOperationCallbacks
  * is mostly safe--the only danger is that we might interrupt JS_NewContext or
  * JS_DestroyContext while the context list is being modified. Therefore we
  * disable the signal handler around calls to those functions.
  */
@@ -4711,16 +4924,28 @@ NewGlobalObject(JSContext *cx)
             return NULL;
 
         if (!JS_DefineProperty(cx, glob, "custom", JSVAL_VOID, its_getter,
                                its_setter, 0))
             return NULL;
         if (!JS_DefineProperty(cx, glob, "customRdOnly", JSVAL_VOID, its_getter,
                                its_setter, JSPROP_READONLY))
             return NULL;
+
+        /* Initialize FakeDOMObject. */
+        static js::DOMCallbacks DOMcallbacks = {
+            InstanceClassHasProtoAtDepth
+        };
+        SetDOMCallbacks(cx->runtime, &DOMcallbacks);
+
+        if (!JS_InitClass(cx, glob, NULL, &dom_class, dom_constructor, 0,
+                          dom_props, dom_methods, NULL, NULL))
+        {
+            return NULL;
+        }
     }
 
     return glob;
 }
 
 static bool
 BindScriptArgs(JSContext *cx, JSObject *obj_, OptionParser *op)
 {