Bug 1254893 - Prep Debugger.Script for a tagged union referent. (r=jimb)
authorShu-yu Guo <shu@rfrn.org>
Fri, 11 Mar 2016 21:43:20 -0800
changeset 288405 5ae46c02868df2b56ff6224554d9f2358a947188
parent 288404 92e23bc3f31d2b4e33575bc5448e1f0e3ef13b4e
child 288406 ab08650fe473611644f52d335c1a6786c120c5f7
push id30079
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:19 +0000
treeherdermozilla-central@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1254893
milestone48.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 1254893 - Prep Debugger.Script for a tagged union referent. (r=jimb)
js/src/vm/Debugger.cpp
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -14,24 +14,27 @@
 #include "jscompartment.h"
 #include "jsfriendapi.h"
 #include "jshashutil.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsprf.h"
 #include "jswrapper.h"
 
+#include "asmjs/WasmModule.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/Parser.h"
 #include "gc/Marking.h"
+#include "gc/Policy.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineJIT.h"
 #include "jit/JSONSpewer.h"
 #include "jit/MIRGraph.h"
 #include "js/GCAPI.h"
+#include "js/GCVariant.h"
 #include "js/UbiNodeBreadthFirst.h"
 #include "js/Vector.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/DebuggerMemory.h"
 #include "vm/SPSProfiler.h"
 #include "vm/TraceLogging.h"
 #include "vm/WrapperObject.h"
 
@@ -47,16 +50,18 @@ using namespace js;
 
 using JS::dbg::AutoEntryMonitor;
 using JS::dbg::Builder;
 using js::frontend::IsIdentifier;
 using mozilla::ArrayLength;
 using mozilla::DebugOnly;
 using mozilla::MakeScopeExit;
 using mozilla::Maybe;
+using mozilla::Variant;
+using mozilla::AsVariant;
 
 
 /*** Forward declarations ************************************************************************/
 
 extern const Class DebuggerFrame_class;
 
 enum {
     JSSLOT_DEBUGFRAME_OWNER,
@@ -2663,16 +2668,17 @@ Debugger::removeAllocationsTrackingForAl
 
 void
 Debugger::markCrossCompartmentEdges(JSTracer* trc)
 {
     objects.markCrossCompartmentEdges<DebuggerObject_trace>(trc);
     environments.markCrossCompartmentEdges<DebuggerEnv_trace>(trc);
     scripts.markCrossCompartmentEdges<DebuggerScript_trace>(trc);
     sources.markCrossCompartmentEdges<DebuggerSource_trace>(trc);
+    wasmModuleScripts.markCrossCompartmentEdges<DebuggerScript_trace>(trc);
 }
 
 /*
  * Ordinarily, WeakMap keys and values are marked because at some point it was
  * discovered that the WeakMap was live; that is, some object containing the
  * WeakMap was marked during mark phase.
  *
  * However, during zone GC, we have to do something about cross-compartment
@@ -2897,17 +2903,18 @@ Debugger::findZoneEdges(Zone* zone, js::
     for (Debugger* dbg : zone->runtimeFromMainThread()->debuggerList) {
         Zone* w = dbg->object->zone();
         if (w == zone || !w->isGCMarking())
             continue;
         if (dbg->debuggeeZones.has(zone) ||
             dbg->scripts.hasKeyInZone(zone) ||
             dbg->sources.hasKeyInZone(zone) ||
             dbg->objects.hasKeyInZone(zone) ||
-            dbg->environments.hasKeyInZone(zone))
+            dbg->environments.hasKeyInZone(zone) ||
+            dbg->wasmModuleScripts.hasKeyInZone(zone))
         {
             finder.addEdgeTo(w);
         }
     }
 }
 
 /* static */ void
 Debugger::finalize(FreeOp* fop, JSObject* obj)
@@ -4892,30 +4899,64 @@ const JSFunctionSpec Debugger::methods[]
 
 const JSFunctionSpec Debugger::static_methods[] {
     JS_FN("isCompilableUnit", Debugger::isCompilableUnit, 1, 0),
     JS_FS_END
 };
 
 /*** Debugger.Script *****************************************************************************/
 
-static inline JSScript*
+// Either a real JSScript or synthesized.
+//
+// If synthesized, the NativeObject is one of the following:
+//
+//   1. A WasmModuleObject, denoting a synthesized toplevel wasm module
+//      script.
+//   2. A wasm JSFunction, denoting a synthesized wasm function script.
+//      NYI!
+using DebuggerScriptReferent = Variant<JSScript*, WasmModuleObject*>;
+
+// Get the Debugger.Script referent as bare Cell. This should only be used for
+// GC operations like tracing. Please use GetScriptReferent below.
+static inline gc::Cell*
+GetScriptReferentCell(JSObject* obj)
+{
+    MOZ_ASSERT(obj->getClass() == &DebuggerScript_class);
+    return static_cast<gc::Cell*>(obj->as<NativeObject>().getPrivate());
+}
+
+static inline DebuggerScriptReferent
 GetScriptReferent(JSObject* obj)
 {
     MOZ_ASSERT(obj->getClass() == &DebuggerScript_class);
-    return static_cast<JSScript*>(obj->as<NativeObject>().getPrivate());
+    if (gc::Cell* cell = GetScriptReferentCell(obj)) {
+        if (cell->getTraceKind() == JS::TraceKind::Script)
+            return AsVariant(static_cast<JSScript*>(cell));
+        MOZ_ASSERT(cell->getTraceKind() == JS::TraceKind::Object);
+        return AsVariant(&static_cast<NativeObject*>(cell)->as<WasmModuleObject>());
+    }
+    return AsVariant(static_cast<JSScript*>(nullptr));
 }
 
 void
 DebuggerScript_trace(JSTracer* trc, JSObject* obj)
 {
     /* This comes from a private pointer, so no barrier needed. */
-    if (JSScript* script = GetScriptReferent(obj)) {
-        TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &script, "Debugger.Script referent");
-        obj->as<NativeObject>().setPrivateUnbarriered(script);
+    DebuggerScriptReferent referent = GetScriptReferent(obj);
+    if (referent.is<JSScript*>()) {
+        if (JSScript* script = referent.as<JSScript*>()) {
+            TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &script,
+                                                       "Debugger.Script script referent");
+            obj->as<NativeObject>().setPrivateUnbarriered(script);
+        }
+    } else {
+        JSObject* wasm = referent.as<WasmModuleObject*>();
+        TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &wasm,
+                                                   "Debugger.Script wasm referent");
+        obj->as<NativeObject>().setPrivateUnbarriered(wasm);
     }
 }
 
 const Class DebuggerScript_class = {
     "Script",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT),
     nullptr, nullptr, nullptr, nullptr,
