Bug 1271650 - Implement a C++ interface for DebuggerFrame.isLive. r=fitzgen
authorEddy Bruel <ejpbruel@mozilla.com>
Wed, 20 Jul 2016 13:50:04 +0200
changeset 306055 ae502e2271f2464d92ef398d7c8c43f835865bd6
parent 306054 0a0f2f8db1e6faa3a56fa69aa280bfbae507c4d3
child 306056 1de4835bc1414570182a83e94a9eb1b644cb7c43
push id30474
push usercbook@mozilla.com
push dateThu, 21 Jul 2016 14:25:10 +0000
treeherdermozilla-central@6b180266ac16 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfitzgen
bugs1271650
milestone50.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 1271650 - Implement a C++ interface for DebuggerFrame.isLive. r=fitzgen
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7073,31 +7073,35 @@ DebuggerFrame::create(JSContext* cx, Han
 
   return &frame;
 }
 
 /* static */ bool
 DebuggerFrame::getCallee(JSContext* cx, Handle<DebuggerFrame*> frame,
                          MutableHandle<DebuggerObject*> result)
 {
+    MOZ_ASSERT(frame->isLive());
+
     AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
     if (!referent.isFunctionFrame()) {
         result.set(nullptr);
         return true;
     }
 
     Debugger* dbg = frame->owner();
 
     RootedObject callee(cx, referent.callee());
     return dbg->wrapDebuggeeObject(cx, callee, result);
 }
 
 /* static */ bool
 DebuggerFrame::getIsConstructing(JSContext* cx, Handle<DebuggerFrame*> frame, bool& result)
 {
+    MOZ_ASSERT(frame->isLive());
+
     Maybe<ScriptFrameIter> maybeIter;
     if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
         return false;
     ScriptFrameIter& iter = *maybeIter;
 
     result = iter.isFunctionFrame() && iter.isConstructing();
     return true;
 }
@@ -7138,16 +7142,18 @@ UpdateFrameIterPc(FrameIter& iter)
 
     iter.updatePcQuadratic();
 }
 
 /* static */ bool
 DebuggerFrame::getEnvironment(JSContext* cx, Handle<DebuggerFrame*> frame,
                               MutableHandle<DebuggerEnvironment*> result)
 {
+    MOZ_ASSERT(frame->isLive());
+
     Debugger* dbg = frame->owner();
 
     Maybe<ScriptFrameIter> maybeIter;
     if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
         return false;
     ScriptFrameIter& iter = *maybeIter;
 
     Rooted<Env*> env(cx);
@@ -7163,16 +7169,34 @@ DebuggerFrame::getEnvironment(JSContext*
 }
 
 /* static */ bool
 DebuggerFrame::getIsGenerator(Handle<DebuggerFrame*> frame)
 {
     return DebuggerFrame::getReferent(frame).script()->isGenerator();
 }
 
+/* statuc */ bool
+DebuggerFrame::isLive() const
+{
+    return !!getPrivate();
+}
+
+/* static */ bool
+DebuggerFrame::requireLive(JSContext* cx, Handle<DebuggerFrame*> frame)
+{
+    if (!frame->isLive()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
+                             "Debugger.Frame");
+        return false;
+    }
+
+    return true;
+}
+
 /* static */ AbstractFramePtr
 DebuggerFrame::getReferent(Handle<DebuggerFrame*> frame)
 {
     AbstractFramePtr referent = AbstractFramePtr::FromRaw(frame->getPrivate());
     if (referent.isScriptFrameIterData()) {
         ScriptFrameIter iter(*(ScriptFrameIter::Data*)(referent.raw()));
         referent = iter.abstractFramePtr();
     }
@@ -7230,37 +7254,36 @@ DebuggerFrame::checkThis(JSContext* cx, 
     if (!thisobj)
         return nullptr;
     if (thisobj->getClass() != &DebuggerFrame::class_) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                              "Debugger.Frame", fnname, thisobj->getClass()->name);
         return nullptr;
     }
 
-    DebuggerFrame* nthisobj = &thisobj->as<DebuggerFrame>();
+    Rooted<DebuggerFrame*> frame(cx, &thisobj->as<DebuggerFrame>());
 
     /*
      * Forbid Debugger.Frame.prototype, which is of class DebuggerFrame::class_
      * but isn't really a working Debugger.Frame object. The prototype object
      * is distinguished by having a nullptr private value. Also, forbid popped
      * frames.
      */
