Bug 777528 - Expose compartment names to the JS engine (r=luke)
authorBill McCloskey <wmccloskey@mozilla.com>
Wed, 25 Jul 2012 18:25:47 -0700
changeset 100491 acee68233906
parent 100490 3926441652e8
child 100492 1d3d70b31587
push id12528
push userwmccloskey@mozilla.com
push date2012-07-26 01:26 +0000
treeherdermozilla-inbound@acee68233906 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs777528
milestone17.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 777528 - Expose compartment names to the JS engine (r=luke)
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -726,16 +726,17 @@ JSRuntime::JSRuntime()
 #ifdef JS_METHODJIT
     jaegerRuntime_(NULL),
 #endif
     nativeStackBase(0),
     nativeStackQuota(0),
     interpreterFrames(NULL),
     cxCallback(NULL),
     destroyCompartmentCallback(NULL),
+    compartmentNameCallback(NULL),
     activityCallback(NULL),
     activityCallbackArg(NULL),
 #ifdef JS_THREADSAFE
     suspendCount(0),
     requestDepth(0),
 # ifdef DEBUG
     checkRequestDepth(0),
 # endif
@@ -1393,16 +1394,22 @@ JS_GetImplementationVersion(void)
 }
 
 JS_PUBLIC_API(void)
 JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback)
 {
     rt->destroyCompartmentCallback = callback;
 }
 
+JS_PUBLIC_API(void)
+JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback)
+{
+    rt->compartmentNameCallback = callback;
+}
+
 JS_PUBLIC_API(JSWrapObjectCallback)
 JS_SetWrapObjectCallbacks(JSRuntime *rt,
                           JSWrapObjectCallback callback,
                           JSSameCompartmentWrapObjectCallback sccallback,
                           JSPreWrapCallback precallback)
 {
     JSWrapObjectCallback old = rt->wrapObjectCallback;
     rt->wrapObjectCallback = callback;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2002,16 +2002,20 @@ typedef JSObject *
  * compartment wrapper that gets passed to wrap.
  */
 typedef JSObject *
 (* JSSameCompartmentWrapObjectCallback)(JSContext *cx, JSObject *obj);
 
 typedef void
 (* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment);
 
+typedef void
+(* JSCompartmentNameCallback)(JSRuntime *rt, JSCompartment *compartment,
+                              char *buf, size_t bufsize);
+
 /*
  * Read structured data from the reader r. This hook is used to read a value
  * previously serialized by a call to the WriteStructuredCloneOp hook.
  *
  * tag and data are the pair of uint32_t values from the header. The callback
  * may use the JS_Read* APIs to read any other relevant parts of the object
  * from the reader r. closure is any value passed to the JS_ReadStructuredClone
  * function. Return the new object on success, NULL on error/exception.
@@ -3114,16 +3118,19 @@ extern JS_PUBLIC_API(void)
 JS_SetJitHardening(JSRuntime *rt, JSBool enabled);
 
 extern JS_PUBLIC_API(const char *)
 JS_GetImplementationVersion(void);
 
 extern JS_PUBLIC_API(void)
 JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback);
 
+extern JS_PUBLIC_API(void)
+JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback);
+
 extern JS_PUBLIC_API(JSWrapObjectCallback)
 JS_SetWrapObjectCallbacks(JSRuntime *rt,
                           JSWrapObjectCallback callback,
                           JSSameCompartmentWrapObjectCallback sccallback,
                           JSPreWrapCallback precallback);
 
 extern JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -442,16 +442,19 @@ struct JSRuntime : js::RuntimeFriendFiel
     js::InterpreterFrames *interpreterFrames;
 
     /* Context create/destroy callback. */
     JSContextCallback   cxCallback;
 
     /* Compartment destroy callback. */
     JSDestroyCompartmentCallback destroyCompartmentCallback;
 
+    /* Call this to get the name of a compartment. */
+    JSCompartmentNameCallback compartmentNameCallback;
+
     js::ActivityCallback  activityCallback;
     void                 *activityCallbackArg;
 
 #ifdef JS_THREADSAFE
     /* Number of JS_SuspendRequest calls withot JS_ResumeRequest. */
     unsigned            suspendCount;
 
     /* The request depth for this thread. */
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1107,17 +1107,17 @@ XPCJSRuntime::~XPCJSRuntime()
         JS_ShutDown();
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
 #endif
     }
 }
 
 static void
