mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 08:42:13 +00:00
Bug 1382172
- Compute names for all JS-implemented XPCOM objects (r=mrbkap)
MozReview-Commit-ID: 4kPbqOpGYnq
This commit is contained in:
parent
cdb7204303
commit
96944ff355
@ -10,10 +10,12 @@
|
||||
#include "jsprf.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
@ -449,6 +451,97 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WrappedJSIdentity,
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
class WrappedJSNamed final : public nsINamed
|
||||
{
|
||||
nsCString mName;
|
||||
|
||||
~WrappedJSNamed() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
WrappedJSNamed(const nsACString& aName) : mName(aName) {}
|
||||
|
||||
NS_IMETHOD GetName(nsACString& aName) override
|
||||
{
|
||||
aName = mName;
|
||||
aName.AppendLiteral(":JS");
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WrappedJSNamed, nsINamed)
|
||||
|
||||
nsCString
|
||||
GetFunctionName(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
RootedObject inner(cx, js::UncheckedUnwrap(obj));
|
||||
JSAutoCompartment ac(cx, inner);
|
||||
|
||||
RootedFunction fun(cx, JS_GetObjectFunction(inner));
|
||||
if (!fun) {
|
||||
// If the object isn't a function, it's likely that it has a single
|
||||
// function property (for things like nsITimerCallback). In this case,
|
||||
// return the name of that function property.
|
||||
|
||||
Rooted<IdVector> idArray(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, inner, &idArray)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return nsCString("error");
|
||||
}
|
||||
|
||||
if (idArray.length() != 1)
|
||||
return nsCString("nonfunction");
|
||||
|
||||
RootedId id(cx, idArray[0]);
|
||||
RootedValue v(cx);
|
||||
if (!JS_GetPropertyById(cx, inner, id, &v)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return nsCString("nonfunction");
|
||||
}
|
||||
|
||||
if (!v.isObject())
|
||||
return nsCString("nonfunction");
|
||||
|
||||
RootedObject vobj(cx, &v.toObject());
|
||||
return GetFunctionName(cx, vobj);
|
||||
}
|
||||
|
||||
RootedString funName(cx, JS_GetFunctionDisplayId(fun));
|
||||
RootedScript script(cx, JS_GetFunctionScript(cx, fun));
|
||||
const char* filename = script ? JS_GetScriptFilename(script) : "anonymous";
|
||||
const char* filenameSuffix = strrchr(filename, '/');
|
||||
|
||||
if (filenameSuffix) {
|
||||
filenameSuffix++;
|
||||
} else {
|
||||
filenameSuffix = filename;
|
||||
}
|
||||
|
||||
nsCString displayName("anonymous");
|
||||
if (funName) {
|
||||
nsCString* displayNamePtr = &displayName;
|
||||
RootedValue funNameVal(cx, StringValue(funName));
|
||||
if (!XPCConvert::JSData2Native(&displayNamePtr, funNameVal, nsXPTType::T_UTF8STRING,
|
||||
nullptr, nullptr))
|
||||
{
|
||||
JS_ClearPendingException(cx);
|
||||
return nsCString("anonymous");
|
||||
}
|
||||
}
|
||||
|
||||
displayName.Append('[');
|
||||
displayName.Append(filenameSuffix, strlen(filenameSuffix));
|
||||
displayName.Append(']');
|
||||
return displayName;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// static
|
||||
bool
|
||||
nsXPCWrappedJSClass::IsWrappedJS(nsISupports* aPtr)
|
||||
@ -590,6 +683,16 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
||||
}
|
||||
}
|
||||
|
||||
// If we're asked to QI to nsINamed, we pretend that this is possible. We'll
|
||||
// try to return a name that makes sense for the wrapped JS value.
|
||||
if (aIID.Equals(NS_GET_IID(nsINamed))) {
|
||||
RootedObject obj(RootingCx(), self->GetJSObject());
|
||||
nsCString name = GetFunctionName(ccx, obj);
|
||||
RefPtr<WrappedJSNamed> named = new WrappedJSNamed(name);
|
||||
*aInstancePtr = named.forget().take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// else...
|
||||
// no can do
|
||||
*aInstancePtr = nullptr;
|
||||
|
41
js/xpconnect/tests/unit/test_function_names.js
Normal file
41
js/xpconnect/tests/unit/test_function_names.js
Normal file
@ -0,0 +1,41 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
function callback() {}
|
||||
|
||||
let sandbox = Cu.Sandbox(this);
|
||||
let callbackWrapped = Cu.evalInSandbox("(function wrapped() {})", sandbox);
|
||||
|
||||
function run_test() {
|
||||
let functions = [
|
||||
[{ notify: callback }, "callback[test_function_names.js]:JS"],
|
||||
[{ notify: { notify: callback } }, "callback[test_function_names.js]:JS"],
|
||||
[callback, "callback[test_function_names.js]:JS"],
|
||||
[function() {}, "run_test/functions<[test_function_names.js]:JS"],
|
||||
[function foobar() {}, "foobar[test_function_names.js]:JS"],
|
||||
[function Δ() {}, "Δ[test_function_names.js]:JS"],
|
||||
[{ notify1: callback, notify2: callback }, "nonfunction:JS"],
|
||||
[{ notify: 10 }, "nonfunction:JS"],
|
||||
[{}, "nonfunction:JS"],
|
||||
[{ notify: callbackWrapped }, "wrapped[test_function_names.js]:JS"],
|
||||
];
|
||||
|
||||
// Use the observer service so we can get double-wrapped functions.
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
|
||||
function observer(subject, topic, data)
|
||||
{
|
||||
let named = subject.QueryInterface(Ci.nsINamed);
|
||||
do_check_eq(named.name, data);
|
||||
dump(`name: ${named.name}\n`);
|
||||
}
|
||||
obs.addObserver(observer, "test-obs-fun", false);
|
||||
|
||||
for (let [f, requiredName] of functions) {
|
||||
obs.notifyObservers(f, "test-obs-fun", requiredName);
|
||||
}
|
||||
}
|
@ -136,3 +136,4 @@ head = head_watchdog.js
|
||||
[test_xray_regexp.js]
|
||||
[test_resolve_dead_promise.js]
|
||||
[test_asyncLoadSubScriptError.js]
|
||||
[test_function_names.js]
|
||||
|
@ -20,5 +20,5 @@ interface nsINamed : nsISupports
|
||||
* WARNING: This attribute will be included in telemetry, so it should
|
||||
* never contain privacy sensitive information.
|
||||
*/
|
||||
readonly attribute ACString name;
|
||||
readonly attribute AUTF8String name;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user