-    if (!nthisobj->getPrivate()) {
-        if (nthisobj->getReservedSlot(JSSLOT_DEBUGFRAME_OWNER).isUndefined()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
-                                 "Debugger.Frame", fnname, "prototype object");
-            return nullptr;
-        }
-        if (checkLive) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
-                                 "Debugger.Frame");
-            return nullptr;
-        }
-    }
-    return nthisobj;
+    if (!frame->getPrivate() &&
+        frame->getReservedSlot(JSSLOT_DEBUGFRAME_OWNER).isUndefined())
+    {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+                             "Debugger.Frame", fnname, "prototype object");
+        return nullptr;
+    }
+
+    if (checkLive && !DebuggerFrame::requireLive(cx, frame))
+        return nullptr;
+
+    return frame;
 }
 
 /*
  * To make frequently fired hooks like onEnterFrame more performant,
  * Debugger.Frame methods should not create a ScriptFrameIter unless it
  * absolutely needs to. That is, unless the method has to call a method on
  * ScriptFrameIter that's otherwise not available on AbstractFramePtr.
  *
@@ -7607,25 +7630,25 @@ DebuggerFrame_getOffset(JSContext* cx, u
     JSScript* script = iter.script();
     UpdateFrameIterPc(iter);
     jsbytecode* pc = iter.pc();
     size_t offset = script->pcToOffset(pc);
     args.rval().setNumber(double(offset));
     return true;
 }
 
-static bool
-DebuggerFrame_getLive(JSContext* cx, unsigned argc, Value* vp)
+/* static */ bool
+DebuggerFrame::liveGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    NativeObject* thisobj = DebuggerFrame::checkThis(cx, args, "get live", false);
-    if (!thisobj)
-        return false;
-    bool hasFrame = !!thisobj->getPrivate();
-    args.rval().setBoolean(hasFrame);
+    Rooted<DebuggerFrame*> frame(cx, DebuggerFrame::checkThis(cx, args, "get live", false));
+    if (!frame)
+        return false;
+
+    args.rval().setBoolean(frame->isLive());
     return true;
 }
 
 static bool
 IsValidHook(const Value& v)
 {
     return v.isUndefined() || (v.isObject() && v.toObject().isCallable());
 }
@@ -7925,17 +7948,17 @@ DebuggerFrame::construct(JSContext* cx, 
 }
 
 const JSPropertySpec DebuggerFrame::properties_[] = {
     JS_PSG("arguments", DebuggerFrame_getArguments, 0),
     JS_PSG("callee", DebuggerFrame::calleeGetter, 0),
     JS_PSG("constructing", DebuggerFrame::constructingGetter, 0),
     JS_PSG("environment", DebuggerFrame::environmentGetter, 0),
     JS_PSG("generator", DebuggerFrame::generatorGetter, 0),
-    JS_PSG("live", DebuggerFrame_getLive, 0),
+    JS_PSG("live", DebuggerFrame::liveGetter, 0),
     JS_PSG("offset", DebuggerFrame_getOffset, 0),
     JS_PSG("older", DebuggerFrame_getOlder, 0),
     JS_PSG("script", DebuggerFrame_getScript, 0),
     JS_PSG("this", DebuggerFrame_getThis, 0),
     JS_PSG("type", DebuggerFrame_getType, 0),
     JS_PSG("implementation", DebuggerFrame_getImplementation, 0),
     JS_PSGS("onStep", DebuggerFrame_getOnStep, DebuggerFrame_setOnStep, 0),
     JS_PSGS("onPop", DebuggerFrame_getOnPop, DebuggerFrame_setOnPop, 0),
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -1150,32 +1150,36 @@ class DebuggerFrame : public NativeObjec
     static MOZ_MUST_USE bool getCallee(JSContext* cx, Handle<DebuggerFrame*> frame,
                                        MutableHandle<DebuggerObject*> result);
     static MOZ_MUST_USE bool getIsConstructing(JSContext* cx, Handle<DebuggerFrame*> frame,
                                                bool& result);
     static MOZ_MUST_USE bool getEnvironment(JSContext* cx, Handle<DebuggerFrame*> frame,
                                             MutableHandle<DebuggerEnvironment*> result);
     static bool getIsGenerator(Handle<DebuggerFrame*> frame);
 
+    bool isLive() const;
+
   private:
     static const ClassOps classOps_;
 
     static const JSPropertySpec properties_[];
     static const JSFunctionSpec methods_[];
 
+    static MOZ_MUST_USE bool requireLive(JSContext* cx, Handle<DebuggerFrame*> frame);
     static AbstractFramePtr getReferent(Handle<DebuggerFrame*> frame);
     static MOZ_MUST_USE bool getScriptFrameIter(JSContext* cx, Handle<DebuggerFrame*> frame,
                                                 mozilla::Maybe<ScriptFrameIter>& result);
 
     static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
 
     static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool constructingGetter(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool environmentGetter(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool generatorGetter(JSContext* cx, unsigned argc, Value* vp);
+    static MOZ_MUST_USE bool liveGetter(JSContext* cx, unsigned argc, Value* vp);
 
     Debugger* owner() const;
 };
 
 class DebuggerObject : public NativeObject
 {
   public:
     static const Class class_;