Bug 988476 - Create Debugger.Memory, a place to expose our memory tools to JS; r=jimb

This commit is contained in:
Nick Fitzgerald 2014-03-28 17:33:33 -07:00
parent ab88e0d360
commit 485ed1e9d2
6 changed files with 119 additions and 16 deletions

View File

@ -0,0 +1,6 @@
assertEq(typeof Debugger.Memory, "function");
let dbg = new Debugger;
assertEq(dbg.memory instanceof Debugger.Memory, true);
load(libdir + "asserts.js");
assertThrowsInstanceOf(() => new Debugger.Memory, TypeError);

View File

@ -163,6 +163,7 @@ UNIFIED_SOURCES += [
'vm/Compression.cpp', 'vm/Compression.cpp',
'vm/DateTime.cpp', 'vm/DateTime.cpp',
'vm/Debugger.cpp', 'vm/Debugger.cpp',
'vm/DebuggerMemory.cpp',
'vm/ErrorObject.cpp', 'vm/ErrorObject.cpp',
'vm/ForkJoin.cpp', 'vm/ForkJoin.cpp',
'vm/GlobalObject.cpp', 'vm/GlobalObject.cpp',

View File

@ -12,19 +12,17 @@
#include "jsnum.h" #include "jsnum.h"
#include "jsobj.h" #include "jsobj.h"
#include "jswrapper.h" #include "jswrapper.h"
#include "frontend/BytecodeCompiler.h" #include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h" #include "gc/Marking.h"
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "js/Vector.h" #include "js/Vector.h"
#include "vm/ArgumentsObject.h" #include "vm/ArgumentsObject.h"
#include "vm/DebuggerMemory.h"
#include "vm/WrapperObject.h" #include "vm/WrapperObject.h"
#include "jsgcinlines.h" #include "jsgcinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsopcodeinlines.h" #include "jsopcodeinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
#include "vm/ObjectImpl-inl.h" #include "vm/ObjectImpl-inl.h"
#include "vm/Stack-inl.h" #include "vm/Stack-inl.h"
@ -1929,11 +1927,17 @@ Debugger::setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp)
"uncaughtExceptionHook"); "uncaughtExceptionHook");
return false; return false;
} }
dbg->uncaughtExceptionHook = args[0].toObjectOrNull(); dbg->uncaughtExceptionHook = args[0].toObjectOrNull();
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
} }
bool
Debugger::getMemory(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGGER(cx, argc, vp, "get memory", args, dbg);
args.rval().set(dbg->object->getReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE));
return true;
}
GlobalObject * GlobalObject *
Debugger::unwrapDebuggeeArgument(JSContext *cx, const Value &v) Debugger::unwrapDebuggeeArgument(JSContext *cx, const Value &v)
@ -2135,17 +2139,24 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp)
return false; return false;
RootedObject proto(cx, &v.toObject()); RootedObject proto(cx, &v.toObject());
JS_ASSERT(proto->getClass() == &Debugger::jsclass); JS_ASSERT(proto->getClass() == &Debugger::jsclass);
/* /*
* Make the new Debugger object. Each one has a reference to * Make the new Debugger object. Each one has a reference to
* Debugger.{Frame,Object,Script}.prototype in reserved slots. The rest of * Debugger.{Frame,Object,Script,Memory}.prototype in reserved slots. The
* the reserved slots are for hooks; they default to undefined. * rest of the reserved slots are for hooks; they default to undefined.
*/ */
RootedObject obj(cx, NewObjectWithGivenProto(cx, &Debugger::jsclass, proto, nullptr)); RootedObject obj(cx, NewObjectWithGivenProto(cx, &Debugger::jsclass, proto, nullptr));
if (!obj) if (!obj)
return false; return false;
for (unsigned slot = JSSLOT_DEBUG_PROTO_START; slot < JSSLOT_DEBUG_PROTO_STOP; slot++) for (unsigned slot = JSSLOT_DEBUG_PROTO_START; slot < JSSLOT_DEBUG_PROTO_STOP; slot++)
obj->setReservedSlot(slot, proto->getReservedSlot(slot)); obj->setReservedSlot(slot, proto->getReservedSlot(slot));
/* Create the Debugger.Memory instance accessible by the
* |Debugger.prototype.memory| getter. */
Value memoryProto = obj->getReservedSlot(JSSLOT_DEBUG_MEMORY_PROTO);
RootedObject memory(cx, NewObjectWithGivenProto(cx, &DebuggerMemory::class_,
&memoryProto.toObject(), nullptr));
if (!memory)
return false;
obj->setReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE, ObjectValue(*memory));
/* Construct the underlying C++ object. */ /* Construct the underlying C++ object. */
Debugger *dbg = cx->new_<Debugger>(cx, obj.get()); Debugger *dbg = cx->new_<Debugger>(cx, obj.get());
@ -2814,9 +2825,9 @@ const JSPropertySpec Debugger::properties[] = {
JS_PSGS("onNewGlobalObject", Debugger::getOnNewGlobalObject, Debugger::setOnNewGlobalObject, 0), JS_PSGS("onNewGlobalObject", Debugger::getOnNewGlobalObject, Debugger::setOnNewGlobalObject, 0),
JS_PSGS("uncaughtExceptionHook", Debugger::getUncaughtExceptionHook, JS_PSGS("uncaughtExceptionHook", Debugger::getUncaughtExceptionHook,
Debugger::setUncaughtExceptionHook, 0), Debugger::setUncaughtExceptionHook, 0),
JS_PSG("memory", Debugger::getMemory, 0),
JS_PS_END JS_PS_END
}; };
const JSFunctionSpec Debugger::methods[] = { const JSFunctionSpec Debugger::methods[] = {
JS_FN("addDebuggee", Debugger::addDebuggee, 1, 0), JS_FN("addDebuggee", Debugger::addDebuggee, 1, 0),
JS_FN("addAllGlobalsAsDebuggees", Debugger::addAllGlobalsAsDebuggees, 0, 0), JS_FN("addAllGlobalsAsDebuggees", Debugger::addAllGlobalsAsDebuggees, 0, 0),
@ -5905,13 +5916,11 @@ JS_DefineDebuggerObject(JSContext *cx, HandleObject obj)
scriptProto(cx), scriptProto(cx),
sourceProto(cx), sourceProto(cx),
objectProto(cx), objectProto(cx),
envProto(cx); envProto(cx),
memoryProto(cx);
objProto = obj->as<GlobalObject>().getOrCreateObjectPrototype(cx); objProto = obj->as<GlobalObject>().getOrCreateObjectPrototype(cx);
if (!objProto) if (!objProto)
return false; return false;
debugProto = js_InitClass(cx, obj, debugProto = js_InitClass(cx, obj,
objProto, &Debugger::jsclass, Debugger::construct, objProto, &Debugger::jsclass, Debugger::construct,
1, Debugger::properties, Debugger::methods, nullptr, nullptr, 1, Debugger::properties, Debugger::methods, nullptr, nullptr,
@ -5946,18 +5955,23 @@ JS_DefineDebuggerObject(JSContext *cx, HandleObject obj)
nullptr, nullptr); nullptr, nullptr);
if (!objectProto) if (!objectProto)
return false; return false;
envProto = js_InitClass(cx, debugCtor, objProto, &DebuggerEnv_class, envProto = js_InitClass(cx, debugCtor, objProto, &DebuggerEnv_class,
DebuggerEnv_construct, 0, DebuggerEnv_construct, 0,
DebuggerEnv_properties, DebuggerEnv_methods, DebuggerEnv_properties, DebuggerEnv_methods,
nullptr, nullptr); nullptr, nullptr);
if (!envProto) if (!envProto)
return false; return false;
memoryProto = js_InitClass(cx, debugCtor, objProto, &DebuggerMemory::class_,
DebuggerMemory::construct, 0, DebuggerMemory::properties,
DebuggerMemory::methods, nullptr, nullptr);
if (!memoryProto)
return false;
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_FRAME_PROTO, ObjectValue(*frameProto)); debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_FRAME_PROTO, ObjectValue(*frameProto));
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_OBJECT_PROTO, ObjectValue(*objectProto)); debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_OBJECT_PROTO, ObjectValue(*objectProto));
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SCRIPT_PROTO, ObjectValue(*scriptProto)); debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SCRIPT_PROTO, ObjectValue(*scriptProto));
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SOURCE_PROTO, ObjectValue(*sourceProto)); debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SOURCE_PROTO, ObjectValue(*sourceProto));
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_ENV_PROTO, ObjectValue(*envProto)); debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_ENV_PROTO, ObjectValue(*envProto));
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_PROTO, ObjectValue(*memoryProto));
return true; return true;
} }

View File

@ -170,7 +170,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
OnNewGlobalObject, OnNewGlobalObject,
HookCount HookCount
}; };
enum { enum {
JSSLOT_DEBUG_PROTO_START, JSSLOT_DEBUG_PROTO_START,
JSSLOT_DEBUG_FRAME_PROTO = JSSLOT_DEBUG_PROTO_START, JSSLOT_DEBUG_FRAME_PROTO = JSSLOT_DEBUG_PROTO_START,
@ -178,12 +177,13 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
JSSLOT_DEBUG_OBJECT_PROTO, JSSLOT_DEBUG_OBJECT_PROTO,
JSSLOT_DEBUG_SCRIPT_PROTO, JSSLOT_DEBUG_SCRIPT_PROTO,
JSSLOT_DEBUG_SOURCE_PROTO, JSSLOT_DEBUG_SOURCE_PROTO,
JSSLOT_DEBUG_MEMORY_PROTO,
JSSLOT_DEBUG_PROTO_STOP, JSSLOT_DEBUG_PROTO_STOP,
JSSLOT_DEBUG_HOOK_START = JSSLOT_DEBUG_PROTO_STOP, JSSLOT_DEBUG_HOOK_START = JSSLOT_DEBUG_PROTO_STOP,
JSSLOT_DEBUG_HOOK_STOP = JSSLOT_DEBUG_HOOK_START + HookCount, JSSLOT_DEBUG_HOOK_STOP = JSSLOT_DEBUG_HOOK_START + HookCount,
JSSLOT_DEBUG_COUNT = JSSLOT_DEBUG_HOOK_STOP JSSLOT_DEBUG_MEMORY_INSTANCE = JSSLOT_DEBUG_HOOK_STOP,
JSSLOT_DEBUG_COUNT
}; };
private: private:
HeapPtrObject object; /* The Debugger object. Strong reference. */ HeapPtrObject object; /* The Debugger object. Strong reference. */
GlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */ GlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */
@ -321,6 +321,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
static bool setOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp); static bool setOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp);
static bool getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp); static bool getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
static bool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp); static bool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
static bool getMemory(JSContext *cx, unsigned argc, Value *vp);
static bool addDebuggee(JSContext *cx, unsigned argc, Value *vp); static bool addDebuggee(JSContext *cx, unsigned argc, Value *vp);
static bool addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp); static bool addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp);
static bool removeDebuggee(JSContext *cx, unsigned argc, Value *vp); static bool removeDebuggee(JSContext *cx, unsigned argc, Value *vp);

View File

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/DebuggerMemory.h"
namespace js {
/* static */ bool
DebuggerMemory::construct(JSContext *cx, unsigned argc, Value *vp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
"Debugger.Memory");
return false;
}
/* static */ const Class DebuggerMemory::class_ = {
"Memory",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGGER_MEMORY_COUNT),
JS_PropertyStub, // addProperty
JS_DeletePropertyStub, // delProperty
JS_PropertyStub, // getProperty
JS_StrictPropertyStub, // setProperty
JS_EnumerateStub, // enumerate
JS_ResolveStub, // resolve
JS_ConvertStub, // convert
nullptr, // finalize
nullptr, // call
nullptr, // hasInstance
nullptr, // construct
nullptr // trace
};
/* static */ const JSPropertySpec DebuggerMemory::properties[] = {
JS_PS_END
};
/* static */ const JSFunctionSpec DebuggerMemory::methods[] = {
JS_FS_END
};
} /* namespace js */

View File

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_DebuggerMemory_h
#define vm_DebuggerMemory_h
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobj.h"
#include "js/Class.h"
#include "js/Value.h"
namespace js {
class DebuggerMemory : public JSObject {
enum {
JSSLOT_DEBUGGER_MEMORY_COUNT
};
public:
static bool construct(JSContext *cx, unsigned argc, Value *vp);
static const Class class_;
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
};
} /* namespace js */
#endif /* vm_DebuggerMemory_h */