@@ -4960,17 +5001,17 @@ Debugger::wrapScript(JSContext* cx, Hand
         CrossCompartmentKey key(CrossCompartmentKey::DebuggerScript, object, script);
         if (!object->compartment()->putWrapper(cx, key, ObjectValue(*scriptobj))) {
             scripts.remove(script);
             ReportOutOfMemory(cx);
             return nullptr;
         }
     }
 
-    MOZ_ASSERT(GetScriptReferent(p->value()) == script);
+    MOZ_ASSERT(GetScriptReferent(p->value()).as<JSScript*>() == script);
     return p->value();
 }
 
 static JSObject*
 DebuggerScript_check(JSContext* cx, const Value& v, const char* clsname, const char* fnname)
 {
     JSObject* thisobj = NonNullObject(cx, v);
     if (!thisobj)
@@ -4980,38 +5021,58 @@ DebuggerScript_check(JSContext* cx, cons
                              clsname, fnname, thisobj->getClass()->name);
         return nullptr;
     }
 
     /*
      * Check for Debugger.Script.prototype, which is of class DebuggerScript_class
      * but whose script is null.
      */
-    if (!GetScriptReferent(thisobj)) {
-        MOZ_ASSERT(!GetScriptReferent(thisobj));
+    if (!GetScriptReferentCell(thisobj)) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                              clsname, fnname, "prototype object");
         return nullptr;
     }
 
     return thisobj;
 }
 
+template <typename ReferentT>
 static JSObject*
-DebuggerScript_checkThis(JSContext* cx, const CallArgs& args, const char* fnname)
-{
-    return DebuggerScript_check(cx, args.thisv(), "Debugger.Script", fnname);
-}
+DebuggerScript_checkThis(JSContext* cx, const CallArgs& args, const char* fnname,
+                         const char* refname)
+{
+    JSObject* thisobj = DebuggerScript_check(cx, args.thisv(), "Debugger.Script", fnname);
+    if (!thisobj)
+        return nullptr;
+
+    if (!GetScriptReferent(thisobj).is<ReferentT>()) {
+        ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
+                              JSDVG_SEARCH_STACK, args.thisv(), nullptr,
+                              refname, nullptr);
+        return nullptr;
+    }
+
+    return thisobj;
+}
+
+#define THIS_DEBUGSCRIPT_REFERENT(cx, argc, vp, fnname, args, obj, referent)        \
+    CallArgs args = CallArgsFromVp(argc, vp);                                       \
+    RootedObject obj(cx, DebuggerScript_check(cx, args.thisv(), fnname));           \
+    if (!obj)                                                                       \
+        return false;                                                               \
+    Rooted<DebuggerScriptReferent> referent(cx, GetScriptReferent(obj))
 
 #define THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, fnname, args, obj, script)            \
     CallArgs args = CallArgsFromVp(argc, vp);                                       \
-    RootedObject obj(cx, DebuggerScript_checkThis(cx, args, fnname));               \
+    RootedObject obj(cx, DebuggerScript_checkThis<JSScript*>(cx, args, fnname,      \
+                                                             "a JS script"));       \
     if (!obj)                                                                       \
         return false;                                                               \
-    Rooted<JSScript*> script(cx, GetScriptReferent(obj))
+    RootedScript script(cx, GetScriptReferent(obj).as<JSScript*>())
 
 static bool
 DebuggerScript_getDisplayName(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get displayName)", args, obj, script);
     Debugger* dbg = Debugger::fromChildJSObject(obj);
 
     JSFunction* func = script->functionNonDelazifying();