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:
Jan de Mooij 2020-09-26 03:00:15 +00:00
Родитель 5a1d3dffad
Коммит 47d9b0c94d
12 изменённых файлов: 2 добавлений и 246 удалений

Просмотреть файл

@ -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();
}