2011-04-18 15:42:07 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
|
|
|
*
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is SpiderMonkey Debug object.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Mozilla Foundation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998-1999
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* Jim Blandy <jimb@mozilla.com>
|
|
|
|
* Jason Orendorff <jorendorff@mozilla.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#ifndef jsdbg_h__
|
|
|
|
#define jsdbg_h__
|
|
|
|
|
|
|
|
#include "jsapi.h"
|
2011-04-21 12:44:53 -07:00
|
|
|
#include "jscompartment.h"
|
2011-04-18 15:42:07 -07:00
|
|
|
#include "jsgc.h"
|
2011-04-27 16:22:28 -07:00
|
|
|
#include "jshashtable.h"
|
2011-04-18 15:42:07 -07:00
|
|
|
#include "jswrapper.h"
|
|
|
|
#include "jsvalue.h"
|
|
|
|
|
|
|
|
namespace js {
|
|
|
|
|
|
|
|
class Debug {
|
|
|
|
friend JSBool ::JS_DefineDebugObject(JSContext *cx, JSObject *obj);
|
|
|
|
|
|
|
|
private:
|
|
|
|
JSObject *object; // The Debug object. Strong reference.
|
|
|
|
JSCompartment *debuggeeCompartment; // Weak reference.
|
|
|
|
JSObject *hooksObject; // See Debug.prototype.hooks. Strong reference.
|
2011-04-19 20:19:38 -07:00
|
|
|
JSObject *uncaughtExceptionHook; // Strong reference.
|
2011-04-18 21:52:17 -07:00
|
|
|
bool enabled;
|
|
|
|
|
2011-04-18 15:42:07 -07:00
|
|
|
// True if hooksObject had a debuggerHandler property when the hooks
|
|
|
|
// property was set.
|
|
|
|
bool hasDebuggerHandler;
|
|
|
|
|
2011-04-29 08:12:46 -07:00
|
|
|
typedef HashMap<StackFrame *, JSObject *, DefaultHasher<StackFrame *>, SystemAllocPolicy>
|
2011-04-27 16:22:28 -07:00
|
|
|
FrameMap;
|
|
|
|
FrameMap frames;
|
|
|
|
|
2011-05-03 09:40:54 -07:00
|
|
|
typedef HashMap<JSObject *, JSObject *, DefaultHasher<JSObject *>, SystemAllocPolicy>
|
|
|
|
ObjectMap;
|
|
|
|
ObjectMap objects;
|
|
|
|
|
2011-04-19 20:19:38 -07:00
|
|
|
JSTrapStatus handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook);
|
|
|
|
JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
|
|
|
|
bool callHook = true);
|
2011-04-18 15:42:07 -07:00
|
|
|
|
|
|
|
static void trace(JSTracer *trc, JSObject *obj);
|
|
|
|
static void finalize(JSContext *cx, JSObject *obj);
|
|
|
|
|
|
|
|
static Class jsclass;
|
|
|
|
static JSBool getHooks(JSContext *cx, uintN argc, Value *vp);
|
|
|
|
static JSBool setHooks(JSContext *cx, uintN argc, Value *vp);
|
2011-04-18 21:52:17 -07:00
|
|
|
static JSBool getEnabled(JSContext *cx, uintN argc, Value *vp);
|
|
|
|
static JSBool setEnabled(JSContext *cx, uintN argc, Value *vp);
|
2011-04-19 20:19:38 -07:00
|
|
|
static JSBool getUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp);
|
|
|
|
static JSBool setUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp);
|
2011-04-18 15:42:07 -07:00
|
|
|
static JSBool construct(JSContext *cx, uintN argc, Value *vp);
|
|
|
|
static JSPropertySpec properties[];
|
|
|
|
|
2011-04-21 12:44:53 -07:00
|
|
|
inline bool hasAnyLiveHooks() const;
|
|
|
|
|
2011-04-29 08:12:46 -07:00
|
|
|
bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
|
2011-04-27 16:22:28 -07:00
|
|
|
static void slowPathLeaveStackFrame(JSContext *cx);
|
|
|
|
|
2011-04-21 12:44:53 -07:00
|
|
|
inline bool observesDebuggerStatement() const;
|
|
|
|
static JSTrapStatus dispatchDebuggerStatement(JSContext *cx, Value *vp);
|
|
|
|
JSTrapStatus handleDebuggerStatement(JSContext *cx, Value *vp);
|
2011-04-18 15:42:07 -07:00
|
|
|
|
|
|
|
public:
|
|
|
|
Debug(JSObject *dbg, JSObject *hooks, JSCompartment *compartment);
|
2011-04-27 16:22:28 -07:00
|
|
|
bool init();
|
|
|
|
inline JSObject *toJSObject() const;
|
|
|
|
static inline Debug *fromJSObject(JSObject *obj);
|
2011-04-18 15:42:07 -07:00
|
|
|
|
2011-04-27 16:22:28 -07:00
|
|
|
// Methods for interaction with the GC.
|
|
|
|
//
|
|
|
|
// A Debug object is live if:
|
2011-04-18 15:42:07 -07:00
|
|
|
// * the Debug JSObject is live (Debug::trace handles this case); OR
|
|
|
|
// * it is in the middle of dispatching an event (the event dispatching
|
|
|
|
// code roots it in this case); OR
|
|
|
|
// * it is enabled, and it is debugging at least one live compartment,
|
|
|
|
// and at least one of the following is true:
|
|
|
|
// - it has a debugger hook installed
|
|
|
|
// - it has a breakpoint set on a live script
|
|
|
|
// - it has a watchpoint set on a live object.
|
|
|
|
//
|
2011-04-27 16:22:28 -07:00
|
|
|
// The last case is handled by the mark() method. If it finds any Debug
|
|
|
|
// objects that are definitely live but not yet marked, it marks them and
|
|
|
|
// returns true. If not, it returns false.
|
2011-04-18 15:42:07 -07:00
|
|
|
//
|
|
|
|
static bool mark(GCMarker *trc, JSCompartment *compartment, JSGCInvocationKind gckind);
|
2011-04-27 16:22:28 -07:00
|
|
|
static void sweepAll(JSRuntime *rt);
|
|
|
|
static void sweepCompartment(JSCompartment *compartment);
|
2011-04-18 15:42:07 -07:00
|
|
|
|
2011-04-21 12:44:53 -07:00
|
|
|
inline bool observesCompartment(JSCompartment *c) const;
|
2011-04-27 15:37:14 -07:00
|
|
|
void detachFrom(JSCompartment *c);
|
2011-04-18 15:42:07 -07:00
|
|
|
|
2011-04-27 16:22:28 -07:00
|
|
|
static inline void leaveStackFrame(JSContext *cx);
|
2011-04-21 12:44:53 -07:00
|
|
|
static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp);
|
2011-05-03 12:04:17 -07:00
|
|
|
|
|
|
|
// Precondition: *vp is a value from a debuggee compartment and cx is in
|
|
|
|
// the debugger's compartment.
|
|
|
|
//
|
|
|
|
// Wrap *vp for the debugger compartment, wrap it in a Debug.Object if it's
|
|
|
|
// an object, store the result in *vp, and return true.
|
|
|
|
//
|
|
|
|
bool wrapDebuggeeValue(JSContext *cx, Value *vp);
|
|
|
|
|
|
|
|
// Inverse of wrapDebuggeeValue.
|
|
|
|
//
|
|
|
|
// Precondition: cx is in a debuggee compartment.
|
|
|
|
//
|
|
|
|
// If *vp is a Debug.Object, store the referent in *vp, appropriately
|
|
|
|
// rewrapped for the debuggee's compartment, regardless of what compartment
|
|
|
|
// the actual referent inhabits. Otherwise, if *vp is an object, throw a
|
|
|
|
// TypeError, because it is not a debuggee value. Otherwise *vp is a
|
|
|
|
// primitive, so copy it to the debuggee's compartment.
|
|
|
|
//
|
|
|
|
bool unwrapDebuggeeValue(JSContext *cx, Value *vp);
|
|
|
|
|
2011-04-18 15:42:07 -07:00
|
|
|
};
|
|
|
|
|
2011-04-21 12:44:53 -07:00
|
|
|
bool
|
|
|
|
Debug::hasAnyLiveHooks() const
|
|
|
|
{
|
|
|
|
return observesDebuggerStatement();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Debug::observesCompartment(JSCompartment *c) const
|
|
|
|
{
|
|
|
|
JS_ASSERT(c);
|
|
|
|
return debuggeeCompartment == c;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
Debug::toJSObject() const
|
|
|
|
{
|
|
|
|
JS_ASSERT(object);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug *
|
|
|
|
Debug::fromJSObject(JSObject *obj)
|
|
|
|
{
|
|
|
|
JS_ASSERT(obj->getClass() == &jsclass);
|
|
|
|
return (Debug *) obj->getPrivate();
|
|
|
|
}
|
|
|
|
|
2011-04-27 16:22:28 -07:00
|
|
|
void
|
|
|
|
Debug::leaveStackFrame(JSContext *cx)
|
|
|
|
{
|
|
|
|
if (!cx->compartment->getDebuggers().empty())
|
|
|
|
slowPathLeaveStackFrame(cx);
|
|
|
|
}
|
|
|
|
|
2011-04-21 12:44:53 -07:00
|
|
|
bool
|
|
|
|
Debug::observesDebuggerStatement() const
|
|
|
|
{
|
|
|
|
return enabled && hasDebuggerHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTrapStatus
|
|
|
|
Debug::onDebuggerStatement(JSContext *cx, js::Value *vp)
|
|
|
|
{
|
|
|
|
return cx->compartment->getDebuggers().empty()
|
|
|
|
? JSTRAP_CONTINUE
|
|
|
|
: dispatchDebuggerStatement(cx, vp);
|
|
|
|
}
|
|
|
|
|
2011-04-18 15:42:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* jsdbg_h__ */
|