зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1667330 - Stop exposing constructor names of JS objects. r=iain
The getConstructorName testing function and UbiNode got the constructor name of a JS object via the ObjectGroup's TypeNewScript. There's currently no way to get that information without TI (and it always depended on brittle optimization heuristics) so this patch removes that code. Differential Revision: https://phabricator.services.mozilla.com/D91419
This commit is contained in:
Родитель
5a1d3dffad
Коммит
47d9b0c94d
|
@ -658,17 +658,6 @@ class JS_PUBLIC_API Base {
|
|||
// Return the object's [[Class]]'s name.
|
||||
virtual const char* jsObjectClassName() const { return nullptr; }
|
||||
|
||||
// If this object was constructed with `new` and we have the data available,
|
||||
// place the contructor function's display name in the out parameter.
|
||||
// Otherwise, place nullptr in the out parameter. Caller maintains ownership
|
||||
// of the out parameter. True is returned on success, false is returned on
|
||||
// OOM.
|
||||
virtual MOZ_MUST_USE bool jsObjectConstructorName(
|
||||
JSContext* cx, UniqueTwoByteChars& outName) const {
|
||||
outName.reset(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Methods for CoarseType::Script referents
|
||||
|
||||
// Return the script's source's filename if available. If unavailable,
|
||||
|
@ -817,10 +806,6 @@ class Node {
|
|||
const char16_t* descriptiveTypeName() const {
|
||||
return base()->descriptiveTypeName();
|
||||
}
|
||||
MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx,
|
||||
UniqueTwoByteChars& outName) const {
|
||||
return base()->jsObjectConstructorName(cx, outName);
|
||||
}
|
||||
|
||||
const char* scriptFilename() const { return base()->scriptFilename(); }
|
||||
|
||||
|
@ -1145,8 +1130,6 @@ class JS_PUBLIC_API Concrete<JSObject> : public TracerConcrete<JSObject> {
|
|||
JS::Realm* realm() const override;
|
||||
|
||||
const char* jsObjectClassName() const override;
|
||||
MOZ_MUST_USE bool jsObjectConstructorName(
|
||||
JSContext* cx, UniqueTwoByteChars& outName) const override;
|
||||
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
|
||||
bool hasAllocationStack() const override;
|
||||
|
|
|
@ -5003,33 +5003,6 @@ static bool SetDiscardSource(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool GetConstructorName(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!args.requireAtLeast(cx, "getConstructorName", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isObject()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_NOT_EXPECTED_TYPE, "getConstructorName",
|
||||
"Object", InformalValueTypeName(args[0]));
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedAtom name(cx);
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
if (!JSObject::constructorDisplayAtom(cx, obj, &name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
args.rval().setString(name);
|
||||
} else {
|
||||
args.rval().setNull();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class AllocationMarkerObject : public NativeObject {
|
||||
public:
|
||||
static const JSClass class_;
|
||||
|
@ -7100,11 +7073,6 @@ gc::ZealModeHelpText),
|
|||
" Explicitly enable source discarding in the current compartment. The default is that "
|
||||
" source discarding is not explicitly enabled."),
|
||||
|
||||
JS_FN_HELP("getConstructorName", GetConstructorName, 1, 0,
|
||||
"getConstructorName(object)",
|
||||
" If the given object was created with `new Ctor`, return the constructor's display name. "
|
||||
" Otherwise, return null."),
|
||||
|
||||
JS_FN_HELP("allocationMarker", AllocationMarker, 0, 0,
|
||||
"allocationMarker([options])",
|
||||
" Return a freshly allocated object whose [[Class]] name is\n"
|
||||
|
|
|
@ -2874,25 +2874,12 @@ bool Debugger::appendAllocationSite(JSContext* cx, HandleObject obj,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Try to get the constructor name from the ObjectGroup's TypeNewScript.
|
||||
// This is only relevant for native objects.
|
||||
RootedAtom ctorName(cx);
|
||||
if (obj->is<NativeObject>()) {
|
||||
AutoRealm ar(cx, obj);
|
||||
if (!JSObject::constructorDisplayAtom(cx, obj, &ctorName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (ctorName) {
|
||||
cx->markAtom(ctorName);
|
||||
}
|
||||
|
||||
auto className = obj->getClass()->name;
|
||||
auto size =
|
||||
JS::ubi::Node(obj.get()).size(cx->runtime()->debuggerMallocSizeOf);
|
||||
auto inNursery = gc::IsInsideNursery(obj);
|
||||
|
||||
if (!allocationsLog.emplaceBack(wrappedFrame, when, className, ctorName, size,
|
||||
if (!allocationsLog.emplaceBack(wrappedFrame, when, className, size,
|
||||
inNursery)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
|
|
@ -582,12 +582,10 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
|
|||
|
||||
struct AllocationsLogEntry {
|
||||
AllocationsLogEntry(HandleObject frame, mozilla::TimeStamp when,
|
||||
const char* className, HandleAtom ctorName, size_t size,
|
||||
bool inNursery)
|
||||
const char* className, size_t size, bool inNursery)
|
||||
: frame(frame),
|
||||
when(when),
|
||||
className(className),
|
||||
ctorName(ctorName),
|
||||
size(size),
|
||||
inNursery(inNursery) {
|
||||
MOZ_ASSERT_IF(frame, UncheckedUnwrap(frame)->is<SavedFrame>() ||
|
||||
|
@ -597,14 +595,11 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
|
|||
HeapPtr<JSObject*> frame;
|
||||
mozilla::TimeStamp when;
|
||||
const char* className;
|
||||
HeapPtr<JSAtom*> ctorName;
|
||||
size_t size;
|
||||
bool inNursery;
|
||||
|
||||
void trace(JSTracer* trc) {
|
||||
TraceNullableEdge(trc, &frame, "Debugger::AllocationsLogEntry::frame");
|
||||
TraceNullableEdge(trc, &ctorName,
|
||||
"Debugger::AllocationsLogEntry::ctorName");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -239,14 +239,6 @@ bool DebuggerMemory::CallData::drainAllocationsLog() {
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedValue ctorName(cx, NullValue());
|
||||
if (entry.ctorName) {
|
||||
ctorName.setString(entry.ctorName);
|
||||
}
|
||||
if (!DefineDataProperty(cx, obj, cx->names().constructor, ctorName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue size(cx, NumberValue(entry.size));
|
||||
if (!DefineDataProperty(cx, obj, cx->names().size, size)) {
|
||||
return false;
|
||||
|
|
|
@ -225,7 +225,6 @@ Objects in the array are of the form:
|
|||
"timestamp": timestamp,
|
||||
"frame": allocationSite,
|
||||
"class": className,
|
||||
"constructor": constructorName,
|
||||
"size": byteSize,
|
||||
"inNursery": inNursery,
|
||||
}
|
||||
|
@ -243,10 +242,6 @@ Where
|
|||
`[[Class]]` property, for example "Array", "Date", "RegExp", or (most
|
||||
commonly) "Object".
|
||||
|
||||
* `constructorName` is the constructor function's display name for objects
|
||||
created by `new Ctor`. If that data is not available, or the object was
|
||||
not created with a `new` expression, this property is `null`.
|
||||
|
||||
* `byteSize` is the size of the object in bytes.
|
||||
|
||||
* `inNursery` is true if the allocation happened inside the nursery. False
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// |jit-test| skip-if: !isTypeInferenceEnabled()
|
||||
// Unfortunately getConstructorName depends on TI's TypeNewScript.
|
||||
|
||||
function Ctor() {}
|
||||
|
||||
var nested = {};
|
||||
nested.Ctor = function () {};
|
||||
nested.object = {};
|
||||
|
||||
function makeInstance() {
|
||||
let LexicalCtor = function () {};
|
||||
return new LexicalCtor;
|
||||
}
|
||||
|
||||
function makeObject() {
|
||||
let object = {};
|
||||
return object;
|
||||
}
|
||||
|
||||
let tests = [
|
||||
{ name: "Ctor", object: new Ctor },
|
||||
{ name: "nested.Ctor", object: new nested.Ctor },
|
||||
{ name: "LexicalCtor", object: makeInstance() },
|
||||
{ name: null, object: {} },
|
||||
{ name: null, object: nested.object },
|
||||
{ name: null, object: makeObject() },
|
||||
];
|
||||
|
||||
for (let { name, object } of tests) {
|
||||
assertEq(getConstructorName(object), name);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
// |jit-test| skip-if: !isTypeInferenceEnabled()
|
||||
// Constructor name depends on TI TypeNewScript heuristics.
|
||||
|
||||
// Test drainAllocationsLog() and constructor names.
|
||||
|
||||
const root = newGlobal({newCompartment: true});
|
||||
const dbg = new Debugger();
|
||||
const wrappedRoot = dbg.addDebuggee(root);
|
||||
|
||||
root.eval(
|
||||
`
|
||||
function Ctor() {}
|
||||
|
||||
var nested = {};
|
||||
nested.Ctor = function () {};
|
||||
|
||||
function makeInstance() {
|
||||
let LexicalCtor = function () {};
|
||||
return new LexicalCtor;
|
||||
}
|
||||
|
||||
function makeObject() {
|
||||
let object = {};
|
||||
return object;
|
||||
}
|
||||
|
||||
this.tests = [
|
||||
{ name: "Ctor", fn: () => new Ctor },
|
||||
{ name: "nested.Ctor", fn: () => new nested.Ctor },
|
||||
{ name: "LexicalCtor", fn: () => makeInstance() },
|
||||
{ name: null, fn: () => ({}) },
|
||||
{ name: null, fn: () => (nested.object = {}) },
|
||||
{ name: null, fn: () => makeObject() },
|
||||
];
|
||||
`
|
||||
);
|
||||
|
||||
for (let { name, fn } of root.tests) {
|
||||
print(name);
|
||||
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
|
||||
fn();
|
||||
|
||||
let entries = dbg.memory.drainAllocationsLog();
|
||||
let ctors = entries.map(e => e.constructor);
|
||||
assertEq(ctors.some(ctor => ctor === name), true);
|
||||
|
||||
dbg.memory.trackingAllocationSites = false;
|
||||
}
|
|
@ -177,20 +177,6 @@ BEGIN_TEST(test_ubiNodeCompartment) {
|
|||
}
|
||||
END_TEST(test_ubiNodeCompartment)
|
||||
|
||||
BEGIN_TEST(test_ubiNodeJSObjectConstructorName) {
|
||||
JS::RootedValue val(cx);
|
||||
EVAL("this.Ctor = function Ctor() {}; new Ctor", &val);
|
||||
CHECK(val.isObject());
|
||||
|
||||
UniqueTwoByteChars ctorName;
|
||||
CHECK(JS::ubi::Node(&val.toObject()).jsObjectConstructorName(cx, ctorName));
|
||||
CHECK(ctorName);
|
||||
CHECK(EqualChars(ctorName.get(), u"Ctor", js_strlen(u"Ctor") + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_ubiNodeJSObjectConstructorName)
|
||||
|
||||
template <typename F, typename G>
|
||||
static bool checkString(const char* expected, F fillBufferFunction,
|
||||
G stringGetterFunction) {
|
||||
|
|
|
@ -4029,35 +4029,6 @@ void JSObject::traceChildren(JSTracer* trc) {
|
|||
}
|
||||
}
|
||||
|
||||
static JSAtom* displayAtomFromObjectGroup(ObjectGroup& group) {
|
||||
AutoSweepObjectGroup sweep(&group);
|
||||
TypeNewScript* script = group.newScript(sweep);
|
||||
if (!script) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return script->function()->displayAtom();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool JSObject::constructorDisplayAtom(JSContext* cx, js::HandleObject obj,
|
||||
js::MutableHandleAtom name) {
|
||||
ObjectGroup* g = JSObject::getGroup(cx, obj);
|
||||
if (!g) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name.set(displayAtomFromObjectGroup(*g));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSAtom* JSObject::maybeConstructorDisplayAtom() const {
|
||||
if (hasLazyGroup()) {
|
||||
return nullptr;
|
||||
}
|
||||
return displayAtomFromObjectGroup(*group());
|
||||
}
|
||||
|
||||
// ES 2016 7.3.20.
|
||||
MOZ_MUST_USE JSObject* js::SpeciesConstructor(
|
||||
JSContext* cx, HandleObject obj, HandleObject defaultCtor,
|
||||
|
|
|
@ -249,21 +249,6 @@ class JSObject
|
|||
*/
|
||||
MOZ_ALWAYS_INLINE bool maybeHasInterestingSymbolProperty() const;
|
||||
|
||||
/*
|
||||
* If this object was instantiated with `new Ctor`, return the constructor's
|
||||
* display atom. Otherwise, return nullptr.
|
||||
*/
|
||||
static bool constructorDisplayAtom(JSContext* cx, js::HandleObject obj,
|
||||
js::MutableHandleAtom name);
|
||||
|
||||
/*
|
||||
* The same as constructorDisplayAtom above, however if this object has a
|
||||
* lazy group, nullptr is returned. This allows for use in situations that
|
||||
* cannot GC and where having some information, even if it is inconsistently
|
||||
* available, is better than no information.
|
||||
*/
|
||||
JSAtom* maybeConstructorDisplayAtom() const;
|
||||
|
||||
/* GC support. */
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
|
|
@ -332,31 +332,6 @@ const char* Concrete<JSObject>::jsObjectClassName() const {
|
|||
return Concrete::get().getClass()->name;
|
||||
}
|
||||
|
||||
bool Concrete<JSObject>::jsObjectConstructorName(
|
||||
JSContext* cx, UniqueTwoByteChars& outName) const {
|
||||
JSAtom* name = Concrete::get().maybeConstructorDisplayAtom();
|
||||
if (!name) {
|
||||
outName.reset(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto len = JS_GetStringLength(name);
|
||||
auto size = len + 1;
|
||||
|
||||
outName.reset(cx->pod_malloc<char16_t>(size * sizeof(char16_t)));
|
||||
if (!outName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::Range<char16_t> chars(outName.get(), size);
|
||||
if (!JS_CopyStringChars(cx, chars, name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outName[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Compartment* Concrete<JSObject>::compartment() const {
|
||||
return Concrete::get().compartment();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче