Bug 1564164: Move DebuggerEnvironment into its own file, js/src/dbg/Environment.cpp. r=jorendorff

This patch should be pure code motion and declaration visibility changes. There
should be no change in behavior.

Differential Revision: https://phabricator.services.mozilla.com/D37363

--HG--
rename : js/src/dbg/Debugger-inl.h => js/src/dbg/Environment-inl.h
rename : js/src/dbg/Debugger.cpp => js/src/dbg/Environment.cpp
rename : js/src/dbg/Debugger.h => js/src/dbg/Environment.h
extra : moz-landing-system : lando
This commit is contained in:
Jim Blandy 2019-07-17 07:12:56 +00:00
parent 1e1784264b
commit b8467981fc
8 changed files with 791 additions and 729 deletions

View File

@ -112,9 +112,4 @@
}
}
inline js::Debugger* js::DebuggerEnvironment::owner() const {
JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
return Debugger::fromJSObject(dbgobj);
}
#endif /* dbg_Debugger_inl_h */

View File

@ -18,6 +18,7 @@
#include "builtin/Promise.h"
#include "dbg/DebuggerMemory.h"
#include "dbg/Environment.h"
#include "dbg/Frame.h"
#include "dbg/NoExecute.h"
#include "dbg/Object.h"
@ -83,28 +84,9 @@ using mozilla::TimeStamp;
/*** Forward declarations, ClassOps and Classes *****************************/
static void DebuggerEnv_trace(JSTracer* trc, JSObject* obj);
static void DebuggerScript_trace(JSTracer* trc, JSObject* obj);
static void DebuggerSource_trace(JSTracer* trc, JSObject* obj);
const ClassOps DebuggerEnvironment::classOps_ = {nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* enumerate */
nullptr, /* newEnumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
DebuggerEnv_trace};
const Class DebuggerEnvironment::class_ = {
"Environment",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(DebuggerEnvironment::RESERVED_SLOTS),
&classOps_};
enum { JSSLOT_DEBUGSCRIPT_OWNER, JSSLOT_DEBUGSCRIPT_COUNT };
static const ClassOps DebuggerScript_classOps = {nullptr, /* addProperty */
@ -3314,7 +3296,7 @@ void Debugger::removeAllocationsTrackingForAllDebuggees() {
void Debugger::traceCrossCompartmentEdges(JSTracer* trc) {
generatorFrames.traceCrossCompartmentEdges<DebuggerFrame::trace>(trc);
objects.traceCrossCompartmentEdges<DebuggerObject::trace>(trc);
environments.traceCrossCompartmentEdges<DebuggerEnv_trace>(trc);
environments.traceCrossCompartmentEdges<DebuggerEnvironment::trace>(trc);
scripts.traceCrossCompartmentEdges<DebuggerScript_trace>(trc);
lazyScripts.traceCrossCompartmentEdges<DebuggerScript_trace>(trc);
sources.traceCrossCompartmentEdges<DebuggerSource_trace>(trc);
@ -8843,629 +8825,6 @@ static const JSPropertySpec DebuggerSource_properties[] = {
static const JSFunctionSpec DebuggerSource_methods[] = {JS_FS_END};
/*** Debugger.Environment ***************************************************/
void DebuggerEnv_trace(JSTracer* trc, JSObject* obj) {
// There is a barrier on private pointers, so the Unbarriered marking
// is okay.
if (Env* referent = (JSObject*)obj->as<NativeObject>().getPrivate()) {
TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
"Debugger.Environment referent");
obj->as<NativeObject>().setPrivateUnbarriered(referent);
}
}
static DebuggerEnvironment* DebuggerEnvironment_checkThis(
JSContext* cx, const CallArgs& args, const char* fnname,
bool requireDebuggee) {
JSObject* thisobj = RequireObject(cx, args.thisv());
if (!thisobj) {
return nullptr;
}
if (thisobj->getClass() != &DebuggerEnvironment::class_) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO, "Debugger.Environment",
fnname, thisobj->getClass()->name);
return nullptr;
}
// Forbid Debugger.Environment.prototype, which is of class
// DebuggerEnvironment::class_ but isn't a real working Debugger.Environment.
// The prototype object is distinguished by having no referent.
DebuggerEnvironment* nthisobj = &thisobj->as<DebuggerEnvironment>();
if (!nthisobj->getPrivate()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO, "Debugger.Environment",
fnname, "prototype object");
return nullptr;
}
// Forbid access to Debugger.Environment objects that are not debuggee
// environments.
if (requireDebuggee) {
Rooted<Env*> env(cx, static_cast<Env*>(nthisobj->getPrivate()));
if (!Debugger::fromChildJSObject(nthisobj)->observesGlobal(
&env->nonCCWGlobal())) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_NOT_DEBUGGEE,
"Debugger.Environment", "environment");
return nullptr;
}
}
return nthisobj;
}
#define THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, fnname, args, environment) \
CallArgs args = CallArgsFromVp(argc, vp); \
Rooted<DebuggerEnvironment*> environment( \
cx, DebuggerEnvironment_checkThis(cx, args, fnname, false)); \
if (!environment) return false;
/* static */
bool DebuggerEnvironment::construct(JSContext* cx, unsigned argc, Value* vp) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
"Debugger.Environment");
return false;
}
static bool IsDeclarative(Env* env) {
return env->is<DebugEnvironmentProxy>() &&
env->as<DebugEnvironmentProxy>().isForDeclarative();
}
template <typename T>
static bool IsDebugEnvironmentWrapper(Env* env) {
return env->is<DebugEnvironmentProxy>() &&
env->as<DebugEnvironmentProxy>().environment().is<T>();
}
bool DebuggerEnvironment::typeGetter(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
DebuggerEnvironmentType type = environment->type();
const char* s;
switch (type) {
case DebuggerEnvironmentType::Declarative:
s = "declarative";
break;
case DebuggerEnvironmentType::With:
s = "with";
break;
case DebuggerEnvironmentType::Object:
s = "object";
break;
}
JSAtom* str = Atomize(cx, s, strlen(s), PinAtom);
if (!str) {
return false;
}
args.rval().setString(str);
return true;
}
bool DebuggerEnvironment::scopeKindGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get scopeKind", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
Maybe<ScopeKind> kind = environment->scopeKind();
if (kind.isSome()) {
const char* s = ScopeKindString(*kind);
JSAtom* str = Atomize(cx, s, strlen(s), PinAtom);
if (!str) {
return false;
}
args.rval().setString(str);
} else {
args.rval().setNull();
}
return true;
}
/* static */
bool DebuggerEnvironment::parentGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedDebuggerEnvironment result(cx);
if (!environment->getParent(cx, &result)) {
return false;
}
args.rval().setObjectOrNull(result);
return true;
}
/* static */
bool DebuggerEnvironment::objectGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
if (environment->type() == DebuggerEnvironmentType::Declarative) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_NO_ENV_OBJECT);
return false;
}
RootedDebuggerObject result(cx);
if (!environment->getObject(cx, &result)) {
return false;
}
args.rval().setObject(*result);
return true;
}
/* static */
bool DebuggerEnvironment::calleeGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get callee", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedDebuggerObject result(cx);
if (!environment->getCallee(cx, &result)) {
return false;
}
args.rval().setObjectOrNull(result);
return true;
}
/* static */
bool DebuggerEnvironment::inspectableGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get inspectable", args, environment);
args.rval().setBoolean(environment->isDebuggee());
return true;
}
/* static */
bool DebuggerEnvironment::optimizedOutGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get optimizedOut", args,
environment);
args.rval().setBoolean(environment->isOptimized());
return true;
}
/* static */
bool DebuggerEnvironment::namesMethod(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "names", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
Rooted<IdVector> ids(cx, IdVector(cx));
if (!DebuggerEnvironment::getNames(cx, environment, &ids)) {
return false;
}
RootedObject obj(cx, IdVectorToArray(cx, ids));
if (!obj) {
return false;
}
args.rval().setObject(*obj);
return true;
}
/* static */
bool DebuggerEnvironment::findMethod(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "find", args, environment);
if (!args.requireAtLeast(cx, "Debugger.Environment.find", 1)) {
return false;
}
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedId id(cx);
if (!ValueToIdentifier(cx, args[0], &id)) {
return false;
}
RootedDebuggerEnvironment result(cx);
if (!DebuggerEnvironment::find(cx, environment, id, &result)) {
return false;
}
args.rval().setObjectOrNull(result);
return true;
}
/* static */
bool DebuggerEnvironment::getVariableMethod(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "getVariable", args, environment);
if (!args.requireAtLeast(cx, "Debugger.Environment.getVariable", 1)) {
return false;
}
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedId id(cx);
if (!ValueToIdentifier(cx, args[0], &id)) {
return false;
}
return DebuggerEnvironment::getVariable(cx, environment, id, args.rval());
}
/* static */
bool DebuggerEnvironment::setVariableMethod(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "setVariable", args, environment);
if (!args.requireAtLeast(cx, "Debugger.Environment.setVariable", 2)) {
return false;
}
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedId id(cx);
if (!ValueToIdentifier(cx, args[0], &id)) {
return false;
}
if (!DebuggerEnvironment::setVariable(cx, environment, id, args[1])) {
return false;
}
args.rval().setUndefined();
return true;
}
bool DebuggerEnvironment::requireDebuggee(JSContext* cx) const {
if (!isDebuggee()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_NOT_DEBUGGEE, "Debugger.Environment",
"environment");
return false;
}
return true;
}
const JSPropertySpec DebuggerEnvironment::properties_[] = {
JS_PSG("type", DebuggerEnvironment::typeGetter, 0),
JS_PSG("scopeKind", DebuggerEnvironment::scopeKindGetter, 0),
JS_PSG("parent", DebuggerEnvironment::parentGetter, 0),
JS_PSG("object", DebuggerEnvironment::objectGetter, 0),
JS_PSG("callee", DebuggerEnvironment::calleeGetter, 0),
JS_PSG("inspectable", DebuggerEnvironment::inspectableGetter, 0),
JS_PSG("optimizedOut", DebuggerEnvironment::optimizedOutGetter, 0),
JS_PS_END};
const JSFunctionSpec DebuggerEnvironment::methods_[] = {
JS_FN("names", DebuggerEnvironment::namesMethod, 0, 0),
JS_FN("find", DebuggerEnvironment::findMethod, 1, 0),
JS_FN("getVariable", DebuggerEnvironment::getVariableMethod, 1, 0),
JS_FN("setVariable", DebuggerEnvironment::setVariableMethod, 2, 0),
JS_FS_END};
/* static */
NativeObject* DebuggerEnvironment::initClass(JSContext* cx,
HandleObject dbgCtor,
Handle<GlobalObject*> global) {
return InitClass(cx, dbgCtor, nullptr, &DebuggerEnvironment::class_,
construct, 0, properties_, methods_, nullptr, nullptr);
}
/* static */
DebuggerEnvironment* DebuggerEnvironment::create(JSContext* cx,
HandleObject proto,
HandleObject referent,
HandleNativeObject debugger) {
NewObjectKind newKind =
IsInsideNursery(referent) ? GenericObject : TenuredObject;
DebuggerEnvironment* obj =
NewObjectWithGivenProto<DebuggerEnvironment>(cx, proto, newKind);
if (!obj) {
return nullptr;
}
obj->setPrivateGCThing(referent);
obj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
return obj;
}
/* static */
DebuggerEnvironmentType DebuggerEnvironment::type() const {
// Don't bother switching compartments just to check env's type.
if (IsDeclarative(referent())) {
return DebuggerEnvironmentType::Declarative;
}
if (IsDebugEnvironmentWrapper<WithEnvironmentObject>(referent())) {
return DebuggerEnvironmentType::With;
}
return DebuggerEnvironmentType::Object;
}
mozilla::Maybe<ScopeKind> DebuggerEnvironment::scopeKind() const {
if (!referent()->is<DebugEnvironmentProxy>()) {
return Nothing();
}
EnvironmentObject& env =
referent()->as<DebugEnvironmentProxy>().environment();
Scope* scope = GetEnvironmentScope(env);
return scope ? Some(scope->kind()) : Nothing();
}
bool DebuggerEnvironment::getParent(
JSContext* cx, MutableHandleDebuggerEnvironment result) const {
// Don't bother switching compartments just to get env's parent.
Rooted<Env*> parent(cx, referent()->enclosingEnvironment());
if (!parent) {
result.set(nullptr);
return true;
}
return owner()->wrapEnvironment(cx, parent, result);
}
bool DebuggerEnvironment::getObject(JSContext* cx,
MutableHandleDebuggerObject result) const {
MOZ_ASSERT(type() != DebuggerEnvironmentType::Declarative);
// Don't bother switching compartments just to get env's object.
RootedObject object(cx);
if (IsDebugEnvironmentWrapper<WithEnvironmentObject>(referent())) {
object.set(&referent()
->as<DebugEnvironmentProxy>()
.environment()
.as<WithEnvironmentObject>()
.object());
} else if (IsDebugEnvironmentWrapper<NonSyntacticVariablesObject>(
referent())) {
object.set(&referent()
->as<DebugEnvironmentProxy>()
.environment()
.as<NonSyntacticVariablesObject>());
} else {
object.set(referent());
MOZ_ASSERT(!object->is<DebugEnvironmentProxy>());
}
return owner()->wrapDebuggeeObject(cx, object, result);
}
bool DebuggerEnvironment::getCallee(JSContext* cx,
MutableHandleDebuggerObject result) const {
if (!referent()->is<DebugEnvironmentProxy>()) {
result.set(nullptr);
return true;
}
JSObject& scope = referent()->as<DebugEnvironmentProxy>().environment();
if (!scope.is<CallObject>()) {
result.set(nullptr);
return true;
}
RootedObject callee(cx, &scope.as<CallObject>().callee());
if (IsInternalFunctionObject(*callee)) {
result.set(nullptr);
return true;
}
return owner()->wrapDebuggeeObject(cx, callee, result);
}
bool DebuggerEnvironment::isDebuggee() const {
MOZ_ASSERT(referent());
MOZ_ASSERT(!referent()->is<EnvironmentObject>());
return owner()->observesGlobal(&referent()->nonCCWGlobal());
}
bool DebuggerEnvironment::isOptimized() const {
return referent()->is<DebugEnvironmentProxy>() &&
referent()->as<DebugEnvironmentProxy>().isOptimizedOut();
}
/* static */
bool DebuggerEnvironment::getNames(JSContext* cx,
HandleDebuggerEnvironment environment,
MutableHandle<IdVector> result) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> referent(cx, environment->referent());
RootedIdVector ids(cx);
{
Maybe<AutoRealm> ar;
ar.emplace(cx, referent);
ErrorCopier ec(ar);
if (!GetPropertyKeys(cx, referent, JSITER_HIDDEN, &ids)) {
return false;
}
}
for (size_t i = 0; i < ids.length(); ++i) {
jsid id = ids[i];
if (JSID_IS_ATOM(id) && IsIdentifier(JSID_TO_ATOM(id))) {
cx->markId(id);
if (!result.append(id)) {
return false;
}
}
}
return true;
}
/* static */
bool DebuggerEnvironment::find(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id,
MutableHandleDebuggerEnvironment result) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> env(cx, environment->referent());
Debugger* dbg = environment->owner();
{
Maybe<AutoRealm> ar;
ar.emplace(cx, env);
cx->markId(id);
// This can trigger resolve hooks.
ErrorCopier ec(ar);
for (; env; env = env->enclosingEnvironment()) {
bool found;
if (!HasProperty(cx, env, id, &found)) {
return false;
}
if (found) {
break;
}
}
}
if (!env) {
result.set(nullptr);
return true;
}
return dbg->wrapEnvironment(cx, env, result);
}
/* static */
bool DebuggerEnvironment::getVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, MutableHandleValue result) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> referent(cx, environment->referent());
Debugger* dbg = environment->owner();
{
Maybe<AutoRealm> ar;
ar.emplace(cx, referent);
cx->markId(id);
// This can trigger getters.
ErrorCopier ec(ar);
bool found;
if (!HasProperty(cx, referent, id, &found)) {
return false;
}
if (!found) {
result.setUndefined();
return true;
}
// For DebugEnvironmentProxys, we get sentinel values for optimized out
// slots and arguments instead of throwing (the default behavior).
//
// See wrapDebuggeeValue for how the sentinel values are wrapped.
if (referent->is<DebugEnvironmentProxy>()) {
Rooted<DebugEnvironmentProxy*> env(
cx, &referent->as<DebugEnvironmentProxy>());
if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, env, id, result)) {
return false;
}
} else {
if (!GetProperty(cx, referent, referent, id, result)) {
return false;
}
}
}
// When we've faked up scope chain objects for optimized-out scopes,
// declarative environments may contain internal JSFunction objects, which
// we shouldn't expose to the user.
if (result.isObject()) {
RootedObject obj(cx, &result.toObject());
if (obj->is<JSFunction>() &&
IsInternalFunctionObject(obj->as<JSFunction>()))
result.setMagic(JS_OPTIMIZED_OUT);
}
return dbg->wrapDebuggeeValue(cx, result);
}
/* static */
bool DebuggerEnvironment::setVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, HandleValue value_) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> referent(cx, environment->referent());
Debugger* dbg = environment->owner();
RootedValue value(cx, value_);
if (!dbg->unwrapDebuggeeValue(cx, &value)) {
return false;
}
{
Maybe<AutoRealm> ar;
ar.emplace(cx, referent);
if (!cx->compartment()->wrap(cx, &value)) {
return false;
}
cx->markId(id);
// This can trigger setters.
ErrorCopier ec(ar);
// Make sure the environment actually has the specified binding.
bool found;
if (!HasProperty(cx, referent, id, &found)) {
return false;
}
if (!found) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_VARIABLE_NOT_FOUND);
return false;
}
// Just set the property.
if (!SetProperty(cx, referent, id, value)) {
return false;
}
}
return true;
}
/*** JS::dbg::Builder *******************************************************/
Builder::Builder(JSContext* cx, js::Debugger* debugger)

View File

@ -1353,87 +1353,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
Debugger& operator=(const Debugger&) = delete;
};
enum class DebuggerEnvironmentType { Declarative, With, Object };
class DebuggerEnvironment : public NativeObject {
public:
enum { OWNER_SLOT };
static const unsigned RESERVED_SLOTS = 1;
static const Class class_;
static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor,
Handle<GlobalObject*> global);
static DebuggerEnvironment* create(JSContext* cx, HandleObject proto,
HandleObject referent,
HandleNativeObject debugger);
DebuggerEnvironmentType type() const;
mozilla::Maybe<ScopeKind> scopeKind() const;
MOZ_MUST_USE bool getParent(JSContext* cx,
MutableHandleDebuggerEnvironment result) const;
MOZ_MUST_USE bool getObject(JSContext* cx,
MutableHandleDebuggerObject result) const;
MOZ_MUST_USE bool getCallee(JSContext* cx,
MutableHandleDebuggerObject result) const;
bool isDebuggee() const;
bool isOptimized() const;
static MOZ_MUST_USE bool getNames(JSContext* cx,
HandleDebuggerEnvironment environment,
MutableHandle<IdVector> result);
static MOZ_MUST_USE bool find(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id,
MutableHandleDebuggerEnvironment result);
static MOZ_MUST_USE bool getVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, MutableHandleValue result);
static MOZ_MUST_USE bool setVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, HandleValue value);
private:
static const ClassOps classOps_;
static const JSPropertySpec properties_[];
static const JSFunctionSpec methods_[];
Env* referent() const {
Env* env = static_cast<Env*>(getPrivate());
MOZ_ASSERT(env);
return env;
}
Debugger* owner() const;
bool requireDebuggee(JSContext* cx) const;
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool typeGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool scopeKindGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool parentGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool objectGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool inspectableGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool optimizedOutGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool namesMethod(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool findMethod(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool getVariableMethod(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool setVariableMethod(JSContext* cx, unsigned argc,
Value* vp);
};
/*
* A Handler represents a reference to a handler function. These handler
* functions are called by the Debugger API to notify the user of certain

View File

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* 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 dbg_Environment_inl_h
#define dbg_Environment_inl_h
#include "dbg/Environment.h"
#include "dbg/Debugger-inl.h"
inline js::Debugger* js::DebuggerEnvironment::owner() const {
JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
return Debugger::fromJSObject(dbgobj);
}
#endif /* dbg_Environment_inl_h */

662
js/src/dbg/Environment.cpp Normal file
View File

@ -0,0 +1,662 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* 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 "dbg/Environment-inl.h"
#include "mozilla/Assertions.h"
#include "dbg/Debugger.h"
#include "dbg/Object.h"
#include "frontend/BytecodeCompiler.h"
#include "vm/Realm.h"
#include "vm/Compartment-inl.h"
using namespace js;
using js::frontend::IsIdentifier;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::Some;
const ClassOps DebuggerEnvironment::classOps_ = {nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* enumerate */
nullptr, /* newEnumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
trace};
const Class DebuggerEnvironment::class_ = {
"Environment",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(DebuggerEnvironment::RESERVED_SLOTS),
&classOps_};
void DebuggerEnvironment::trace(JSTracer* trc, JSObject* obj) {
// There is a barrier on private pointers, so the Unbarriered marking
// is okay.
if (Env* referent = (JSObject*)obj->as<NativeObject>().getPrivate()) {
TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
"Debugger.Environment referent");
obj->as<NativeObject>().setPrivateUnbarriered(referent);
}
}
static DebuggerEnvironment* DebuggerEnvironment_checkThis(
JSContext* cx, const CallArgs& args, const char* fnname,
bool requireDebuggee) {
JSObject* thisobj = RequireObject(cx, args.thisv());
if (!thisobj) {
return nullptr;
}
if (thisobj->getClass() != &DebuggerEnvironment::class_) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO, "Debugger.Environment",
fnname, thisobj->getClass()->name);
return nullptr;
}
// Forbid Debugger.Environment.prototype, which is of class
// DebuggerEnvironment::class_ but isn't a real working Debugger.Environment.
// The prototype object is distinguished by having no referent.
DebuggerEnvironment* nthisobj = &thisobj->as<DebuggerEnvironment>();
if (!nthisobj->getPrivate()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO, "Debugger.Environment",
fnname, "prototype object");
return nullptr;
}
// Forbid access to Debugger.Environment objects that are not debuggee
// environments.
if (requireDebuggee) {
Rooted<Env*> env(cx, static_cast<Env*>(nthisobj->getPrivate()));
if (!Debugger::fromChildJSObject(nthisobj)->observesGlobal(
&env->nonCCWGlobal())) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_NOT_DEBUGGEE,
"Debugger.Environment", "environment");
return nullptr;
}
}
return nthisobj;
}
#define THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, fnname, args, environment) \
CallArgs args = CallArgsFromVp(argc, vp); \
Rooted<DebuggerEnvironment*> environment( \
cx, DebuggerEnvironment_checkThis(cx, args, fnname, false)); \
if (!environment) return false;
/* static */
bool DebuggerEnvironment::construct(JSContext* cx, unsigned argc, Value* vp) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
"Debugger.Environment");
return false;
}
static bool IsDeclarative(Env* env) {
return env->is<DebugEnvironmentProxy>() &&
env->as<DebugEnvironmentProxy>().isForDeclarative();
}
template <typename T>
static bool IsDebugEnvironmentWrapper(Env* env) {
return env->is<DebugEnvironmentProxy>() &&
env->as<DebugEnvironmentProxy>().environment().is<T>();
}
bool DebuggerEnvironment::typeGetter(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
DebuggerEnvironmentType type = environment->type();
const char* s;
switch (type) {
case DebuggerEnvironmentType::Declarative:
s = "declarative";
break;
case DebuggerEnvironmentType::With:
s = "with";
break;
case DebuggerEnvironmentType::Object:
s = "object";
break;
}
JSAtom* str = Atomize(cx, s, strlen(s), PinAtom);
if (!str) {
return false;
}
args.rval().setString(str);
return true;
}
bool DebuggerEnvironment::scopeKindGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get scopeKind", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
Maybe<ScopeKind> kind = environment->scopeKind();
if (kind.isSome()) {
const char* s = ScopeKindString(*kind);
JSAtom* str = Atomize(cx, s, strlen(s), PinAtom);
if (!str) {
return false;
}
args.rval().setString(str);
} else {
args.rval().setNull();
}
return true;
}
/* static */
bool DebuggerEnvironment::parentGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedDebuggerEnvironment result(cx);
if (!environment->getParent(cx, &result)) {
return false;
}
args.rval().setObjectOrNull(result);
return true;
}
/* static */
bool DebuggerEnvironment::objectGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
if (environment->type() == DebuggerEnvironmentType::Declarative) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_NO_ENV_OBJECT);
return false;
}
RootedDebuggerObject result(cx);
if (!environment->getObject(cx, &result)) {
return false;
}
args.rval().setObject(*result);
return true;
}
/* static */
bool DebuggerEnvironment::calleeGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get callee", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedDebuggerObject result(cx);
if (!environment->getCallee(cx, &result)) {
return false;
}
args.rval().setObjectOrNull(result);
return true;
}
/* static */
bool DebuggerEnvironment::inspectableGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get inspectable", args, environment);
args.rval().setBoolean(environment->isDebuggee());
return true;
}
/* static */
bool DebuggerEnvironment::optimizedOutGetter(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get optimizedOut", args,
environment);
args.rval().setBoolean(environment->isOptimized());
return true;
}
/* static */
bool DebuggerEnvironment::namesMethod(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "names", args, environment);
if (!environment->requireDebuggee(cx)) {
return false;
}
Rooted<IdVector> ids(cx, IdVector(cx));
if (!DebuggerEnvironment::getNames(cx, environment, &ids)) {
return false;
}
RootedObject obj(cx, IdVectorToArray(cx, ids));
if (!obj) {
return false;
}
args.rval().setObject(*obj);
return true;
}
/* static */
bool DebuggerEnvironment::findMethod(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "find", args, environment);
if (!args.requireAtLeast(cx, "Debugger.Environment.find", 1)) {
return false;
}
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedId id(cx);
if (!ValueToIdentifier(cx, args[0], &id)) {
return false;
}
RootedDebuggerEnvironment result(cx);
if (!DebuggerEnvironment::find(cx, environment, id, &result)) {
return false;
}
args.rval().setObjectOrNull(result);
return true;
}
/* static */
bool DebuggerEnvironment::getVariableMethod(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "getVariable", args, environment);
if (!args.requireAtLeast(cx, "Debugger.Environment.getVariable", 1)) {
return false;
}
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedId id(cx);
if (!ValueToIdentifier(cx, args[0], &id)) {
return false;
}
return DebuggerEnvironment::getVariable(cx, environment, id, args.rval());
}
/* static */
bool DebuggerEnvironment::setVariableMethod(JSContext* cx, unsigned argc,
Value* vp) {
THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "setVariable", args, environment);
if (!args.requireAtLeast(cx, "Debugger.Environment.setVariable", 2)) {
return false;
}
if (!environment->requireDebuggee(cx)) {
return false;
}
RootedId id(cx);
if (!ValueToIdentifier(cx, args[0], &id)) {
return false;
}
if (!DebuggerEnvironment::setVariable(cx, environment, id, args[1])) {
return false;
}
args.rval().setUndefined();
return true;
}
bool DebuggerEnvironment::requireDebuggee(JSContext* cx) const {
if (!isDebuggee()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_NOT_DEBUGGEE, "Debugger.Environment",
"environment");
return false;
}
return true;
}
const JSPropertySpec DebuggerEnvironment::properties_[] = {
JS_PSG("type", DebuggerEnvironment::typeGetter, 0),
JS_PSG("scopeKind", DebuggerEnvironment::scopeKindGetter, 0),
JS_PSG("parent", DebuggerEnvironment::parentGetter, 0),
JS_PSG("object", DebuggerEnvironment::objectGetter, 0),
JS_PSG("callee", DebuggerEnvironment::calleeGetter, 0),
JS_PSG("inspectable", DebuggerEnvironment::inspectableGetter, 0),
JS_PSG("optimizedOut", DebuggerEnvironment::optimizedOutGetter, 0),
JS_PS_END};
const JSFunctionSpec DebuggerEnvironment::methods_[] = {
JS_FN("names", DebuggerEnvironment::namesMethod, 0, 0),
JS_FN("find", DebuggerEnvironment::findMethod, 1, 0),
JS_FN("getVariable", DebuggerEnvironment::getVariableMethod, 1, 0),
JS_FN("setVariable", DebuggerEnvironment::setVariableMethod, 2, 0),
JS_FS_END};
/* static */
NativeObject* DebuggerEnvironment::initClass(JSContext* cx,
HandleObject dbgCtor,
Handle<GlobalObject*> global) {
return InitClass(cx, dbgCtor, nullptr, &DebuggerEnvironment::class_,
construct, 0, properties_, methods_, nullptr, nullptr);
}
/* static */
DebuggerEnvironment* DebuggerEnvironment::create(JSContext* cx,
HandleObject proto,
HandleObject referent,
HandleNativeObject debugger) {
NewObjectKind newKind =
IsInsideNursery(referent) ? GenericObject : TenuredObject;
DebuggerEnvironment* obj =
NewObjectWithGivenProto<DebuggerEnvironment>(cx, proto, newKind);
if (!obj) {
return nullptr;
}
obj->setPrivateGCThing(referent);
obj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
return obj;
}
/* static */
DebuggerEnvironmentType DebuggerEnvironment::type() const {
// Don't bother switching compartments just to check env's type.
if (IsDeclarative(referent())) {
return DebuggerEnvironmentType::Declarative;
}
if (IsDebugEnvironmentWrapper<WithEnvironmentObject>(referent())) {
return DebuggerEnvironmentType::With;
}
return DebuggerEnvironmentType::Object;
}
mozilla::Maybe<ScopeKind> DebuggerEnvironment::scopeKind() const {
if (!referent()->is<DebugEnvironmentProxy>()) {
return Nothing();
}
EnvironmentObject& env =
referent()->as<DebugEnvironmentProxy>().environment();
Scope* scope = GetEnvironmentScope(env);
return scope ? Some(scope->kind()) : Nothing();
}
bool DebuggerEnvironment::getParent(
JSContext* cx, MutableHandleDebuggerEnvironment result) const {
// Don't bother switching compartments just to get env's parent.
Rooted<Env*> parent(cx, referent()->enclosingEnvironment());
if (!parent) {
result.set(nullptr);
return true;
}
return owner()->wrapEnvironment(cx, parent, result);
}
bool DebuggerEnvironment::getObject(JSContext* cx,
MutableHandleDebuggerObject result) const {
MOZ_ASSERT(type() != DebuggerEnvironmentType::Declarative);
// Don't bother switching compartments just to get env's object.
RootedObject object(cx);
if (IsDebugEnvironmentWrapper<WithEnvironmentObject>(referent())) {
object.set(&referent()
->as<DebugEnvironmentProxy>()
.environment()
.as<WithEnvironmentObject>()
.object());
} else if (IsDebugEnvironmentWrapper<NonSyntacticVariablesObject>(
referent())) {
object.set(&referent()
->as<DebugEnvironmentProxy>()
.environment()
.as<NonSyntacticVariablesObject>());
} else {
object.set(referent());
MOZ_ASSERT(!object->is<DebugEnvironmentProxy>());
}
return owner()->wrapDebuggeeObject(cx, object, result);
}
bool DebuggerEnvironment::getCallee(JSContext* cx,
MutableHandleDebuggerObject result) const {
if (!referent()->is<DebugEnvironmentProxy>()) {
result.set(nullptr);
return true;
}
JSObject& scope = referent()->as<DebugEnvironmentProxy>().environment();
if (!scope.is<CallObject>()) {
result.set(nullptr);
return true;
}
RootedObject callee(cx, &scope.as<CallObject>().callee());
if (IsInternalFunctionObject(*callee)) {
result.set(nullptr);
return true;
}
return owner()->wrapDebuggeeObject(cx, callee, result);
}
bool DebuggerEnvironment::isDebuggee() const {
MOZ_ASSERT(referent());
MOZ_ASSERT(!referent()->is<EnvironmentObject>());
return owner()->observesGlobal(&referent()->nonCCWGlobal());
}
bool DebuggerEnvironment::isOptimized() const {
return referent()->is<DebugEnvironmentProxy>() &&
referent()->as<DebugEnvironmentProxy>().isOptimizedOut();
}
/* static */
bool DebuggerEnvironment::getNames(JSContext* cx,
HandleDebuggerEnvironment environment,
MutableHandle<IdVector> result) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> referent(cx, environment->referent());
RootedIdVector ids(cx);
{
Maybe<AutoRealm> ar;
ar.emplace(cx, referent);
ErrorCopier ec(ar);
if (!GetPropertyKeys(cx, referent, JSITER_HIDDEN, &ids)) {
return false;
}
}
for (size_t i = 0; i < ids.length(); ++i) {
jsid id = ids[i];
if (JSID_IS_ATOM(id) && IsIdentifier(JSID_TO_ATOM(id))) {
cx->markId(id);
if (!result.append(id)) {
return false;
}
}
}
return true;
}
/* static */
bool DebuggerEnvironment::find(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id,
MutableHandleDebuggerEnvironment result) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> env(cx, environment->referent());
Debugger* dbg = environment->owner();
{
Maybe<AutoRealm> ar;
ar.emplace(cx, env);
cx->markId(id);
// This can trigger resolve hooks.
ErrorCopier ec(ar);
for (; env; env = env->enclosingEnvironment()) {
bool found;
if (!HasProperty(cx, env, id, &found)) {
return false;
}
if (found) {
break;
}
}
}
if (!env) {
result.set(nullptr);
return true;
}
return dbg->wrapEnvironment(cx, env, result);
}
/* static */
bool DebuggerEnvironment::getVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, MutableHandleValue result) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> referent(cx, environment->referent());
Debugger* dbg = environment->owner();
{
Maybe<AutoRealm> ar;
ar.emplace(cx, referent);
cx->markId(id);
// This can trigger getters.
ErrorCopier ec(ar);
bool found;
if (!HasProperty(cx, referent, id, &found)) {
return false;
}
if (!found) {
result.setUndefined();
return true;
}
// For DebugEnvironmentProxys, we get sentinel values for optimized out
// slots and arguments instead of throwing (the default behavior).
//
// See wrapDebuggeeValue for how the sentinel values are wrapped.
if (referent->is<DebugEnvironmentProxy>()) {
Rooted<DebugEnvironmentProxy*> env(
cx, &referent->as<DebugEnvironmentProxy>());
if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, env, id, result)) {
return false;
}
} else {
if (!GetProperty(cx, referent, referent, id, result)) {
return false;
}
}
}
// When we've faked up scope chain objects for optimized-out scopes,
// declarative environments may contain internal JSFunction objects, which
// we shouldn't expose to the user.
if (result.isObject()) {
RootedObject obj(cx, &result.toObject());
if (obj->is<JSFunction>() &&
IsInternalFunctionObject(obj->as<JSFunction>()))
result.setMagic(JS_OPTIMIZED_OUT);
}
return dbg->wrapDebuggeeValue(cx, result);
}
/* static */
bool DebuggerEnvironment::setVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, HandleValue value_) {
MOZ_ASSERT(environment->isDebuggee());
Rooted<Env*> referent(cx, environment->referent());
Debugger* dbg = environment->owner();
RootedValue value(cx, value_);
if (!dbg->unwrapDebuggeeValue(cx, &value)) {
return false;
}
{
Maybe<AutoRealm> ar;
ar.emplace(cx, referent);
if (!cx->compartment()->wrap(cx, &value)) {
return false;
}
cx->markId(id);
// This can trigger setters.
ErrorCopier ec(ar);
// Make sure the environment actually has the specified binding.
bool found;
if (!HasProperty(cx, referent, id, &found)) {
return false;
}
if (!found) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_VARIABLE_NOT_FOUND);
return false;
}
// Just set the property.
if (!SetProperty(cx, referent, id, value)) {
return false;
}
}
return true;
}

106
js/src/dbg/Environment.h Normal file
View File

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* 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 dbg_Environment_h
#define dbg_Environment_h
#include "dbg/Debugger.h"
#include "gc/Rooting.h"
#include "js/Class.h"
#include "js/PropertySpec.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "vm/GlobalObject.h"
#include "vm/NativeObject.h"
namespace js {
enum class DebuggerEnvironmentType { Declarative, With, Object };
class DebuggerEnvironment : public NativeObject {
public:
enum { OWNER_SLOT };
static const unsigned RESERVED_SLOTS = 1;
static const Class class_;
static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor,
Handle<GlobalObject*> global);
static DebuggerEnvironment* create(JSContext* cx, HandleObject proto,
HandleObject referent,
HandleNativeObject debugger);
static void trace(JSTracer* trc, JSObject* obj);
DebuggerEnvironmentType type() const;
mozilla::Maybe<ScopeKind> scopeKind() const;
MOZ_MUST_USE bool getParent(JSContext* cx,
MutableHandleDebuggerEnvironment result) const;
MOZ_MUST_USE bool getObject(JSContext* cx,
MutableHandleDebuggerObject result) const;
MOZ_MUST_USE bool getCallee(JSContext* cx,
MutableHandleDebuggerObject result) const;
bool isDebuggee() const;
bool isOptimized() const;
static MOZ_MUST_USE bool getNames(JSContext* cx,
HandleDebuggerEnvironment environment,
MutableHandle<IdVector> result);
static MOZ_MUST_USE bool find(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id,
MutableHandleDebuggerEnvironment result);
static MOZ_MUST_USE bool getVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, MutableHandleValue result);
static MOZ_MUST_USE bool setVariable(JSContext* cx,
HandleDebuggerEnvironment environment,
HandleId id, HandleValue value);
private:
static const ClassOps classOps_;
static const JSPropertySpec properties_[];
static const JSFunctionSpec methods_[];
Env* referent() const {
Env* env = static_cast<Env*>(getPrivate());
MOZ_ASSERT(env);
return env;
}
Debugger* owner() const;
bool requireDebuggee(JSContext* cx) const;
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool typeGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool scopeKindGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool parentGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool objectGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool inspectableGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool optimizedOutGetter(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool namesMethod(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool findMethod(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool getVariableMethod(JSContext* cx, unsigned argc,
Value* vp);
static MOZ_MUST_USE bool setVariableMethod(JSContext* cx, unsigned argc,
Value* vp);
};
} /* namespace js */
#endif /* dbg_Environment_h */

View File

@ -9,6 +9,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/ScopeExit.h"
#include "dbg/Environment.h"
#include "dbg/NoExecute.h"
#include "dbg/Object.h"
#include "frontend/BytecodeCompilation.h"

View File

@ -23,6 +23,7 @@ include('../js-cxxflags.mozbuild')
SOURCES = [
'Debugger.cpp',
'DebuggerMemory.cpp',
'Environment.cpp',
'Frame.cpp',
'NoExecute.cpp',
'Object.cpp',