-GetCompartmentName(JSCompartment *c, nsCString &name)
+GetCompartmentName(JSCompartment *c, nsCString &name, bool replaceSlashes)
 {
     if (js::IsAtomsCompartment(c)) {
         name.AssignLiteral("atoms");
     } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
         nsJSPrincipals::get(principals)->GetScriptLocation(name);
 
         // If the compartment's location (name) differs from the principal's
         // script location, append the compartment's location to allow
@@ -1126,21 +1126,22 @@ GetCompartmentName(JSCompartment *c, nsC
         CompartmentPrivate *compartmentPrivate = GetCompartmentPrivate(c);
         if (compartmentPrivate) {
             const nsACString& location = compartmentPrivate->GetLocation();
             if (!location.IsEmpty() && !location.Equals(name)) {
                 name.AppendLiteral(", ");
                 name.Append(location);
             }
         }
-        
+
         // A hack: replace forward slashes with '\\' so they aren't
         // treated as path separators.  Users of the reporters
         // (such as about:memory) have to undo this change.
-        name.ReplaceChar('/', '\\');
+        if (replaceSlashes)
+            name.ReplaceChar('/', '\\');
     } else {
         name.AssignLiteral("null-principal");
     }
 }
 
 static PRInt64
 GetGCChunkTotalBytes()
 {
@@ -1606,17 +1607,17 @@ class JSCompartmentsMultiReporter MOZ_FI
 
     typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths; 
 
     static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c)
     {
         // silently ignore OOM errors
         Paths *paths = static_cast<Paths *>(data);
         nsCString path;
-        GetCompartmentName(c, path);
+        GetCompartmentName(c, path, true);
         path.Insert(js::IsSystemCompartment(c)
                     ? NS_LITERAL_CSTRING("compartments/system/")
                     : NS_LITERAL_CSTRING("compartments/user/"),
                     0);
         paths->append(path);
     }
 
     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
@@ -1719,17 +1720,17 @@ class XPCJSRuntimeStats : public JS::Run
             free(compartmentStatsVector[i].extra2);
         }
     }
 
     virtual void initExtraCompartmentStats(JSCompartment *c,
                                            JS::CompartmentStats *cstats) MOZ_OVERRIDE {
         nsCAutoString cJSPathPrefix, cDOMPathPrefix;
         nsCString cName;
-        GetCompartmentName(c, cName);
+        GetCompartmentName(c, cName, true);
 
         // Get the compartment's global.
         nsXPConnect *xpc = nsXPConnect::GetXPConnect();
         JSContext *cx = xpc->GetSafeJSContext();
         if (JSObject *global = JS_GetGlobalForCompartmentOrNull(cx, c)) {
             // Need to enter the compartment, otherwise GetNativeOfWrapper()
             // might crash.
             JSAutoEnterCompartment aec;
@@ -1935,16 +1936,27 @@ AccumulateTelemetryCallback(int id, uint
         Telemetry::Accumulate(Telemetry::GC_INCREMENTAL_DISABLED, sample);
         break;
       case JS_TELEMETRY_GC_NON_INCREMENTAL:
         Telemetry::Accumulate(Telemetry::GC_NON_INCREMENTAL, sample);
         break;
     }
 }
 
+static void
+CompartmentNameCallback(JSRuntime *rt, JSCompartment *comp,
+                        char *buf, size_t bufsize)
+{
+    nsCString name;
+    GetCompartmentName(comp, name, false);
+    if (name.Length() >= bufsize)
+        name.Truncate(bufsize - 1);
+    memcpy(buf, name.get(), name.Length() + 1);
+}
+
 bool XPCJSRuntime::gNewDOMBindingsEnabled;
 bool XPCJSRuntime::gExperimentalBindingsEnabled;
 
 bool PreserveWrapper(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(obj)));
     nsISupports *native = nsXPConnect::GetXPConnect()->GetNativeOfWrapper(cx, obj);
     if (!native)
@@ -2022,16 +2034,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
 #ifdef MOZ_ASAN
     // ASan requires more stack space due to redzones
     JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024);
 #else  
     JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
 #endif
     JS_SetContextCallback(mJSRuntime, ContextCallback);
     JS_SetDestroyCompartmentCallback(mJSRuntime, CompartmentDestroyedCallback);
+    JS_SetCompartmentNameCallback(mJSRuntime, CompartmentNameCallback);
     JS_SetGCCallback(mJSRuntime, GCCallback);
     JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback);
     JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
     JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
     JS_SetWrapObjectCallbacks(mJSRuntime,
                               xpc::WrapperFactory::Rewrap,
                               xpc::WrapperFactory::WrapForSameCompartment,
                               xpc::WrapperFactory::PrepareForWrapping);