summaryrefslogtreecommitdiff
path: root/js/jsd
diff options
context:
space:
mode:
Diffstat (limited to 'js/jsd')
-rw-r--r--js/jsd/Makefile.in31
-rw-r--r--js/jsd/README6
-rw-r--r--js/jsd/idl/jsdIDebuggerService.idl1219
-rw-r--r--js/jsd/idl/moz.build14
-rw-r--r--js/jsd/jsd.h1109
-rw-r--r--js/jsd/jsd1640.def77
-rw-r--r--js/jsd/jsd1640.rc67
-rw-r--r--js/jsd/jsd3240.rc86
-rw-r--r--js/jsd/jsd_atom.cpp147
-rw-r--r--js/jsd/jsd_high.cpp419
-rw-r--r--js/jsd/jsd_hook.cpp332
-rw-r--r--js/jsd/jsd_java.cpp779
-rw-r--r--js/jsd/jsd_lock.cpp227
-rw-r--r--js/jsd/jsd_lock.h43
-rw-r--r--js/jsd/jsd_obj.cpp234
-rw-r--r--js/jsd/jsd_scpt.cpp966
-rw-r--r--js/jsd/jsd_stak.cpp572
-rw-r--r--js/jsd/jsd_step.cpp286
-rw-r--r--js/jsd/jsd_text.cpp527
-rw-r--r--js/jsd/jsd_val.cpp739
-rw-r--r--js/jsd/jsd_xpc.cpp3430
-rw-r--r--js/jsd/jsd_xpc.h372
-rw-r--r--js/jsd/jsdebug.cpp1371
-rw-r--r--js/jsd/jsdebug.h1564
-rw-r--r--js/jsd/jsdstubs.cpp18
-rw-r--r--js/jsd/jshash.cpp444
-rw-r--r--js/jsd/jshash.h120
-rwxr-xr-xjs/jsd/mkshell.bat8
-rw-r--r--js/jsd/moz.build35
-rw-r--r--js/jsd/resource.h21
-rw-r--r--js/jsd/test/Makefile.in19
-rw-r--r--js/jsd/test/bug507448.js25
-rw-r--r--js/jsd/test/jsd-test.js119
-rw-r--r--js/jsd/test/moz.build8
-rw-r--r--js/jsd/test/test-bug617870-callhooks.js52
-rw-r--r--js/jsd/test/test-bug638178-execlines.js95
-rw-r--r--js/jsd/test/test_bug507448.html112
-rw-r--r--js/jsd/test/test_bug617870-callhooks.html83
-rw-r--r--js/jsd/test/test_bug638178-execlines.html46
-rw-r--r--js/jsd/test/test_evalCached.js23
-rw-r--r--js/jsd/test/test_jsval_retval.js42
-rw-r--r--js/jsd/test/xpcshell.ini9
42 files changed, 15896 insertions, 0 deletions
diff --git a/js/jsd/Makefile.in b/js/jsd/Makefile.in
new file mode 100644
index 0000000..10e7461
--- /dev/null
+++ b/js/jsd/Makefile.in
@@ -0,0 +1,31 @@
+#!gmake
+#
+# 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/.
+
+
+
+DEPTH = @DEPTH@
+topsrcdir = @top_srcdir@
+VPATH = @srcdir@
+srcdir = @srcdir@
+relativesrcdir = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+IS_COMPONENT = 1
+LIBXUL_LIBRARY = 1
+
+MODULE_NAME = JavaScript_Debugger
+EXPORT_LIBRARY = 1
+
+# REQUIRES = java js
+
+ifdef JS_THREADSAFE
+DEFINES += -DJS_THREADSAFE
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -DEXPORT_JSD_API
diff --git a/js/jsd/README b/js/jsd/README
new file mode 100644
index 0000000..25295a8
--- /dev/null
+++ b/js/jsd/README
@@ -0,0 +1,6 @@
+js/jsd contains code for debugging support for the C-based JavaScript engine
+in js/src. jsd_xpc.cpp provides an XPCOM binding for the library.
+
+js/jsd/jsdb is a console debugger using only native code (see README in that
+directory.) This debugger is no longer being actively developed, though it
+should work.
diff --git a/js/jsd/idl/jsdIDebuggerService.idl b/js/jsd/idl/jsdIDebuggerService.idl
new file mode 100644
index 0000000..618f342
--- /dev/null
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -0,0 +1,1219 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsISupports.idl"
+
+%{ C++
+#include "jsdebug.h"
+#include "nsAString.h"
+%}
+
+[ptr] native JSDContext(JSDContext);
+[ptr] native JSDObject(JSDObject);
+[ptr] native JSDProperty(JSDProperty);
+[ptr] native JSDScript(JSDScript);
+[ptr] native JSDStackFrameInfo(JSDStackFrameInfo);
+[ptr] native JSDThreadState(JSDThreadState);
+[ptr] native JSDValue(JSDValue);
+[ptr] native JSRuntime(JSRuntime);
+[ptr] native JSContext(JSContext);
+[ptr] native JSCompartment(JSCompartment);
+
+/* interfaces we declare in this file */
+interface jsdIDebuggerService;
+interface jsdIFilter;
+interface jsdINestCallback;
+interface jsdIFilterEnumerator;
+interface jsdIContextEnumerator;
+interface jsdIScriptEnumerator;
+interface jsdIScriptHook;
+interface jsdIErrorHook;
+interface jsdIExecutionHook;
+interface jsdICallHook;
+interface jsdIEphemeral;
+interface jsdIContext;
+interface jsdIStackFrame;
+interface jsdIScript;
+interface jsdIValue;
+interface jsdIObject;
+interface jsdIProperty;
+interface jsdIActivationCallback;
+
+/**
+ * Debugger service. It is not a good idea to have more than one active client
+ * of the debugger service.
+ */
+[scriptable, uuid(029b8f0a-aa84-47eb-a60f-1a4752b7ad06)]
+interface jsdIDebuggerService : nsISupports
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+
+ /**
+ * Called when an error or warning occurs.
+ */
+ attribute jsdIErrorHook errorHook;
+ /**
+ * Called when a jsdIScript is created or destroyed.
+ */
+ attribute jsdIScriptHook scriptHook;
+ /**
+ * Called when the engine encounters a breakpoint.
+ */
+ attribute jsdIExecutionHook breakpointHook;
+ /**
+ * Called when the engine encounters the debugger keyword.
+ */
+ attribute jsdIExecutionHook debuggerHook;
+ /**
+ * Called when the errorHook returns false.
+ */
+ attribute jsdIExecutionHook debugHook;
+ /**
+ * Called before the next PC is executed.
+ */
+ attribute jsdIExecutionHook interruptHook;
+ /**
+ * Called when an exception is thrown (even if it will be caught.)
+ */
+ attribute jsdIExecutionHook throwHook;
+ /**
+ * Called before and after a toplevel script is evaluated.
+ */
+ attribute jsdICallHook topLevelHook;
+ /**
+ * Called before and after a function is called.
+ */
+ attribute jsdICallHook functionHook;
+
+ /**
+ * Link native frames in call stacks.
+ */
+ const unsigned long ENABLE_NATIVE_FRAMES = 0x01;
+ /**
+ * Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in
+ * profile data, otherwise it is not profiled. Setting the
+ * PROFILE_WHEN_SET flag reverses this convention.
+ */
+ const unsigned long PROFILE_WHEN_SET = 0x02;
+ /**
+ * Normally, when the script in the top frame of a thread state has a 1 in
+ * JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the
+ * DEBUG_WHEN_SET flag reverses this convention.
+ */
+ const unsigned long DEBUG_WHEN_SET = 0x04;
+ /**
+ * When this flag is set the internal call hook will collect profile data.
+ */
+ const unsigned long COLLECT_PROFILE_DATA = 0x08;
+ /**
+ * When this flag is set, stack frames that are disabled for debugging
+ * will not appear in the call stack chain.
+ */
+ const unsigned long HIDE_DISABLED_FRAMES = 0x10;
+ /**
+ * When this flag is set, the debugger will only check the
+ * JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This
+ * makes it possible to stop in an enabled frame which was called from
+ * a stack that contains a disabled frame.
+ *
+ * When this flag is *not* set, any stack that contains a disabled frame
+ * will not be debugged (the execution hook will not be invoked.)
+ *
+ * This only applies when the reason for calling the hook would have
+ * been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT,
+ * TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless
+ * of this setting, as long as the top frame is not disabled.
+ *
+ * If HIDE_DISABLED_FRAMES is set, this is effectively set as well.
+ */
+ const unsigned long MASK_TOP_FRAME_ONLY = 0x20;
+ /**
+ * This flag has been retired, do not re-use. It previously provided a hook
+ * for object allocation.
+ */
+ const unsigned long DISABLE_OBJECT_TRACE_RETIRED = 0x40;
+
+ /**
+ * Debugger service flags.
+ */
+ attribute unsigned long flags;
+
+ /**
+ * Major version number of implementation.
+ */
+ readonly attribute unsigned long implementationMajor;
+ /**
+ * Minor version number of implementation.
+ */
+ readonly attribute unsigned long implementationMinor;
+ /**
+ * Free form AUTF8String identifier for implementation.
+ */
+ readonly attribute AUTF8String implementationString;
+
+ /**
+ * |true| if the debugger service has been turned on. This does not
+ * necessarily mean another app is actively using the service, as the
+ * autostart pref may have turned the service on.
+ */
+ readonly attribute boolean isOn;
+
+
+ /**
+ * Synchronous activation of the debugger is no longer supported,
+ * and will throw an exception.
+ */
+ void on();
+
+ /**
+ * Turn on the debugger. This function should only be called from
+ * JavaScript code. The debugger will be enabled on the runtime the call is
+ * made on, as determined by nsIXPCNativeCallContext.
+ *
+ * The debugger will be activated asynchronously, because there can be no
+ * JS on the stack when code is to be re-compiled for debug mode.
+ */
+ void asyncOn(in jsdIActivationCallback callback);
+
+ /**
+ * Called by nsIXPConnect after it's had a chance to recompile for
+ * debug mode.
+ */
+ [noscript] void activateDebugger(in JSRuntime rt);
+
+ /**
+ * Called by nsIXPConnect to deactivate debugger on setup failure.
+ */
+ [noscript] void deactivateDebugger();
+
+ /**
+ * Recompile all active scripts in the runtime for debugMode.
+ */
+ [noscript] void recompileForDebugMode(in JSContext cx, in JSCompartment comp, in boolean mode);
+
+ /**
+ * Turn the debugger off. This will invalidate all of your jsdIEphemeral
+ * derived objects, and clear all of your breakpoints.
+ */
+ void off ();
+
+ /**
+ * Peek at the current pause depth of the debugger.
+ *
+ * @return depth Number of pause() calls still waiting to be unPause()d.
+ */
+ readonly attribute unsigned long pauseDepth;
+ /**
+ * Temporarily disable the debugger. Hooks will not be called while the
+ * debugger is paused. Multiple calls to pause will increase the "pause
+ * depth", and equal number of unPause calles must be made to resume
+ * normal debugging.
+ *
+ * @return depth Number of times pause has been called since the debugger
+ * has been unpaused.
+ */
+ unsigned long pause();
+ /**
+ * Undo a pause. Once this is called, the debugger won't start
+ * getting execution callbacks until the stack is fully unwound so
+ * that no JS scripts are live. There is no way to query whether
+ * there are such scripts left to unwind at a given point in time.
+ *
+ * @return depth The number of remaining pending pause calls.
+ */
+ unsigned long unPause();
+
+ /**
+ * Force the engine to perform garbage collection.
+ */
+ void GC();
+
+ /**
+ * Clear profile data for all scripts.
+ */
+ void clearProfileData();
+
+ /**
+ * Adds an execution hook filter. These filters are consulted each time one
+ * of the jsdIExecutionHooks is about to be called. Filters are matched in
+ * a first in, first compared fashion. The first filter to match determines
+ * whether or not the hook is called. Use swapFilter to reorder existing
+ * filters, and removeFilter to remove them.
+ *
+ * If |filter| is already present this method throws NS_ERROR_INVALID_ARG.
+ *
+ * @param filter Object representing the filter to add.
+ * @param after Insert |filter| after this one. Pass null to insert at
+ * the beginning.
+ */
+ void insertFilter(in jsdIFilter filter, in jsdIFilter after);
+ /**
+ * Same as insertFilter, except always add to the end of the list.
+ */
+ void appendFilter(in jsdIFilter filter);
+ /**
+ * Remove a filter.
+ *
+ * If |filter| is not present this method throws NS_ERROR_INVALID_ARG.
+ *
+ * @param filter Object representing the filter to remove. Must be the exact
+ * object passed to addFilter, not just a new object with the same
+ * properties.
+ */
+ void removeFilter(in jsdIFilter filter);
+ /**
+ * Swap position of two filters.
+ *
+ * If |filter_a| is not present, this method throws NS_ERROR_INVALID_ARG.
+ * If |filter_b| is not present, filter_a is replaced by filter_b.
+ * If |filter_a| == |filter_b|, then filter is refreshed.
+ */
+ void swapFilters(in jsdIFilter filter_a, in jsdIFilter filter_b);
+ /**
+ * Enumerate registered filters. This routine refreshes each filter before
+ * passing them on to the enumeration function. Calling this with a null
+ * |enumerator| is equivalent to jsdIService::refreshFilters.
+ *
+ * @param enumerator jsdIFilterEnumerator instance to be called back for the
+ * enumeration.
+ */
+ void enumerateFilters(in jsdIFilterEnumerator enumerator);
+ /**
+ * Force the debugger to resync its internal filter cache with the
+ * actual values in the jsdIFilter objects. To refresh a single filter
+ * use jsdIService::swapFilters. This method is equivalent to
+ * jsdIService::enumerateFilters with a null enumerator.
+ */
+ void refreshFilters();
+ /**
+ * Clear the list of filters.
+ */
+ void clearFilters();
+
+ /**
+ * Enumerate all known contexts.
+ */
+ void enumerateContexts(in jsdIContextEnumerator enumerator);
+
+ /**
+ * Enumerate all scripts the debugger knows about. Any scripts created
+ * before you turned the debugger on, or after turning the debugger off
+ * will not be available unless the autostart perf is set.
+ *
+ * @param enumerator jsdIScriptEnumerator instance to be called back for
+ * the enumeration.
+ */
+ void enumerateScripts(in jsdIScriptEnumerator enumerator);
+ /**
+ * Clear all breakpoints in all scripts.
+ */
+ void clearAllBreakpoints();
+
+ /**
+ * When called from JavaScript, this method returns the jsdIValue wrapper
+ * for the given value. If a wrapper does not exist one will be created.
+ * When called from another language this method returns an xpconnect
+ * defined error code.
+ */
+ jsdIValue wrapValue(in jsval value);
+
+ /* XXX these two routines are candidates for refactoring. The only problem
+ * is that it is not clear where and how they should land.
+ */
+
+ /**
+ * Push a new network queue, and enter a new UI event loop.
+ * @param callback jsdINestCallback instance to be called back after the
+ * network queue has been pushed, but before the
+ * UI loop starts.
+ * @return depth returns the current number of times the event loop has been
+ * nested. your code can use it for sanity checks.
+ */
+ unsigned long enterNestedEventLoop(in jsdINestCallback callback);
+ /**
+ * Exit the current nested event loop after the current iteration completes,
+ * and pop the network event queue.
+ *
+ * @return depth returns the current number of times the event loop has been
+ * nested. your code can use it for sanity checks.
+ */
+ unsigned long exitNestedEventLoop();
+
+ /**
+ * Output dump of JS heap.
+ *
+ * @param fileName Filename to dump the heap into.
+ */
+ void dumpHeap(in AUTF8String fileName);
+};
+
+/* callback interfaces */
+
+/**
+ * Object representing a pattern of global object and/or url the debugger should
+ * ignore. The debugger service itself will not modify properties of these
+ * objects.
+ */
+[scriptable, uuid(9ae587cd-b78c-47f0-a612-4b3a211a6a71)]
+interface jsdIFilter : nsISupports
+{
+ /**
+ * These two bytes of the flags attribute are reserved for interpretation
+ * by the jsdService implementation. You can do what you like with the
+ * remaining flags.
+ */
+ const unsigned long FLAG_RESERVED_MASK = 0xFF;
+ /**
+ * Filters without this flag set are ignored.
+ */
+ const unsigned long FLAG_ENABLED = 0x01;
+ /**
+ * Filters with this flag set are "pass" filters, they allow matching hooks
+ * to continue. Filters without this flag block matching hooks.
+ */
+ const unsigned long FLAG_PASS = 0x02;
+
+ /**
+ * FLAG_* values from above, OR'd together.
+ */
+ attribute unsigned long flags;
+
+ /**
+ * String representing the url pattern to be filtered. Supports limited
+ * glob matching, at the beginning and end of the pattern only. For example,
+ * "chrome://venkman*" filters all urls that start with chrome/venkman,
+ * "*.cgi" filters all cgi's, and "http://myserver/utils.js" filters only
+ * the utils.js file on "myserver". A null urlPattern matches all urls.
+ *
+ * The jsdIService caches this value internally, to if it changes you must
+ * swap the filter with itself using jsdIService::swapFilters.
+ */
+ attribute AUTF8String urlPattern;
+
+ /**
+ * Line number for the start of this filter. Line numbers are one based.
+ * Assigning a 0 to this attribute will tell the debugger to ignore the
+ * entire file.
+ */
+ attribute unsigned long startLine;
+
+ /**
+ * Line number for the end of this filter. Line numbers are one based.
+ * Assigning a 0 to this attribute will tell the debugger to ignore from
+ * |startLine| to the end of the file.
+ */
+ attribute unsigned long endLine;
+};
+
+/**
+ * Notify client code that debugMode has been activated.
+ */
+[scriptable, function, uuid(6da7f5fb-3a84-4abe-9e23-8b2045960732)]
+interface jsdIActivationCallback : nsISupports
+{
+ void onDebuggerActivated();
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enterNestedEventLoop.
+ */
+[scriptable, function, uuid(88bea60f-9b5d-4b39-b08b-1c3a278782c6)]
+interface jsdINestCallback : nsISupports
+{
+ /**
+ * This method will be called after pre-nesting work has completed, such
+ * as pushing the js context and network event queue, but before the new
+ * event loop starts.
+ */
+ void onNest();
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enumerateFilters.
+ */
+[scriptable, function, uuid(e391ba85-9379-4762-b387-558e38db730f)]
+interface jsdIFilterEnumerator : nsISupports
+{
+ /**
+ * The enumerateFilter method will be called once for every filter the
+ * debugger knows about.
+ */
+ void enumerateFilter(in jsdIFilter filter);
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enumerateScripts.
+ */
+[scriptable, function, uuid(4eef60c2-9bbc-48fa-b196-646a832c6c81)]
+interface jsdIScriptEnumerator : nsISupports
+{
+ /**
+ * The enumerateScript method will be called once for every script the
+ * debugger knows about.
+ */
+ void enumerateScript(in jsdIScript script);
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enumerateContexts.
+ */
+[scriptable, function, uuid(57d18286-550c-4ca9-ac33-56f12ebba91e)]
+interface jsdIContextEnumerator : nsISupports
+{
+ /**
+ * The enumerateContext method will be called once for every context
+ * currently in use.
+ */
+ void enumerateContext(in jsdIContext executionContext);
+};
+
+/**
+ * Set jsdIDebuggerService::scriptHook to an instance of one of these.
+ */
+[scriptable, uuid(d030d1a2-a58a-4f19-b9e3-96da4e2cdd09)]
+interface jsdIScriptHook : nsISupports
+{
+ /**
+ * Called when scripts are created.
+ */
+ void onScriptCreated(in jsdIScript script);
+ /**
+ * Called when the JavaScript engine destroys a script. The jsdIScript
+ * object passed in will already be invalidated.
+ */
+ void onScriptDestroyed(in jsdIScript script);
+};
+
+/**
+ * Hook instances of this interface up to the
+ * jsdIDebuggerService::functionHook and toplevelHook properties.
+ */
+[scriptable, function, uuid(3eff1314-7ae3-4cf8-833b-c33c24a55633)]
+interface jsdICallHook : nsISupports
+{
+ /**
+ * TYPE_* values must be kept in sync with the JSD_HOOK_* #defines
+ * in jsdebug.h.
+ */
+
+ /**
+ * Toplevel script is starting.
+ */
+ const unsigned long TYPE_TOPLEVEL_START = 0;
+ /**
+ * Toplevel script has completed.
+ */
+ const unsigned long TYPE_TOPLEVEL_END = 1;
+ /**
+ * Function is being called.
+ */
+ const unsigned long TYPE_FUNCTION_CALL = 2;
+ /**
+ * Function is returning.
+ */
+ const unsigned long TYPE_FUNCTION_RETURN = 3;
+
+ /**
+ * Called before the JavaScript engine executes a top level script or calls
+ * a function.
+ */
+ void onCall(in jsdIStackFrame frame, in unsigned long type);
+};
+
+[scriptable, function, uuid(e6b45eee-d974-4d85-9d9e-f5a67218deb4)]
+interface jsdIErrorHook : nsISupports
+{
+ /**
+ * REPORT_* values must be kept in sync with JSREPORT_* #defines in
+ * jsapi.h
+ */
+
+ /**
+ * Report is an error.
+ */
+ const unsigned long REPORT_ERROR = 0x00;
+ /**
+ * Report is only a warning.
+ */
+ const unsigned long REPORT_WARNING = 0x01;
+ /**
+ * Report represents an uncaught exception.
+ */
+ const unsigned long REPORT_EXCEPTION = 0x02;
+ /**
+ * Report is due to strict mode.
+ */
+ const unsigned long REPORT_STRICT = 0x04;
+
+ /**
+ * Called when the JavaScript engine encounters an error. Return |true|
+ * to pass the error along, |false| to invoke the debugHook.
+ */
+ boolean onError(in AUTF8String message, in AUTF8String fileName,
+ in unsigned long line, in unsigned long pos,
+ in unsigned long flags, in unsigned long errnum,
+ in jsdIValue exc);
+};
+
+/**
+ * Hook instances of this interface up to the
+ * jsdIDebuggerService::breakpointHook, debuggerHook, errorHook, interruptHook,
+ * and throwHook properties.
+ */
+[scriptable, function, uuid(3a722496-9d78-4f0a-a797-293d9e8cb8d2)]
+interface jsdIExecutionHook : nsISupports
+{
+ /**
+ * TYPE_* values must be kept in sync with JSD_HOOK_* #defines in jsdebug.h.
+ */
+
+ /**
+ * Execution stopped because we're in single step mode.
+ */
+ const unsigned long TYPE_INTERRUPTED = 0;
+ /**
+ * Execution stopped by a trap instruction (i.e. breakoint.)
+ */
+ const unsigned long TYPE_BREAKPOINT = 1;
+ /**
+ * Error handler returned an "invoke debugger" value.
+ */
+ const unsigned long TYPE_DEBUG_REQUESTED = 2;
+ /**
+ * Debugger keyword encountered.
+ */
+ const unsigned long TYPE_DEBUGGER_KEYWORD = 3;
+ /**
+ * Exception was thrown.
+ */
+ const unsigned long TYPE_THROW = 4;
+
+ /**
+ * RETURN_* values must be kept in sync with JSD_HOOK_RETURN_* #defines in
+ * jsdebug.h.
+ */
+
+ /**
+ * Indicates unrecoverable error processing the hook. This will cause
+ * the script being executed to be aborted without raising a JavaScript
+ * exception.
+ */
+ const unsigned long RETURN_HOOK_ERROR = 0;
+ /**
+ * Continue processing normally. This is the "do nothing special" return
+ * value for all hook types *except* TYPE_THROW. Returning RETURN_CONTINUE
+ * from TYPE_THROW cause the exception to be ignored. Return
+ * RETURN_CONTINUE_THROW to continue exception processing from TYPE_THROW
+ * hooks.
+ */
+ const unsigned long RETURN_CONTINUE = 1;
+ /**
+ * Same effect as RETURN_HOOK_ERROR.
+ */
+ const unsigned long RETURN_ABORT = 2;
+ /**
+ * Return the value of the |val| parameter.
+ */
+ const unsigned long RETURN_RET_WITH_VAL = 3;
+ /**
+ * Throw the value of the |val| parameter.
+ */
+ const unsigned long RETURN_THROW_WITH_VAL = 4;
+ /**
+ * Continue the current throw.
+ */
+ const unsigned long RETURN_CONTINUE_THROW = 5;
+
+ /**
+ * @param frame A jsdIStackFrame object representing the bottom stack frame.
+ * @param type One of the jsdIExecutionHook::TYPE_ constants.
+ * @param val in - Current exception (if any) when this method is called.
+ * out - If you return RETURN_THROW_WITH_VAL, value to be
+ * thrown.
+ * If you return RETURN_RET_WITH_VAL, value to return.
+ * All other return values, not significant.
+ * @retval One of the jsdIExecutionHook::RETURN_* constants.
+ */
+ unsigned long onExecute(in jsdIStackFrame frame,
+ in unsigned long type, inout jsdIValue val);
+};
+
+/**
+ * Objects which inherit this interface may go away, with (jsdIScript) or
+ * without (all others) notification. These objects are generally wrappers
+ * around JSD structures that go away when you call jsdService::Off().
+ */
+[scriptable, uuid(46f1e23e-1dd2-11b2-9ceb-8285f2e95e69)]
+interface jsdIEphemeral : nsISupports
+{
+ /**
+ * |true| if this object is still valid. If not, many or all of the methods
+ * and/or properties of the inheritor may no longer be callable.
+ */
+ readonly attribute boolean isValid;
+ /**
+ * Mark this instance as invalid.
+ */
+ [noscript] void invalidate();
+};
+
+/* handle objects */
+
+/**
+ * Context object. Only context's which are also nsISupports objects can be
+ * reflected by this interface.
+ */
+[scriptable, uuid(3e5c934d-6863-4d81-96f5-76a3b962fc2b)]
+interface jsdIContext : jsdIEphemeral
+{
+ /* Internal use only. */
+ [noscript] readonly attribute JSContext JSContext;
+
+ /**
+ * OPT_* values must be kept in sync with JSOPTION_* #defines in jsapi.h.
+ */
+
+ /**
+ * Strict mode is on.
+ */
+ const long OPT_STRICT = 0x01;
+ /**
+ * Warnings reported as errors.
+ */
+ const long OPT_WERR = 0x02;
+ /**
+ * Makes eval() use the last object on its 'obj' param's scope chain as the
+ * ECMA 'variables object'.
+ */
+ const long OPT_VAROBJFIX = 0x04;
+ /**
+ * Private data for this object is an nsISupports object. Attempting to
+ * alter this bit will result in an NS_ERROR_ILLEGAL_VALUE.
+ */
+ const long OPT_ISUPPORTS = 0x08;
+ /**
+ * OPT_* values above, OR'd together.
+ */
+ attribute unsigned long options;
+
+ /**
+ * Unique tag among all valid jsdIContext objects, useful as a hash key.
+ */
+ readonly attribute unsigned long tag;
+
+ /**
+ * Private data for this context, if it is an nsISupports, |null| otherwise.
+ */
+ readonly attribute nsISupports privateData;
+
+ /**
+ * Retrieve the underlying context wrapped by this jsdIContext.
+ */
+ readonly attribute nsISupports wrappedContext;
+
+ /**
+ * Top of the scope chain for this context.
+ */
+ readonly attribute jsdIValue globalObject;
+
+ /**
+ * |true| if this context should be allowed to run scripts, |false|
+ * otherwise. This attribute is only valid for contexts which implement
+ * nsIScriptContext. Setting or getting this attribute on any other
+ * context will throw a NS_ERROR_NO_INTERFACE exception.
+ */
+ attribute boolean scriptsEnabled;
+};
+
+/**
+ * Stack frame objects. These are only valid inside the jsdIExecutionHook which
+ * gave it to you. After you return from that handler the bottom frame, and any
+ * frame you found attached through it, are invalidated via the jsdIEphemeral
+ * interface. Once a jsdIStackFrame has been invalidated all method and
+ * property accesses will throw a NS_ERROR_NOT_AVAILABLE exception.
+ */
+[scriptable, uuid(7c95422c-7579-4a6f-8ef7-e5b391552ee5)]
+interface jsdIStackFrame : jsdIEphemeral
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDThreadState JSDThreadState;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDStackFrameInfo JSDStackFrameInfo;
+
+ /**
+ * True if stack frame represents a frame created as a result of a debugger
+ * evaluation.
+ */
+ readonly attribute boolean isDebugger;
+ /**
+ * True if stack frame is constructing a new object.
+ */
+ readonly attribute boolean isConstructing;
+
+ /**
+ * Link to the caller's stack frame.
+ */
+ readonly attribute jsdIStackFrame callingFrame;
+ /**
+ * Executon context.
+ */
+ readonly attribute jsdIContext executionContext;
+ /**
+ * Function name executing in this stack frame.
+ */
+ readonly attribute AUTF8String functionName;
+ /**
+ * Script running in this stack frame, null for native frames.
+ */
+ readonly attribute jsdIScript script;
+ /**
+ * Current program counter in this stack frame.
+ */
+ readonly attribute unsigned long pc;
+ /**
+ * Current line number (using the script's pc to line map.)
+ */
+ readonly attribute unsigned long line;
+ /**
+ * Function object running in this stack frame.
+ */
+ readonly attribute jsdIValue callee;
+ /**
+ * Top object in the scope chain.
+ */
+ readonly attribute jsdIValue scope;
+ /**
+ * |this| object for this stack frame.
+ */
+ readonly attribute jsdIValue thisValue;
+ /**
+ * Evaluate arbitrary JavaScript in this stack frame.
+ * @param bytes Script to be evaluated.
+ * @param fileName Filename to compile this script under. This is the
+ * filename you'll see in error messages, etc.
+ * @param line Starting line number for this script. One based.
+ * @retval Result of evaluating the script.
+ */
+ boolean eval(in AString bytes, in AUTF8String fileName,
+ in unsigned long line, out jsdIValue result);
+
+};
+
+/**
+ * Script object. In JavaScript engine terms, there's a single script for each
+ * function, and one for the top level script.
+ */
+[scriptable, uuid(8ce9b2a2-cc33-48a8-9f47-8696186ed9a5)]
+interface jsdIScript : jsdIEphemeral
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDScript JSDScript;
+
+ /**
+ * Last version set on this context.
+ * Scripts typically select this with the "language" attribute.
+ * See the VERSION_* consts on jsdIDebuggerService.
+ */
+ readonly attribute long version;
+
+ /**
+ * Tag value guaranteed unique among jsdIScript objects. Useful as a
+ * hash key in script.
+ */
+ readonly attribute unsigned long tag;
+
+ /**
+ * FLAG_* values need to be kept in sync with JSD_SCRIPT_* #defines in
+ * jsdebug.h.
+ */
+
+ /**
+ * Determines whether or not to collect profile information for this
+ * script. The context flag FLAG_PROFILE_WHEN_SET decides the logic.
+ */
+ const unsigned long FLAG_PROFILE = 0x01;
+ /**
+ * Determines whether or not to ignore breakpoints, etc. in this script.
+ * The context flag JSD_DEBUG_WHEN_SET decides the logic.
+ */
+ const unsigned long FLAG_DEBUG = 0x02;
+ /**
+ * Determines whether to invoke the onScriptDestroy callback for this
+ * script. The default is for this to be true if the onScriptCreated
+ * callback was invoked for this script.
+ */
+ const unsigned long FLAG_CALL_DESTROY_HOOK = 0x04;
+
+ /**
+ * FLAG_* attributes from above, OR'd together.
+ */
+ attribute unsigned long flags;
+
+ /**
+ * Filename given for this script when it was compiled.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute AUTF8String fileName;
+ /**
+ * Function name for this script. "anonymous" for unnamed functions (or
+ * a function actually named anonymous), empty for top level scripts.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute AUTF8String functionName;
+ /**
+ * The names of the arguments for this function; empty if this is
+ * not a function.
+ */
+ void getParameterNames([optional] out unsigned long count,
+ [array, size_is(count), retval] out wstring paramNames);
+ /**
+ * Fetch the function object as a jsdIValue.
+ */
+ readonly attribute jsdIValue functionObject;
+ /**
+ * Source code for this script, without function declaration.
+ */
+ readonly attribute AString functionSource;
+ /**
+ * Line number in source file containing the first line of this script.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute unsigned long baseLineNumber;
+ /**
+ * Total number of lines in this script.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute unsigned long lineExtent;
+
+ /**
+ * Number of times this script has been called.
+ */
+ readonly attribute unsigned long callCount;
+ /**
+ * Number of times this script called itself, directly or indirectly.
+ */
+ readonly attribute unsigned long maxRecurseDepth;
+ /**
+ * Shortest execution time recorded, in milliseconds.
+ */
+ readonly attribute double minExecutionTime;
+ /**
+ * Longest execution time recorded, in milliseconds.
+ */
+ readonly attribute double maxExecutionTime;
+ /**
+ * Total time spent in this function, in milliseconds.
+ */
+ readonly attribute double totalExecutionTime;
+ /**
+ * Shortest execution time recorded, in milliseconds, excluding time spent
+ * in other called code.
+ */
+ readonly attribute double minOwnExecutionTime;
+ /**
+ * Longest execution time recorded, in milliseconds, excluding time spent
+ * in other called code.
+ */
+ readonly attribute double maxOwnExecutionTime;
+ /**
+ * Total time spent in this function, in milliseconds, excluding time spent
+ * in other called code.
+ */
+ readonly attribute double totalOwnExecutionTime;
+
+ /**
+ * Clear profile data for this script.
+ */
+ void clearProfileData();
+
+ const unsigned long PCMAP_SOURCETEXT = 1; /* map to actual source text */
+ const unsigned long PCMAP_PRETTYPRINT = 2; /* map to pretty printed source */
+
+ /**
+ * Get the closest line number to a given PC.
+ * The |pcmap| argument specifies which pc to source line map to use.
+ */
+ unsigned long pcToLine(in unsigned long pc, in unsigned long pcmap);
+ /**
+ * Get the first PC associated with a line.
+ * The |pcmap| argument specifies which pc to source line map to use.
+ */
+ unsigned long lineToPc(in unsigned long line, in unsigned long pcmap);
+ /**
+ * Determine is a particular line is executable, like checking that
+ * lineToPc == pcToLine, except in one call.
+ * The |pcmap| argument specifies which pc to source line map to use.
+ */
+ boolean isLineExecutable(in unsigned long line, in unsigned long pcmap);
+
+ /**
+ * Return a list of all executable lines in a script.
+ * |pcmap| specifies which pc to source line map to use.
+ * |startLine| and |maxLines| may be used to retrieve a chunk at a time.
+ */
+ void getExecutableLines(in unsigned long pcmap,
+ in unsigned long startLine, in unsigned long maxLines,
+ [optional] out unsigned long count,
+ [array, size_is(count), retval] out unsigned long executableLines);
+
+ /**
+ * Set a breakpoint at a PC in this script.
+ */
+ void setBreakpoint(in unsigned long pc);
+ /**
+ * Clear a breakpoint at a PC in this script.
+ */
+ void clearBreakpoint(in unsigned long pc);
+ /**
+ * Clear all breakpoints set in this script.
+ */
+ void clearAllBreakpoints();
+ /**
+ * Call interrupt hook at least once per source line
+ */
+ void enableSingleStepInterrupts(in boolean mode);
+};
+
+/**
+ * Value objects. Represents typeless JavaScript values (jsval in SpiderMonkey
+ * terminology.) These are valid until the debugger is turned off. Holding a
+ * jsdIValue adds a root for the underlying JavaScript value, so don't keep it
+ * if you don't need to.
+ */
+[scriptable, uuid(1cd3535b-4ddb-4202-9053-e0ec88f5c82b)]
+interface jsdIValue : jsdIEphemeral
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDValue JSDValue;
+
+ /**
+ * |false| unless the value is a function declared in script.
+ */
+ readonly attribute boolean isNative;
+ /**
+ * |true| if the value represents a number, either double or integer.
+ * |false| for all other values, including numbers assigned as strings
+ * (eg. x = "1";)
+ */
+ readonly attribute boolean isNumber;
+ /**
+ * |true| if the value represents a JavaScript primitive number or AUTF8String
+ */
+ readonly attribute boolean isPrimitive;
+
+ /** Value is either |true| or |false|. */
+ const unsigned long TYPE_BOOLEAN = 0;
+ /** Value is a primitive number that is too large to fit in an integer. */
+ const unsigned long TYPE_DOUBLE = 1;
+ /** Value is a primitive number that fits into an integer. */
+ const unsigned long TYPE_INT = 2;
+ /** Value is a function. */
+ const unsigned long TYPE_FUNCTION = 3;
+ /** Value is |null|. */
+ const unsigned long TYPE_NULL = 4;
+ /** Value is an object. */
+ const unsigned long TYPE_OBJECT = 5;
+ /** Value is a primitive AUTF8String. */
+ const unsigned long TYPE_STRING = 6;
+ /** Value is void. */
+ const unsigned long TYPE_VOID = 7;
+
+ /**
+ * One of the TYPE_* values above.
+ */
+ readonly attribute unsigned long jsType;
+ /**
+ * Prototype value if this value represents an object, null if the value is
+ * not an object or the object has no prototype.
+ */
+ readonly attribute jsdIValue jsPrototype;
+ /**
+ * Parent value if this value represents an object, null if the value is not
+ * an object or the object has no parent.
+ */
+ readonly attribute jsdIValue jsParent;
+ /**
+ * Class name if this value represents an object. Empty AUTF8String if the value
+ * is not an object.
+ */
+ readonly attribute AUTF8String jsClassName;
+ /**
+ * Constructor name if this value represents an object. Empty AUTF8String if the
+ * value is not an object.
+ */
+ readonly attribute jsdIValue jsConstructor;
+ /**
+ * Function name if this value represents a function. Empty AUTF8String if the
+ * value is not a function.
+ */
+ readonly attribute AUTF8String jsFunctionName;
+
+ /**
+ * Value if interpreted as a boolean. Converts if necessary.
+ */
+ readonly attribute boolean booleanValue;
+ /**
+ * Value if interpreted as a double. Converts if necessary.
+ */
+ readonly attribute double doubleValue;
+ /**
+ * Value if interpreted as an integer. Converts if necessary.
+ */
+ readonly attribute long intValue;
+ /**
+ * Value if interpreted as an object.
+ */
+ readonly attribute jsdIObject objectValue;
+ /**
+ * Value if interpreted as a AUTF8String. Converts if necessary.
+ */
+ readonly attribute AUTF8String stringValue;
+
+ /**
+ * Number of properties. 0 if the value is not an object, or the value is
+ * an object but has no properties.
+ */
+ readonly attribute long propertyCount;
+
+ /**
+ * Retrieves all properties if this value represents an object. If this
+ * value is not an object a 0 element array is returned.
+ * @param propArray Array of jsdIProperty values for this value.
+ * @param length Size of array.
+ */
+ void getProperties([array, size_is(length)] out jsdIProperty propArray,
+ out unsigned long length);
+ /**
+ * Retrieves a single property from the value. Only valid if the value
+ * represents an object.
+ * @param name Name of the property to retrieve.
+ * @retval jsdIProperty for the requested property name or null if no
+ * property exists for the requested name.
+ */
+ jsdIProperty getProperty(in AUTF8String name);
+
+ /**
+ * jsdIValues are wrappers around JavaScript engine structures. Much of the
+ * data is copied instead of shared. The refresh method is used to resync
+ * the jsdIValue with the underlying structure.
+ */
+ void refresh();
+
+ /**
+ * When called from JavaScript, this method returns the JavaScript value
+ * wrapped by this jsdIValue. The calling script is free to use the result
+ * as it would any other JavaScript value.
+ * When called from another language this method returns an xpconnect
+ * defined error code.
+ */
+ [implicit_jscontext] jsval getWrappedValue();
+
+ /**
+ * If this is a function value, return its associated jsdIScript.
+ * Otherwise, return null.
+ */
+ readonly attribute jsdIScript script;
+};
+
+/**
+ * Properties specific to values which are also objects.
+ * XXX We don't add roots for these yet, so make sure you hold on to the
+ * jsdIValue from whence your jsdIObject instance came for at least as long as
+ * you hold the jsdIObject.
+ * XXX Maybe the jsClassName, jsConstructorName, and property related attribute/
+ * functions from jsdIValue should move to this interface. We could inherit from
+ * jsdIValue or use interface flattening or something.
+ */
+[scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)]
+interface jsdIObject : nsISupports
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDObject JSDObject;
+
+ /**
+ * The URL (filename) that contains the script which caused this object
+ * to be created.
+ */
+ readonly attribute AUTF8String creatorURL;
+ /**
+ * Line number in the creatorURL where this object was created.
+ */
+ readonly attribute unsigned long creatorLine;
+ /**
+ * The URL (filename) that contains the script which defined the constructor
+ * used to create this object.
+ */
+ readonly attribute AUTF8String constructorURL;
+ /**
+ * Line number in the creatorURL where this object was created.
+ */
+ readonly attribute unsigned long constructorLine;
+ /**
+ * jsdIValue for this object.
+ */
+ readonly attribute jsdIValue value;
+};
+
+/**
+ * Representation of a property of an object. When an instance is invalid, all
+ * method and property access will result in a NS_UNAVAILABLE error.
+ */
+[scriptable, uuid(acf1329e-aaf6-4d6a-a1eb-f75858566f09)]
+interface jsdIProperty : jsdIEphemeral
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDProperty JSDProperty;
+
+ /**
+ * FLAG_* values must be kept in sync with JSDPD_* #defines in jsdebug.h.
+ */
+
+ /** visible to for/in loop */
+ const unsigned long FLAG_ENUMERATE = 0x01;
+ /** assignment is error */
+ const unsigned long FLAG_READONLY = 0x02;
+ /** property cannot be deleted */
+ const unsigned long FLAG_PERMANENT = 0x04;
+ /** property has an alias id */
+ const unsigned long FLAG_ALIAS = 0x08;
+ /** argument to function */
+ const unsigned long FLAG_ARGUMENT = 0x10;
+ /** local variable in function */
+ const unsigned long FLAG_VARIABLE = 0x20;
+ /** exception occurred looking up property, value is exception */
+ const unsigned long FLAG_EXCEPTION = 0x40;
+ /** native getter returned JS_FALSE without throwing an exception */
+ const unsigned long FLAG_ERROR = 0x80;
+ /** found via explicit lookup (property defined elsewhere.) */
+ const unsigned long FLAG_HINTED = 0x800;
+
+ /** FLAG_* values OR'd together, representing the flags for this property. */
+ readonly attribute unsigned long flags;
+ /** jsdIValue representing the alias for this property. */
+ readonly attribute jsdIValue alias;
+ /** name for this property. */
+ readonly attribute jsdIValue name;
+ /** value of this property. */
+ readonly attribute jsdIValue value;
+};
diff --git a/js/jsd/idl/moz.build b/js/jsd/idl/moz.build
new file mode 100644
index 0000000..4300fd3
--- /dev/null
+++ b/js/jsd/idl/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+ 'jsdIDebuggerService.idl',
+]
+
+XPIDL_MODULE = 'jsdservice'
+
+MODULE = 'jsdebug'
+
diff --git a/js/jsd/jsd.h b/js/jsd/jsd.h
new file mode 100644
index 0000000..91ebf5e
--- /dev/null
+++ b/js/jsd/jsd.h
@@ -0,0 +1,1109 @@
+/* -*- 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/. */
+
+/*
+ * Header for JavaScript Debugging support - Internal ONLY declarations
+ */
+
+#ifndef jsd_h___
+#define jsd_h___
+
+/*
+* NOTE: This is a *private* header file and should only be included by
+* the sources in js/jsd. Defining EXPORT_JSD_API in an outside module
+* using jsd would be bad.
+*/
+#define EXPORT_JSD_API 1 /* if used, must be set before include of jsdebug.h */
+
+/*
+* These can be controled by the makefile, but this allows a place to set
+* the values always used in the mozilla client, but perhaps done differently
+* in other embeddings.
+*/
+#ifdef MOZILLA_CLIENT
+#define JSD_THREADSAFE 1
+/* define JSD_HAS_DANGEROUS_THREAD 1 */
+#define JSD_USE_NSPR_LOCKS 1
+#endif /* MOZILLA_CLIENT */
+
+#include "jstypes.h"
+#include "jsprf.h"
+#include "jsutil.h" /* Added by JSIFY */
+#include "jshash.h" /* Added by JSIFY */
+#include "jsclist.h"
+#include "jsdebug.h"
+#include "jsapi.h"
+#include "jsdbgapi.h"
+#include "jsd_lock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef LIVEWIRE
+#include <base/pblock.h>
+#include <base/session.h>
+#include <frame/log.h>
+#include <frame/req.h>
+#endif /* LIVEWIRE */
+
+#define JSD_MAJOR_VERSION 1
+#define JSD_MINOR_VERSION 1
+
+/***************************************************************************/
+/* handy macros */
+#undef CHECK_BIT_FLAG
+#define CHECK_BIT_FLAG(f,b) ((f)&(b))
+#undef SET_BIT_FLAG
+#define SET_BIT_FLAG(f,b) ((f)|=(b))
+#undef CLEAR_BIT_FLAG
+#define CLEAR_BIT_FLAG(f,b) ((f)&=(~(b)))
+
+#define JSD_IS_DEBUG_ENABLED(jsdc,jsdscript) \
+ (!(((jsdc->flags & JSD_DEBUG_WHEN_SET) ? 1 : 0) ^ \
+ ((jsdscript->flags & JSD_SCRIPT_DEBUG_BIT) ? 1 : 0)))
+#define JSD_IS_PROFILE_ENABLED(jsdc,jsdscript) \
+ ((jsdc->flags & JSD_COLLECT_PROFILE_DATA) && \
+ (!(((jsdc->flags & JSD_PROFILE_WHEN_SET) ? 1 : 0) ^ \
+ ((jsdscript->flags & JSD_SCRIPT_PROFILE_BIT) ? 1 : 0))))
+
+
+/***************************************************************************/
+/* These are not exposed in jsdebug.h - typedef here for consistency */
+
+typedef struct JSDExecHook JSDExecHook;
+typedef struct JSDAtom JSDAtom;
+typedef struct JSDProfileData JSDProfileData;
+/***************************************************************************/
+/* Our structures */
+
+/*
+* XXX What I'm calling a JSDContext is really more of a JSDTaskState.
+*/
+
+struct JSDContext
+{
+ JSCList links; /* we are part of a JSCList */
+ JSBool inited;
+ void* data;
+ uint32_t flags;
+ JSD_ScriptHookProc scriptHook;
+ void* scriptHookData;
+ JSD_ExecutionHookProc interruptHook;
+ void* interruptHookData;
+ JSRuntime* jsrt;
+ JSD_ErrorReporter errorReporter;
+ void* errorReporterData;
+ JSCList threadsStates;
+ JSD_ExecutionHookProc debugBreakHook;
+ void* debugBreakHookData;
+ JSD_ExecutionHookProc debuggerHook;
+ void* debuggerHookData;
+ JSD_ExecutionHookProc throwHook;
+ void* throwHookData;
+ JSD_CallHookProc functionHook;
+ void* functionHookData;
+ JSD_CallHookProc toplevelHook;
+ void* toplevelHookData;
+ JSObject* glob;
+ JSD_UserCallbacks userCallbacks;
+ void* user;
+ JSCList scripts;
+ JSHashTable* scriptsTable;
+ JSCList sources;
+ JSCList removedSources;
+ unsigned sourceAlterCount;
+ JSHashTable* atoms;
+ JSCList objectsList;
+ JSHashTable* objectsTable;
+ JSDProfileData* callingFunctionPData;
+ int64_t lastReturnTime;
+#ifdef JSD_THREADSAFE
+ JSDStaticLock* scriptsLock;
+ JSDStaticLock* sourceTextLock;
+ JSDStaticLock* objectsLock;
+ JSDStaticLock* atomsLock;
+ JSDStaticLock* threadStatesLock;
+#endif /* JSD_THREADSAFE */
+#ifdef JSD_HAS_DANGEROUS_THREAD
+ void* dangerousThread;
+#endif /* JSD_HAS_DANGEROUS_THREAD */
+
+};
+
+struct JSDScript
+{
+ JSCList links; /* we are part of a JSCList */
+ JSDContext* jsdc; /* JSDContext for this jsdscript */
+ JSScript* script; /* script we are wrapping */
+ unsigned lineBase; /* we cache this */
+ unsigned lineExtent; /* we cache this */
+ JSCList hooks; /* JSCList of JSDExecHooks for this script */
+ char* url;
+ uint32_t flags;
+ void* data;
+
+ JSDProfileData *profileData;
+
+#ifdef LIVEWIRE
+ LWDBGApp* app;
+ LWDBGScript* lwscript;
+#endif
+};
+
+struct JSDProfileData
+{
+ JSDProfileData* caller;
+ int64_t lastCallStart;
+ int64_t runningTime;
+ unsigned callCount;
+ unsigned recurseDepth;
+ unsigned maxRecurseDepth;
+ double minExecutionTime;
+ double maxExecutionTime;
+ double totalExecutionTime;
+ double minOwnExecutionTime;
+ double maxOwnExecutionTime;
+ double totalOwnExecutionTime;
+};
+
+struct JSDSourceText
+{
+ JSCList links; /* we are part of a JSCList */
+ char* url;
+ char* text;
+ unsigned textLength;
+ unsigned textSpace;
+ JSBool dirty;
+ JSDSourceStatus status;
+ unsigned alterCount;
+ JSBool doingEval;
+};
+
+struct JSDExecHook
+{
+ JSCList links; /* we are part of a JSCList */
+ JSDScript* jsdscript;
+ uintptr_t pc;
+ JSD_ExecutionHookProc hook;
+ void* callerdata;
+};
+
+#define TS_HAS_DISABLED_FRAME 0x01
+
+struct JSDThreadState
+{
+ JSCList links; /* we are part of a JSCList */
+ JSContext* context;
+ void* thread;
+ JSCList stack;
+ unsigned stackDepth;
+ unsigned flags;
+};
+
+struct JSDStackFrameInfo
+{
+ JSCList links; /* we are part of a JSCList */
+ JSDThreadState* jsdthreadstate;
+ JSDScript* jsdscript;
+ uintptr_t pc;
+ bool isConstructing;
+ JSAbstractFramePtr frame;
+};
+
+#define GOT_PROTO ((short) (1 << 0))
+#define GOT_PROPS ((short) (1 << 1))
+#define GOT_PARENT ((short) (1 << 2))
+#define GOT_CTOR ((short) (1 << 3))
+
+struct JSDValue
+{
+ jsval val;
+ int nref;
+ JSCList props;
+ JSString* string;
+ JSString* funName;
+ const char* className;
+ JSDValue* proto;
+ JSDValue* parent;
+ JSDValue* ctor;
+ unsigned flags;
+};
+
+struct JSDProperty
+{
+ JSCList links; /* we are part of a JSCList */
+ int nref;
+ JSDValue* val;
+ JSDValue* name;
+ JSDValue* alias;
+ unsigned flags;
+};
+
+struct JSDAtom
+{
+ char* str; /* must be first element in struct for compare */
+ int refcount;
+};
+
+struct JSDObject
+{
+ JSCList links; /* we are part of a JSCList */
+ JSObject* obj;
+ JSDAtom* newURL;
+ unsigned newLineno;
+ JSDAtom* ctorURL;
+ unsigned ctorLineno;
+ JSDAtom* ctorName;
+};
+
+/***************************************************************************/
+/* Code validation support */
+
+#ifdef DEBUG
+extern void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc);
+extern void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript);
+extern void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc);
+extern void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate);
+extern void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe);
+extern void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook);
+extern void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval);
+extern void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop);
+extern void JSD_ASSERT_VALID_OBJECT(JSDObject* jsdobj);
+#else
+#define JSD_ASSERT_VALID_CONTEXT(x) ((void)0)
+#define JSD_ASSERT_VALID_SCRIPT(x) ((void)0)
+#define JSD_ASSERT_VALID_SOURCE_TEXT(x) ((void)0)
+#define JSD_ASSERT_VALID_THREAD_STATE(x)((void)0)
+#define JSD_ASSERT_VALID_STACK_FRAME(x) ((void)0)
+#define JSD_ASSERT_VALID_EXEC_HOOK(x) ((void)0)
+#define JSD_ASSERT_VALID_VALUE(x) ((void)0)
+#define JSD_ASSERT_VALID_PROPERTY(x) ((void)0)
+#define JSD_ASSERT_VALID_OBJECT(x) ((void)0)
+#endif
+
+/***************************************************************************/
+/* higher level functions */
+
+extern JSDContext*
+jsd_DebuggerOnForUser(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user,
+ JSObject* scopeobj);
+
+extern JSDContext*
+jsd_DebuggerOn(void);
+
+extern void
+jsd_DebuggerOff(JSDContext* jsdc);
+
+extern void
+jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff);
+
+extern void
+jsd_DebuggerUnpause(JSDContext* jsdc);
+
+extern void
+jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user);
+
+extern JSDContext*
+jsd_JSDContextForJSContext(JSContext* context);
+
+extern void*
+jsd_SetContextPrivate(JSDContext* jsdc, void *data);
+
+extern void*
+jsd_GetContextPrivate(JSDContext* jsdc);
+
+extern void
+jsd_ClearAllProfileData(JSDContext* jsdc);
+
+extern JSBool
+jsd_SetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter reporter,
+ void* callerdata);
+
+extern JSBool
+jsd_GetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter* reporter,
+ void** callerdata);
+
+/***************************************************************************/
+/* Script functions */
+
+extern JSBool
+jsd_InitScriptManager(JSDContext *jsdc);
+
+extern void
+jsd_DestroyScriptManager(JSDContext* jsdc);
+
+extern JSDScript*
+jsd_FindJSDScript(JSDContext* jsdc,
+ JSScript *script);
+
+extern JSDScript*
+jsd_FindOrCreateJSDScript(JSDContext *jsdc,
+ JSContext *cx,
+ JSScript *script,
+ JSAbstractFramePtr frame);
+
+extern JSDProfileData*
+jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script);
+
+extern uint32_t
+jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script);
+
+extern void
+jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags);
+
+extern unsigned
+jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script);
+
+extern unsigned
+jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script);
+
+extern double
+jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+extern double
+jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+extern double
+jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+extern double
+jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+extern double
+jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+extern double
+jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+extern void
+jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script);
+
+extern JSScript *
+jsd_GetJSScript (JSDContext *jsdc, JSDScript *script);
+
+extern JSFunction *
+jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script);
+
+extern JSDScript*
+jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp);
+
+extern void *
+jsd_SetScriptPrivate (JSDScript *jsdscript, void *data);
+
+extern void *
+jsd_GetScriptPrivate (JSDScript *jsdscript);
+
+extern JSBool
+jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript);
+
+extern const char*
+jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript);
+
+extern JSString*
+jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript);
+
+extern unsigned
+jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript);
+
+extern unsigned
+jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript);
+
+extern JSBool
+jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
+
+extern JSBool
+jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata);
+
+extern uintptr_t
+jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line);
+
+extern unsigned
+jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc);
+
+extern JSBool
+jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned startLine, unsigned maxLines,
+ unsigned* count, unsigned** lines, uintptr_t** pcs);
+
+extern void
+jsd_NewScriptHookProc(
+ JSContext *cx,
+ const char *filename, /* URL this script loads from */
+ unsigned lineno, /* line where this script starts */
+ JSScript *script,
+ JSFunction *fun,
+ void* callerdata);
+
+extern void
+jsd_DestroyScriptHookProc(
+ JSFreeOp *fop,
+ JSScript *script,
+ void* callerdata);
+
+/* Script execution hook functions */
+
+extern JSBool
+jsd_SetExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+extern JSBool
+jsd_ClearExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc);
+
+extern JSBool
+jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript);
+
+extern JSBool
+jsd_ClearAllExecutionHooks(JSDContext* jsdc);
+
+extern void
+jsd_ScriptCreated(JSDContext* jsdc,
+ JSContext *cx,
+ const char *filename, /* URL this script loads from */
+ unsigned lineno, /* line where this script starts */
+ JSScript *script,
+ JSFunction *fun);
+
+extern void
+jsd_ScriptDestroyed(JSDContext* jsdc,
+ JSFreeOp *fop,
+ JSScript *script);
+
+/***************************************************************************/
+/* Source Text functions */
+
+extern JSDSourceText*
+jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp);
+
+extern JSDSourceText*
+jsd_FindSourceForURL(JSDContext* jsdc, const char* url);
+
+extern const char*
+jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern JSBool
+jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
+ const char** ppBuf, int* pLen);
+
+extern void
+jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern JSDSourceStatus
+jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern JSBool
+jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern void
+jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty);
+
+extern unsigned
+jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern unsigned
+jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern JSDSourceText*
+jsd_NewSourceText(JSDContext* jsdc, const char* url);
+
+extern JSDSourceText*
+jsd_AppendSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status);
+
+extern JSDSourceText*
+jsd_AppendUCSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const jschar* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status);
+
+/* convienence function for adding complete source of url in one call */
+extern JSBool
+jsd_AddFullSourceText(JSDContext* jsdc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ const char* url);
+
+extern void
+jsd_DestroyAllSources(JSDContext* jsdc);
+
+extern char*
+jsd_BuildNormalizedURL(const char* url_string);
+
+extern void
+jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url);
+
+extern void
+jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url);
+
+/***************************************************************************/
+/* Interrupt Hook functions */
+
+extern JSBool
+jsd_SetInterruptHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+extern JSBool
+jsd_ClearInterruptHook(JSDContext* jsdc);
+
+extern JSBool
+jsd_EnableSingleStepInterrupts(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ JSBool enable);
+
+extern JSBool
+jsd_SetDebugBreakHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+extern JSBool
+jsd_ClearDebugBreakHook(JSDContext* jsdc);
+
+extern JSBool
+jsd_SetDebuggerHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+extern JSBool
+jsd_ClearDebuggerHook(JSDContext* jsdc);
+
+extern JSTrapStatus
+jsd_CallExecutionHook(JSDContext* jsdc,
+ JSContext* cx,
+ unsigned type,
+ JSD_ExecutionHookProc hook,
+ void* hookData,
+ jsval* rval);
+
+extern JSBool
+jsd_CallCallHook (JSDContext* jsdc,
+ JSContext* cx,
+ unsigned type,
+ JSD_CallHookProc hook,
+ void* hookData);
+
+extern JSBool
+jsd_SetThrowHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+extern JSBool
+jsd_ClearThrowHook(JSDContext* jsdc);
+
+extern JSTrapStatus
+jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
+ jsval *rval, void *closure);
+
+extern JSTrapStatus
+jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
+ jsval *rval, void *closure);
+
+extern JSBool
+jsd_SetFunctionHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata);
+
+extern JSBool
+jsd_ClearFunctionHook(JSDContext* jsdc);
+
+extern JSBool
+jsd_SetTopLevelHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata);
+
+extern JSBool
+jsd_ClearTopLevelHook(JSDContext* jsdc);
+
+/***************************************************************************/
+/* Stack Frame functions */
+
+extern unsigned
+jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+extern JSDStackFrameInfo*
+jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+extern JSContext*
+jsd_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+extern JSDStackFrameInfo*
+jsd_GetCallingStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSDScript*
+jsd_GetScriptForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern uintptr_t
+jsd_GetPCForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSDValue*
+jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSDValue*
+jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSBool
+jsd_IsStackFrameDebugger(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSBool
+jsd_IsStackFrameConstructing(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSDValue*
+jsd_GetThisForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSString*
+jsd_GetIdForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSDThreadState*
+jsd_NewThreadState(JSDContext* jsdc, JSContext *cx);
+
+extern void
+jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+extern JSBool
+jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const jschar *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JSBool eatExceptions, JS::MutableHandleValue rval);
+
+extern JSBool
+jsd_EvaluateScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const char *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JSBool eatExceptions, JS::MutableHandleValue rval);
+
+extern JSString*
+jsd_ValToStringInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ jsval val);
+
+extern JSBool
+jsd_IsValidThreadState(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate);
+
+extern JSBool
+jsd_IsValidFrameInThreadState(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+extern JSDValue*
+jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+extern JSBool
+jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
+ JSDValue* jsdval);
+
+/***************************************************************************/
+/* Locking support */
+
+/* protos are in js_lock.h for:
+ * jsd_CreateLock
+ * jsd_Lock
+ * jsd_Unlock
+ * jsd_IsLocked
+ * jsd_CurrentThread
+ */
+
+#ifdef JSD_THREADSAFE
+
+/* the system-wide lock */
+extern JSDStaticLock* _jsd_global_lock;
+#define JSD_LOCK() \
+ JS_BEGIN_MACRO \
+ if(!_jsd_global_lock) \
+ _jsd_global_lock = jsd_CreateLock(); \
+ JS_ASSERT(_jsd_global_lock); \
+ jsd_Lock(_jsd_global_lock); \
+ JS_END_MACRO
+
+#define JSD_UNLOCK() \
+ JS_BEGIN_MACRO \
+ JS_ASSERT(_jsd_global_lock); \
+ jsd_Unlock(_jsd_global_lock); \
+ JS_END_MACRO
+
+/* locks for the subsystems of a given context */
+#define JSD_INIT_LOCKS(jsdc) \
+ ( (NULL != (jsdc->scriptsLock = jsd_CreateLock())) && \
+ (NULL != (jsdc->sourceTextLock = jsd_CreateLock())) && \
+ (NULL != (jsdc->atomsLock = jsd_CreateLock())) && \
+ (NULL != (jsdc->objectsLock = jsd_CreateLock())) && \
+ (NULL != (jsdc->threadStatesLock = jsd_CreateLock())) )
+
+#define JSD_LOCK_SCRIPTS(jsdc) jsd_Lock(jsdc->scriptsLock)
+#define JSD_UNLOCK_SCRIPTS(jsdc) jsd_Unlock(jsdc->scriptsLock)
+
+#define JSD_LOCK_SOURCE_TEXT(jsdc) jsd_Lock(jsdc->sourceTextLock)
+#define JSD_UNLOCK_SOURCE_TEXT(jsdc) jsd_Unlock(jsdc->sourceTextLock)
+
+#define JSD_LOCK_ATOMS(jsdc) jsd_Lock(jsdc->atomsLock)
+#define JSD_UNLOCK_ATOMS(jsdc) jsd_Unlock(jsdc->atomsLock)
+
+#define JSD_LOCK_OBJECTS(jsdc) jsd_Lock(jsdc->objectsLock)
+#define JSD_UNLOCK_OBJECTS(jsdc) jsd_Unlock(jsdc->objectsLock)
+
+#define JSD_LOCK_THREADSTATES(jsdc) jsd_Lock(jsdc->threadStatesLock)
+#define JSD_UNLOCK_THREADSTATES(jsdc) jsd_Unlock(jsdc->threadStatesLock)
+
+#else /* !JSD_THREADSAFE */
+
+#define JSD_LOCK() ((void)0)
+#define JSD_UNLOCK() ((void)0)
+
+#define JSD_INIT_LOCKS(jsdc) 1
+
+#define JSD_LOCK_SCRIPTS(jsdc) ((void)0)
+#define JSD_UNLOCK_SCRIPTS(jsdc) ((void)0)
+
+#define JSD_LOCK_SOURCE_TEXT(jsdc) ((void)0)
+#define JSD_UNLOCK_SOURCE_TEXT(jsdc) ((void)0)
+
+#define JSD_LOCK_ATOMS(jsdc) ((void)0)
+#define JSD_UNLOCK_ATOMS(jsdc) ((void)0)
+
+#define JSD_LOCK_OBJECTS(jsdc) ((void)0)
+#define JSD_UNLOCK_OBJECTS(jsdc) ((void)0)
+
+#define JSD_LOCK_THREADSTATES(jsdc) ((void)0)
+#define JSD_UNLOCK_THREADSTATES(jsdc) ((void)0)
+
+#endif /* JSD_THREADSAFE */
+
+/* NOTE: These are intended for ASSERTs. Thus we supply checks for both
+ * LOCKED and UNLOCKED (rather that just LOCKED and !LOCKED) so that in
+ * the DEBUG non-Threadsafe case we can have an ASSERT that always succeeds
+ * without having to special case things in the code.
+ */
+#if defined(JSD_THREADSAFE) && defined(DEBUG)
+#define JSD_SCRIPTS_LOCKED(jsdc) (jsd_IsLocked(jsdc->scriptsLock))
+#define JSD_SOURCE_TEXT_LOCKED(jsdc) (jsd_IsLocked(jsdc->sourceTextLock))
+#define JSD_ATOMS_LOCKED(jsdc) (jsd_IsLocked(jsdc->atomsLock))
+#define JSD_OBJECTS_LOCKED(jsdc) (jsd_IsLocked(jsdc->objectsLock))
+#define JSD_THREADSTATES_LOCKED(jsdc) (jsd_IsLocked(jsdc->threadStatesLock))
+#define JSD_SCRIPTS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->scriptsLock))
+#define JSD_SOURCE_TEXT_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->sourceTextLock))
+#define JSD_ATOMS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->atomsLock))
+#define JSD_OBJECTS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->objectsLock))
+#define JSD_THREADSTATES_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->threadStatesLock))
+#else
+#define JSD_SCRIPTS_LOCKED(jsdc) 1
+#define JSD_SOURCE_TEXT_LOCKED(jsdc) 1
+#define JSD_ATOMS_LOCKED(jsdc) 1
+#define JSD_OBJECTS_LOCKED(jsdc) 1
+#define JSD_THREADSTATES_LOCKED(jsdc) 1
+#define JSD_SCRIPTS_UNLOCKED(jsdc) 1
+#define JSD_SOURCE_TEXT_UNLOCKED(jsdc) 1
+#define JSD_ATOMS_UNLOCKED(jsdc) 1
+#define JSD_OBJECTS_UNLOCKED(jsdc) 1
+#define JSD_THREADSTATES_UNLOCKED(jsdc) 1
+#endif /* defined(JSD_THREADSAFE) && defined(DEBUG) */
+
+/***************************************************************************/
+/* Threading support */
+
+#ifdef JSD_THREADSAFE
+
+#define JSD_CURRENT_THREAD() jsd_CurrentThread()
+
+#else /* !JSD_THREADSAFE */
+
+#define JSD_CURRENT_THREAD() ((void*)0)
+
+#endif /* JSD_THREADSAFE */
+
+/***************************************************************************/
+/* Dangerous thread support */
+
+#ifdef JSD_HAS_DANGEROUS_THREAD
+
+#define JSD_IS_DANGEROUS_THREAD(jsdc) \
+ (JSD_CURRENT_THREAD() == jsdc->dangerousThread)
+
+#else /* !JSD_HAS_DANGEROUS_THREAD */
+
+#define JSD_IS_DANGEROUS_THREAD(jsdc) 0
+
+#endif /* JSD_HAS_DANGEROUS_THREAD */
+
+/***************************************************************************/
+/* Value and Property Functions */
+
+extern JSDValue*
+jsd_NewValue(JSDContext* jsdc, jsval val);
+
+extern void
+jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval);
+
+extern jsval
+jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval);
+
+extern void
+jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+extern JSBool
+jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSBool
+jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+extern JSBool
+jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval);
+
+extern int32_t
+jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval);
+
+extern double
+jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSString*
+jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSString*
+jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSFunction*
+jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+extern unsigned
+jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSDProperty*
+jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp);
+
+extern JSDProperty*
+jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name);
+
+extern JSDValue*
+jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSDValue*
+jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSDValue*
+jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval);
+
+extern const char*
+jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval);
+
+extern JSDScript*
+jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+extern void
+jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop);
+
+extern JSDValue*
+jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop);
+
+extern JSDValue*
+jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop);
+
+extern JSDValue*
+jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop);
+
+extern unsigned
+jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop);
+
+/**************************************************/
+/* Stepping Functions */
+
+extern void *
+jsd_FunctionCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
+ JSBool before, JSBool *ok, void *closure);
+
+extern void *
+jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
+ JSBool before, JSBool *ok, void *closure);
+
+/**************************************************/
+/* Object Functions */
+
+extern JSBool
+jsd_InitObjectManager(JSDContext* jsdc);
+
+extern void
+jsd_DestroyObjectManager(JSDContext* jsdc);
+
+extern void
+jsd_DestroyObjects(JSDContext* jsdc);
+
+extern void
+jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj,
+ JSAbstractFramePtr frame);
+
+extern JSDObject*
+jsd_IterateObjects(JSDContext* jsdc, JSDObject** iterp);
+
+extern JSObject*
+jsd_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj);
+
+extern const char*
+jsd_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj);
+
+extern unsigned
+jsd_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj);
+
+extern const char*
+jsd_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj);
+
+extern unsigned
+jsd_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj);
+
+extern const char*
+jsd_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj);
+
+extern JSDObject*
+jsd_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj);
+
+extern JSDObject*
+jsd_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* returns new refcounted JSDValue
+*/
+extern JSDValue*
+jsd_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj);
+
+/**************************************************/
+/* Atom Functions */
+
+extern JSBool
+jsd_CreateAtomTable(JSDContext* jsdc);
+
+extern void
+jsd_DestroyAtomTable(JSDContext* jsdc);
+
+extern JSDAtom*
+jsd_AddAtom(JSDContext* jsdc, const char* str);
+
+extern JSDAtom*
+jsd_CloneAtom(JSDContext* jsdc, JSDAtom* atom);
+
+extern void
+jsd_DropAtom(JSDContext* jsdc, JSDAtom* atom);
+
+#define JSD_ATOM_TO_STRING(a) ((const char*)((a)->str))
+
+struct AutoSaveExceptionState {
+ AutoSaveExceptionState(JSContext *cx) : mCx(cx) {
+ mState = JS_SaveExceptionState(cx);
+ }
+ ~AutoSaveExceptionState() {
+ JS_RestoreExceptionState(mCx, mState);
+ }
+ JSContext *mCx;
+ JSExceptionState *mState;
+};
+
+/***************************************************************************/
+/* Livewire specific API */
+#ifdef LIVEWIRE
+
+extern LWDBGScript*
+jsdlw_GetLWScript(JSDContext* jsdc, JSDScript* jsdscript);
+
+extern char*
+jsdlw_BuildAppRelativeFilename(LWDBGApp* app, const char* filename);
+
+extern JSDSourceText*
+jsdlw_PreLoadSource(JSDContext* jsdc, LWDBGApp* app,
+ const char* filename, JSBool clear);
+
+extern JSDSourceText*
+jsdlw_ForceLoadSource(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern JSBool
+jsdlw_UserCodeAtPC(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc);
+
+extern JSBool
+jsdlw_RawToProcessedLineNumber(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned lineIn, unsigned* lineOut);
+
+extern JSBool
+jsdlw_ProcessedToRawLineNumber(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned lineIn, unsigned* lineOut);
+
+#if 0
+/* our hook proc for LiveWire app start/stop */
+extern void
+jsdlw_AppHookProc(LWDBGApp* app,
+ JSBool created,
+ void *callerdata);
+#endif
+
+
+#endif
+/***************************************************************************/
+
+#endif /* jsd_h___ */
diff --git a/js/jsd/jsd1640.def b/js/jsd/jsd1640.def
new file mode 100644
index 0000000..48af380
--- /dev/null
+++ b/js/jsd/jsd1640.def
@@ -0,0 +1,77 @@
+; -*- Mode: Fundamental; tab-width: 4; indent-tabs-mode: nil -*-
+;
+; 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/.
+
+
+LIBRARY JSD1640.DLL
+EXETYPE WINDOWS
+PROTMODE
+
+DESCRIPTION 'Netscape 16-bit JavaScript Debugger Library'
+
+CODE LOADONCALL MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+
+HEAPSIZE 8192
+
+EXPORTS
+ WEP @1 RESIDENTNAME NONAME
+ _JSD_AppendSourceText
+ _JSD_ClearAllExecutionHooks
+ _JSD_ClearAllExecutionHooksForScript
+ _JSD_ClearDebugBreakHook
+ _JSD_ClearExecutionHook
+ _JSD_ClearInterruptHook
+ _JSD_ClearSourceText
+ _JSD_DebuggerOff
+ _JSD_DebuggerOn
+ _JSD_EvaluateScriptInStackFrame
+ _JSD_FindSourceForURL
+ _JSD_GetCallingStackFrame
+ _JSD_GetClosestLine
+ _JSD_GetClosestPC
+ _JSD_GetCountOfStackFrames
+ _JSD_GetMajorVersion
+ _JSD_GetMinorVersion
+ _JSD_GetPCForStackFrame
+ _JSD_GetScriptBaseLineNumber
+ _JSD_GetScriptFilename
+ _JSD_GetScriptForStackFrame
+ _JSD_GetScriptFunctionId
+ _JSD_GetScriptHook
+ _JSD_GetScriptLineExtent
+ _JSD_GetSourceAlterCount
+ _JSD_GetSourceStatus
+ _JSD_GetSourceText
+ _JSD_GetSourceURL
+ _JSD_GetStackFrame
+ _JSD_IncrementSourceAlterCount
+ _JSD_IsSourceDirty
+ _JSD_IterateScripts
+ _JSD_IterateSources
+ _JSD_LockScriptSubsystem
+ _JSD_LockSourceTextSubsystem
+ _JSD_NewSourceText
+ _JSD_SetDebugBreakHook
+ _JSD_SetErrorReporter
+ _JSD_SetExecutionHook
+ _JSD_SetInterruptHook
+ _JSD_SetScriptHook
+ _JSD_SetSourceDirty
+ _JSD_SetUserCallbacks
+ _JSD_UnlockScriptSubsystem
+ _JSD_UnlockSourceTextSubsystem
+ _Java_netscape_jsdebug_DebugController__0005fsetController_stub
+ _Java_netscape_jsdebug_DebugController_executeScriptInStackFrame_stub
+ _Java_netscape_jsdebug_DebugController_sendInterrupt_stub
+ _Java_netscape_jsdebug_DebugController_setInstructionHook0_stub
+ _Java_netscape_jsdebug_JSPC_getSourceLocation_stub
+ _Java_netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem_stub
+ _Java_netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector_stub
+ _Java_netscape_jsdebug_JSStackFrameInfo_getCaller0_stub
+ _Java_netscape_jsdebug_JSStackFrameInfo_getPC_stub
+ _Java_netscape_jsdebug_JSThreadState_countStackFrames_stub
+ _Java_netscape_jsdebug_JSThreadState_getCurrentFrame_stub
+ _Java_netscape_jsdebug_Script_getClosestPC_stub
diff --git a/js/jsd/jsd1640.rc b/js/jsd/jsd1640.rc
new file mode 100644
index 0000000..7c3cf55
--- /dev/null
+++ b/js/jsd/jsd1640.rc
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+// Version stamp for this .DLL
+
+#include <windows.h>
+
+#include <ver.h>
+
+
+
+VS_VERSION_INFO VERSIONINFO
+
+ FILEVERSION 4 // major, minor, release (alpha 1), build #
+
+ PRODUCTVERSION 4
+
+ FILEFLAGSMASK 0
+
+ FILEFLAGS 0 // final version
+
+ FILEOS VOS_DOS_WINDOWS16
+
+ FILETYPE VFT_DLL
+
+ FILESUBTYPE 0 // not used
+
+BEGIN
+
+ BLOCK "StringFileInfo"
+
+ BEGIN
+
+ BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
+
+ BEGIN
+
+ VALUE "CompanyName", "Netscape Communications Corporation\0"
+
+ VALUE "FileDescription", "Netscape 16-bit JavaScript Debugger Module\0"
+
+ VALUE "FileVersion", "4.0\0"
+
+ VALUE "InternalName", "JSD1640\0"
+
+ VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
+
+ VALUE "LegalTrademarks", "Netscape, Mozilla\0"
+
+ VALUE "OriginalFilename","JSD1640.DLL\0"
+
+ VALUE "ProductName", "NETSCAPE\0"
+
+ VALUE "ProductVersion", "4.0\0"
+
+ END
+
+ END
+
+END
+
diff --git a/js/jsd/jsd3240.rc b/js/jsd/jsd3240.rc
new file mode 100644
index 0000000..5b2bc34
--- /dev/null
+++ b/js/jsd/jsd3240.rc
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+
+
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winver.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,0,0,0
+ PRODUCTVERSION 4,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x10004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "Netscape Communications Corporation\0"
+ VALUE "FileDescription", "Netscape 32-bit JavaScript Debugger Module\0"
+ VALUE "FileVersion", "4.0\0"
+ VALUE "InternalName", "JSD3240\0"
+ VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
+ VALUE "LegalTrademarks", "Netscape, Mozilla\0"
+ VALUE "OriginalFilename", "jsd3240.dll\0"
+ VALUE "ProductName", "NETSCAPE\0"
+ VALUE "ProductVersion", "4.0\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""winver.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+///////////////////////////////////////////////////////////////////////////// \ No newline at end of file
diff --git a/js/jsd/jsd_atom.cpp b/js/jsd/jsd_atom.cpp
new file mode 100644
index 0000000..dec6b39
--- /dev/null
+++ b/js/jsd/jsd_atom.cpp
@@ -0,0 +1,147 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Atom support
+ */
+
+#include "jsd.h"
+
+/* #define TEST_ATOMS 1 */
+
+#ifdef TEST_ATOMS
+static void
+_testAtoms(JSDContext*jsdc)
+{
+ JSDAtom* atom0 = jsd_AddAtom(jsdc, "foo");
+ JSDAtom* atom1 = jsd_AddAtom(jsdc, "foo");
+ JSDAtom* atom2 = jsd_AddAtom(jsdc, "bar");
+ JSDAtom* atom3 = jsd_CloneAtom(jsdc, atom1);
+ JSDAtom* atom4 = jsd_CloneAtom(jsdc, atom2);
+
+ const char* c0 = JSD_ATOM_TO_STRING(atom0);
+ const char* c1 = JSD_ATOM_TO_STRING(atom1);
+ const char* c2 = JSD_ATOM_TO_STRING(atom2);
+ const char* c3 = JSD_ATOM_TO_STRING(atom3);
+ const char* c4 = JSD_ATOM_TO_STRING(atom4);
+
+ jsd_DropAtom(jsdc, atom0);
+ jsd_DropAtom(jsdc, atom1);
+ jsd_DropAtom(jsdc, atom2);
+ jsd_DropAtom(jsdc, atom3);
+ jsd_DropAtom(jsdc, atom4);
+}
+#endif
+
+static int
+_atom_smasher(JSHashEntry *he, int i, void *arg)
+{
+ JS_ASSERT(he);
+ JS_ASSERT(he->value);
+ JS_ASSERT(((JSDAtom*)(he->value))->str);
+
+ free(((JSDAtom*)(he->value))->str);
+ free(he->value);
+ he->value = NULL;
+ he->key = NULL;
+ return HT_ENUMERATE_NEXT;
+}
+
+static int
+_compareAtomKeys(const void *v1, const void *v2)
+{
+ return 0 == strcmp((const char*)v1, (const char*)v2);
+}
+
+static int
+_compareAtoms(const void *v1, const void *v2)
+{
+ return 0 == strcmp(((JSDAtom*)v1)->str, ((JSDAtom*)v2)->str);
+}
+
+
+JSBool
+jsd_CreateAtomTable(JSDContext* jsdc)
+{
+ jsdc->atoms = JS_NewHashTable(256, JS_HashString,
+ _compareAtomKeys, _compareAtoms,
+ NULL, NULL);
+#ifdef TEST_ATOMS
+ _testAtoms(jsdc);
+#endif
+ return !!jsdc->atoms;
+}
+
+void
+jsd_DestroyAtomTable(JSDContext* jsdc)
+{
+ if( jsdc->atoms )
+ {
+ JS_HashTableEnumerateEntries(jsdc->atoms, _atom_smasher, NULL);
+ JS_HashTableDestroy(jsdc->atoms);
+ jsdc->atoms = NULL;
+ }
+}
+
+JSDAtom*
+jsd_AddAtom(JSDContext* jsdc, const char* str)
+{
+ JSDAtom* atom;
+
+ if(!str)
+ {
+ JS_ASSERT(0);
+ return NULL;
+ }
+
+ JSD_LOCK_ATOMS(jsdc);
+
+ atom = (JSDAtom*) JS_HashTableLookup(jsdc->atoms, str);
+
+ if( atom )
+ atom->refcount++;
+ else
+ {
+ atom = (JSDAtom*) malloc(sizeof(JSDAtom));
+ if( atom )
+ {
+ atom->str = strdup(str);
+ atom->refcount = 1;
+ if(!JS_HashTableAdd(jsdc->atoms, atom->str, atom))
+ {
+ free(atom->str);
+ free(atom);
+ atom = NULL;
+ }
+ }
+ }
+
+ JSD_UNLOCK_ATOMS(jsdc);
+ return atom;
+}
+
+JSDAtom*
+jsd_CloneAtom(JSDContext* jsdc, JSDAtom* atom)
+{
+ JSD_LOCK_ATOMS(jsdc);
+ atom->refcount++;
+ JSD_UNLOCK_ATOMS(jsdc);
+ return atom;
+}
+
+void
+jsd_DropAtom(JSDContext* jsdc, JSDAtom* atom)
+{
+ JSD_LOCK_ATOMS(jsdc);
+ if(! --atom->refcount)
+ {
+ JS_HashTableRemove(jsdc->atoms, atom->str);
+ free(atom->str);
+ free(atom);
+ }
+ JSD_UNLOCK_ATOMS(jsdc);
+}
+
diff --git a/js/jsd/jsd_high.cpp b/js/jsd/jsd_high.cpp
new file mode 100644
index 0000000..ed3512a
--- /dev/null
+++ b/js/jsd/jsd_high.cpp
@@ -0,0 +1,419 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - 'High Level' functions
+ */
+
+#include "jsd.h"
+#include "nsCxPusher.h"
+#include "nsContentUtils.h"
+
+using mozilla::AutoSafeJSContext;
+
+/***************************************************************************/
+
+/* XXX not 'static' because of old Mac CodeWarrior bug */
+JSCList _jsd_context_list = JS_INIT_STATIC_CLIST(&_jsd_context_list);
+
+/* these are used to connect JSD_SetUserCallbacks() with JSD_DebuggerOn() */
+static JSD_UserCallbacks _callbacks;
+static void* _user = NULL;
+static JSRuntime* _jsrt = NULL;
+
+#ifdef JSD_HAS_DANGEROUS_THREAD
+static void* _dangerousThread = NULL;
+#endif
+
+#ifdef JSD_THREADSAFE
+JSDStaticLock* _jsd_global_lock = NULL;
+#endif
+
+#ifdef DEBUG
+void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc)
+{
+ JS_ASSERT(jsdc->inited);
+ JS_ASSERT(jsdc->jsrt);
+ JS_ASSERT(jsdc->glob);
+}
+#endif
+
+/***************************************************************************/
+/* xpconnect related utility functions implemented in jsd_xpc.cpp */
+
+extern void
+global_finalize(JSFreeOp* fop, JSObject* obj);
+
+extern JSObject*
+CreateJSDGlobal(JSContext *cx, JSClass *clasp);
+
+/***************************************************************************/
+
+
+static JSClass global_class = {
+ "JSDGlobal", JSCLASS_GLOBAL_FLAGS |
+ JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
+ JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, global_finalize
+};
+
+static JSBool
+_validateUserCallbacks(JSD_UserCallbacks* callbacks)
+{
+ return !callbacks ||
+ (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
+}
+
+static JSDContext*
+_newJSDContext(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user,
+ JSObject* scopeobj)
+{
+ JSDContext* jsdc = NULL;
+ bool ok = true;
+ AutoSafeJSContext cx;
+
+ if( ! jsrt )
+ return NULL;
+
+ if( ! _validateUserCallbacks(callbacks) )
+ return NULL;
+
+ jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
+ if( ! jsdc )
+ goto label_newJSDContext_failure;
+
+ if( ! JSD_INIT_LOCKS(jsdc) )
+ goto label_newJSDContext_failure;
+
+ JS_INIT_CLIST(&jsdc->links);
+
+ jsdc->jsrt = jsrt;
+
+ if( callbacks )
+ memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
+
+ jsdc->user = user;
+
+#ifdef JSD_HAS_DANGEROUS_THREAD
+ jsdc->dangerousThread = _dangerousThread;
+#endif
+
+ JS_INIT_CLIST(&jsdc->threadsStates);
+ JS_INIT_CLIST(&jsdc->sources);
+ JS_INIT_CLIST(&jsdc->removedSources);
+
+ jsdc->sourceAlterCount = 1;
+
+ if( ! jsd_CreateAtomTable(jsdc) )
+ goto label_newJSDContext_failure;
+
+ if( ! jsd_InitObjectManager(jsdc) )
+ goto label_newJSDContext_failure;
+
+ if( ! jsd_InitScriptManager(jsdc) )
+ goto label_newJSDContext_failure;
+
+
+ jsdc->glob = CreateJSDGlobal(cx, &global_class);
+
+ if( ! jsdc->glob )
+ goto label_newJSDContext_failure;
+
+ {
+ JSAutoCompartment ac(cx, jsdc->glob);
+ ok = JS_AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
+ JS_InitStandardClasses(cx, jsdc->glob);
+ }
+ if( ! ok )
+ goto label_newJSDContext_failure;
+
+ jsdc->data = NULL;
+ jsdc->inited = JS_TRUE;
+
+ JSD_LOCK();
+ JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
+ JSD_UNLOCK();
+
+ return jsdc;
+
+label_newJSDContext_failure:
+ if( jsdc ) {
+ if ( jsdc->glob )
+ JS_RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
+ jsd_DestroyObjectManager(jsdc);
+ jsd_DestroyAtomTable(jsdc);
+ free(jsdc);
+ }
+ return NULL;
+}
+
+static void
+_destroyJSDContext(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+
+ JSD_LOCK();
+ JS_REMOVE_LINK(&jsdc->links);
+ JSD_UNLOCK();
+
+ if ( jsdc->glob ) {
+ JS_RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
+ }
+ jsd_DestroyObjectManager(jsdc);
+ jsd_DestroyAtomTable(jsdc);
+
+ jsdc->inited = JS_FALSE;
+
+ /*
+ * We should free jsdc here, but we let it leak in case there are any
+ * asynchronous hooks calling into the system using it as a handle
+ *
+ * XXX we also leak the locks
+ */
+}
+
+/***************************************************************************/
+
+JSDContext*
+jsd_DebuggerOnForUser(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user,
+ JSObject* scopeobj)
+{
+ JSDContext* jsdc;
+
+ jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
+ if( ! jsdc )
+ return NULL;
+
+ /*
+ * Set hooks here. The new/destroy script hooks are on even when
+ * the debugger is paused. The destroy hook so we'll clean up
+ * internal data structures when scripts are destroyed, and the
+ * newscript hook for backwards compatibility for now. We'd like
+ * to stop doing that.
+ */
+ JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
+ JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc);
+ jsd_DebuggerUnpause(jsdc);
+#ifdef LIVEWIRE
+ LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc);
+#endif
+ if( jsdc->userCallbacks.setContext )
+ jsdc->userCallbacks.setContext(jsdc, jsdc->user);
+ return jsdc;
+}
+
+JSDContext*
+jsd_DebuggerOn(void)
+{
+ JS_ASSERT(_jsrt);
+ JS_ASSERT(_validateUserCallbacks(&_callbacks));
+ return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, NULL);
+}
+
+void
+jsd_DebuggerOff(JSDContext* jsdc)
+{
+ jsd_DebuggerPause(jsdc, JS_TRUE);
+ /* clear hooks here */
+ JS_SetNewScriptHookProc(jsdc->jsrt, NULL, NULL);
+ JS_SetDestroyScriptHookProc(jsdc->jsrt, NULL, NULL);
+#ifdef LIVEWIRE
+ LWDBG_SetNewScriptHookProc(NULL,NULL);
+#endif
+
+ /* clean up */
+ JSD_LockScriptSubsystem(jsdc);
+ jsd_DestroyScriptManager(jsdc);
+ JSD_UnlockScriptSubsystem(jsdc);
+ jsd_DestroyAllSources(jsdc);
+
+ _destroyJSDContext(jsdc);
+
+ if( jsdc->userCallbacks.setContext )
+ jsdc->userCallbacks.setContext(NULL, jsdc->user);
+}
+
+void
+jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff)
+{
+ JS_SetDebuggerHandler(jsdc->jsrt, NULL, NULL);
+ if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) {
+ JS_SetExecuteHook(jsdc->jsrt, NULL, NULL);
+ JS_SetCallHook(jsdc->jsrt, NULL, NULL);
+ }
+ JS_SetThrowHook(jsdc->jsrt, NULL, NULL);
+ JS_SetDebugErrorHook(jsdc->jsrt, NULL, NULL);
+}
+
+static JSBool
+jsd_DebugErrorHook(JSContext *cx, const char *message,
+ JSErrorReport *report, void *closure);
+
+void
+jsd_DebuggerUnpause(JSDContext* jsdc)
+{
+ JS_SetDebuggerHandler(jsdc->jsrt, jsd_DebuggerHandler, jsdc);
+ JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
+ JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
+ JS_SetThrowHook(jsdc->jsrt, jsd_ThrowHandler, jsdc);
+ JS_SetDebugErrorHook(jsdc->jsrt, jsd_DebugErrorHook, jsdc);
+}
+
+void
+jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
+{
+ _jsrt = jsrt;
+ _user = user;
+
+#ifdef JSD_HAS_DANGEROUS_THREAD
+ _dangerousThread = JSD_CURRENT_THREAD();
+#endif
+
+ if( callbacks )
+ memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
+ else
+ memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
+}
+
+void*
+jsd_SetContextPrivate(JSDContext* jsdc, void *data)
+{
+ jsdc->data = data;
+ return data;
+}
+
+void*
+jsd_GetContextPrivate(JSDContext* jsdc)
+{
+ return jsdc->data;
+}
+
+void
+jsd_ClearAllProfileData(JSDContext* jsdc)
+{
+ JSDScript *current;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ current = (JSDScript *)jsdc->scripts.next;
+ while (current != (JSDScript *)&jsdc->scripts)
+ {
+ jsd_ClearScriptProfileData(jsdc, current);
+ current = (JSDScript *)current->links.next;
+ }
+
+ JSD_UNLOCK_SCRIPTS(jsdc);
+}
+
+JSDContext*
+jsd_JSDContextForJSContext(JSContext* context)
+{
+ JSDContext* iter;
+ JSDContext* jsdc = NULL;
+ JSRuntime* runtime = JS_GetRuntime(context);
+
+ JSD_LOCK();
+ for( iter = (JSDContext*)_jsd_context_list.next;
+ iter != (JSDContext*)&_jsd_context_list;
+ iter = (JSDContext*)iter->links.next )
+ {
+ if( runtime == iter->jsrt )
+ {
+ jsdc = iter;
+ break;
+ }
+ }
+ JSD_UNLOCK();
+ return jsdc;
+}
+
+static JSBool
+jsd_DebugErrorHook(JSContext *cx, const char *message,
+ JSErrorReport *report, void *closure)
+{
+ JSDContext* jsdc = (JSDContext*) closure;
+ JSD_ErrorReporter errorReporter;
+ void* errorReporterData;
+
+ if( ! jsdc )
+ {
+ JS_ASSERT(0);
+ return JS_TRUE;
+ }
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return JS_TRUE;
+
+ /* local in case hook gets cleared on another thread */
+ JSD_LOCK();
+ errorReporter = jsdc->errorReporter;
+ errorReporterData = jsdc->errorReporterData;
+ JSD_UNLOCK();
+
+ if(!errorReporter)
+ return JS_TRUE;
+
+ switch(errorReporter(jsdc, cx, message, report, errorReporterData))
+ {
+ case JSD_ERROR_REPORTER_PASS_ALONG:
+ return JS_TRUE;
+ case JSD_ERROR_REPORTER_RETURN:
+ return JS_FALSE;
+ case JSD_ERROR_REPORTER_DEBUG:
+ {
+ jsval rval;
+ JSD_ExecutionHookProc hook;
+ void* hookData;
+
+ /* local in case hook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->debugBreakHook;
+ hookData = jsdc->debugBreakHookData;
+ JSD_UNLOCK();
+
+ jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
+ hook, hookData, &rval);
+ /* XXX Should make this dependent on ExecutionHook retval */
+ return JS_TRUE;
+ }
+ case JSD_ERROR_REPORTER_CLEAR_RETURN:
+ if(report && JSREPORT_IS_EXCEPTION(report->flags))
+ JS_ClearPendingException(cx);
+ return JS_FALSE;
+ default:
+ JS_ASSERT(0);
+ break;
+ }
+ return JS_TRUE;
+}
+
+JSBool
+jsd_SetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter reporter,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->errorReporter = reporter;
+ jsdc->errorReporterData = callerdata;
+ JSD_UNLOCK();
+ return JS_TRUE;
+}
+
+JSBool
+jsd_GetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter* reporter,
+ void** callerdata)
+{
+ JSD_LOCK();
+ if( reporter )
+ *reporter = jsdc->errorReporter;
+ if( callerdata )
+ *callerdata = jsdc->errorReporterData;
+ JSD_UNLOCK();
+ return JS_TRUE;
+}
diff --git a/js/jsd/jsd_hook.cpp b/js/jsd/jsd_hook.cpp
new file mode 100644
index 0000000..95e6318
--- /dev/null
+++ b/js/jsd/jsd_hook.cpp
@@ -0,0 +1,332 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Hook support
+ */
+
+#include "jsd.h"
+
+JSTrapStatus
+jsd_InterruptHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
+ void *closure)
+{
+ JSDScript* jsdscript;
+ JSDContext* jsdc = (JSDContext*) closure;
+ JSD_ExecutionHookProc hook;
+ void* hookData;
+
+ if( ! jsdc || ! jsdc->inited )
+ return JSTRAP_CONTINUE;
+
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return JSTRAP_CONTINUE;
+
+ /* local in case jsdc->interruptHook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->interruptHook;
+ hookData = jsdc->interruptHookData;
+ JSD_UNLOCK();
+
+ if (!hook)
+ return JSTRAP_CONTINUE;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr());
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if( ! jsdscript )
+ return JSTRAP_CONTINUE;
+
+#ifdef LIVEWIRE
+ if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (uintptr_t)pc) )
+ return JSTRAP_CONTINUE;
+#endif
+
+ return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_INTERRUPTED,
+ hook, hookData, rval);
+}
+
+JSTrapStatus
+jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
+ jsval *rval, void *closure)
+{
+ JSDScript* jsdscript;
+ JSDContext* jsdc = (JSDContext*) closure;
+ JSD_ExecutionHookProc hook;
+ void* hookData;
+
+ if( ! jsdc || ! jsdc->inited )
+ return JSTRAP_CONTINUE;
+
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return JSTRAP_CONTINUE;
+
+ /* local in case jsdc->debuggerHook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->debuggerHook;
+ hookData = jsdc->debuggerHookData;
+ JSD_UNLOCK();
+ if(!hook)
+ return JSTRAP_CONTINUE;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr());
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if( ! jsdscript )
+ return JSTRAP_CONTINUE;
+
+ return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUGGER_KEYWORD,
+ hook, hookData, rval);
+}
+
+
+JSTrapStatus
+jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
+ jsval *rval, void *closure)
+{
+ JSDScript* jsdscript;
+ JSDContext* jsdc = (JSDContext*) closure;
+ JSD_ExecutionHookProc hook;
+ void* hookData;
+
+ if( ! jsdc || ! jsdc->inited )
+ return JSTRAP_CONTINUE;
+
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return JSTRAP_CONTINUE;
+
+ /* local in case jsdc->throwHook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->throwHook;
+ hookData = jsdc->throwHookData;
+ JSD_UNLOCK();
+ if (!hook)
+ return JSTRAP_CONTINUE;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr());
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if( ! jsdscript )
+ return JSTRAP_CONTINUE;
+
+ JS_GetPendingException(cx, rval);
+
+ return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_THROW,
+ hook, hookData, rval);
+}
+
+JSTrapStatus
+jsd_CallExecutionHook(JSDContext* jsdc,
+ JSContext *cx,
+ unsigned type,
+ JSD_ExecutionHookProc hook,
+ void* hookData,
+ jsval* rval)
+{
+ unsigned hookanswer = JSD_HOOK_THROW == type ?
+ JSD_HOOK_RETURN_CONTINUE_THROW :
+ JSD_HOOK_RETURN_CONTINUE;
+ JSDThreadState* jsdthreadstate;
+
+ if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc,cx)))
+ {
+ if ((type != JSD_HOOK_THROW && type != JSD_HOOK_INTERRUPTED) ||
+ jsdc->flags & JSD_MASK_TOP_FRAME_ONLY ||
+ !(jsdthreadstate->flags & TS_HAS_DISABLED_FRAME))
+ {
+ /*
+ * if it's not a throw and it's not an interrupt,
+ * or we're only masking the top frame,
+ * or there are no disabled frames in this stack,
+ * then call out.
+ */
+ hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval);
+ jsd_DestroyThreadState(jsdc, jsdthreadstate);
+ }
+ }
+
+ switch(hookanswer)
+ {
+ case JSD_HOOK_RETURN_ABORT:
+ case JSD_HOOK_RETURN_HOOK_ERROR:
+ return JSTRAP_ERROR;
+ case JSD_HOOK_RETURN_RET_WITH_VAL:
+ return JSTRAP_RETURN;
+ case JSD_HOOK_RETURN_THROW_WITH_VAL:
+ return JSTRAP_THROW;
+ case JSD_HOOK_RETURN_CONTINUE:
+ break;
+ case JSD_HOOK_RETURN_CONTINUE_THROW:
+ /* only makes sense for jsd_ThrowHandler (which init'd rval) */
+ JS_ASSERT(JSD_HOOK_THROW == type);
+ return JSTRAP_THROW;
+ default:
+ JS_ASSERT(0);
+ break;
+ }
+ return JSTRAP_CONTINUE;
+}
+
+JSBool
+jsd_CallCallHook (JSDContext* jsdc,
+ JSContext *cx,
+ unsigned type,
+ JSD_CallHookProc hook,
+ void* hookData)
+{
+ JSBool hookanswer;
+ JSDThreadState* jsdthreadstate;
+
+ hookanswer = JS_FALSE;
+ if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc, cx)))
+ {
+ hookanswer = hook(jsdc, jsdthreadstate, type, hookData);
+ jsd_DestroyThreadState(jsdc, jsdthreadstate);
+ }
+
+ return hookanswer;
+}
+
+JSBool
+jsd_SetInterruptHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->interruptHookData = callerdata;
+ jsdc->interruptHook = hook;
+ JS_SetInterrupt(jsdc->jsrt, jsd_InterruptHandler, (void*) jsdc);
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearInterruptHook(JSDContext* jsdc)
+{
+ JSD_LOCK();
+ JS_ClearInterrupt(jsdc->jsrt, NULL, NULL );
+ jsdc->interruptHook = NULL;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_SetDebugBreakHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->debugBreakHookData = callerdata;
+ jsdc->debugBreakHook = hook;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearDebugBreakHook(JSDContext* jsdc)
+{
+ JSD_LOCK();
+ jsdc->debugBreakHook = NULL;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_SetDebuggerHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->debuggerHookData = callerdata;
+ jsdc->debuggerHook = hook;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearDebuggerHook(JSDContext* jsdc)
+{
+ JSD_LOCK();
+ jsdc->debuggerHook = NULL;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_SetThrowHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->throwHookData = callerdata;
+ jsdc->throwHook = hook;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearThrowHook(JSDContext* jsdc)
+{
+ JSD_LOCK();
+ jsdc->throwHook = NULL;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_SetFunctionHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->functionHookData = callerdata;
+ jsdc->functionHook = hook;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearFunctionHook(JSDContext* jsdc)
+{
+ JSD_LOCK();
+ jsdc->functionHook = NULL;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_SetTopLevelHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->toplevelHookData = callerdata;
+ jsdc->toplevelHook = hook;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearTopLevelHook(JSDContext* jsdc)
+{
+ JSD_LOCK();
+ jsdc->toplevelHook = NULL;
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
diff --git a/js/jsd/jsd_java.cpp b/js/jsd/jsd_java.cpp
new file mode 100644
index 0000000..c5c0aec
--- /dev/null
+++ b/js/jsd/jsd_java.cpp
@@ -0,0 +1,779 @@
+/* -*- 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/. */
+
+/* this is all going away... replaced by code in js/jsd/java */
+
+#if 0
+
+#include "native.h"
+#include "jsdebug.h"
+
+#include "_gen/netscape_jsdebug_DebugController.h"
+#include "_gen/netscape_jsdebug_Script.h"
+#include "_gen/netscape_jsdebug_JSThreadState.h"
+#include "_gen/netscape_jsdebug_JSStackFrameInfo.h"
+#include "_gen/netscape_jsdebug_JSPC.h"
+#include "_gen/netscape_jsdebug_JSSourceTextProvider.h"
+#include "_gen/netscape_jsdebug_JSErrorReporter.h"
+
+static JSDContext* context = 0;
+static struct Hnetscape_jsdebug_DebugController* controller = 0;
+
+/***************************************************************************/
+/* helpers */
+
+static JHandle*
+_constructInteger(ExecEnv *ee, long i)
+{
+ return (JHandle*)
+ execute_java_constructor(ee, "java/lang/Integer", 0, "(I)", i);
+}
+
+static JHandle*
+_putHash(ExecEnv *ee, JHandle* tbl, JHandle* key, JHandle* ob)
+{
+ return (JHandle*)
+ execute_java_dynamic_method(
+ ee, tbl, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+ key, ob );
+}
+
+static JHandle*
+_getHash(ExecEnv *ee, JHandle* tbl, JHandle* key)
+{
+ return (JHandle*)
+ execute_java_dynamic_method(
+ ee, tbl, "get",
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ key );
+}
+
+static JHandle*
+_removeHash(ExecEnv *ee, JHandle* tbl, JHandle* key)
+{
+ return (JHandle*)
+ execute_java_dynamic_method(
+ ee, tbl, "remove",
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ key );
+}
+
+struct Hnetscape_jsdebug_JSStackFrameInfo*
+_constructJSStackFrameInfo( ExecEnv* ee, JSDStackFrameInfo* jsdframe,
+ struct Hnetscape_jsdebug_JSThreadState* threadState )
+{
+ struct Hnetscape_jsdebug_JSStackFrameInfo* frame;
+
+ frame = (struct Hnetscape_jsdebug_JSStackFrameInfo*)
+ execute_java_constructor( ee, "netscape/jsdebug/JSStackFrameInfo", 0,
+ "(Lnetscape/jsdebug/JSThreadState;)",
+ threadState );
+ if( ! frame )
+ return NULL;
+
+ /* XXX fill in additional fields */
+ unhand(frame)->_nativePtr = (long) jsdframe;
+
+ return frame;
+}
+
+struct Hnetscape_jsdebug_JSPC*
+_constructJSPC( ExecEnv* ee, struct Hnetscape_jsdebug_Script* script, long pc )
+{
+ struct Hnetscape_jsdebug_JSPC * pcOb;
+
+ pcOb = (struct Hnetscape_jsdebug_JSPC *)
+ execute_java_constructor( ee, "netscape/jsdebug/JSPC", 0,
+ "(Lnetscape/jsdebug/Script;I)",
+ script, pc );
+ if( ! pcOb )
+ return NULL;
+
+ /* XXX fill in additional fields */
+
+ return pcOb;
+}
+
+static Hnetscape_jsdebug_Script*
+_scriptObFromJSDScriptPtr( ExecEnv* ee, JSDScript* jsdscript )
+{
+ JHandle* tbl = (JHandle*) unhand(controller)->scriptTable;
+ JHandle* key = _constructInteger(ee,(long)jsdscript);
+ return (Hnetscape_jsdebug_Script*) _getHash( ee, tbl, key );
+}
+
+/***************************************************************************/
+
+void
+_scriptHook( JSDContext* jsdc,
+ JSDScript* jsdscript,
+ JSBool creating,
+ void* callerdata )
+{
+ Hnetscape_jsdebug_Script* script;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return;
+
+ if( creating )
+ {
+ char* url = (char*)JSD_GetScriptFilename (jsdc, jsdscript);
+ JSString* function = JSD_GetScriptFunctionId (jsdc, jsdscript);
+ int base = JSD_GetScriptBaseLineNumber (jsdc, jsdscript);
+ int extent = JSD_GetScriptLineExtent (jsdc, jsdscript);
+
+ if( ! url )
+ {
+ return;
+ /* url = ""; */
+ }
+
+ /* create Java Object for Script */
+ script = (Hnetscape_jsdebug_Script*)
+ execute_java_constructor(ee, "netscape/jsdebug/Script", 0, "()");
+
+ if( ! script )
+ return;
+
+ /* set the members */
+ unhand(script)->_url = makeJavaString(url,strlen(url));
+ unhand(script)->_function = function ? makeJavaString(function,strlen(function)) : 0;
+ unhand(script)->_baseLineNumber = base;
+ unhand(script)->_lineExtent = extent;
+ unhand(script)->_nativePtr = (long)jsdscript;
+
+ /* add it to the hash table */
+ _putHash( ee, (JHandle*) unhand(controller)->scriptTable,
+ _constructInteger(ee, (long)jsdscript), (JHandle*)script );
+
+ /* call the hook */
+ if( unhand(controller)->scriptHook )
+ {
+ execute_java_dynamic_method( ee,(JHandle*)unhand(controller)->scriptHook,
+ "justLoadedScript",
+ "(Lnetscape/jsdebug/Script;)V",
+ script );
+ }
+ }
+ else
+ {
+ JHandle* tbl = (JHandle*) unhand(controller)->scriptTable;
+ JHandle* key = _constructInteger(ee,(long)jsdscript);
+
+ /* find Java Object for Script */
+ script = (Hnetscape_jsdebug_Script*) _getHash( ee, tbl, key );
+
+ if( ! script )
+ return;
+
+ /* remove it from the hash table */
+ _removeHash( ee, tbl, key );
+
+ /* call the hook */
+ if( unhand(controller)->scriptHook )
+ {
+ execute_java_dynamic_method( ee,(JHandle*)unhand(controller)->scriptHook,
+ "aboutToUnloadScript",
+ "(Lnetscape/jsdebug/Script;)V",
+ script );
+ }
+ /* set the Script as invalid */
+ execute_java_dynamic_method( ee,(JHandle*)script,
+ "_setInvalid",
+ "()V" );
+ }
+}
+
+/***************************************************************************/
+unsigned
+_executionHook( JSDContext* jsdc,
+ JSDThreadState* jsdstate,
+ unsigned type,
+ void* callerdata )
+{
+ Hnetscape_jsdebug_JSThreadState* threadState;
+ Hnetscape_jsdebug_Script* script;
+ JHandle* pcOb;
+ JSDStackFrameInfo* jsdframe;
+ JSDScript* jsdscript;
+ int pc;
+ JHandle* tblScript;
+ JHandle* keyScript;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* get the JSDStackFrameInfo */
+ jsdframe = JSD_GetStackFrame(jsdc, jsdstate);
+ if( ! jsdframe )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* get the JSDScript */
+ jsdscript = JSD_GetScriptForStackFrame(jsdc, jsdstate, jsdframe);
+ if( ! jsdscript )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* find Java Object for Script */
+ tblScript = (JHandle*) unhand(controller)->scriptTable;
+ keyScript = _constructInteger(ee, (long)jsdscript);
+ script = (Hnetscape_jsdebug_Script*) _getHash( ee, tblScript, keyScript );
+ if( ! script )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* generate a JSPC */
+ pc = JSD_GetPCForStackFrame(jsdc, jsdstate, jsdframe);
+
+ pcOb = (JHandle*)
+ _constructJSPC(ee, script, pc);
+ if( ! pcOb )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* build a JSThreadState */
+ threadState = (struct Hnetscape_jsdebug_JSThreadState*)
+ execute_java_constructor( ee, "netscape/jsdebug/JSThreadState",0,"()");
+ if( ! threadState )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* populate the ThreadState */
+ /* XXX FILL IN THE REST... */
+ unhand(threadState)->valid = 1; /* correct value for true? */
+ unhand(threadState)->currentFramePtr = (long) jsdframe;
+ unhand(threadState)->nativeThreadState = (long) jsdstate;
+ unhand(threadState)->continueState = netscape_jsdebug_JSThreadState_DEBUG_STATE_RUN;
+
+ /* XXX FILL IN THE REST... */
+
+
+ /* find and call the appropriate Hook */
+ if( JSD_HOOK_INTERRUPTED == type )
+ {
+ JHandle* hook;
+
+ /* clear the JSD level hook (must reset on next sendInterrupt0()*/
+ JSD_ClearInterruptHook(context);
+
+ hook = (JHandle*) unhand(controller)->interruptHook;
+ if( ! hook )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* call the hook */
+ execute_java_dynamic_method(
+ ee, hook, "aboutToExecute",
+ "(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V",
+ threadState, pcOb );
+ }
+ else if( JSD_HOOK_DEBUG_REQUESTED == type )
+ {
+ JHandle* hook;
+
+ hook = (JHandle*) unhand(controller)->debugBreakHook;
+ if( ! hook )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* call the hook */
+ execute_java_dynamic_method(
+ ee, hook, "aboutToExecute",
+ "(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V",
+ threadState, pcOb );
+ }
+ else if( JSD_HOOK_BREAKPOINT == type )
+ {
+ JHandle* hook;
+
+ hook = (JHandle*)
+ execute_java_dynamic_method(
+ ee,(JHandle*)controller,
+ "getInstructionHook0",
+ "(Lnetscape/jsdebug/PC;)Lnetscape/jsdebug/InstructionHook;",
+ pcOb );
+ if( ! hook )
+ return JSD_HOOK_RETURN_HOOK_ERROR;
+
+ /* call the hook */
+ execute_java_dynamic_method(
+ ee, hook, "aboutToExecute",
+ "(Lnetscape/jsdebug/ThreadStateBase;)V",
+ threadState );
+ }
+
+ if( netscape_jsdebug_JSThreadState_DEBUG_STATE_THROW ==
+ unhand(threadState)->continueState )
+ return JSD_HOOK_RETURN_ABORT;
+
+ return JSD_HOOK_RETURN_CONTINUE;
+}
+
+unsigned
+_errorReporter( JSDContext* jsdc,
+ JSContext* cx,
+ const char* message,
+ JSErrorReport* report,
+ void* callerdata )
+{
+ JHandle* reporter;
+ JHandle* msg = NULL;
+ JHandle* filename = NULL;
+ int lineno = 0;
+ JHandle* linebuf = NULL;
+ int tokenOffset = 0;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return JSD_ERROR_REPORTER_PASS_ALONG;
+
+ reporter = (JHandle*) unhand(controller)->errorReporter;
+ if( ! reporter )
+ return JSD_ERROR_REPORTER_PASS_ALONG;
+
+ if( message )
+ msg = (JHandle*) makeJavaString((char*)message, strlen(message));
+ if( report && report->filename )
+ filename = (JHandle*) makeJavaString((char*)report->filename, strlen(report->filename));
+ if( report && report->linebuf )
+ linebuf = (JHandle*) makeJavaString((char*)report->linebuf, strlen(report->linebuf));
+ if( report )
+ lineno = report->lineno;
+ if( report && report->linebuf && report->tokenptr )
+ tokenOffset = report->tokenptr - report->linebuf;
+
+ return (int)
+ execute_java_dynamic_method(
+ ee, reporter, "reportError",
+ "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)I",
+ msg,
+ filename,
+ lineno,
+ linebuf,
+ tokenOffset );
+}
+
+/***************************************************************************/
+/* from "_gen\netscape_jsdebug_DebugController.h" */
+
+
+/* XXX HACK */
+JSDContext* _simContext = 0;
+
+void netscape_jsdebug_DebugController__setController(struct Hnetscape_jsdebug_DebugController * self,/*boolean*/ long on)
+{
+ if(on)
+ {
+ context = JSD_DebuggerOn();
+ if( ! context )
+ return;
+
+ _simContext = context; /* XXX HACK */
+
+ unhand(self)->_nativeContext = (long) context;
+ controller = self;
+ JSD_SetScriptHook(context, _scriptHook, (void*)1 );
+ JSD_SetErrorReporter(context, _errorReporter, (void*)1 );
+ JSD_SetDebugBreakHook(context, _executionHook, (void*)1 );
+ }
+ else
+ {
+ /* XXX stop somehow... */
+ /* kill context */
+ JSD_SetDebugBreakHook(context, NULL, NULL );
+ JSD_SetErrorReporter(context, NULL, NULL);
+ JSD_SetScriptHook(context, NULL, NULL);
+ context = 0;
+ controller = 0;
+ }
+}
+
+void netscape_jsdebug_DebugController_setInstructionHook0(struct Hnetscape_jsdebug_DebugController * self,struct Hnetscape_jsdebug_PC * pcOb)
+{
+ Hnetscape_jsdebug_Script* script;
+ JSDScript* jsdscript;
+ unsigned pc;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return;
+
+ script = (Hnetscape_jsdebug_Script*)
+ execute_java_dynamic_method(ee, (JHandle*)pcOb, "getScript","()Lnetscape/jsdebug/Script;");
+
+ if( ! script )
+ return;
+
+ jsdscript = (JSDScript*) unhand(script)->_nativePtr;
+ if( ! jsdscript )
+ return;
+
+ pc = (unsigned)
+ execute_java_dynamic_method(ee, (JHandle*)pcOb, "getPC","()I");
+
+ JSD_SetExecutionHook(context, jsdscript, pc, _executionHook, 0);
+}
+
+void netscape_jsdebug_DebugController_sendInterrupt0(struct Hnetscape_jsdebug_DebugController * self)
+{
+ if( ! context || ! controller )
+ return;
+ JSD_SetInterruptHook(context, _executionHook, 0);
+}
+
+struct Hjava_lang_String *netscape_jsdebug_DebugController_executeScriptInStackFrame0(struct Hnetscape_jsdebug_DebugController *self,struct Hnetscape_jsdebug_JSStackFrameInfo *frame,struct Hjava_lang_String *src,struct Hjava_lang_String *filename,long lineno)
+{
+ struct Hnetscape_jsdebug_JSThreadState* threadStateOb;
+ JSDThreadState* jsdthreadstate;
+ JSDStackFrameInfo* jsdframe;
+ char* filenameC;
+ char* srcC;
+ JSString* jsstr;
+ jsval rval;
+ JSBool success;
+ int srclen;
+
+ threadStateOb = (struct Hnetscape_jsdebug_JSThreadState*)unhand(frame)->threadState;
+ jsdthreadstate = (JSDThreadState*) unhand(threadStateOb)->nativeThreadState;
+
+ jsdframe = (JSDStackFrameInfo*) unhand(frame)->_nativePtr;
+
+ if( ! context || ! controller || ! jsdframe )
+ return NULL;
+
+ filenameC = allocCString(filename);
+ if( ! filenameC )
+ return NULL;
+ srcC = allocCString(src);
+ if( ! srcC )
+ {
+ free(filenameC);
+ return NULL;
+ }
+
+ srclen = strlen(srcC);
+
+ success = JSD_EvaluateScriptInStackFrame(context, jsdthreadstate, jsdframe,
+ srcC, srclen,
+ filenameC, lineno, &rval);
+
+ /* XXX crashing on Windows under Symantec (though I can't see why!)*/
+
+ free(filenameC);
+ free(srcC);
+
+
+ if( ! success )
+ return NULL;
+
+ if( JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval) )
+ return NULL;
+
+ jsstr = JSD_ValToStringInStackFrame(context,jsdthreadstate,jsdframe,rval);
+ if( ! jsstr )
+ return NULL;
+
+ /* XXXbe should use JS_GetStringChars and preserve Unicode. */
+ return makeJavaString((char*)JS_GetStringBytes(jsstr), JS_GetStringLength(jsstr));
+}
+
+long netscape_jsdebug_DebugController_getNativeMajorVersion(struct Hnetscape_jsdebug_DebugController* self)
+{
+ return (long) JSD_GetMajorVersion();
+}
+
+long netscape_jsdebug_DebugController_getNativeMinorVersion(struct Hnetscape_jsdebug_DebugController* self)
+{
+ return (long) JSD_GetMinorVersion();
+}
+
+/***************************************************************************/
+/* from "_gen\netscape_jsdebug_Script.h" */
+
+struct Hnetscape_jsdebug_JSPC *netscape_jsdebug_Script_getClosestPC(struct Hnetscape_jsdebug_Script * self,long line)
+{
+ unsigned pc;
+ JSDScript* jsdscript;
+
+ if( ! context || ! controller )
+ return 0;
+
+ jsdscript = (JSDScript*) unhand(self)->_nativePtr;
+ if( ! jsdscript )
+ return 0;
+
+ pc = JSD_GetClosestPC(context, jsdscript, line);
+
+ if( -1 == pc )
+ return 0;
+ return _constructJSPC( 0, self, pc);
+}
+
+/***************************************************************************/
+/* from "_gen\netscape_jsdebug_JSThreadState.h" */
+
+long netscape_jsdebug_JSThreadState_countStackFrames(struct Hnetscape_jsdebug_JSThreadState * self)
+{
+ JSDThreadState* jsdstate;
+
+ if( ! context || ! controller )
+ return 0;
+
+ jsdstate = (JSDThreadState*) unhand(self)->nativeThreadState;
+
+ if( ! jsdstate )
+ return 0;
+
+ return (long) JSD_GetCountOfStackFrames(context, jsdstate);
+}
+
+struct Hnetscape_jsdebug_StackFrameInfo *netscape_jsdebug_JSThreadState_getCurrentFrame(struct Hnetscape_jsdebug_JSThreadState * self)
+{
+ JSDThreadState* jsdstate;
+ JSDStackFrameInfo* jsdframe;
+
+ if( ! context || ! controller )
+ return NULL;
+
+ jsdstate = (JSDThreadState*) unhand(self)->nativeThreadState;
+
+ if( ! jsdstate )
+ return NULL;
+
+ jsdframe = JSD_GetStackFrame(context, jsdstate);
+ if( ! jsdframe )
+ return NULL;
+
+ return (struct Hnetscape_jsdebug_StackFrameInfo*)
+ _constructJSStackFrameInfo( 0, jsdframe, self );
+}
+
+
+/***************************************************************************/
+/* from "_gen\netscape_jsdebug_JSStackFrameInfo.h" */
+
+struct Hnetscape_jsdebug_StackFrameInfo *netscape_jsdebug_JSStackFrameInfo_getCaller0(struct Hnetscape_jsdebug_JSStackFrameInfo * self)
+{
+ JSDStackFrameInfo* jsdframeCur;
+ JSDStackFrameInfo* jsdframeCaller;
+ struct Hnetscape_jsdebug_JSThreadState* threadState;
+ JSDThreadState* jsdthreadstate;
+
+ if( ! context || ! controller )
+ return NULL;
+
+ jsdframeCur = (JSDStackFrameInfo*) unhand(self)->_nativePtr;
+ if( ! jsdframeCur )
+ return NULL;
+
+ threadState = (struct Hnetscape_jsdebug_JSThreadState*) unhand(self)->threadState;
+ if( ! threadState )
+ return NULL;
+
+ jsdthreadstate = (JSDThreadState*) unhand(threadState)->nativeThreadState;
+ if( ! jsdthreadstate )
+ return NULL;
+
+ jsdframeCaller = JSD_GetCallingStackFrame(context, jsdthreadstate, jsdframeCur);
+ if( ! jsdframeCaller )
+ return NULL;
+
+ return (struct Hnetscape_jsdebug_StackFrameInfo*)
+ _constructJSStackFrameInfo( 0, jsdframeCaller, threadState );
+}
+struct Hnetscape_jsdebug_PC *netscape_jsdebug_JSStackFrameInfo_getPC(struct Hnetscape_jsdebug_JSStackFrameInfo * self)
+{
+ JSDScript* jsdscript;
+ JSDStackFrameInfo* jsdframe;
+ struct Hnetscape_jsdebug_Script* script;
+ struct Hnetscape_jsdebug_JSThreadState* threadState;
+ JSDThreadState* jsdthreadstate;
+ int pc;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return NULL;
+
+ jsdframe = (JSDStackFrameInfo*) unhand(self)->_nativePtr;
+ if( ! jsdframe )
+ return NULL;
+
+ threadState = (struct Hnetscape_jsdebug_JSThreadState*) unhand(self)->threadState;
+ if( ! threadState )
+ return NULL;
+
+ jsdthreadstate = (JSDThreadState*) unhand(threadState)->nativeThreadState;
+ if( ! jsdthreadstate )
+ return NULL;
+
+ jsdscript = JSD_GetScriptForStackFrame(context, jsdthreadstate, jsdframe );
+ if( ! jsdscript )
+ return NULL;
+
+ script = _scriptObFromJSDScriptPtr(ee, jsdscript);
+ if( ! script )
+ return NULL;
+
+ pc = JSD_GetPCForStackFrame(context, jsdthreadstate, jsdframe);
+ if( ! pc )
+ return NULL;
+
+ return (struct Hnetscape_jsdebug_PC*) _constructJSPC(ee, script, pc);
+}
+
+/***************************************************************************/
+/* from "_gen\netscape_jsdebug_JSPC.h" */
+
+struct Hnetscape_jsdebug_SourceLocation *netscape_jsdebug_JSPC_getSourceLocation(struct Hnetscape_jsdebug_JSPC * self)
+{
+ JSDScript* jsdscript;
+ struct Hnetscape_jsdebug_Script* script;
+ struct Hnetscape_jsdebug_JSPC* newPCOb;
+ int line;
+ int newpc;
+ int pc;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return NULL;
+
+ script = unhand(self)->script;
+
+ if( ! script )
+ return NULL;
+
+ jsdscript = (JSDScript*) unhand(script)->_nativePtr;
+ if( ! jsdscript )
+ return NULL;
+ pc = unhand(self)->pc;
+
+ line = JSD_GetClosestLine(context, jsdscript, pc);
+ newpc = JSD_GetClosestPC(context, jsdscript, line);
+
+ newPCOb = _constructJSPC(ee, script, newpc );
+ if( ! newPCOb )
+ return NULL;
+
+ return (struct Hnetscape_jsdebug_SourceLocation *)
+ execute_java_constructor( ee, "netscape/jsdebug/JSSourceLocation", 0,
+ "(Lnetscape/jsdebug/JSPC;I)",
+ newPCOb, line );
+}
+
+/***************************************************************************/
+/* from "_gen\netscape_jsdebug_JSSourceTextProvider.h" */
+
+struct Hnetscape_jsdebug_SourceTextItem *netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem0(struct Hnetscape_jsdebug_JSSourceTextProvider * self,struct Hjava_lang_String * url)
+{
+ /* this should attempt to load the source for the indicated URL */
+ return NULL;
+}
+
+void netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector(struct Hnetscape_jsdebug_JSSourceTextProvider * self)
+{
+
+ JHandle* vec;
+ JHandle* itemOb;
+ JSDSourceText* iterp = 0;
+ JSDSourceText* item;
+ const char* url;
+ struct Hjava_lang_String* urlOb;
+ ExecEnv* ee = EE();
+
+ if( ! context || ! controller || ! ee )
+ return;
+
+ /* create new vector */
+ vec = (JHandle*) execute_java_constructor(ee, "netscape/util/Vector", 0, "()");
+ if( ! vec )
+ return;
+
+ /* lock the native subsystem */
+ JSD_LockSourceTextSubsystem(context);
+
+ /* iterate through the native items */
+ while( 0 != (item = JSD_IterateSources(context, &iterp)) )
+ {
+ int urlStrLen;
+ int status = JSD_GetSourceStatus(context,item);
+
+ /* try to find Java object */
+ url = JSD_GetSourceURL(context, item);
+ if( ! url || 0 == (urlStrLen = strlen(url)) ) /* ignoring those with no url */
+ continue;
+
+ urlOb = makeJavaString((char*)url,urlStrLen);
+ if( ! urlOb )
+ continue;
+
+ itemOb = (JHandle*)
+ execute_java_dynamic_method( ee, (JHandle*)self, "findSourceTextItem0",
+ "(Ljava/lang/String;)Lnetscape/jsdebug/SourceTextItem;",
+ urlOb );
+
+ if( ! itemOb )
+ {
+ /* if not found then generate new item */
+ struct Hjava_lang_String* textOb;
+ const char* str;
+ int length;
+
+ if( ! JSD_GetSourceText(context, item, &str, &length ) )
+ {
+ str = "";
+ length = 0;
+ }
+ textOb = makeJavaString((char*)str, length);
+
+ itemOb = (JHandle*)
+ execute_java_constructor(ee, "netscape/jsdebug/SourceTextItem",0,
+ "(Ljava/lang/String;Ljava/lang/String;I)",
+ urlOb, textOb, status );
+ }
+ else if( JSD_IsSourceDirty(context, item) &&
+ JSD_SOURCE_CLEARED != status )
+ {
+ /* if found and dirty then update */
+ struct Hjava_lang_String* textOb;
+ const char* str;
+ int length;
+
+ if( ! JSD_GetSourceText(context, item, &str, &length ) )
+ {
+ str = "";
+ length = 0;
+ }
+ textOb = makeJavaString((char*)str, length);
+ execute_java_dynamic_method(ee, itemOb, "setText",
+ "(Ljava/lang/String;)V", textOb);
+ execute_java_dynamic_method(ee, itemOb, "setStatus",
+ "(I)V", status );
+ execute_java_dynamic_method(ee, itemOb, "setDirty", "(Z)V", 1 );
+ }
+
+ /* we have our copy; clear the native cached text */
+ if( JSD_SOURCE_INITED != status &&
+ JSD_SOURCE_PARTIAL != status &&
+ JSD_SOURCE_CLEARED != status )
+ {
+ JSD_ClearSourceText(context, item);
+ }
+
+ /* set the item clean */
+ JSD_SetSourceDirty(context, item, FALSE );
+
+ /* add the item to the vector */
+ if( itemOb )
+ execute_java_dynamic_method(ee, vec, "addElement",
+ "(Ljava/lang/Object;)V", itemOb );
+ }
+ /* unlock the native subsystem */
+ JSD_UnlockSourceTextSubsystem(context);
+
+ /* set main vector to our new vector */
+
+ unhand(self)->_sourceTextVector = (struct Hnetscape_util_Vector*) vec;
+}
+
+
+#endif
diff --git a/js/jsd/jsd_lock.cpp b/js/jsd/jsd_lock.cpp
new file mode 100644
index 0000000..9583f28
--- /dev/null
+++ b/js/jsd/jsd_lock.cpp
@@ -0,0 +1,227 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Locking and threading support
+ */
+
+/*
+* ifdef JSD_USE_NSPR_LOCKS then you must build and run against NSPR2.
+* Otherwise, there are stubs that can be filled in with your own locking
+* code. Also, note that these stubs include a jsd_CurrentThread()
+* implementation that only works on Win32 - this is needed for the inprocess
+* Java-based debugger.
+*/
+
+#include "jsd.h"
+
+#include "js/Utility.h"
+
+#ifdef JSD_THREADSAFE
+
+#ifdef JSD_USE_NSPR_LOCKS
+
+#include "prlock.h"
+#include "prthread.h"
+
+#ifdef JSD_ATTACH_THREAD_HACK
+#include "pprthred.h" /* need this as long as JS_AttachThread is needed */
+#endif
+
+struct JSDStaticLock
+{
+ void* owner;
+ PRLock* lock;
+ int count;
+#ifdef DEBUG
+ uint16_t sig;
+#endif
+};
+
+/*
+ * This exists to wrap non-NSPR theads (e.g. Java threads) in NSPR wrappers.
+ * XXX We ignore the memory leak issue.
+ * It is claimed that future versions of NSPR will automatically wrap on
+ * the call to PR_GetCurrentThread.
+ *
+ * XXX We ignore the memory leak issue - i.e. we never call PR_DetachThread.
+ *
+ */
+#undef _CURRENT_THREAD
+#ifdef JSD_ATTACH_THREAD_HACK
+#define _CURRENT_THREAD(out) \
+JS_BEGIN_MACRO \
+ out = (void*) PR_GetCurrentThread(); \
+ if(!out) \
+ out = (void*) JS_AttachThread(PR_USER_THREAD,PR_PRIORITY_NORMAL,NULL);\
+ JS_ASSERT(out); \
+JS_END_MACRO
+#else
+#define _CURRENT_THREAD(out) \
+JS_BEGIN_MACRO \
+ out = (void*) PR_GetCurrentThread(); \
+ JS_ASSERT(out); \
+JS_END_MACRO
+#endif
+
+#ifdef DEBUG
+#define JSD_LOCK_SIG 0x10CC10CC
+void ASSERT_VALID_LOCK(JSDStaticLock* lock)
+{
+ JS_ASSERT(lock);
+ JS_ASSERT(lock->lock);
+ JS_ASSERT(lock->count >= 0);
+ JS_ASSERT(lock->sig == (uint16_t) JSD_LOCK_SIG);
+}
+#else
+#define ASSERT_VALID_LOCK(x) ((void)0)
+#endif
+
+JSDStaticLock*
+jsd_CreateLock()
+{
+ JSDStaticLock* lock;
+
+ if( ! (lock = js_pod_calloc<JSDStaticLock>()) ||
+ ! (lock->lock = PR_NewLock()) )
+ {
+ if(lock)
+ {
+ free(lock);
+ lock = NULL;
+ }
+ }
+#ifdef DEBUG
+ if(lock) lock->sig = (uint16_t) JSD_LOCK_SIG;
+#endif
+ return lock;
+}
+
+void
+jsd_Lock(JSDStaticLock* lock)
+{
+ void* me;
+ ASSERT_VALID_LOCK(lock);
+ _CURRENT_THREAD(me);
+
+ if(lock->owner == me)
+ {
+ lock->count++;
+ JS_ASSERT(lock->count > 1);
+ }
+ else
+ {
+ PR_Lock(lock->lock); /* this can block... */
+ JS_ASSERT(lock->owner == 0);
+ JS_ASSERT(lock->count == 0);
+ lock->count = 1;
+ lock->owner = me;
+ }
+}
+
+void
+jsd_Unlock(JSDStaticLock* lock)
+{
+ void* me;
+ ASSERT_VALID_LOCK(lock);
+ _CURRENT_THREAD(me);
+
+ /* it's an error to unlock a lock you don't own */
+ JS_ASSERT(lock->owner == me);
+ if(lock->owner != me)
+ return;
+
+ if(--lock->count == 0)
+ {
+ lock->owner = NULL;
+ PR_Unlock(lock->lock);
+ }
+}
+
+#ifdef DEBUG
+JSBool
+jsd_IsLocked(JSDStaticLock* lock)
+{
+ void* me;
+ ASSERT_VALID_LOCK(lock);
+ _CURRENT_THREAD(me);
+ if (lock->owner != me)
+ return JS_FALSE;
+ JS_ASSERT(lock->count > 0);
+ return JS_TRUE;
+}
+#endif /* DEBUG */
+
+void*
+jsd_CurrentThread()
+{
+ void* me;
+ _CURRENT_THREAD(me);
+ return me;
+}
+
+
+#else /* ! JSD_USE_NSPR_LOCKS */
+
+#ifdef WIN32
+#pragma message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
+#pragma message("!! you are compiling the stubbed version of jsd_lock.c !!")
+#pragma message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
+#endif
+
+/*
+ * NOTE: 'Real' versions of these locks must be reentrant in the sense that
+ * they support nested calls to lock and unlock.
+ */
+
+void*
+jsd_CreateLock()
+{
+ return (void*)1;
+}
+
+void
+jsd_Lock(void* lock)
+{
+}
+
+void
+jsd_Unlock(void* lock)
+{
+}
+
+#ifdef DEBUG
+JSBool
+jsd_IsLocked(void* lock)
+{
+ return JS_TRUE;
+}
+#endif /* DEBUG */
+
+/*
+ * This Windows only thread id code is here to allow the Java-based
+ * JSDebugger to work with the single threaded js.c shell (even without
+ * real locking and threading support).
+ */
+
+#ifdef WIN32
+/* bogus (but good enough) declaration*/
+extern void* __stdcall GetCurrentThreadId(void);
+#endif
+
+void*
+jsd_CurrentThread()
+{
+#ifdef WIN32
+ return GetCurrentThreadId();
+#else
+ return (void*)1;
+#endif
+}
+
+#endif /* JSD_USE_NSPR_LOCKS */
+
+#endif /* JSD_THREADSAFE */
diff --git a/js/jsd/jsd_lock.h b/js/jsd/jsd_lock.h
new file mode 100644
index 0000000..b1e8c31
--- /dev/null
+++ b/js/jsd/jsd_lock.h
@@ -0,0 +1,43 @@
+/* -*- 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/. */
+
+/*
+ * Header for JavaScript Debugging support - Locking and threading functions
+ */
+
+#ifndef jsd_lock_h___
+#define jsd_lock_h___
+
+/*
+ * If you want to support threading and locking, define JSD_THREADSAFE and
+ * implement the functions below.
+ */
+
+/*
+ * NOTE: These locks must be reentrant in the sense that they support
+ * nested calls to lock and unlock.
+ */
+
+typedef struct JSDStaticLock JSDStaticLock;
+
+extern JSDStaticLock*
+jsd_CreateLock();
+
+extern void
+jsd_Lock(JSDStaticLock* lock);
+
+extern void
+jsd_Unlock(JSDStaticLock* lock);
+
+#ifdef DEBUG
+extern JSBool
+jsd_IsLocked(JSDStaticLock* lock);
+#endif /* DEBUG */
+
+extern void*
+jsd_CurrentThread();
+
+#endif /* jsd_lock_h___ */
diff --git a/js/jsd/jsd_obj.cpp b/js/jsd/jsd_obj.cpp
new file mode 100644
index 0000000..a27b533
--- /dev/null
+++ b/js/jsd/jsd_obj.cpp
@@ -0,0 +1,234 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Object support
+ */
+
+#include "jsd.h"
+
+/*
+* #define JSD_TRACE 1
+*/
+
+#ifdef JSD_TRACE
+#define TRACEOBJ(jsdc, jsdobj, which) _traceObj(jsdc, jsdobj, which)
+
+static char *
+_describeObj(JSDContext* jsdc, JSDObject *jsdobj)
+{
+ return
+ JS_smprintf("%0x new'd in %s at line %d using ctor %s in %s at line %d",
+ (int)jsdobj,
+ JSD_GetObjectNewURL(jsdc, jsdobj),
+ JSD_GetObjectNewLineNumber(jsdc, jsdobj),
+ JSD_GetObjectConstructorName(jsdc, jsdobj),
+ JSD_GetObjectConstructorURL(jsdc, jsdobj),
+ JSD_GetObjectConstructorLineNumber(jsdc, jsdobj));
+}
+
+static void
+_traceObj(JSDContext* jsdc, JSDObject* jsdobj, int which)
+{
+ char* description;
+
+ if( !jsdobj )
+ return;
+
+ description = _describeObj(jsdc, jsdobj);
+
+ printf("%s : %s\n",
+ which == 0 ? "new " :
+ which == 1 ? "final" :
+ "ctor ",
+ description);
+ if(description)
+ free(description);
+}
+#else
+#define TRACEOBJ(jsdc, jsdobj, which) ((void)0)
+#endif /* JSD_TRACE */
+
+#ifdef DEBUG
+void JSD_ASSERT_VALID_OBJECT(JSDObject* jsdobj)
+{
+ JS_ASSERT(jsdobj);
+ JS_ASSERT(!JS_CLIST_IS_EMPTY(&jsdobj->links));
+ JS_ASSERT(jsdobj->obj);
+}
+#endif
+
+
+static void
+_destroyJSDObject(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc));
+
+ JS_REMOVE_LINK(&jsdobj->links);
+ JS_HashTableRemove(jsdc->objectsTable, jsdobj->obj);
+
+ if(jsdobj->newURL)
+ jsd_DropAtom(jsdc, jsdobj->newURL);
+ if(jsdobj->ctorURL)
+ jsd_DropAtom(jsdc, jsdobj->ctorURL);
+ if(jsdobj->ctorName)
+ jsd_DropAtom(jsdc, jsdobj->ctorName);
+ free(jsdobj);
+}
+
+void
+jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj,
+ JSAbstractFramePtr frame)
+{
+ JSDObject* jsdobj;
+ JS::RootedScript script(cx);
+ JSDScript* jsdscript;
+ const char* ctorURL;
+ JSString* ctorNameStr;
+ const char* ctorName;
+
+ JSD_LOCK_OBJECTS(jsdc);
+ jsdobj = jsd_GetJSDObjectForJSObject(jsdc, obj);
+ if( jsdobj && !jsdobj->ctorURL )
+ {
+ script = frame.script();
+ if( script )
+ {
+ ctorURL = JS_GetScriptFilename(cx, script);
+ if( ctorURL )
+ jsdobj->ctorURL = jsd_AddAtom(jsdc, ctorURL);
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, frame);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if( jsdscript && (ctorNameStr = jsd_GetScriptFunctionId(jsdc, jsdscript)) ) {
+ if( (ctorName = JS_EncodeString(cx, ctorNameStr)) ) {
+ jsdobj->ctorName = jsd_AddAtom(jsdc, ctorName);
+ JS_free(cx, (void *) ctorName);
+ }
+ }
+ jsdobj->ctorLineno = JS_GetScriptBaseLineNumber(cx, script);
+ }
+ }
+ TRACEOBJ(jsdc, jsdobj, 3);
+ JSD_UNLOCK_OBJECTS(jsdc);
+}
+
+static JSHashNumber
+_hash_root(const void *key)
+{
+ return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
+}
+
+JSBool
+jsd_InitObjectManager(JSDContext* jsdc)
+{
+ JS_INIT_CLIST(&jsdc->objectsList);
+ jsdc->objectsTable = JS_NewHashTable(256, _hash_root,
+ JS_CompareValues, JS_CompareValues,
+ NULL, NULL);
+ return !!jsdc->objectsTable;
+}
+
+void
+jsd_DestroyObjectManager(JSDContext* jsdc)
+{
+ jsd_DestroyObjects(jsdc);
+ JSD_LOCK_OBJECTS(jsdc);
+ JS_HashTableDestroy(jsdc->objectsTable);
+ JSD_UNLOCK_OBJECTS(jsdc);
+}
+
+void
+jsd_DestroyObjects(JSDContext* jsdc)
+{
+ JSD_LOCK_OBJECTS(jsdc);
+ while( !JS_CLIST_IS_EMPTY(&jsdc->objectsList) )
+ _destroyJSDObject(jsdc, (JSDObject*)JS_NEXT_LINK(&jsdc->objectsList));
+ JSD_UNLOCK_OBJECTS(jsdc);
+}
+
+JSDObject*
+jsd_IterateObjects(JSDContext* jsdc, JSDObject** iterp)
+{
+ JSDObject *jsdobj = *iterp;
+
+ JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc));
+
+ if( !jsdobj )
+ jsdobj = (JSDObject *)jsdc->objectsList.next;
+ if( jsdobj == (JSDObject *)&jsdc->objectsList )
+ return NULL;
+ *iterp = (JSDObject*) jsdobj->links.next;
+ return jsdobj;
+}
+
+JSObject*
+jsd_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ return jsdobj->obj;
+}
+
+const char*
+jsd_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ if( jsdobj->newURL )
+ return JSD_ATOM_TO_STRING(jsdobj->newURL);
+ return NULL;
+}
+
+unsigned
+jsd_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ return jsdobj->newLineno;
+}
+
+const char*
+jsd_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ if( jsdobj->ctorURL )
+ return JSD_ATOM_TO_STRING(jsdobj->ctorURL);
+ return NULL;
+}
+
+unsigned
+jsd_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ return jsdobj->ctorLineno;
+}
+
+const char*
+jsd_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ if( jsdobj->ctorName )
+ return JSD_ATOM_TO_STRING(jsdobj->ctorName);
+ return NULL;
+}
+
+JSDObject*
+jsd_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj)
+{
+ JSDObject* jsdobj;
+
+ JSD_LOCK_OBJECTS(jsdc);
+ jsdobj = (JSDObject*) JS_HashTableLookup(jsdc->objectsTable, jsobj);
+ JSD_UNLOCK_OBJECTS(jsdc);
+ return jsdobj;
+}
+
+JSDObject*
+jsd_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return jsd_GetJSDObjectForJSObject(jsdc, JSVAL_TO_OBJECT(jsdval->val));
+}
+
+JSDValue*
+jsd_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ return jsd_NewValue(jsdc, OBJECT_TO_JSVAL(jsdobj->obj));
+}
+
+
diff --git a/js/jsd/jsd_scpt.cpp b/js/jsd/jsd_scpt.cpp
new file mode 100644
index 0000000..91e9b2f
--- /dev/null
+++ b/js/jsd/jsd_scpt.cpp
@@ -0,0 +1,966 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Script support
+ */
+
+#include "jsd.h"
+#include "jsfriendapi.h"
+#include "nsCxPusher.h"
+
+using mozilla::AutoSafeJSContext;
+
+/* Comment this out to disable (NT specific) dumping as we go */
+/*
+** #ifdef DEBUG
+** #define JSD_DUMP 1
+** #endif
+*/
+
+#define NOT_SET_YET -1
+
+/***************************************************************************/
+
+#ifdef DEBUG
+void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
+{
+ JS_ASSERT(jsdscript);
+ JS_ASSERT(jsdscript->script);
+}
+void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
+{
+ JS_ASSERT(jsdhook);
+ JS_ASSERT(jsdhook->hook);
+}
+#endif
+
+#ifdef LIVEWIRE
+static JSBool
+HasFileExtention(const char* name, const char* ext)
+{
+ int i;
+ int len = strlen(ext);
+ const char* p = strrchr(name,'.');
+ if( !p )
+ return JS_FALSE;
+ p++;
+ for(i = 0; i < len; i++ )
+ {
+ JS_ASSERT(islower(ext[i]));
+ if( 0 == p[i] || tolower(p[i]) != ext[i] )
+ return JS_FALSE;
+ }
+ if( 0 != p[i] )
+ return JS_FALSE;
+ return JS_TRUE;
+}
+#endif /* LIVEWIRE */
+
+static JSDScript*
+_newJSDScript(JSDContext* jsdc,
+ JSContext *cx,
+ JSScript *script_)
+{
+ JS::RootedScript script(cx, script_);
+ if ( JS_GetScriptIsSelfHosted(script) )
+ return NULL;
+
+ JSDScript* jsdscript;
+ unsigned lineno;
+ const char* raw_filename;
+
+ JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
+
+ /* these are inlined javascript: urls and we can't handle them now */
+ lineno = (unsigned) JS_GetScriptBaseLineNumber(cx, script);
+ if( lineno == 0 )
+ return NULL;
+
+ jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
+ if( ! jsdscript )
+ return NULL;
+
+ raw_filename = JS_GetScriptFilename(cx,script);
+
+ JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
+ JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
+ jsdscript->jsdc = jsdc;
+ jsdscript->script = script;
+ jsdscript->lineBase = lineno;
+ jsdscript->lineExtent = (unsigned)NOT_SET_YET;
+ jsdscript->data = NULL;
+#ifndef LIVEWIRE
+ jsdscript->url = (char*) jsd_BuildNormalizedURL(raw_filename);
+#else
+ jsdscript->app = LWDBG_GetCurrentApp();
+ if( jsdscript->app && raw_filename )
+ {
+ jsdscript->url = jsdlw_BuildAppRelativeFilename(jsdscript->app, raw_filename);
+ if( function )
+ {
+ JSString* funid = JS_GetFunctionId(function);
+ char* funbytes;
+ const char* funnanme;
+ if( fuinid )
+ {
+ funbytes = JS_EncodeString(cx, funid);
+ funname = funbytes ? funbytes : "";
+ }
+ else
+ {
+ funbytes = NULL;
+ funname = "anonymous";
+ }
+ jsdscript->lwscript =
+ LWDBG_GetScriptOfFunction(jsdscript->app,funname);
+ JS_Free(cx, funbytes);
+
+ /* also, make sure this file is added to filelist if is .js file */
+ if( HasFileExtention(raw_filename,"js") ||
+ HasFileExtention(raw_filename,"sjs") )
+ {
+ jsdlw_PreLoadSource(jsdc, jsdscript->app, raw_filename, JS_FALSE);
+ }
+ }
+ else
+ {
+ jsdscript->lwscript = LWDBG_GetCurrentTopLevelScript();
+ }
+ }
+#endif
+
+ JS_INIT_CLIST(&jsdscript->hooks);
+
+ return jsdscript;
+}
+
+static void
+_destroyJSDScript(JSDContext* jsdc,
+ JSDScript* jsdscript)
+{
+ JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
+
+ /* destroy all hooks */
+ jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
+
+ JS_REMOVE_LINK(&jsdscript->links);
+ if(jsdscript->url)
+ free(jsdscript->url);
+
+ if (jsdscript->profileData)
+ free(jsdscript->profileData);
+
+ free(jsdscript);
+}
+
+/***************************************************************************/
+
+#ifdef JSD_DUMP
+#ifndef XP_WIN
+void
+OutputDebugString (char *buf)
+{
+ fprintf (stderr, "%s", buf);
+}
+#endif
+
+static void
+_dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
+{
+ const char* name;
+ JSString* fun;
+ unsigned base;
+ unsigned extent;
+ char Buf[256];
+ size_t n;
+
+ name = jsd_GetScriptFilename(jsdc, jsdscript);
+ fun = jsd_GetScriptFunctionId(jsdc, jsdscript);
+ base = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
+ extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
+ n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
+ leadingtext, (unsigned) jsdscript->script,
+ name ? name : "no URL"));
+ if (n + 1 < sizeof(Buf)) {
+ if (fun) {
+ n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
+ } else {
+ n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
+ JS_ASSERT_STRING_IS_FLAT(fun), 0);
+ Buf[sizeof(Buf) - 1] = '\0';
+ }
+ if (n + 1 < sizeof(Buf))
+ snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
+ }
+ OutputDebugString( Buf );
+}
+
+static void
+_dumpJSDScriptList( JSDContext* jsdc )
+{
+ JSDScript* iterp = NULL;
+ JSDScript* jsdscript = NULL;
+
+ OutputDebugString( "*** JSDScriptDump\n" );
+ while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
+ _dumpJSDScript( jsdc, jsdscript, " script: " );
+}
+#endif /* JSD_DUMP */
+
+/***************************************************************************/
+static JSHashNumber
+jsd_hash_script(const void *key)
+{
+ return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
+}
+
+static void *
+jsd_alloc_script_table(void *priv, size_t size)
+{
+ return malloc(size);
+}
+
+static void
+jsd_free_script_table(void *priv, void *item, size_t size)
+{
+ free(item);
+}
+
+static JSHashEntry *
+jsd_alloc_script_entry(void *priv, const void *item)
+{
+ return (JSHashEntry*) malloc(sizeof(JSHashEntry));
+}
+
+static void
+jsd_free_script_entry(void *priv, JSHashEntry *he, unsigned flag)
+{
+ if (flag == HT_FREE_ENTRY)
+ {
+ _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
+ free(he);
+ }
+}
+
+static JSHashAllocOps script_alloc_ops = {
+ jsd_alloc_script_table, jsd_free_script_table,
+ jsd_alloc_script_entry, jsd_free_script_entry
+};
+
+#ifndef JSD_SCRIPT_HASH_SIZE
+#define JSD_SCRIPT_HASH_SIZE 1024
+#endif
+
+JSBool
+jsd_InitScriptManager(JSDContext* jsdc)
+{
+ JS_INIT_CLIST(&jsdc->scripts);
+ jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
+ JS_CompareValues, JS_CompareValues,
+ &script_alloc_ops, (void*) jsdc);
+ return !!jsdc->scriptsTable;
+}
+
+void
+jsd_DestroyScriptManager(JSDContext* jsdc)
+{
+ JSD_LOCK_SCRIPTS(jsdc);
+ if (jsdc->scriptsTable)
+ JS_HashTableDestroy(jsdc->scriptsTable);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+}
+
+JSDScript*
+jsd_FindJSDScript( JSDContext* jsdc,
+ JSScript *script )
+{
+ JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
+ return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
+}
+
+JSDScript *
+jsd_FindOrCreateJSDScript(JSDContext *jsdc,
+ JSContext *cx,
+ JSScript *script_,
+ JSAbstractFramePtr frame)
+{
+ JS::RootedScript script(cx, script_);
+ JSDScript *jsdscript;
+ JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
+
+ jsdscript = jsd_FindJSDScript(jsdc, script);
+ if (jsdscript)
+ return jsdscript;
+
+ /* Fallback for unknown scripts: create a new script. */
+ if (!frame) {
+ JSBrokenFrameIterator iter(cx);
+ if (!iter.done())
+ frame = iter.abstractFramePtr();
+ }
+ if (frame)
+ jsdscript = _newJSDScript(jsdc, cx, script);
+
+ return jsdscript;
+}
+
+JSDProfileData*
+jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
+{
+ if (!script->profileData)
+ script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
+
+ return script->profileData;
+}
+
+uint32_t
+jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
+{
+ return script->flags;
+}
+
+void
+jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
+{
+ script->flags = flags;
+}
+
+unsigned
+jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->callCount;
+
+ return 0;
+}
+
+unsigned
+jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->maxRecurseDepth;
+
+ return 0;
+}
+
+double
+jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->minExecutionTime;
+
+ return 0.0;
+}
+
+double
+jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->maxExecutionTime;
+
+ return 0.0;
+}
+
+double
+jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->totalExecutionTime;
+
+ return 0.0;
+}
+
+double
+jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->minOwnExecutionTime;
+
+ return 0.0;
+}
+
+double
+jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->maxOwnExecutionTime;
+
+ return 0.0;
+}
+
+double
+jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ return script->profileData->totalOwnExecutionTime;
+
+ return 0.0;
+}
+
+void
+jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
+{
+ if (script->profileData)
+ {
+ free(script->profileData);
+ script->profileData = NULL;
+ }
+}
+
+JSScript *
+jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
+{
+ return script->script;
+}
+
+JSFunction *
+jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
+{
+ AutoSafeJSContext cx; // NB: Actually unused.
+ return JS_GetScriptFunction(cx, script->script);
+}
+
+JSDScript*
+jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
+{
+ JSDScript *jsdscript = *iterp;
+
+ JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
+
+ if( !jsdscript )
+ jsdscript = (JSDScript *)jsdc->scripts.next;
+ if( jsdscript == (JSDScript *)&jsdc->scripts )
+ return NULL;
+ *iterp = (JSDScript*) jsdscript->links.next;
+ return jsdscript;
+}
+
+void *
+jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
+{
+ void *rval = jsdscript->data;
+ jsdscript->data = data;
+ return rval;
+}
+
+void *
+jsd_GetScriptPrivate(JSDScript *jsdscript)
+{
+ return jsdscript->data;
+}
+
+JSBool
+jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSDScript *current;
+
+ JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
+
+ for( current = (JSDScript *)jsdc->scripts.next;
+ current != (JSDScript *)&jsdc->scripts;
+ current = (JSDScript *)current->links.next )
+ {
+ if(jsdscript == current)
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+}
+
+const char*
+jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ return jsdscript->url;
+}
+
+JSString*
+jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSString* str;
+ JSFunction *fun = jsd_GetJSFunction(jsdc, jsdscript);
+
+ if( ! fun )
+ return NULL;
+ str = JS_GetFunctionId(fun);
+
+ /* For compatibility we return "anonymous", not an empty string here. */
+ return str ? str : JS_GetAnonymousString(jsdc->jsrt);
+}
+
+unsigned
+jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ return jsdscript->lineBase;
+}
+
+unsigned
+jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdc->glob); // Just in case.
+ if( NOT_SET_YET == (int)jsdscript->lineExtent )
+ jsdscript->lineExtent = JS_GetScriptLineExtent(cx, jsdscript->script);
+ return jsdscript->lineExtent;
+}
+
+uintptr_t
+jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line)
+{
+ uintptr_t pc;
+
+ if( !jsdscript )
+ return 0;
+#ifdef LIVEWIRE
+ if( jsdscript->lwscript )
+ {
+ unsigned newline;
+ jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline);
+ if( line != newline )
+ line = newline;
+ }
+#endif
+
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdscript->script);
+ pc = (uintptr_t) JS_LineNumberToPC(cx, jsdscript->script, line );
+ return pc;
+}
+
+unsigned
+jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
+{
+ unsigned first = jsdscript->lineBase;
+ unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
+ unsigned line = 0;
+
+ if (pc) {
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdscript->script);
+ line = JS_PCToLineNumber(cx, jsdscript->script, (jsbytecode*)pc);
+ }
+
+ if( line < first )
+ return first;
+ if( line > last )
+ return last;
+
+#ifdef LIVEWIRE
+ if( jsdscript && jsdscript->lwscript )
+ {
+ unsigned newline;
+ jsdlw_ProcessedToRawLineNumber(jsdc, jsdscript, line, &newline);
+ line = newline;
+ }
+#endif
+
+ return line;
+}
+
+JSBool
+jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned startLine, unsigned maxLines,
+ unsigned* count, unsigned** retLines, uintptr_t** retPCs)
+{
+ unsigned first = jsdscript->lineBase;
+ unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
+ JSBool ok;
+ jsbytecode **pcs;
+ unsigned i;
+
+ if (last < startLine)
+ return JS_TRUE;
+
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdscript->script);
+
+ ok = JS_GetLinePCs(cx, jsdscript->script,
+ startLine, maxLines,
+ count, retLines, &pcs);
+
+ if (ok) {
+ if (retPCs) {
+ for (i = 0; i < *count; ++i) {
+ (*retPCs)[i] = (*pcs)[i];
+ }
+ }
+
+ JS_free(cx, pcs);
+ }
+
+ return ok;
+}
+
+JSBool
+jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
+{
+ JSD_LOCK();
+ jsdc->scriptHook = hook;
+ jsdc->scriptHookData = callerdata;
+ JSD_UNLOCK();
+ return JS_TRUE;
+}
+
+JSBool
+jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
+{
+ JSD_LOCK();
+ if( hook )
+ *hook = jsdc->scriptHook;
+ if( callerdata )
+ *callerdata = jsdc->scriptHookData;
+ JSD_UNLOCK();
+ return JS_TRUE;
+}
+
+JSBool
+jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
+{
+ JSBool rv;
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdscript->script);
+ JSD_LOCK();
+ rv = JS_SetSingleStepMode(cx, jsdscript->script, enable);
+ JSD_UNLOCK();
+ return rv;
+}
+
+
+/***************************************************************************/
+
+void
+jsd_NewScriptHookProc(
+ JSContext *cx,
+ const char *filename, /* URL this script loads from */
+ unsigned lineno, /* line where this script starts */
+ JSScript *script,
+ JSFunction *fun,
+ void* callerdata )
+{
+ JSDScript* jsdscript = NULL;
+ JSDContext* jsdc = (JSDContext*) callerdata;
+ JSD_ScriptHookProc hook;
+ void* hookData;
+
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = _newJSDScript(jsdc, cx, script);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if( ! jsdscript )
+ return;
+
+#ifdef JSD_DUMP
+ JSD_LOCK_SCRIPTS(jsdc);
+ _dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
+ _dumpJSDScriptList( jsdc );
+ JSD_UNLOCK_SCRIPTS(jsdc);
+#endif /* JSD_DUMP */
+
+ /* local in case jsdc->scriptHook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->scriptHook;
+ if( hook )
+ jsdscript->flags = jsdscript->flags | JSD_SCRIPT_CALL_DESTROY_HOOK_BIT;
+ hookData = jsdc->scriptHookData;
+ JSD_UNLOCK();
+
+ if( hook )
+ hook(jsdc, jsdscript, JS_TRUE, hookData);
+}
+
+void
+jsd_DestroyScriptHookProc(
+ JSFreeOp *fop,
+ JSScript *script_,
+ void* callerdata )
+{
+ JSDScript* jsdscript = NULL;
+ JSDContext* jsdc = (JSDContext*) callerdata;
+ // NB: We're called during GC, so we can't push a cx. Root directly with
+ // the runtime.
+ JS::RootedScript script(jsdc->jsrt, script_);
+ JSD_ScriptHookProc hook;
+ void* hookData;
+
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindJSDScript(jsdc, script);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+
+ if( ! jsdscript )
+ return;
+
+#ifdef JSD_DUMP
+ JSD_LOCK_SCRIPTS(jsdc);
+ _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
+ JSD_UNLOCK_SCRIPTS(jsdc);
+#endif /* JSD_DUMP */
+
+ /* local in case hook gets cleared on another thread */
+ JSD_LOCK();
+ hook = (jsdscript->flags & JSD_SCRIPT_CALL_DESTROY_HOOK_BIT) ? jsdc->scriptHook : NULL;
+ hookData = jsdc->scriptHookData;
+ JSD_UNLOCK();
+
+ if( hook )
+ hook(jsdc, jsdscript, JS_FALSE, hookData);
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+
+#ifdef JSD_DUMP
+ JSD_LOCK_SCRIPTS(jsdc);
+ _dumpJSDScriptList(jsdc);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+#endif /* JSD_DUMP */
+}
+
+
+/***************************************************************************/
+
+static JSDExecHook*
+_findHook(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
+{
+ JSDExecHook* jsdhook;
+ JSCList* list = &jsdscript->hooks;
+
+ for( jsdhook = (JSDExecHook*)list->next;
+ jsdhook != (JSDExecHook*)list;
+ jsdhook = (JSDExecHook*)jsdhook->links.next )
+ {
+ if (jsdhook->pc == pc)
+ return jsdhook;
+ }
+ return NULL;
+}
+
+static JSBool
+_isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
+{
+ JSDExecHook* current;
+ JSCList* list;
+ JSDScript* jsdscript;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindJSDScript(jsdc, script);
+ if( ! jsdscript)
+ {
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ return JS_FALSE;
+ }
+
+ list = &jsdscript->hooks;
+
+ for( current = (JSDExecHook*)list->next;
+ current != (JSDExecHook*)list;
+ current = (JSDExecHook*)current->links.next )
+ {
+ if(current == jsdhook)
+ {
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ return JS_TRUE;
+ }
+ }
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ return JS_FALSE;
+}
+
+
+JSTrapStatus
+jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval,
+ jsval closure)
+{
+ JS::RootedScript script(cx, script_);
+ JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
+ JSD_ExecutionHookProc hook;
+ void* hookData;
+ JSDContext* jsdc;
+ JSDScript* jsdscript;
+
+ JSD_LOCK();
+
+ if( NULL == (jsdc = jsd_JSDContextForJSContext(cx)) ||
+ ! _isActiveHook(jsdc, script, jsdhook) )
+ {
+ JSD_UNLOCK();
+ return JSTRAP_CONTINUE;
+ }
+
+ JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
+ JS_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc);
+ JS_ASSERT(jsdhook->jsdscript->script == script);
+ JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
+
+ hook = jsdhook->hook;
+ hookData = jsdhook->callerdata;
+ jsdscript = jsdhook->jsdscript;
+
+ /* do not use jsdhook-> after this point */
+ JSD_UNLOCK();
+
+ if( ! jsdc || ! jsdc->inited )
+ return JSTRAP_CONTINUE;
+
+ if( JSD_IS_DANGEROUS_THREAD(jsdc) )
+ return JSTRAP_CONTINUE;
+
+#ifdef LIVEWIRE
+ if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (uintptr_t)pc) )
+ return JSTRAP_CONTINUE;
+#endif
+
+ return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
+ hook, hookData, rval);
+}
+
+
+
+JSBool
+jsd_SetExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSDExecHook* jsdhook;
+ JSBool rv;
+
+ JSD_LOCK();
+ if( ! hook )
+ {
+ jsd_ClearExecutionHook(jsdc, jsdscript, pc);
+ JSD_UNLOCK();
+ return JS_TRUE;
+ }
+
+ jsdhook = _findHook(jsdc, jsdscript, pc);
+ if( jsdhook )
+ {
+ jsdhook->hook = hook;
+ jsdhook->callerdata = callerdata;
+ JSD_UNLOCK();
+ return JS_TRUE;
+ }
+ /* else... */
+
+ jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
+ if( ! jsdhook ) {
+ JSD_UNLOCK();
+ return JS_FALSE;
+ }
+ jsdhook->jsdscript = jsdscript;
+ jsdhook->pc = pc;
+ jsdhook->hook = hook;
+ jsdhook->callerdata = callerdata;
+
+ {
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdscript->script);
+ rv = JS_SetTrap(cx, jsdscript->script,
+ (jsbytecode*)pc, jsd_TrapHandler,
+ PRIVATE_TO_JSVAL(jsdhook));
+ }
+
+ if ( ! rv ) {
+ free(jsdhook);
+ JSD_UNLOCK();
+ return JS_FALSE;
+ }
+
+ JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc)
+{
+ JSDExecHook* jsdhook;
+
+ JSD_LOCK();
+
+ jsdhook = _findHook(jsdc, jsdscript, pc);
+ if( ! jsdhook )
+ {
+ JSD_UNLOCK();
+ return JS_FALSE;
+ }
+
+ {
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdscript->script);
+ JS_ClearTrap(cx, jsdscript->script,
+ (jsbytecode*)pc, NULL, NULL );
+ }
+
+ JS_REMOVE_LINK(&jsdhook->links);
+ free(jsdhook);
+
+ JSD_UNLOCK();
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
+{
+ JSDExecHook* jsdhook;
+ JSCList* list = &jsdscript->hooks;
+ JSD_LOCK();
+
+ while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
+ {
+ JS_REMOVE_LINK(&jsdhook->links);
+ free(jsdhook);
+ }
+
+ JS_ClearScriptTraps(jsdc->jsrt, jsdscript->script);
+ JSD_UNLOCK();
+
+ return JS_TRUE;
+}
+
+JSBool
+jsd_ClearAllExecutionHooks(JSDContext* jsdc)
+{
+ JSDScript* jsdscript;
+ JSDScript* iterp = NULL;
+
+ JSD_LOCK();
+ while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
+ jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
+ JSD_UNLOCK();
+ return JS_TRUE;
+}
+
+void
+jsd_ScriptCreated(JSDContext* jsdc,
+ JSContext *cx,
+ const char *filename, /* URL this script loads from */
+ unsigned lineno, /* line where this script starts */
+ JSScript *script,
+ JSFunction *fun)
+{
+ jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
+}
+
+void
+jsd_ScriptDestroyed(JSDContext* jsdc,
+ JSFreeOp *fop,
+ JSScript *script)
+{
+ jsd_DestroyScriptHookProc(fop, script, jsdc);
+}
diff --git a/js/jsd/jsd_stak.cpp b/js/jsd/jsd_stak.cpp
new file mode 100644
index 0000000..8249c35
--- /dev/null
+++ b/js/jsd/jsd_stak.cpp
@@ -0,0 +1,572 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Call stack support
+ */
+
+#include "jsd.h"
+#include "jsfriendapi.h"
+#include "nsCxPusher.h"
+
+using mozilla::AutoPushJSContext;
+
+#ifdef DEBUG
+void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
+{
+ JS_ASSERT(jsdthreadstate);
+ JS_ASSERT(jsdthreadstate->stackDepth > 0);
+}
+
+void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe)
+{
+ JS_ASSERT(jsdframe);
+ JS_ASSERT(jsdframe->jsdthreadstate);
+}
+#endif
+
+static JSDStackFrameInfo*
+_addNewFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSScript* script,
+ uintptr_t pc,
+ bool isConstructing,
+ JSAbstractFramePtr frame)
+{
+ JSDStackFrameInfo* jsdframe;
+ JSDScript* jsdscript = NULL;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindJSDScript(jsdc, script);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES &&
+ !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)))
+ {
+ return NULL;
+ }
+
+ if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
+ jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
+
+ jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
+ if( ! jsdframe )
+ return NULL;
+
+ jsdframe->jsdthreadstate = jsdthreadstate;
+ jsdframe->jsdscript = jsdscript;
+ jsdframe->isConstructing = isConstructing;
+ jsdframe->pc = pc;
+ jsdframe->frame = frame;
+
+ JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
+ jsdthreadstate->stackDepth++;
+
+ return jsdframe;
+}
+
+static void
+_destroyFrame(JSDStackFrameInfo* jsdframe)
+{
+ /* kill any alloc'd objects in frame here... */
+
+ if( jsdframe )
+ free(jsdframe);
+}
+
+JSDThreadState*
+jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
+{
+ JSDThreadState* jsdthreadstate;
+
+ jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
+ if( ! jsdthreadstate )
+ return NULL;
+
+ jsdthreadstate->context = cx;
+ jsdthreadstate->thread = JSD_CURRENT_THREAD();
+ JS_INIT_CLIST(&jsdthreadstate->stack);
+ jsdthreadstate->stackDepth = 0;
+
+ JS_BeginRequest(jsdthreadstate->context);
+
+ JSBrokenFrameIterator iter(cx);
+ while(!iter.done())
+ {
+ JSAbstractFramePtr frame = iter.abstractFramePtr();
+ JS::RootedScript script(cx, frame.script());
+ uintptr_t pc = (uintptr_t)iter.pc();
+ JS::RootedValue dummyThis(cx);
+
+ /*
+ * don't construct a JSDStackFrame for dummy frames (those without a
+ * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
+ * isn't set.
+ */
+ if (frame.getThisValue(cx, &dummyThis))
+ {
+ bool isConstructing = iter.isConstructing();
+ JSDStackFrameInfo *frameInfo = _addNewFrame( jsdc, jsdthreadstate, script, pc, isConstructing, frame );
+
+ if ((jsdthreadstate->stackDepth == 0 && !frameInfo) ||
+ (jsdthreadstate->stackDepth == 1 && frameInfo &&
+ frameInfo->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frameInfo->jsdscript)))
+ {
+ /*
+ * if we failed to create the first frame, or the top frame
+ * is not enabled for debugging, fail the entire thread state.
+ */
+ JS_INIT_CLIST(&jsdthreadstate->links);
+ JS_EndRequest(jsdthreadstate->context);
+ jsd_DestroyThreadState(jsdc, jsdthreadstate);
+ return NULL;
+ }
+ }
+
+ ++iter;
+ }
+ JS_EndRequest(jsdthreadstate->context);
+
+ if (jsdthreadstate->stackDepth == 0)
+ {
+ free(jsdthreadstate);
+ return NULL;
+ }
+
+ JSD_LOCK_THREADSTATES(jsdc);
+ JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return jsdthreadstate;
+}
+
+void
+jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSDStackFrameInfo* jsdframe;
+ JSCList* list;
+
+ JS_ASSERT(jsdthreadstate);
+ JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
+
+ JSD_LOCK_THREADSTATES(jsdc);
+ JS_REMOVE_LINK(&jsdthreadstate->links);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ list = &jsdthreadstate->stack;
+ while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
+ {
+ JS_REMOVE_LINK(&jsdframe->links);
+ _destroyFrame(jsdframe);
+ }
+ free(jsdthreadstate);
+}
+
+unsigned
+jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ unsigned count = 0;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
+ count = jsdthreadstate->stackDepth;
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return count;
+}
+
+JSDStackFrameInfo*
+jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSDStackFrameInfo* jsdframe = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
+ jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return jsdframe;
+}
+
+JSContext *
+jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSContext* cx = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+ if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
+ cx = jsdthreadstate->context;
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return cx;
+}
+
+JSDStackFrameInfo*
+jsd_GetCallingStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSDStackFrameInfo* nextjsdframe = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
+ nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return nextjsdframe;
+}
+
+JSDScript*
+jsd_GetScriptForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSDScript* jsdscript = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ jsdscript = jsdframe->jsdscript;
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return jsdscript;
+}
+
+uintptr_t
+jsd_GetPCForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ uintptr_t pc = 0;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ pc = jsdframe->pc;
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return pc;
+}
+
+JSDValue*
+jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSObject* obj;
+ JSDValue* jsdval = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ {
+ obj = jsdframe->frame.callObject(jsdthreadstate->context);
+ if(obj)
+ jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
+ }
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return jsdval;
+}
+
+JSDValue*
+jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JS::RootedObject obj(jsdthreadstate->context);
+ JSDValue* jsdval = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ {
+ JS_BeginRequest(jsdthreadstate->context);
+ obj = jsdframe->frame.scopeChain(jsdthreadstate->context);
+ JS_EndRequest(jsdthreadstate->context);
+ if(obj)
+ jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
+ }
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ return jsdval;
+}
+
+JSDValue*
+jsd_GetThisForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSDValue* jsdval = NULL;
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ {
+ JSBool ok;
+ JS::RootedValue thisval(jsdthreadstate->context);
+ JS_BeginRequest(jsdthreadstate->context);
+ ok = jsdframe->frame.getThisValue(jsdthreadstate->context, &thisval);
+ JS_EndRequest(jsdthreadstate->context);
+ if(ok)
+ jsdval = JSD_NewValue(jsdc, thisval);
+ }
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+ return jsdval;
+}
+
+JSString*
+jsd_GetIdForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSString *rv = NULL;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ {
+ JSFunction *fun = jsdframe->frame.maybeFun();
+ if( fun )
+ {
+ rv = JS_GetFunctionId (fun);
+
+ /*
+ * For compatibility we return "anonymous", not an empty string
+ * here.
+ */
+ if( !rv )
+ rv = JS_GetAnonymousString(jsdc->jsrt);
+ }
+ }
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+ return rv;
+}
+
+JSBool
+jsd_IsStackFrameDebugger(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSBool rv = JS_TRUE;
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ {
+ rv = jsdframe->frame.isDebuggerFrame();
+ }
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+ return rv;
+}
+
+JSBool
+jsd_IsStackFrameConstructing(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSBool rv = JS_TRUE;
+ JSD_LOCK_THREADSTATES(jsdc);
+
+ if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
+ {
+ rv = jsdframe->isConstructing;
+ }
+
+ JSD_UNLOCK_THREADSTATES(jsdc);
+ return rv;
+}
+
+JSBool
+jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const jschar *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JSBool eatExceptions, JS::MutableHandleValue rval)
+{
+ JSBool retval;
+ JSBool valid;
+ JSExceptionState* exceptionState = NULL;
+
+ JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
+
+ JSD_LOCK_THREADSTATES(jsdc);
+ valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ if( ! valid )
+ return JS_FALSE;
+
+ AutoPushJSContext cx(jsdthreadstate->context);
+ JS_ASSERT(cx);
+
+ if (eatExceptions)
+ exceptionState = JS_SaveExceptionState(cx);
+ JS_ClearPendingException(cx);
+ jsd_StartingEvalUsingFilename(jsdc, filename);
+ retval = jsdframe->frame.evaluateUCInStackFrame(cx, bytes, length, filename, lineno,
+ rval);
+ jsd_FinishedEvalUsingFilename(jsdc, filename);
+ if (eatExceptions)
+ JS_RestoreExceptionState(cx, exceptionState);
+
+ return retval;
+}
+
+JSBool
+jsd_EvaluateScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const char *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JSBool eatExceptions, JS::MutableHandleValue rval)
+{
+ JSBool retval;
+ JSBool valid;
+ JSExceptionState* exceptionState = NULL;
+
+ JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
+
+ JSD_LOCK_THREADSTATES(jsdc);
+ valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ if (!valid)
+ return JS_FALSE;
+
+ AutoPushJSContext cx(jsdthreadstate->context);
+ JS_ASSERT(cx);
+
+ if (eatExceptions)
+ exceptionState = JS_SaveExceptionState(cx);
+ JS_ClearPendingException(cx);
+ jsd_StartingEvalUsingFilename(jsdc, filename);
+ retval = jsdframe->frame.evaluateInStackFrame(cx, bytes, length, filename, lineno,
+ rval);
+ jsd_FinishedEvalUsingFilename(jsdc, filename);
+ if (eatExceptions)
+ JS_RestoreExceptionState(cx, exceptionState);
+
+ return retval;
+}
+
+JSString*
+jsd_ValToStringInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ jsval val)
+{
+ JSBool valid;
+ JSString* retval;
+ JSExceptionState* exceptionState;
+ JSContext* cx;
+
+ JSD_LOCK_THREADSTATES(jsdc);
+ valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+
+ if( ! valid )
+ return NULL;
+
+ cx = jsdthreadstate->context;
+ JS_ASSERT(cx);
+
+ exceptionState = JS_SaveExceptionState(cx);
+ retval = JS_ValueToString(cx, val);
+ JS_RestoreExceptionState(cx, exceptionState);
+
+ return retval;
+}
+
+JSBool
+jsd_IsValidThreadState(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate)
+{
+ JSDThreadState *cur;
+
+ JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );
+
+ for( cur = (JSDThreadState*)jsdc->threadsStates.next;
+ cur != (JSDThreadState*)&jsdc->threadsStates;
+ cur = (JSDThreadState*)cur->links.next )
+ {
+ if( cur == jsdthreadstate )
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+}
+
+JSBool
+jsd_IsValidFrameInThreadState(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
+
+ if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
+ return JS_FALSE;
+ if( jsdframe->jsdthreadstate != jsdthreadstate )
+ return JS_FALSE;
+
+ JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
+ JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
+
+ return JS_TRUE;
+}
+
+static JSContext*
+_getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSBool valid;
+ JSD_LOCK_THREADSTATES(jsdc);
+ valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
+ JSD_UNLOCK_THREADSTATES(jsdc);
+ if( valid )
+ return jsdthreadstate->context;
+ return NULL;
+}
+
+JSDValue*
+jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSContext* cx;
+ jsval val;
+
+ if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
+ return NULL;
+
+ if(JS_GetPendingException(cx, &val))
+ return jsd_NewValue(jsdc, val);
+ return NULL;
+}
+
+JSBool
+jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
+ JSDValue* jsdval)
+{
+ JSContext* cx;
+
+ if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
+ return JS_FALSE;
+
+ if(jsdval)
+ JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
+ else
+ JS_ClearPendingException(cx);
+ return JS_TRUE;
+}
+
diff --git a/js/jsd/jsd_step.cpp b/js/jsd/jsd_step.cpp
new file mode 100644
index 0000000..da1886a
--- /dev/null
+++ b/js/jsd/jsd_step.cpp
@@ -0,0 +1,286 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Stepping support
+ */
+
+#include "jsd.h"
+
+/*
+* #define JSD_TRACE 1
+*/
+
+#ifdef JSD_TRACE
+
+static char*
+_indentSpaces(int i)
+{
+#define MAX_INDENT 63
+ static char* p = NULL;
+ if(!p)
+ {
+ p = calloc(1, MAX_INDENT+1);
+ if(!p) return "";
+ memset(p, ' ', MAX_INDENT);
+ }
+ if(i > MAX_INDENT) return p;
+ return p + MAX_INDENT-i;
+}
+
+static void
+_interpreterTrace(JSDContext* jsdc, JSContext *cx, JSAbstractFramePtr frame,
+ bool isConstructing, JSBool before)
+{
+ JSDScript* jsdscript = NULL;
+ JSScript * script;
+ static indent = 0;
+ JSString* funName = NULL;
+
+ script = frame.script();
+ if(script)
+ {
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, frame);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ if(jsdscript)
+ funName = JSD_GetScriptFunctionId(jsdc, jsdscript);
+ }
+
+ if(before)
+ printf("%sentering ", _indentSpaces(indent++));
+ else
+ printf("%sleaving ", _indentSpaces(--indent));
+
+ if (!funName)
+ printf("TOP_LEVEL");
+ else
+ JS_FileEscapedString(stdout, funName, 0);
+
+ if(before)
+ {
+ jsval thisVal;
+
+ printf("%s this: ", isConstructing ? "constructing":"");
+
+ if (JS_GetFrameThis(cx, frame, &thisVal))
+ printf("0x%0llx", (uintptr_t) thisVal);
+ else
+ puts("<unavailable>");
+ }
+ printf("\n");
+ JS_ASSERT(indent >= 0);
+}
+#endif
+
+JSBool
+_callHook(JSDContext *jsdc, JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
+ JSBool before, unsigned type, JSD_CallHookProc hook, void *hookData)
+{
+ JSDScript* jsdscript;
+ JSScript* jsscript;
+ JSBool hookresult = JS_TRUE;
+
+ if (!jsdc || !jsdc->inited)
+ return JS_FALSE;
+
+ if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA))
+ {
+ /* no hook to call, no profile data needs to be collected,
+ * so there is nothing to do here.
+ */
+ return hookresult;
+ }
+
+ if (before && isConstructing) {
+ JS::RootedValue newObj(cx);
+ if (!frame.getThisValue(cx, &newObj))
+ return JS_FALSE;
+ jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), frame);
+ }
+
+ jsscript = frame.script();
+ if (jsscript)
+ {
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, frame);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+
+ if (jsdscript)
+ {
+ if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript))
+ {
+ JSDProfileData *pdata;
+ pdata = jsd_GetScriptProfileData (jsdc, jsdscript);
+ if (pdata)
+ {
+ if (before)
+ {
+ if (!pdata->lastCallStart)
+ {
+ int64_t now;
+ JSDProfileData *callerpdata;
+
+ /* Get the time just the once, for consistency. */
+ now = JS_Now();
+ /* This contains a pointer to the profile data for
+ * the caller of this function. */
+ callerpdata = jsdc->callingFunctionPData;
+ if (callerpdata)
+ {
+ int64_t ll_delta;
+ pdata->caller = callerpdata;
+ /* We need to 'stop' the timer for the caller.
+ * Use time since last return if appropriate. */
+ ll_delta = jsdc->lastReturnTime
+ ? now - jsdc->lastReturnTime
+ : now - callerpdata->lastCallStart;
+ callerpdata->runningTime += ll_delta;
+ }
+ /* We're the new current function, and no return
+ * has happened yet. */
+ jsdc->callingFunctionPData = pdata;
+ jsdc->lastReturnTime = 0;
+ /* This function has no running time (just been
+ * called!), and we'll need the call start time. */
+ pdata->runningTime = 0;
+ pdata->lastCallStart = now;
+ } else {
+ if (++pdata->recurseDepth > pdata->maxRecurseDepth)
+ pdata->maxRecurseDepth = pdata->recurseDepth;
+ }
+ /* make sure we're called for the return too. */
+ hookresult = JS_TRUE;
+ } else if (!pdata->recurseDepth && pdata->lastCallStart) {
+ int64_t now, ll_delta;
+ double delta;
+ now = JS_Now();
+ ll_delta = now - pdata->lastCallStart;
+ delta = ll_delta;
+ delta /= 1000.0;
+ pdata->totalExecutionTime += delta;
+ /* minExecutionTime starts as 0, so we need to overwrite
+ * it on the first call always. */
+ if ((0 == pdata->callCount) ||
+ delta < pdata->minExecutionTime)
+ {
+ pdata->minExecutionTime = delta;
+ }
+ if (delta > pdata->maxExecutionTime)
+ pdata->maxExecutionTime = delta;
+
+ /* If we last returned from a function (as opposed to
+ * having last entered this function), we need to inc.
+ * the running total by the time delta since the last
+ * return, and use the running total instead of the
+ * delta calculated above. */
+ if (jsdc->lastReturnTime)
+ {
+ /* Add last chunk to running time, and use total
+ * running time as 'delta'. */
+ ll_delta = now - jsdc->lastReturnTime;
+ pdata->runningTime += ll_delta;
+ delta = pdata->runningTime;
+ delta /= 1000.0;
+ }
+
+ pdata->totalOwnExecutionTime += delta;
+ /* See minExecutionTime comment above. */
+ if ((0 == pdata->callCount) ||
+ delta < pdata->minOwnExecutionTime)
+ {
+ pdata->minOwnExecutionTime = delta;
+ }
+ if (delta > pdata->maxOwnExecutionTime)
+ pdata->maxOwnExecutionTime = delta;
+
+ /* Current function is now our caller. */
+ jsdc->callingFunctionPData = pdata->caller;
+ /* No hanging pointers, please. */
+ pdata->caller = NULL;
+ /* Mark the time we returned, and indicate this
+ * function is no longer running. */
+ jsdc->lastReturnTime = now;
+ pdata->lastCallStart = 0;
+ ++pdata->callCount;
+ } else if (pdata->recurseDepth) {
+ --pdata->recurseDepth;
+ ++pdata->callCount;
+ }
+ }
+ if (hook)
+ jsd_CallCallHook (jsdc, cx, type, hook, hookData);
+ } else {
+ if (hook)
+ hookresult =
+ jsd_CallCallHook (jsdc, cx, type, hook, hookData);
+ else
+ hookresult = JS_TRUE;
+ }
+ }
+ }
+
+#ifdef JSD_TRACE
+ _interpreterTrace(jsdc, cx, frame, isConstructing, before);
+ return JS_TRUE;
+#else
+ return hookresult;
+#endif
+
+}
+
+void *
+jsd_FunctionCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
+ JSBool before, JSBool *ok, void *closure)
+{
+ JSDContext* jsdc;
+ JSD_CallHookProc hook;
+ void* hookData;
+
+ jsdc = (JSDContext*) closure;
+
+ /* local in case jsdc->functionHook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->functionHook;
+ hookData = jsdc->functionHookData;
+ JSD_UNLOCK();
+
+ if (_callHook (jsdc, cx, frame, isConstructing, before,
+ (before) ? JSD_HOOK_FUNCTION_CALL : JSD_HOOK_FUNCTION_RETURN,
+ hook, hookData))
+ {
+ return closure;
+ }
+
+ return NULL;
+}
+
+void *
+jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
+ JSBool before, JSBool *ok, void *closure)
+{
+ JSDContext* jsdc;
+ JSD_CallHookProc hook;
+ void* hookData;
+
+ jsdc = (JSDContext*) closure;
+
+ /* local in case jsdc->toplevelHook gets cleared on another thread */
+ JSD_LOCK();
+ hook = jsdc->toplevelHook;
+ hookData = jsdc->toplevelHookData;
+ JSD_UNLOCK();
+
+ if (_callHook (jsdc, cx, frame, isConstructing, before,
+ (before) ? JSD_HOOK_TOPLEVEL_START : JSD_HOOK_TOPLEVEL_END,
+ hook, hookData))
+ {
+ return closure;
+ }
+
+ return NULL;
+
+}
diff --git a/js/jsd/jsd_text.cpp b/js/jsd/jsd_text.cpp
new file mode 100644
index 0000000..cd6f58d
--- /dev/null
+++ b/js/jsd/jsd_text.cpp
@@ -0,0 +1,527 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Source Text functions
+ */
+
+#include <ctype.h>
+#include "jsd.h"
+
+#ifdef DEBUG
+void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc)
+{
+ JS_ASSERT(jsdsrc);
+ JS_ASSERT(jsdsrc->url);
+}
+#endif
+
+/***************************************************************************/
+/* XXX add notification */
+
+static void
+_clearText(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ if( jsdsrc->text )
+ free(jsdsrc->text);
+ jsdsrc->text = NULL;
+ jsdsrc->textLength = 0;
+ jsdsrc->textSpace = 0;
+ jsdsrc->status = JSD_SOURCE_CLEARED;
+ jsdsrc->dirty = JS_TRUE;
+ jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
+ jsdsrc->doingEval = JS_FALSE;
+}
+
+static JSBool
+_appendText(JSDContext* jsdc, JSDSourceText* jsdsrc,
+ const char* text, size_t length)
+{
+#define MEMBUF_GROW 1000
+
+ unsigned neededSize = jsdsrc->textLength + length;
+
+ if( neededSize > jsdsrc->textSpace )
+ {
+ char* newBuf;
+ unsigned iNewSize;
+
+ /* if this is the first alloc, the req might be all that's needed*/
+ if( ! jsdsrc->textSpace )
+ iNewSize = length;
+ else
+ iNewSize = (neededSize * 5 / 4) + MEMBUF_GROW;
+
+ newBuf = (char*) realloc(jsdsrc->text, iNewSize);
+ if( ! newBuf )
+ {
+ /* try again with the minimal size really asked for */
+ iNewSize = neededSize;
+ newBuf = (char*) realloc(jsdsrc->text, iNewSize);
+ if( ! newBuf )
+ {
+ /* out of memory */
+ _clearText( jsdc, jsdsrc );
+ jsdsrc->status = JSD_SOURCE_FAILED;
+ return JS_FALSE;
+ }
+ }
+
+ jsdsrc->text = newBuf;
+ jsdsrc->textSpace = iNewSize;
+ }
+
+ memcpy(jsdsrc->text + jsdsrc->textLength, text, length);
+ jsdsrc->textLength += length;
+ return JS_TRUE;
+}
+
+static JSDSourceText*
+_newSource(JSDContext* jsdc, char* url)
+{
+ JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText));
+ if( ! jsdsrc )
+ return NULL;
+
+ jsdsrc->url = url;
+ jsdsrc->status = JSD_SOURCE_INITED;
+ jsdsrc->dirty = JS_TRUE;
+ jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
+
+ return jsdsrc;
+}
+
+static void
+_destroySource(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JS_ASSERT(NULL == jsdsrc->text); /* must _clearText() first */
+ free(jsdsrc->url);
+ free(jsdsrc);
+}
+
+static void
+_removeSource(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JS_REMOVE_LINK(&jsdsrc->links);
+ _clearText(jsdc, jsdsrc);
+ _destroySource(jsdc, jsdsrc);
+}
+
+static JSDSourceText*
+_addSource(JSDContext* jsdc, char* url)
+{
+ JSDSourceText* jsdsrc = _newSource(jsdc, url);
+ if( ! jsdsrc )
+ return NULL;
+ JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources);
+ return jsdsrc;
+}
+
+static void
+_moveSourceToRemovedList(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ _clearText(jsdc, jsdsrc);
+ JS_REMOVE_LINK(&jsdsrc->links);
+ JS_INSERT_LINK(&jsdsrc->links, &jsdc->removedSources);
+}
+
+static void
+_removeSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc )
+{
+ JS_REMOVE_LINK(&jsdsrc->links);
+ _destroySource( jsdc, jsdsrc );
+}
+
+static JSBool
+_isSourceInSourceList(JSDContext* jsdc, JSDSourceText* jsdsrcToFind)
+{
+ JSDSourceText *jsdsrc;
+
+ for( jsdsrc = (JSDSourceText*)jsdc->sources.next;
+ jsdsrc != (JSDSourceText*)&jsdc->sources;
+ jsdsrc = (JSDSourceText*)jsdsrc->links.next )
+ {
+ if( jsdsrc == jsdsrcToFind )
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+}
+
+/* compare strings in a case insensitive manner with a length limit
+*/
+
+static int
+strncasecomp (const char* one, const char * two, int n)
+{
+ const char *pA;
+ const char *pB;
+
+ for(pA=one, pB=two;; pA++, pB++)
+ {
+ int tmp;
+ if (pA == one+n)
+ return 0;
+ if (!(*pA && *pB))
+ return *pA - *pB;
+ tmp = tolower(*pA) - tolower(*pB);
+ if (tmp)
+ return tmp;
+ }
+}
+
+static const char file_url_prefix[] = "file:";
+#define FILE_URL_PREFIX_LEN (sizeof file_url_prefix - 1)
+
+char*
+jsd_BuildNormalizedURL( const char* url_string )
+{
+ char *new_url_string;
+
+ if( ! url_string )
+ return NULL;
+
+ if (!strncasecomp(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) &&
+ url_string[FILE_URL_PREFIX_LEN + 0] == '/' &&
+ url_string[FILE_URL_PREFIX_LEN + 1] == '/') {
+ new_url_string = JS_smprintf("%s%s",
+ file_url_prefix,
+ url_string + FILE_URL_PREFIX_LEN + 2);
+ } else {
+ new_url_string = strdup(url_string);
+ }
+ return new_url_string;
+}
+
+/***************************************************************************/
+
+void
+jsd_DestroyAllSources( JSDContext* jsdc )
+{
+ JSDSourceText *jsdsrc;
+ JSDSourceText *next;
+
+ for( jsdsrc = (JSDSourceText*)jsdc->sources.next;
+ jsdsrc != (JSDSourceText*)&jsdc->sources;
+ jsdsrc = next )
+ {
+ next = (JSDSourceText*)jsdsrc->links.next;
+ _removeSource( jsdc, jsdsrc );
+ }
+
+ for( jsdsrc = (JSDSourceText*)jsdc->removedSources.next;
+ jsdsrc != (JSDSourceText*)&jsdc->removedSources;
+ jsdsrc = next )
+ {
+ next = (JSDSourceText*)jsdsrc->links.next;
+ _removeSourceFromRemovedList( jsdc, jsdsrc );
+ }
+
+}
+
+JSDSourceText*
+jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp)
+{
+ JSDSourceText *jsdsrc = *iterp;
+
+ if( !jsdsrc )
+ jsdsrc = (JSDSourceText *)jsdc->sources.next;
+ if( jsdsrc == (JSDSourceText *)&jsdc->sources )
+ return NULL;
+ *iterp = (JSDSourceText *)jsdsrc->links.next;
+ return jsdsrc;
+}
+
+JSDSourceText*
+jsd_FindSourceForURL(JSDContext* jsdc, const char* url)
+{
+ JSDSourceText *jsdsrc;
+
+ for( jsdsrc = (JSDSourceText *)jsdc->sources.next;
+ jsdsrc != (JSDSourceText *)&jsdc->sources;
+ jsdsrc = (JSDSourceText *)jsdsrc->links.next )
+ {
+ if( 0 == strcmp(jsdsrc->url, url) )
+ return jsdsrc;
+ }
+ return NULL;
+}
+
+const char*
+jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ return jsdsrc->url;
+}
+
+JSBool
+jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
+ const char** ppBuf, int* pLen )
+{
+ *ppBuf = jsdsrc->text;
+ *pLen = jsdsrc->textLength;
+ return JS_TRUE;
+}
+
+void
+jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ if( JSD_SOURCE_INITED != jsdsrc->status &&
+ JSD_SOURCE_PARTIAL != jsdsrc->status )
+ {
+ _clearText(jsdc, jsdsrc);
+ }
+}
+
+JSDSourceStatus
+jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ return jsdsrc->status;
+}
+
+JSBool
+jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ return jsdsrc->dirty;
+}
+
+void
+jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty)
+{
+ jsdsrc->dirty = dirty;
+}
+
+unsigned
+jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ return jsdsrc->alterCount;
+}
+
+unsigned
+jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ return jsdsrc->alterCount = jsdc->sourceAlterCount++;
+}
+
+/***************************************************************************/
+
+#if defined(DEBUG) && 0
+void DEBUG_ITERATE_SOURCES( JSDContext* jsdc )
+{
+ JSDSourceText* iterp = NULL;
+ JSDSourceText* jsdsrc = NULL;
+ int dummy;
+
+ while( NULL != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) )
+ {
+ const char* url;
+ const char* text;
+ int len;
+ JSBool dirty;
+ JSDStreamStatus status;
+ JSBool gotSrc;
+
+ url = JSD_GetSourceURL(jsdc, jsdsrc);
+ dirty = JSD_IsSourceDirty(jsdc, jsdsrc);
+ status = JSD_GetSourceStatus(jsdc, jsdsrc);
+ gotSrc = JSD_GetSourceText(jsdc, jsdsrc, &text, &len );
+
+ dummy = 0; /* gives us a line to set breakpoint... */
+ }
+}
+#else
+#define DEBUG_ITERATE_SOURCES(x) ((void)x)
+#endif
+
+/***************************************************************************/
+
+JSDSourceText*
+jsd_NewSourceText(JSDContext* jsdc, const char* url)
+{
+ JSDSourceText* jsdsrc;
+ char* new_url_string;
+
+ JSD_LOCK_SOURCE_TEXT(jsdc);
+
+#ifdef LIVEWIRE
+ new_url_string = url; /* we take ownership of alloc'd string */
+#else
+ new_url_string = jsd_BuildNormalizedURL(url);
+#endif
+ if( ! new_url_string )
+ return NULL;
+
+ jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string);
+
+ if( jsdsrc )
+ {
+ if( jsdsrc->doingEval )
+ {
+ free(new_url_string);
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return NULL;
+ }
+ else
+ _moveSourceToRemovedList(jsdc, jsdsrc);
+ }
+
+ jsdsrc = _addSource( jsdc, new_url_string );
+
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+
+ return jsdsrc;
+}
+
+JSDSourceText*
+jsd_AppendSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status)
+{
+ JSD_LOCK_SOURCE_TEXT(jsdc);
+
+ if( jsdsrc->doingEval )
+ {
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return NULL;
+ }
+
+ if( ! _isSourceInSourceList( jsdc, jsdsrc ) )
+ {
+ _removeSourceFromRemovedList( jsdc, jsdsrc );
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return NULL;
+ }
+
+ if( text && length && ! _appendText( jsdc, jsdsrc, text, length ) )
+ {
+ jsdsrc->dirty = JS_TRUE;
+ jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
+ jsdsrc->status = JSD_SOURCE_FAILED;
+ _moveSourceToRemovedList(jsdc, jsdsrc);
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return NULL;
+ }
+
+ jsdsrc->dirty = JS_TRUE;
+ jsdsrc->alterCount = jsdc->sourceAlterCount++ ;
+ jsdsrc->status = status;
+ DEBUG_ITERATE_SOURCES(jsdc);
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return jsdsrc;
+}
+
+JSDSourceText*
+jsd_AppendUCSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const jschar* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status)
+{
+#define UNICODE_TRUNCATE_BUF_SIZE 1024
+ static char* buf = NULL;
+ int remaining = length;
+
+ if(!text || !length)
+ return jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status);
+
+ JSD_LOCK_SOURCE_TEXT(jsdc);
+ if(!buf)
+ {
+ buf = js_pod_malloc<char>(UNICODE_TRUNCATE_BUF_SIZE);
+ if(!buf)
+ {
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return NULL;
+ }
+ }
+ while(remaining && jsdsrc) {
+ int bytes = (remaining < UNICODE_TRUNCATE_BUF_SIZE) ? remaining : UNICODE_TRUNCATE_BUF_SIZE;
+ int i;
+ for(i = 0; i < bytes; i++)
+ buf[i] = (const char) *(text++);
+ jsdsrc = jsd_AppendSourceText(jsdc,jsdsrc,
+ buf, bytes,
+ JSD_SOURCE_PARTIAL);
+ remaining -= bytes;
+ }
+ if(jsdsrc && status != JSD_SOURCE_PARTIAL)
+ jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status);
+
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ return jsdsrc;
+}
+
+/* convienence function for adding complete source of url in one call */
+JSBool
+jsd_AddFullSourceText(JSDContext* jsdc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ const char* url)
+{
+ JSDSourceText* jsdsrc;
+
+ JSD_LOCK_SOURCE_TEXT(jsdc);
+
+ jsdsrc = jsd_NewSourceText(jsdc, url);
+ if( jsdsrc )
+ jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
+ text, length, JSD_SOURCE_PARTIAL );
+ if( jsdsrc )
+ jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
+ NULL, 0, JSD_SOURCE_COMPLETED );
+
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+
+ return jsdsrc ? JS_TRUE : JS_FALSE;
+}
+
+/***************************************************************************/
+
+void
+jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url)
+{
+ JSDSourceText* jsdsrc;
+
+ /* NOTE: We leave it locked! */
+ JSD_LOCK_SOURCE_TEXT(jsdc);
+
+ jsdsrc = jsd_FindSourceForURL(jsdc, url);
+ if(jsdsrc)
+ {
+#if 0
+#ifndef JSD_LOWLEVEL_SOURCE
+ JS_ASSERT(! jsdsrc->doingEval);
+#endif
+#endif
+ jsdsrc->doingEval = JS_TRUE;
+ }
+}
+
+void
+jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url)
+{
+ JSDSourceText* jsdsrc;
+
+ /* NOTE: We ASSUME it is locked! */
+
+ jsdsrc = jsd_FindSourceForURL(jsdc, url);
+ if(jsdsrc)
+ {
+#if 0
+#ifndef JSD_LOWLEVEL_SOURCE
+ /*
+ * when using this low level source addition, this jsdsrc might
+ * not have existed before the eval, but does exist now (without
+ * this flag set!)
+ */
+ JS_ASSERT(jsdsrc->doingEval);
+#endif
+#endif
+ jsdsrc->doingEval = JS_FALSE;
+ }
+
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+}
diff --git a/js/jsd/jsd_val.cpp b/js/jsd/jsd_val.cpp
new file mode 100644
index 0000000..8853144
--- /dev/null
+++ b/js/jsd/jsd_val.cpp
@@ -0,0 +1,739 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - Value and Property support
+ */
+
+#include "jsd.h"
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "jswrapper.h"
+#include "nsCxPusher.h"
+
+using mozilla::AutoSafeJSContext;
+
+#ifdef DEBUG
+void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
+{
+ JS_ASSERT(jsdval);
+ JS_ASSERT(jsdval->nref > 0);
+ if(!JS_CLIST_IS_EMPTY(&jsdval->props))
+ {
+ JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS));
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val));
+ }
+
+ if(jsdval->proto)
+ {
+ JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
+ JS_ASSERT(jsdval->proto->nref > 0);
+ }
+ if(jsdval->parent)
+ {
+ JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT));
+ JS_ASSERT(jsdval->parent->nref > 0);
+ }
+ if(jsdval->ctor)
+ {
+ JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR));
+ JS_ASSERT(jsdval->ctor->nref > 0);
+ }
+}
+
+void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop)
+{
+ JS_ASSERT(jsdprop);
+ JS_ASSERT(jsdprop->name);
+ JS_ASSERT(jsdprop->name->nref > 0);
+ JS_ASSERT(jsdprop->val);
+ JS_ASSERT(jsdprop->val->nref > 0);
+ if(jsdprop->alias)
+ JS_ASSERT(jsdprop->alias->nref > 0);
+}
+#endif
+
+
+JSBool
+jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return !JSVAL_IS_PRIMITIVE(jsdval->val) || JSVAL_IS_NULL(jsdval->val);
+}
+
+JSBool
+jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_NUMBER(jsdval->val);
+}
+
+JSBool
+jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_INT(jsdval->val);
+}
+
+JSBool
+jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_DOUBLE(jsdval->val);
+}
+
+JSBool
+jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_STRING(jsdval->val);
+}
+
+JSBool
+jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_BOOLEAN(jsdval->val);
+}
+
+JSBool
+jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_NULL(jsdval->val);
+}
+
+JSBool
+jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_VOID(jsdval->val);
+}
+
+JSBool
+jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
+{
+ return JSVAL_IS_PRIMITIVE(jsdval->val);
+}
+
+JSBool
+jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx; // NB: Actually unused.
+ return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
+ JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(jsdval->val));
+}
+
+JSBool
+jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ JS::RootedFunction fun(cx);
+
+ if(jsd_IsValueFunction(jsdc, jsdval))
+ {
+ JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val));
+ AutoSaveExceptionState as(cx);
+ JSBool ok = JS_FALSE;
+ fun = JSD_GetValueFunction(jsdc, jsdval);
+ if(fun)
+ ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
+ JS_ASSERT(fun);
+ return ok;
+ }
+ return !JSVAL_IS_PRIMITIVE(jsdval->val);
+}
+
+/***************************************************************************/
+
+JSBool
+jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
+{
+ jsval val = jsdval->val;
+ if(!JSVAL_IS_BOOLEAN(val))
+ return JS_FALSE;
+ return JSVAL_TO_BOOLEAN(val);
+}
+
+int32_t
+jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
+{
+ jsval val = jsdval->val;
+ if(!JSVAL_IS_INT(val))
+ return 0;
+ return JSVAL_TO_INT(val);
+}
+
+double
+jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
+{
+ if(!JSVAL_IS_DOUBLE(jsdval->val))
+ return 0;
+ return JSVAL_TO_DOUBLE(jsdval->val);
+}
+
+JSString*
+jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ JS::RootedValue stringval(cx);
+ JS::RootedString string(cx);
+ JS::RootedObject scopeObj(cx);
+
+ if(jsdval->string)
+ return jsdval->string;
+
+ /* Reuse the string without copying or re-rooting it */
+ if(JSVAL_IS_STRING(jsdval->val)) {
+ jsdval->string = JSVAL_TO_STRING(jsdval->val);
+ return jsdval->string;
+ }
+
+ /* Objects call JS_ValueToString in their own compartment. */
+ scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob;
+ {
+ JSAutoCompartment ac(cx, scopeObj);
+ AutoSaveExceptionState as(cx);
+ string = JS_ValueToString(cx, jsdval->val);
+ }
+
+ JSAutoCompartment ac2(cx, jsdc->glob);
+ if(string) {
+ stringval = STRING_TO_JSVAL(string);
+ }
+ if(!string || !JS_WrapValue(cx, stringval.address())) {
+ return NULL;
+ }
+
+ jsdval->string = JSVAL_TO_STRING(stringval);
+ if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
+ jsdval->string = NULL;
+
+ return jsdval->string;
+}
+
+JSString*
+jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ JS::RootedFunction fun(cx);
+
+ if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
+ {
+ JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val));
+ AutoSaveExceptionState as(cx);
+ fun = JSD_GetValueFunction(jsdc, jsdval);
+ if(!fun)
+ return NULL;
+ jsdval->funName = JS_GetFunctionId(fun);
+
+ /* For compatibility we return "anonymous", not an empty string here. */
+ if (!jsdval->funName)
+ jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
+ }
+ return jsdval->funName;
+}
+
+/***************************************************************************/
+
+/*
+ * Create a new JSD value referring to a jsval. Copy string values into the
+ * JSD compartment. Leave all other GCTHINGs in their native compartments
+ * and access them through cross-compartment calls.
+ */
+JSDValue*
+jsd_NewValue(JSDContext* jsdc, jsval value)
+{
+ AutoSafeJSContext cx;
+ JS::RootedValue val(cx, value);
+ JSDValue* jsdval;
+
+ if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
+ return NULL;
+
+ if(JSVAL_IS_GCTHING(val))
+ {
+ JSBool ok;
+ JSAutoCompartment ac(cx, jsdc->glob);
+
+ ok = JS_AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
+ if(ok && JSVAL_IS_STRING(val)) {
+ if(!JS_WrapValue(cx, val.address())) {
+ ok = JS_FALSE;
+ }
+ }
+
+ if(!ok)
+ {
+ free(jsdval);
+ return NULL;
+ }
+ }
+ jsdval->val = val;
+ jsdval->nref = 1;
+ JS_INIT_CLIST(&jsdval->props);
+
+ return jsdval;
+}
+
+void
+jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JS_ASSERT(jsdval->nref > 0);
+ if(0 == --jsdval->nref)
+ {
+ jsd_RefreshValue(jsdc, jsdval);
+ if(JSVAL_IS_GCTHING(jsdval->val))
+ {
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, jsdc->glob);
+ JS_RemoveValueRoot(cx, &jsdval->val);
+ }
+ free(jsdval);
+ }
+}
+
+jsval
+jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ JS::RootedObject obj(cx);
+ JS::RootedValue val(cx, jsdval->val);
+ if (!JSVAL_IS_PRIMITIVE(val)) {
+ JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(val));
+ obj = JS_ObjectToOuterObject(cx, JSVAL_TO_OBJECT(val));
+ if (!obj)
+ {
+ JS_ClearPendingException(cx);
+ val = JSVAL_NULL;
+ }
+ else
+ val = OBJECT_TO_JSVAL(obj);
+ }
+
+ return val;
+}
+
+static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd,
+ unsigned additionalFlags)
+{
+ JSDProperty* jsdprop;
+
+ if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
+ return NULL;
+
+ JS_INIT_CLIST(&jsdprop->links);
+ jsdprop->nref = 1;
+ jsdprop->flags = pd->flags | additionalFlags;
+
+ if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
+ goto new_prop_fail;
+
+ if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
+ goto new_prop_fail;
+
+ if((jsdprop->flags & JSDPD_ALIAS) &&
+ !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
+ goto new_prop_fail;
+
+ return jsdprop;
+new_prop_fail:
+ jsd_DropProperty(jsdc, jsdprop);
+ return NULL;
+}
+
+static void _freeProps(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSDProperty* jsdprop;
+
+ while(jsdprop = (JSDProperty*)jsdval->props.next,
+ jsdprop != (JSDProperty*)&jsdval->props)
+ {
+ JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
+ jsd_DropProperty(jsdc, jsdprop);
+ }
+ JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
+ CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
+}
+
+static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ JS::RootedObject obj(cx);
+ JSPropertyDescArray pda;
+ unsigned i;
+
+ JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
+ JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
+ JS_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val));
+
+ if(JSVAL_IS_PRIMITIVE(jsdval->val))
+ return JS_FALSE;
+
+ obj = JSVAL_TO_OBJECT(jsdval->val);
+
+ JSAutoCompartment ac(cx, obj);
+
+ if(!JS_GetPropertyDescArray(cx, obj, &pda))
+ {
+ return JS_FALSE;
+ }
+
+ for(i = 0; i < pda.length; i++)
+ {
+ JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
+ if(!prop)
+ {
+ _freeProps(jsdc, jsdval);
+ break;
+ }
+ JS_APPEND_LINK(&prop->links, &jsdval->props);
+ }
+ JS_PutPropertyDescArray(cx, &pda);
+ SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
+ return !JS_CLIST_IS_EMPTY(&jsdval->props);
+}
+
+#undef DROP_CLEAR_VALUE
+#define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = NULL;}
+
+void
+jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ if(jsdval->string)
+ {
+ /* if the jsval is a string, then we didn't need to root the string */
+ if(!JSVAL_IS_STRING(jsdval->val))
+ {
+ JSAutoCompartment ac(cx, jsdc->glob);
+ JS_RemoveStringRoot(cx, &jsdval->string);
+ }
+ jsdval->string = NULL;
+ }
+
+ jsdval->funName = NULL;
+ jsdval->className = NULL;
+ DROP_CLEAR_VALUE(jsdc, jsdval->proto);
+ DROP_CLEAR_VALUE(jsdc, jsdval->parent);
+ DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
+ _freeProps(jsdc, jsdval);
+ jsdval->flags = 0;
+}
+
+/***************************************************************************/
+
+unsigned
+jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSDProperty* jsdprop;
+ unsigned count = 0;
+
+ if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
+ if(!_buildProps(jsdc, jsdval))
+ return 0;
+
+ for(jsdprop = (JSDProperty*)jsdval->props.next;
+ jsdprop != (JSDProperty*)&jsdval->props;
+ jsdprop = (JSDProperty*)jsdprop->links.next)
+ {
+ count++;
+ }
+ return count;
+}
+
+JSDProperty*
+jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
+{
+ JSDProperty* jsdprop = *iterp;
+ if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
+ {
+ JS_ASSERT(!jsdprop);
+ if(!_buildProps(jsdc, jsdval))
+ return NULL;
+ }
+
+ if(!jsdprop)
+ jsdprop = (JSDProperty*)jsdval->props.next;
+ if(jsdprop == (JSDProperty*)&jsdval->props)
+ return NULL;
+ *iterp = (JSDProperty*)jsdprop->links.next;
+
+ JS_ASSERT(jsdprop);
+ jsdprop->nref++;
+ return jsdprop;
+}
+
+JSDProperty*
+jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr)
+{
+ AutoSafeJSContext cx;
+ JSAutoCompartment acBase(cx, jsdc->glob);
+ JSDProperty* jsdprop;
+ JSDProperty* iter = NULL;
+ JS::RootedObject obj(cx);
+ JS::RootedString name(cx, nameStr);
+ unsigned attrs = 0;
+ JSBool found;
+ JSPropertyDesc pd;
+ const jschar * nameChars;
+ size_t nameLen;
+ JS::RootedValue val(cx), nameval(cx);
+ JS::RootedId nameid(cx);
+
+ if(!jsd_IsValueObject(jsdc, jsdval))
+ return NULL;
+
+ /* If we already have the prop, then return it */
+ while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
+ {
+ JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
+ if(propName) {
+ int result;
+ if (JS_CompareStrings(cx, propName, name, &result) && !result)
+ return jsdprop;
+ }
+ JSD_DropProperty(jsdc, jsdprop);
+ }
+ /* Not found in property list, look it up explicitly */
+
+ if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
+ return NULL;
+
+ if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
+ return NULL;
+
+ {
+ JSAutoCompartment ac(cx, obj);
+
+ JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
+ if (!found)
+ {
+ return NULL;
+ }
+
+ JS_ClearPendingException(cx);
+
+ if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, val.address()))
+ {
+ if (JS_IsExceptionPending(cx))
+ {
+ if (!JS_GetPendingException(cx, &pd.value))
+ {
+ return NULL;
+ }
+ pd.flags = JSPD_EXCEPTION;
+ }
+ else
+ {
+ pd.flags = JSPD_ERROR;
+ pd.value = JSVAL_VOID;
+ }
+ }
+ else
+ {
+ pd.value = val;
+ }
+ }
+
+ nameval = STRING_TO_JSVAL(name);
+ if (!JS_ValueToId(cx, nameval, nameid.address()) ||
+ !JS_IdToValue(cx, nameid, &pd.id)) {
+ return NULL;
+ }
+
+ pd.spare = 0;
+ pd.alias = JSVAL_NULL;
+ pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
+ | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0
+ | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
+
+ return _newProperty(jsdc, &pd, JSDPD_HINTED);
+}
+
+/*
+ * Retrieve a JSFunction* from a JSDValue*. This differs from
+ * JS_ValueToFunction by fully unwrapping the object first.
+ */
+JSFunction*
+jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+
+ JS::RootedObject obj(cx);
+ JS::RootedFunction fun(cx);
+
+ if (JSVAL_IS_PRIMITIVE(jsdval->val))
+ return NULL;
+
+ obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val));
+ JSAutoCompartment ac(cx, obj);
+ fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj));
+
+ return fun;
+}
+
+JSDValue*
+jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
+ {
+ JS::RootedObject obj(cx);
+ JS::RootedObject proto(cx);
+ JS_ASSERT(!jsdval->proto);
+ SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
+ if(JSVAL_IS_PRIMITIVE(jsdval->val))
+ return NULL;
+ obj = JSVAL_TO_OBJECT(jsdval->val);
+ if(!JS_GetPrototype(cx, obj, proto.address()))
+ return NULL;
+ if(!proto)
+ return NULL;
+ jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
+ }
+ if(jsdval->proto)
+ jsdval->proto->nref++;
+ return jsdval->proto;
+}
+
+JSDValue*
+jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
+{
+ if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
+ {
+ AutoSafeJSContext cx;
+ JS::RootedObject obj(cx);
+ JS::RootedObject parent(cx);
+ JS_ASSERT(!jsdval->parent);
+ SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
+ if(JSVAL_IS_PRIMITIVE(jsdval->val))
+ return NULL;
+ obj = JSVAL_TO_OBJECT(jsdval->val);
+ {
+ JSAutoCompartment ac(cx, obj);
+ parent = JS_GetParentOrScopeChain(cx, obj);
+ }
+ if(!parent)
+ return NULL;
+ jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
+ }
+ if(jsdval->parent)
+ jsdval->parent->nref++;
+ return jsdval->parent;
+}
+
+JSDValue*
+jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
+{
+ if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
+ {
+ AutoSafeJSContext cx;
+ JS::RootedObject obj(cx);
+ JS::RootedObject proto(cx);
+ JS::RootedObject ctor(cx);
+ JS_ASSERT(!jsdval->ctor);
+ SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
+ if(JSVAL_IS_PRIMITIVE(jsdval->val))
+ return NULL;
+ obj = JSVAL_TO_OBJECT(jsdval->val);
+ if(!JS_GetPrototype(cx, obj, proto.address()))
+ return NULL;
+ if(!proto)
+ return NULL;
+ {
+ JSAutoCompartment ac(cx, obj);
+ ctor = JS_GetConstructor(cx, proto);
+ }
+ if(!ctor)
+ return NULL;
+ jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
+ }
+ if(jsdval->ctor)
+ jsdval->ctor->nref++;
+ return jsdval->ctor;
+}
+
+const char*
+jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
+{
+ jsval val = jsdval->val;
+ if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val))
+ {
+ AutoSafeJSContext cx;
+ JS::RootedObject obj(cx, JSVAL_TO_OBJECT(val));
+ JSAutoCompartment ac(cx, obj);
+ jsdval->className = JS_GetDebugClassName(obj);
+ }
+ return jsdval->className;
+}
+
+JSDScript*
+jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ AutoSafeJSContext cx;
+ JS::RootedValue val(cx, jsdval->val);
+ JSFunction* fun = NULL;
+ JS::RootedScript script(cx);
+ JSDScript* jsdscript;
+
+ if (!jsd_IsValueFunction(jsdc, jsdval))
+ return NULL;
+
+ {
+ JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(val));
+ AutoSaveExceptionState as(cx);
+ fun = JSD_GetValueFunction(jsdc, jsdval);
+ if (fun)
+ script = JS_GetFunctionScript(cx, fun);
+ }
+
+ if (!script)
+ return NULL;
+
+ JSD_LOCK_SCRIPTS(jsdc);
+ jsdscript = jsd_FindJSDScript(jsdc, script);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+ return jsdscript;
+}
+
+
+/***************************************************************************/
+/***************************************************************************/
+
+JSDValue*
+jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ jsdprop->name->nref++;
+ return jsdprop->name;
+}
+
+JSDValue*
+jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ jsdprop->val->nref++;
+ return jsdprop->val;
+}
+
+JSDValue*
+jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ if(jsdprop->alias)
+ jsdprop->alias->nref++;
+ return jsdprop->alias;
+}
+
+unsigned
+jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ return jsdprop->flags;
+}
+
+void
+jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ JS_ASSERT(jsdprop->nref > 0);
+ if(0 == --jsdprop->nref)
+ {
+ JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
+ DROP_CLEAR_VALUE(jsdc, jsdprop->val);
+ DROP_CLEAR_VALUE(jsdc, jsdprop->name);
+ DROP_CLEAR_VALUE(jsdc, jsdprop->alias);
+ free(jsdprop);
+ }
+}
diff --git a/js/jsd/jsd_xpc.cpp b/js/jsd/jsd_xpc.cpp
new file mode 100644
index 0000000..9e32581
--- /dev/null
+++ b/js/jsd/jsd_xpc.cpp
@@ -0,0 +1,3430 @@
+/* -*- 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 "jsdbgapi.h"
+#include "jslock.h"
+#include "jsd_xpc.h"
+
+#include "js/GCAPI.h"
+
+#include "nsIXPConnect.h"
+#include "mozilla/ModuleUtils.h"
+#include "nsIServiceManager.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsICategoryManager.h"
+#include "nsIJSRuntimeService.h"
+#include "nsIThreadInternal.h"
+#include "nsTArray.h"
+#include "nsThreadUtils.h"
+#include "nsMemory.h"
+#include "jsdebug.h"
+#include "nsReadableUtils.h"
+#include "nsCRT.h"
+#include "nsCycleCollectionParticipant.h"
+#include "mozilla/Attributes.h"
+
+/* XXX DOM dependency */
+#include "nsIScriptContext.h"
+#include "SandboxPrivate.h"
+#include "nsJSPrincipals.h"
+#include "nsContentUtils.h"
+#include "nsCxPusher.h"
+
+using mozilla::AutoSafeJSContext;
+using mozilla::AutoPushJSContext;
+
+/*
+ * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
+ * script hook. This was a hack to avoid some js engine problems that should
+ * be fixed now (see Mozilla bug 77636).
+ */
+#undef CAUTIOUS_SCRIPTHOOK
+
+#ifdef DEBUG_verbose
+# define DEBUG_COUNT(name, count) \
+ { if ((count % 10) == 0) printf (name ": %i\n", count); }
+# define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ " name,count)}
+# define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- " name,count)}
+#else
+# define DEBUG_CREATE(name, count)
+# define DEBUG_DESTROY(name, count)
+#endif
+
+#define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
+#define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
+
+#define JSDSERVICE_CID \
+{ /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \
+ 0xf1299dc2, \
+ 0x1dd1, \
+ 0x11b2, \
+ {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
+}
+
+#define JSDASO_CID \
+{ /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \
+ 0x2fd6b7f6, \
+ 0xeb8c, \
+ 0x4f32, \
+ {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
+}
+
+#define JSDS_MAJOR_VERSION 1
+#define JSDS_MINOR_VERSION 2
+
+#define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1"
+#define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1"
+
+#define AUTOREG_CATEGORY "xpcom-autoregistration"
+#define APPSTART_CATEGORY "app-startup"
+#define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
+#define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
+
+static void
+jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc);
+
+/*******************************************************************************
+ * global vars
+ ******************************************************************************/
+
+const char implementationString[] = "Mozilla JavaScript Debugger Service";
+
+const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
+const char jsdARObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
+const char jsdASObserverCtrID[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
+
+#ifdef DEBUG_verbose
+uint32_t gScriptCount = 0;
+uint32_t gValueCount = 0;
+uint32_t gPropertyCount = 0;
+uint32_t gContextCount = 0;
+uint32_t gFrameCount = 0;
+#endif
+
+static jsdService *gJsds = 0;
+static JS::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
+static bool gGCRunning = false;
+
+static struct DeadScript {
+ PRCList links;
+ JSDContext *jsdc;
+ jsdIScript *script;
+} *gDeadScripts = nullptr;
+
+enum PatternType {
+ ptIgnore = 0U,
+ ptStartsWith = 1U,
+ ptEndsWith = 2U,
+ ptContains = 3U,
+ ptEquals = 4U
+};
+
+static struct FilterRecord {
+ PRCList links;
+ jsdIFilter *filterObject;
+ nsCString urlPattern;
+ PatternType patternType;
+ uint32_t startLine;
+ uint32_t endLine;
+} *gFilters = nullptr;
+
+static struct LiveEphemeral *gLiveValues = nullptr;
+static struct LiveEphemeral *gLiveProperties = nullptr;
+static struct LiveEphemeral *gLiveContexts = nullptr;
+static struct LiveEphemeral *gLiveStackFrames = nullptr;
+
+/*******************************************************************************
+ * utility functions for ephemeral lists
+ *******************************************************************************/
+already_AddRefed<jsdIEphemeral>
+jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
+{
+ if (!*listHead)
+ return nullptr;
+
+ LiveEphemeral *lv_record =
+ reinterpret_cast<LiveEphemeral *>
+ (PR_NEXT_LINK(&(*listHead)->links));
+ do
+ {
+ if (lv_record->key == key)
+ {
+ nsCOMPtr<jsdIEphemeral> ret = lv_record->value;
+ return ret.forget();
+ }
+ lv_record = reinterpret_cast<LiveEphemeral *>
+ (PR_NEXT_LINK(&lv_record->links));
+ }
+ while (lv_record != *listHead);
+
+ return nullptr;
+}
+
+void
+jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
+{
+ LiveEphemeral *lv_record =
+ reinterpret_cast<LiveEphemeral *>
+ (PR_NEXT_LINK(&(*listHead)->links));
+ do
+ {
+ LiveEphemeral *next =
+ reinterpret_cast<LiveEphemeral *>
+ (PR_NEXT_LINK(&lv_record->links));
+ lv_record->value->Invalidate();
+ lv_record = next;
+ }
+ while (*listHead);
+}
+
+void
+jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
+{
+ if (*listHead) {
+ /* if the list exists, add to it */
+ PR_APPEND_LINK(&item->links, &(*listHead)->links);
+ } else {
+ /* otherwise create the list */
+ PR_INIT_CLIST(&item->links);
+ *listHead = item;
+ }
+}
+
+void
+jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
+{
+ LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
+ (PR_NEXT_LINK(&item->links));
+
+ if (next == item)
+ {
+ /* if the current item is also the next item, we're the only element,
+ * null out the list head */
+ NS_ASSERTION (*listHead == item,
+ "How could we not be the head of a one item list?");
+ *listHead = nullptr;
+ }
+ else if (item == *listHead)
+ {
+ /* otherwise, if we're currently the list head, change it */
+ *listHead = next;
+ }
+
+ PR_REMOVE_AND_INIT_LINK(&item->links);
+}
+
+/*******************************************************************************
+ * utility functions for filters
+ *******************************************************************************/
+void
+jsds_FreeFilter (FilterRecord *rec)
+{
+ NS_IF_RELEASE (rec->filterObject);
+ PR_Free (rec);
+}
+
+/* copies appropriate |filter| attributes into |rec|.
+ * False return indicates failure, the contents of |rec| will not be changed.
+ */
+bool
+jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
+{
+ NS_ASSERTION (rec, "jsds_SyncFilter without rec");
+ NS_ASSERTION (filter, "jsds_SyncFilter without filter");
+
+ uint32_t startLine;
+ nsresult rv = filter->GetStartLine(&startLine);
+ if (NS_FAILED(rv))
+ return false;
+
+ uint32_t endLine;
+ rv = filter->GetStartLine(&endLine);
+ if (NS_FAILED(rv))
+ return false;
+
+ nsAutoCString urlPattern;
+ rv = filter->GetUrlPattern (urlPattern);
+ if (NS_FAILED(rv))
+ return false;
+
+ uint32_t len = urlPattern.Length();
+ if (len) {
+ if (urlPattern[0] == '*') {
+ /* pattern starts with a *, shift all chars once to the left,
+ * including the trailing null. */
+ urlPattern = Substring(urlPattern, 1, len);
+
+ if (urlPattern[len - 2] == '*') {
+ /* pattern is in the format "*foo*", overwrite the final * with
+ * a null. */
+ urlPattern.Truncate(len - 2);
+ rec->patternType = ptContains;
+ } else {
+ /* pattern is in the format "*foo", just make a note of the
+ * new length. */
+ rec->patternType = ptEndsWith;
+ }
+ } else if (urlPattern[len - 1] == '*') {
+ /* pattern is in the format "foo*", overwrite the final * with a
+ * null. */
+ urlPattern.Truncate(len - 1);
+ rec->patternType = ptStartsWith;
+ } else {
+ /* pattern is in the format "foo". */
+ rec->patternType = ptEquals;
+ }
+ } else {
+ rec->patternType = ptIgnore;
+ }
+
+ /* we got everything we need without failing, now copy it into rec. */
+
+ if (rec->filterObject != filter) {
+ NS_IF_RELEASE(rec->filterObject);
+ NS_ADDREF(filter);
+ rec->filterObject = filter;
+ }
+
+ rec->startLine = startLine;
+ rec->endLine = endLine;
+
+ rec->urlPattern = urlPattern;
+
+ return true;
+
+}
+
+FilterRecord *
+jsds_FindFilter (jsdIFilter *filter)
+{
+ if (!gFilters)
+ return nullptr;
+
+ FilterRecord *current = gFilters;
+
+ do {
+ if (current->filterObject == filter)
+ return current;
+ current = reinterpret_cast<FilterRecord *>
+ (PR_NEXT_LINK(&current->links));
+ } while (current != gFilters);
+
+ return nullptr;
+}
+
+/* returns true if the hook should be executed. */
+bool
+jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
+{
+ JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
+
+ if (!frame) {
+ NS_WARNING("No frame in threadstate");
+ return false;
+ }
+
+ JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
+ if (!script)
+ return true;
+
+ uintptr_t pc = JSD_GetPCForStackFrame (jsdc, state, frame);
+
+ nsCString url(JSD_GetScriptFilename (jsdc, script));
+ if (url.IsEmpty()) {
+ NS_WARNING ("Script with no filename");
+ return false;
+ }
+
+ if (!gFilters)
+ return true;
+
+ uint32_t currentLine = JSD_GetClosestLine (jsdc, script, pc);
+ uint32_t len = 0;
+ FilterRecord *currentFilter = gFilters;
+ do {
+ uint32_t flags = 0;
+
+#ifdef DEBUG
+ nsresult rv =
+#endif
+ currentFilter->filterObject->GetFlags(&flags);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
+
+ if (flags & jsdIFilter::FLAG_ENABLED) {
+ /* If there is no start line, or the start line is before
+ * or equal to the current */
+ if ((!currentFilter->startLine ||
+ currentFilter->startLine <= currentLine) &&
+ /* and there is no end line, or the end line is after
+ * or equal to the current */
+ (!currentFilter->endLine ||
+ currentFilter->endLine >= currentLine)) {
+ /* then we're going to have to compare the url. */
+ if (currentFilter->patternType == ptIgnore)
+ return !!(flags & jsdIFilter::FLAG_PASS);
+
+ if (!len)
+ len = url.Length();
+ nsCString urlPattern = currentFilter->urlPattern;
+ uint32_t patternLength = urlPattern.Length();
+ if (len >= patternLength) {
+ switch (currentFilter->patternType) {
+ case ptEquals:
+ if (urlPattern.Equals(url))
+ return !!(flags & jsdIFilter::FLAG_PASS);
+ break;
+ case ptStartsWith:
+ if (urlPattern.Equals(Substring(url, 0, patternLength)))
+ return !!(flags & jsdIFilter::FLAG_PASS);
+ break;
+ case ptEndsWith:
+ if (urlPattern.Equals(Substring(url, len - patternLength)))
+ return !!(flags & jsdIFilter::FLAG_PASS);
+ break;
+ case ptContains:
+ {
+ nsACString::const_iterator start, end;
+ url.BeginReading(start);
+ url.EndReading(end);
+ if (FindInReadable(currentFilter->urlPattern, start, end))
+ return !!(flags & jsdIFilter::FLAG_PASS);
+ }
+ break;
+ default:
+ NS_ERROR("Invalid pattern type");
+ }
+ }
+ }
+ }
+ currentFilter = reinterpret_cast<FilterRecord *>
+ (PR_NEXT_LINK(&currentFilter->links));
+ } while (currentFilter != gFilters);
+
+ return true;
+
+}
+
+/*******************************************************************************
+ * c callbacks
+ *******************************************************************************/
+
+static void
+jsds_NotifyPendingDeadScripts (JSRuntime *rt)
+{
+ jsdService *jsds = gJsds;
+
+ nsCOMPtr<jsdIScriptHook> hook;
+ if (jsds) {
+ NS_ADDREF(jsds);
+ jsds->GetScriptHook (getter_AddRefs(hook));
+ jsds->DoPause(nullptr, true);
+ }
+
+ DeadScript *deadScripts = gDeadScripts;
+ gDeadScripts = nullptr;
+ while (deadScripts) {
+ DeadScript *ds = deadScripts;
+ /* get next deleted script */
+ deadScripts = reinterpret_cast<DeadScript *>
+ (PR_NEXT_LINK(&ds->links));
+ if (deadScripts == ds)
+ deadScripts = nullptr;
+
+ if (hook)
+ {
+ /* tell the user this script has been destroyed */
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JS_UNKEEP_ATOMS(rt);
+#endif
+ hook->OnScriptDestroyed (ds->script);
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JS_KEEP_ATOMS(rt);
+#endif
+ }
+
+ /* take it out of the circular list */
+ PR_REMOVE_LINK(&ds->links);
+
+ /* addref came from the FromPtr call in jsds_ScriptHookProc */
+ NS_RELEASE(ds->script);
+ /* free the struct! */
+ PR_Free(ds);
+ }
+
+ if (jsds) {
+ jsds->DoUnPause(nullptr, true);
+ NS_RELEASE(jsds);
+ }
+}
+
+static void
+jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc)
+{
+ if (progress == JS::GC_CYCLE_END || progress == JS::GC_SLICE_END) {
+ NS_ASSERTION(gGCRunning, "GC slice callback was missed");
+
+ while (gDeadScripts)
+ jsds_NotifyPendingDeadScripts (rt);
+
+ gGCRunning = false;
+ } else {
+ NS_ASSERTION(!gGCRunning, "should not re-enter GC");
+ gGCRunning = true;
+ }
+
+ if (gPrevGCSliceCallback)
+ (*gPrevGCSliceCallback)(rt, progress, desc);
+}
+
+static unsigned
+jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
+ JSErrorReport *report, void *callerdata)
+{
+ static bool running = false;
+
+ nsCOMPtr<jsdIErrorHook> hook;
+ gJsds->GetErrorHook(getter_AddRefs(hook));
+ if (!hook)
+ return JSD_ERROR_REPORTER_PASS_ALONG;
+
+ if (running)
+ return JSD_ERROR_REPORTER_PASS_ALONG;
+
+ running = true;
+
+ nsCOMPtr<jsdIValue> val;
+ if (JS_IsExceptionPending(cx)) {
+ jsval jv;
+ JS_GetPendingException(cx, &jv);
+ JSDValue *jsdv = JSD_NewValue (jsdc, jv);
+ val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
+ }
+
+ nsAutoCString fileName;
+ uint32_t line;
+ uint32_t pos;
+ uint32_t flags;
+ uint32_t errnum;
+ bool rval;
+ if (report) {
+ fileName.Assign(report->filename);
+ line = report->lineno;
+ pos = report->tokenptr - report->linebuf;
+ flags = report->flags;
+ errnum = report->errorNumber;
+ }
+ else
+ {
+ line = 0;
+ pos = 0;
+ flags = 0;
+ errnum = 0;
+ }
+
+ gJsds->DoPause(nullptr, true);
+ hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
+ gJsds->DoUnPause(nullptr, true);
+
+ running = false;
+ if (!rval)
+ return JSD_ERROR_REPORTER_DEBUG;
+
+ return JSD_ERROR_REPORTER_PASS_ALONG;
+}
+
+static JSBool
+jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
+ unsigned type, void* callerdata)
+{
+ nsCOMPtr<jsdICallHook> hook;
+
+ switch (type)
+ {
+ case JSD_HOOK_TOPLEVEL_START:
+ case JSD_HOOK_TOPLEVEL_END:
+ gJsds->GetTopLevelHook(getter_AddRefs(hook));
+ break;
+
+ case JSD_HOOK_FUNCTION_CALL:
+ case JSD_HOOK_FUNCTION_RETURN:
+ gJsds->GetFunctionHook(getter_AddRefs(hook));
+ break;
+
+ default:
+ NS_ASSERTION (0, "Unknown hook type.");
+ }
+
+ if (!hook)
+ return JS_TRUE;
+
+ if (!jsds_FilterHook (jsdc, jsdthreadstate))
+ return JS_FALSE;
+
+ JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
+ nsCOMPtr<jsdIStackFrame> frame =
+ getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
+ native_frame));
+ gJsds->DoPause(nullptr, true);
+ hook->OnCall(frame, type);
+ gJsds->DoUnPause(nullptr, true);
+ jsdStackFrame::InvalidateAll();
+
+ return JS_TRUE;
+}
+
+static uint32_t
+jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
+ unsigned type, void* callerdata, jsval* rval)
+{
+ nsCOMPtr<jsdIExecutionHook> hook(0);
+ uint32_t hook_rv = JSD_HOOK_RETURN_CONTINUE;
+ nsCOMPtr<jsdIValue> js_rv;
+
+ switch (type)
+ {
+ case JSD_HOOK_INTERRUPTED:
+ gJsds->GetInterruptHook(getter_AddRefs(hook));
+ break;
+ case JSD_HOOK_DEBUG_REQUESTED:
+ gJsds->GetDebugHook(getter_AddRefs(hook));
+ break;
+ case JSD_HOOK_DEBUGGER_KEYWORD:
+ gJsds->GetDebuggerHook(getter_AddRefs(hook));
+ break;
+ case JSD_HOOK_BREAKPOINT:
+ {
+ /* we can't pause breakpoints the way we pause the other
+ * execution hooks (at least, not easily.) Instead we bail
+ * here if the service is paused. */
+ uint32_t level;
+ gJsds->GetPauseDepth(&level);
+ if (!level)
+ gJsds->GetBreakpointHook(getter_AddRefs(hook));
+ }
+ break;
+ case JSD_HOOK_THROW:
+ {
+ hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
+ gJsds->GetThrowHook(getter_AddRefs(hook));
+ if (hook) {
+ JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
+ js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
+ }
+ break;
+ }
+ default:
+ NS_ASSERTION (0, "Unknown hook type.");
+ }
+
+ if (!hook)
+ return hook_rv;
+
+ if (!jsds_FilterHook (jsdc, jsdthreadstate))
+ return JSD_HOOK_RETURN_CONTINUE;
+
+ JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
+ nsCOMPtr<jsdIStackFrame> frame =
+ getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
+ native_frame));
+ gJsds->DoPause(nullptr, true);
+ jsdIValue *inout_rv = js_rv;
+ NS_IF_ADDREF(inout_rv);
+ hook->OnExecute (frame, type, &inout_rv, &hook_rv);
+ js_rv = inout_rv;
+ NS_IF_RELEASE(inout_rv);
+ gJsds->DoUnPause(nullptr, true);
+ jsdStackFrame::InvalidateAll();
+
+ if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
+ hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
+ *rval = JSVAL_VOID;
+ if (js_rv) {
+ JSDValue *jsdv;
+ if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
+ *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
+ }
+ }
+
+ return hook_rv;
+}
+
+static void
+jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
+ void* callerdata)
+{
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JSRuntime *rt = JS_GetRuntime(nsContentUtils::GetSafeJSContext());
+#endif
+
+ if (creating) {
+ nsCOMPtr<jsdIScriptHook> hook;
+ gJsds->GetScriptHook(getter_AddRefs(hook));
+
+ /* a script is being created */
+ if (!hook) {
+ /* nobody cares, just exit */
+ return;
+ }
+
+ nsCOMPtr<jsdIScript> script =
+ getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JS_UNKEEP_ATOMS(rt);
+#endif
+ gJsds->DoPause(nullptr, true);
+ hook->OnScriptCreated (script);
+ gJsds->DoUnPause(nullptr, true);
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JS_KEEP_ATOMS(rt);
+#endif
+ } else {
+ /* a script is being destroyed. even if there is no registered hook
+ * we'll still need to invalidate the jsdIScript record, in order
+ * to remove the reference held in the JSDScript private data. */
+ nsCOMPtr<jsdIScript> jsdis =
+ static_cast<jsdIScript *>(JSD_GetScriptPrivate(jsdscript));
+ if (!jsdis)
+ return;
+
+ jsdis->Invalidate();
+
+ if (!gGCRunning) {
+ nsCOMPtr<jsdIScriptHook> hook;
+ gJsds->GetScriptHook(getter_AddRefs(hook));
+ if (!hook)
+ return;
+
+ /* if GC *isn't* running, we can tell the user about the script
+ * delete now. */
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JS_UNKEEP_ATOMS(rt);
+#endif
+
+ gJsds->DoPause(nullptr, true);
+ hook->OnScriptDestroyed (jsdis);
+ gJsds->DoUnPause(nullptr, true);
+#ifdef CAUTIOUS_SCRIPTHOOK
+ JS_KEEP_ATOMS(rt);
+#endif
+ } else {
+ /* if a GC *is* running, we've got to wait until it's done before
+ * we can execute any JS, so we queue the notification in a PRCList
+ * until GC tells us it's done. See jsds_GCCallbackProc(). */
+ DeadScript *ds = PR_NEW(DeadScript);
+ if (!ds)
+ return; /* NS_ERROR_OUT_OF_MEMORY */
+
+ ds->jsdc = jsdc;
+ ds->script = jsdis;
+ NS_ADDREF(ds->script);
+ if (gDeadScripts)
+ /* if the queue exists, add to it */
+ PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
+ else {
+ /* otherwise create the queue */
+ PR_INIT_CLIST(&ds->links);
+ gDeadScripts = ds;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * reflected jsd data structures
+ *******************************************************************************/
+
+/* Contexts */
+/*
+NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
+
+NS_IMETHODIMP
+jsdContext::GetJSDContext(JSDContext **_rval)
+{
+ *_rval = mCx;
+ return NS_OK;
+}
+*/
+
+/* Objects */
+NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
+
+NS_IMETHODIMP
+jsdObject::GetJSDContext(JSDContext **_rval)
+{
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdObject::GetJSDObject(JSDObject **_rval)
+{
+ *_rval = mObject;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdObject::GetCreatorURL(nsACString &_rval)
+{
+ _rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdObject::GetCreatorLine(uint32_t *_rval)
+{
+ *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdObject::GetConstructorURL(nsACString &_rval)
+{
+ _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdObject::GetConstructorLine(uint32_t *_rval)
+{
+ *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdObject::GetValue(jsdIValue **_rval)
+{
+ JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+/* Properties */
+NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
+
+jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
+ mCx(aCx), mProperty(aProperty)
+{
+ DEBUG_CREATE ("jsdProperty", gPropertyCount);
+ mValid = (aCx && aProperty);
+ mLiveListEntry.value = this;
+ jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
+}
+
+jsdProperty::~jsdProperty ()
+{
+ DEBUG_DESTROY ("jsdProperty", gPropertyCount);
+ if (mValid)
+ Invalidate();
+}
+
+NS_IMETHODIMP
+jsdProperty::Invalidate()
+{
+ ASSERT_VALID_EPHEMERAL;
+ mValid = false;
+ jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
+ JSD_DropProperty (mCx, mProperty);
+ return NS_OK;
+}
+
+void
+jsdProperty::InvalidateAll()
+{
+ if (gLiveProperties)
+ jsds_InvalidateAllEphemerals (&gLiveProperties);
+}
+
+NS_IMETHODIMP
+jsdProperty::GetJSDContext(JSDContext **_rval)
+{
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdProperty::GetJSDProperty(JSDProperty **_rval)
+{
+ *_rval = mProperty;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdProperty::GetIsValid(bool *_rval)
+{
+ *_rval = mValid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdProperty::GetAlias(jsdIValue **_rval)
+{
+ JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdProperty::GetFlags(uint32_t *_rval)
+{
+ *_rval = JSD_GetPropertyFlags (mCx, mProperty);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdProperty::GetName(jsdIValue **_rval)
+{
+ JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdProperty::GetValue(jsdIValue **_rval)
+{
+ JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+/* Scripts */
+NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
+
+static NS_IMETHODIMP
+AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str)
+{
+ if (!str) {
+ x->SetLength(0);
+ return NS_OK;
+ }
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, JSD_GetDefaultGlobal(aCx)); // Just in case.
+ size_t length = JS_GetStringEncodingLength(cx, str);
+ if (length == size_t(-1))
+ return NS_ERROR_FAILURE;
+ x->SetLength(uint32_t(length));
+ if (x->Length() != uint32_t(length))
+ return NS_ERROR_OUT_OF_MEMORY;
+ JS_EncodeStringToBuffer(cx, str, x->BeginWriting(), length);
+ return NS_OK;
+}
+
+jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
+ mTag(0),
+ mCx(aCx),
+ mScript(aScript),
+ mFileName(0),
+ mFunctionName(0),
+ mBaseLineNumber(0),
+ mLineExtent(0),
+ mPPLineMap(0),
+ mFirstPC(0)
+{
+ DEBUG_CREATE ("jsdScript", gScriptCount);
+
+ if (mScript) {
+ /* copy the script's information now, so we have it later, when it
+ * gets destroyed. */
+ JSD_LockScriptSubsystem(mCx);
+ mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
+ mFunctionName = new nsCString();
+ if (mFunctionName) {
+ JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
+ if (str)
+ AssignToJSString(mCx, mFunctionName, str);
+ }
+ mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
+ mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
+ mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
+ JSD_UnlockScriptSubsystem(mCx);
+
+ mValid = true;
+ }
+}
+
+jsdScript::~jsdScript ()
+{
+ DEBUG_DESTROY ("jsdScript", gScriptCount);
+ delete mFileName;
+ delete mFunctionName;
+
+ if (mPPLineMap)
+ PR_Free(mPPLineMap);
+
+ /* Invalidate() needs to be called to release an owning reference to
+ * ourselves, so if we got here without being invalidated, something
+ * has gone wrong with our ref count. */
+ NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
+}
+
+/*
+ * This method populates a line <-> pc map for a pretty printed version of this
+ * script. It does this by decompiling, and then recompiling the script. The
+ * resulting script is scanned for the line map, and then left as GC fodder.
+ */
+PCMapEntry *
+jsdScript::CreatePPLineMap()
+{
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, JSD_GetDefaultGlobal (mCx)); // Just in case.
+ JS::RootedObject obj(cx, JS_NewObject(cx, NULL, NULL, NULL));
+ if (!obj)
+ return nullptr;
+ JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
+ JS::RootedScript script(cx); /* In JSD compartment */
+ uint32_t baseLine;
+ JS::RootedString jsstr(cx);
+ size_t length;
+ const jschar *chars;
+
+ if (fun) {
+ unsigned nargs;
+
+ {
+ JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
+ nargs = JS_GetFunctionArgumentCount(cx, fun);
+ if (nargs > 12)
+ return nullptr;
+ jsstr = JS_DecompileFunctionBody (cx, fun, 4);
+ if (!jsstr)
+ return nullptr;
+
+ if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
+ return nullptr;
+ }
+
+ JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
+ const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
+ "arg5", "arg6", "arg7", "arg8",
+ "arg9", "arg10", "arg11", "arg12" };
+ fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
+ length, "x-jsd:ppbuffer?type=function", 3);
+ if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
+ return nullptr;
+ baseLine = 3;
+ } else {
+ script = JSD_GetJSScript(mCx, mScript);
+ JSString *jsstr;
+
+ {
+ JSAutoCompartment ac(cx, script);
+
+ jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
+ if (!jsstr)
+ return nullptr;
+
+ if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
+ return nullptr;
+ }
+
+ JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
+ script = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1);
+ if (!script)
+ return nullptr;
+ baseLine = 1;
+ }
+
+ uint32_t scriptExtent = JS_GetScriptLineExtent (cx, script);
+ jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
+ /* allocate worst case size of map (number of lines in script + 1
+ * for our 0 record), we'll shrink it with a realloc later. */
+ PCMapEntry *lineMap =
+ static_cast<PCMapEntry *>
+ (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
+ uint32_t lineMapSize = 0;
+
+ if (lineMap) {
+ for (uint32_t line = baseLine; line < scriptExtent + baseLine; ++line) {
+ jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
+ if (line == JS_PCToLineNumber (cx, script, pc)) {
+ lineMap[lineMapSize].line = line;
+ lineMap[lineMapSize].pc = pc - firstPC;
+ ++lineMapSize;
+ }
+ }
+ if (scriptExtent != lineMapSize) {
+ lineMap =
+ static_cast<PCMapEntry *>
+ (PR_Realloc(mPPLineMap = lineMap,
+ lineMapSize * sizeof(PCMapEntry)));
+ if (!lineMap) {
+ PR_Free(mPPLineMap);
+ lineMapSize = 0;
+ }
+ }
+ }
+
+ mPCMapSize = lineMapSize;
+ return mPPLineMap = lineMap;
+}
+
+uint32_t
+jsdScript::PPPcToLine (uint32_t aPC)
+{
+ if (!mPPLineMap && !CreatePPLineMap())
+ return 0;
+ uint32_t i;
+ for (i = 1; i < mPCMapSize; ++i) {
+ if (mPPLineMap[i].pc > aPC)
+ return mPPLineMap[i - 1].line;
+ }
+
+ return mPPLineMap[mPCMapSize - 1].line;
+}
+
+uint32_t
+jsdScript::PPLineToPc (uint32_t aLine)
+{
+ if (!mPPLineMap && !CreatePPLineMap())
+ return 0;
+ uint32_t i;
+ for (i = 1; i < mPCMapSize; ++i) {
+ if (mPPLineMap[i].line > aLine)
+ return mPPLineMap[i - 1].pc;
+ }
+
+ return mPPLineMap[mPCMapSize - 1].pc;
+}
+
+NS_IMETHODIMP
+jsdScript::GetJSDContext(JSDContext **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetJSDScript(JSDScript **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mScript;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetVersion (int32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ AutoSafeJSContext cx;
+ JS::RootedScript script(cx, JSD_GetJSScript(mCx, mScript));
+ JSAutoCompartment ac(cx, script);
+ *_rval = static_cast<int32_t>(JS_GetScriptVersion(cx, script));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetTag(uint32_t *_rval)
+{
+ if (!mTag)
+ mTag = ++jsdScript::LastTag;
+
+ *_rval = mTag;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::Invalidate()
+{
+ ASSERT_VALID_EPHEMERAL;
+ mValid = false;
+
+ /* release the addref we do in FromPtr */
+ jsdIScript *script = static_cast<jsdIScript *>
+ (JSD_GetScriptPrivate(mScript));
+ NS_ASSERTION (script == this, "That's not my script!");
+ NS_RELEASE(script);
+ JSD_SetScriptPrivate(mScript, NULL);
+ return NS_OK;
+}
+
+void
+jsdScript::InvalidateAll ()
+{
+ JSDContext *cx;
+ if (NS_FAILED(gJsds->GetJSDContext (&cx)))
+ return;
+
+ JSDScript *script;
+ JSDScript *iter = NULL;
+
+ JSD_LockScriptSubsystem(cx);
+ while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
+ nsCOMPtr<jsdIScript> jsdis =
+ static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
+ if (jsdis)
+ jsdis->Invalidate();
+ }
+ JSD_UnlockScriptSubsystem(cx);
+}
+
+NS_IMETHODIMP
+jsdScript::GetIsValid(bool *_rval)
+{
+ *_rval = mValid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::SetFlags(uint32_t flags)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSD_SetScriptFlags(mCx, mScript, flags);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetFlags(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptFlags(mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetFileName(nsACString &_rval)
+{
+ _rval.Assign(*mFileName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetFunctionName(nsACString &_rval)
+{
+ _rval.Assign(*mFunctionName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetParameterNames(uint32_t* count, PRUnichar*** paramNames)
+{
+ ASSERT_VALID_EPHEMERAL;
+ AutoSafeJSContext cx;
+ JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
+ if (!fun) {
+ *count = 0;
+ *paramNames = nullptr;
+ return NS_OK;
+ }
+
+ JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
+
+ unsigned nargs;
+ if (!JS_FunctionHasLocalNames(cx, fun) ||
+ (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
+ *count = 0;
+ *paramNames = nullptr;
+ return NS_OK;
+ }
+
+ PRUnichar **ret =
+ static_cast<PRUnichar**>(NS_Alloc(nargs * sizeof(PRUnichar*)));
+ if (!ret)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ void *mark;
+ uintptr_t *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
+ if (!names) {
+ NS_Free(ret);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ nsresult rv = NS_OK;
+ for (unsigned i = 0; i < nargs; ++i) {
+ JSAtom *atom = JS_LocalNameToAtom(names[i]);
+ if (!atom) {
+ ret[i] = 0;
+ } else {
+ JSString *str = JS_AtomKey(atom);
+ ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
+ if (!ret[i]) {
+ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ break;
+ }
+ }
+ }
+ JS_ReleaseFunctionLocalNameArray(cx, mark);
+ if (NS_FAILED(rv))
+ return rv;
+ *count = nargs;
+ *paramNames = ret;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetFunctionObject(jsdIValue **_rval)
+{
+ JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
+ if (!fun)
+ return NS_ERROR_NOT_AVAILABLE;
+
+ AutoSafeJSContext jsContext;
+ JS::RootedObject obj(jsContext, JS_GetFunctionObject(fun));
+ if (!obj)
+ return NS_ERROR_FAILURE;
+
+ JSDContext *cx;
+ if (NS_FAILED(gJsds->GetJSDContext (&cx)))
+ return NS_ERROR_NOT_INITIALIZED;
+
+ JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
+ if (!jsdv)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ *_rval = jsdValue::FromPtr(cx, jsdv);
+ if (!*_rval) {
+ JSD_DropValue(cx, jsdv);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetFunctionSource(nsAString & aFunctionSource)
+{
+ ASSERT_VALID_EPHEMERAL;
+ AutoSafeJSContext cx_;
+ JSContext *cx = cx_; // Appease the type system with Maybe<>s below.
+ JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
+
+ JSString *jsstr;
+ mozilla::Maybe<JSAutoCompartment> ac;
+ if (fun) {
+ ac.construct(cx, JS_GetFunctionObject(fun));
+ jsstr = JS_DecompileFunction (cx, fun, 4);
+ } else {
+ JS::RootedScript script(cx, JSD_GetJSScript (mCx, mScript));
+ ac.construct(cx, script);
+ jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
+ }
+ if (!jsstr)
+ return NS_ERROR_FAILURE;
+
+ size_t length;
+ const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
+ if (!chars)
+ return NS_ERROR_FAILURE;
+
+ aFunctionSource = nsDependentString(chars, length);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetBaseLineNumber(uint32_t *_rval)
+{
+ *_rval = mBaseLineNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetLineExtent(uint32_t *_rval)
+{
+ *_rval = mLineExtent;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetCallCount(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptCallCount (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetMaxRecurseDepth(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetMinExecutionTime(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetMaxExecutionTime(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetTotalExecutionTime(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetMinOwnExecutionTime(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetMaxOwnExecutionTime(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::GetTotalOwnExecutionTime(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::ClearProfileData()
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSD_ClearScriptProfileData(mCx, mScript);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::PcToLine(uint32_t aPC, uint32_t aPcmap, uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (aPcmap == PCMAP_SOURCETEXT) {
+ *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
+ } else if (aPcmap == PCMAP_PRETTYPRINT) {
+ *_rval = PPPcToLine(aPC);
+ } else {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::LineToPc(uint32_t aLine, uint32_t aPcmap, uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (aPcmap == PCMAP_SOURCETEXT) {
+ uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
+ *_rval = pc - mFirstPC;
+ } else if (aPcmap == PCMAP_PRETTYPRINT) {
+ *_rval = PPLineToPc(aLine);
+ } else {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::EnableSingleStepInterrupts(bool enable)
+{
+ ASSERT_VALID_EPHEMERAL;
+
+ /* Must have set interrupt hook before enabling */
+ if (enable && !jsdService::GetService()->CheckInterruptHook())
+ return NS_ERROR_NOT_INITIALIZED;
+
+ return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE);
+}
+
+NS_IMETHODIMP
+jsdScript::GetExecutableLines(uint32_t aPcmap, uint32_t aStartLine, uint32_t aMaxLines,
+ uint32_t* aCount, uint32_t** aExecutableLines)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (aPcmap == PCMAP_SOURCETEXT) {
+ uintptr_t start = JSD_GetClosestPC(mCx, mScript, 0);
+ unsigned lastLine = JSD_GetScriptBaseLineNumber(mCx, mScript)
+ + JSD_GetScriptLineExtent(mCx, mScript) - 1;
+ uintptr_t end = JSD_GetClosestPC(mCx, mScript, lastLine + 1);
+
+ *aExecutableLines = static_cast<uint32_t*>(NS_Alloc((end - start + 1) * sizeof(uint32_t)));
+ if (!JSD_GetLinePCs(mCx, mScript, aStartLine, aMaxLines, aCount, aExecutableLines, NULL))
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+ }
+
+ if (aPcmap == PCMAP_PRETTYPRINT) {
+ if (!mPPLineMap) {
+ if (!CreatePPLineMap())
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ nsTArray<uint32_t> lines;
+ uint32_t i;
+
+ for (i = 0; i < mPCMapSize; ++i) {
+ if (mPPLineMap[i].line >= aStartLine)
+ break;
+ }
+
+ for (; i < mPCMapSize && lines.Length() < aMaxLines; ++i) {
+ lines.AppendElement(mPPLineMap[i].line);
+ }
+
+ if (aCount)
+ *aCount = lines.Length();
+
+ *aExecutableLines = static_cast<uint32_t*>(NS_Alloc(lines.Length() * sizeof(uint32_t)));
+ if (!*aExecutableLines)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ for (i = 0; i < lines.Length(); ++i)
+ (*aExecutableLines)[i] = lines[i];
+
+ return NS_OK;
+ }
+
+ return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+jsdScript::IsLineExecutable(uint32_t aLine, uint32_t aPcmap, bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (aPcmap == PCMAP_SOURCETEXT) {
+ uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
+ *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
+ } else if (aPcmap == PCMAP_PRETTYPRINT) {
+ if (!mPPLineMap && !CreatePPLineMap())
+ return NS_ERROR_OUT_OF_MEMORY;
+ *_rval = false;
+ for (uint32_t i = 0; i < mPCMapSize; ++i) {
+ if (mPPLineMap[i].line >= aLine) {
+ *_rval = (mPPLineMap[i].line == aLine);
+ break;
+ }
+ }
+ } else {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::SetBreakpoint(uint32_t aPC)
+{
+ ASSERT_VALID_EPHEMERAL;
+ uintptr_t pc = mFirstPC + aPC;
+ JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::ClearBreakpoint(uint32_t aPC)
+{
+ ASSERT_VALID_EPHEMERAL;
+ uintptr_t pc = mFirstPC + aPC;
+ JSD_ClearExecutionHook (mCx, mScript, pc);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdScript::ClearAllBreakpoints()
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSD_LockScriptSubsystem(mCx);
+ JSD_ClearAllExecutionHooksForScript (mCx, mScript);
+ JSD_UnlockScriptSubsystem(mCx);
+ return NS_OK;
+}
+
+/* Contexts */
+NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
+
+jsdIContext *
+jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
+{
+ if (!aJSDCx || !aJSCx)
+ return nullptr;
+
+ nsCOMPtr<jsdIContext> jsdicx;
+ nsCOMPtr<jsdIEphemeral> eph =
+ jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
+ if (eph)
+ {
+ jsdicx = do_QueryInterface(eph);
+ }
+ else
+ {
+ nsCOMPtr<nsISupports> iscx;
+ if (JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
+ iscx = static_cast<nsISupports *>(JS_GetContextPrivate(aJSCx));
+ jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
+ }
+
+ jsdIContext *ctx = nullptr;
+ jsdicx.swap(ctx);
+ return ctx;
+}
+
+jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
+ nsISupports *aISCx) : mValid(true), mTag(0),
+ mJSDCx(aJSDCx),
+ mJSCx(aJSCx), mISCx(aISCx)
+{
+ DEBUG_CREATE ("jsdContext", gContextCount);
+ mLiveListEntry.value = this;
+ mLiveListEntry.key = static_cast<void *>(aJSCx);
+ jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
+}
+
+jsdContext::~jsdContext()
+{
+ DEBUG_DESTROY ("jsdContext", gContextCount);
+ if (mValid)
+ {
+ /* call Invalidate() to take ourselves out of the live list */
+ Invalidate();
+ }
+}
+
+NS_IMETHODIMP
+jsdContext::GetIsValid(bool *_rval)
+{
+ *_rval = mValid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::Invalidate()
+{
+ ASSERT_VALID_EPHEMERAL;
+ mValid = false;
+ jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
+ return NS_OK;
+}
+
+void
+jsdContext::InvalidateAll()
+{
+ if (gLiveContexts)
+ jsds_InvalidateAllEphemerals (&gLiveContexts);
+}
+
+NS_IMETHODIMP
+jsdContext::GetJSContext(JSContext **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mJSCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::GetOptions(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JS_GetOptions(mJSCx);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::SetOptions(uint32_t options)
+{
+ ASSERT_VALID_EPHEMERAL;
+ uint32_t lastOptions = JS_GetOptions(mJSCx);
+
+ /* don't let users change this option, they'd just be shooting themselves
+ * in the foot. */
+ if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
+ return NS_ERROR_ILLEGAL_VALUE;
+
+ JS_SetOptions(mJSCx, options);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::GetPrivateData(nsISupports **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ uint32_t options = JS_GetOptions(mJSCx);
+ if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
+ {
+ *_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
+ NS_IF_ADDREF(*_rval);
+ }
+ else
+ {
+ *_rval = nullptr;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::GetWrappedContext(nsISupports **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ NS_IF_ADDREF(*_rval = mISCx);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::GetTag(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (!mTag)
+ mTag = ++jsdContext::LastTag;
+
+ *_rval = mTag;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::GetGlobalObject (jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSObject *glob = js::GetDefaultGlobalForContext(mJSCx);
+ JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
+ if (!jsdv)
+ return NS_ERROR_FAILURE;
+ *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
+ if (!*_rval)
+ return NS_ERROR_FAILURE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::GetScriptsEnabled (bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (!mISCx) {
+ *_rval = true;
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
+ if (!context)
+ return NS_ERROR_NO_INTERFACE;
+
+ *_rval = context->GetScriptsEnabled();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::SetScriptsEnabled (bool _rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (!mISCx) {
+ if (_rval)
+ return NS_OK;
+ return NS_ERROR_NO_INTERFACE;
+ }
+
+ nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
+ if (!context)
+ return NS_ERROR_NO_INTERFACE;
+
+ context->SetScriptsEnabled(_rval, true);
+
+ return NS_OK;
+}
+
+/* Stack Frames */
+NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
+
+jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
+ JSDStackFrameInfo *aStackFrameInfo) :
+ mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
+{
+ DEBUG_CREATE ("jsdStackFrame", gFrameCount);
+ mValid = (aCx && aThreadState && aStackFrameInfo);
+ if (mValid) {
+ mLiveListEntry.key = aStackFrameInfo;
+ mLiveListEntry.value = this;
+ jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
+ }
+}
+
+jsdStackFrame::~jsdStackFrame()
+{
+ DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
+ if (mValid)
+ {
+ /* call Invalidate() to take ourselves out of the live list */
+ Invalidate();
+ }
+}
+
+jsdIStackFrame *
+jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
+ JSDStackFrameInfo *aStackFrameInfo)
+{
+ if (!aStackFrameInfo)
+ return nullptr;
+
+ jsdIStackFrame *rv;
+ nsCOMPtr<jsdIStackFrame> frame;
+
+ nsCOMPtr<jsdIEphemeral> eph =
+ jsds_FindEphemeral (&gLiveStackFrames,
+ reinterpret_cast<void *>(aStackFrameInfo));
+
+ if (eph)
+ {
+ frame = do_QueryInterface(eph);
+ rv = frame;
+ }
+ else
+ {
+ rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
+ }
+
+ NS_IF_ADDREF(rv);
+ return rv;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::Invalidate()
+{
+ ASSERT_VALID_EPHEMERAL;
+ mValid = false;
+ jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
+ return NS_OK;
+}
+
+void
+jsdStackFrame::InvalidateAll()
+{
+ if (gLiveStackFrames)
+ jsds_InvalidateAllEphemerals (&gLiveStackFrames);
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetJSDContext(JSDContext **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mThreadState;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mStackFrameInfo;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetIsValid(bool *_rval)
+{
+ *_rval = mValid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+ *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
+ *_rval = jsdContext::FromPtr (mCx, cx);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetFunctionName(nsACString &_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
+ if (str)
+ return AssignToJSString(mCx, &_rval, str);
+
+ _rval.Assign("anonymous");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetIsDebugger(bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetIsConstructing(bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetScript(jsdIScript **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+ *_rval = jsdScript::FromPtr (mCx, script);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetPc(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+ if (!script)
+ return NS_ERROR_FAILURE;
+ uintptr_t pcbase = JSD_GetClosestPC(mCx, script, 0);
+
+ uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
+ if (pc)
+ *_rval = pc - pcbase;
+ else
+ *_rval = pcbase;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetLine(uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+ if (script) {
+ uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
+ *_rval = JSD_GetClosestLine (mCx, script, pc);
+ } else {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetCallee(jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetScope(jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdStackFrame::GetThisValue(jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
+ mStackFrameInfo);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
+ uint32_t line, jsdIValue **result, bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+
+ if (bytes.IsEmpty())
+ return NS_ERROR_INVALID_ARG;
+
+ // get pointer to buffer contained in |bytes|
+ nsAString::const_iterator h;
+ bytes.BeginReading(h);
+ const jschar *char_bytes = reinterpret_cast<const jschar *>(h.get());
+
+ JSExceptionState *estate = 0;
+
+ AutoPushJSContext cx(JSD_GetJSContext (mCx, mThreadState));
+
+ JS::RootedValue jv(cx);
+
+ estate = JS_SaveExceptionState (cx);
+ JS_ClearPendingException (cx);
+
+ *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
+ mStackFrameInfo,
+ char_bytes, bytes.Length(),
+ PromiseFlatCString(fileName).get(),
+ line, &jv);
+ if (!*_rval) {
+ if (JS_IsExceptionPending(cx))
+ JS_GetPendingException (cx, jv.address());
+ else
+ jv = JSVAL_NULL;
+ }
+
+ JS_RestoreExceptionState (cx, estate);
+
+ JSDValue *jsdv = JSD_NewValue (mCx, jv);
+ if (!jsdv)
+ return NS_ERROR_FAILURE;
+ *result = jsdValue::FromPtr (mCx, jsdv);
+ if (!*result)
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+/* Values */
+NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
+jsdIValue *
+jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
+{
+ /* value will be dropped by te jsdValue destructor. */
+
+ if (!aValue)
+ return nullptr;
+
+ jsdIValue *rv = new jsdValue (aCx, aValue);
+ NS_IF_ADDREF(rv);
+ return rv;
+}
+
+jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(true),
+ mCx(aCx),
+ mValue(aValue)
+{
+ DEBUG_CREATE ("jsdValue", gValueCount);
+ mLiveListEntry.value = this;
+ jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
+}
+
+jsdValue::~jsdValue()
+{
+ DEBUG_DESTROY ("jsdValue", gValueCount);
+ if (mValid)
+ /* call Invalidate() to take ourselves out of the live list */
+ Invalidate();
+}
+
+NS_IMETHODIMP
+jsdValue::GetIsValid(bool *_rval)
+{
+ *_rval = mValid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::Invalidate()
+{
+ ASSERT_VALID_EPHEMERAL;
+ mValid = false;
+ jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
+ JSD_DropValue (mCx, mValue);
+ return NS_OK;
+}
+
+void
+jsdValue::InvalidateAll()
+{
+ if (gLiveValues)
+ jsds_InvalidateAllEphemerals (&gLiveValues);
+}
+
+NS_IMETHODIMP
+jsdValue::GetJSDContext(JSDContext **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJSDValue (JSDValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = mValue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetIsNative (bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_IsValueNative (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetIsNumber (bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_IsValueNumber (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetIsPrimitive (bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_IsValuePrimitive (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJsType (uint32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ jsval val;
+
+ val = JSD_GetValueWrappedJSVal (mCx, mValue);
+
+ if (JSVAL_IS_NULL(val))
+ *_rval = TYPE_NULL;
+ else if (JSVAL_IS_BOOLEAN(val))
+ *_rval = TYPE_BOOLEAN;
+ else if (JSVAL_IS_DOUBLE(val))
+ *_rval = TYPE_DOUBLE;
+ else if (JSVAL_IS_INT(val))
+ *_rval = TYPE_INT;
+ else if (JSVAL_IS_STRING(val))
+ *_rval = TYPE_STRING;
+ else if (JSVAL_IS_VOID(val))
+ *_rval = TYPE_VOID;
+ else if (JSD_IsValueFunction (mCx, mValue))
+ *_rval = TYPE_FUNCTION;
+ else if (!JSVAL_IS_PRIMITIVE(val))
+ *_rval = TYPE_OBJECT;
+ else
+ NS_ASSERTION (0, "Value has no discernible type.");
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJsPrototype (jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJsParent (jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJsClassName(nsACString &_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ _rval.Assign(JSD_GetValueClassName(mCx, mValue));
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJsConstructor (jsdIValue **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetJsFunctionName(nsACString &_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ return AssignToJSString(mCx, &_rval, JSD_GetValueFunctionId(mCx, mValue));
+}
+
+NS_IMETHODIMP
+jsdValue::GetBooleanValue(bool *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetValueBoolean (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetDoubleValue(double *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetValueDouble (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetIntValue(int32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *_rval = JSD_GetValueInt (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetObjectValue(jsdIObject **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDObject *obj;
+ obj = JSD_GetObjectForValue (mCx, mValue);
+ *_rval = jsdObject::FromPtr (mCx, obj);
+ if (!*_rval)
+ return NS_ERROR_FAILURE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetStringValue(nsACString &_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ AutoSafeJSContext cx;
+ JSString *jstr_val = JSD_GetValueString(mCx, mValue);
+ if (jstr_val) {
+ size_t length;
+ const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
+ if (!chars)
+ return NS_ERROR_FAILURE;
+ nsDependentString depStr(chars, length);
+ CopyUTF16toUTF8(depStr, _rval);
+ } else {
+ _rval.Truncate();
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetPropertyCount (int32_t *_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ if (JSD_IsValueObject(mCx, mValue))
+ *_rval = JSD_GetCountOfProperties (mCx, mValue);
+ else
+ *_rval = -1;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetProperties (jsdIProperty ***propArray, uint32_t *length)
+{
+ ASSERT_VALID_EPHEMERAL;
+ *propArray = nullptr;
+ if (length)
+ *length = 0;
+
+ uint32_t prop_count = JSD_IsValueObject(mCx, mValue)
+ ? JSD_GetCountOfProperties (mCx, mValue)
+ : 0;
+ NS_ENSURE_TRUE(prop_count, NS_OK);
+
+ jsdIProperty **pa_temp =
+ static_cast<jsdIProperty **>
+ (nsMemory::Alloc(sizeof (jsdIProperty *) *
+ prop_count));
+ NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
+
+ uint32_t i = 0;
+ JSDProperty *iter = NULL;
+ JSDProperty *prop;
+ while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
+ pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
+ ++i;
+ }
+
+ NS_ASSERTION (prop_count == i, "property count mismatch");
+
+ /* if caller doesn't care about length, don't bother telling them */
+ *propArray = pa_temp;
+ if (length)
+ *length = prop_count;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ AutoSafeJSContext cx;
+ JSAutoCompartment ac(cx, JSD_GetDefaultGlobal (mCx)); // Just in case.
+
+ /* not rooting this */
+ JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
+ if (!jstr_name)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
+
+ *_rval = jsdProperty::FromPtr (mCx, prop);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::Refresh()
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSD_RefreshValue (mCx, mValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetWrappedValue(JSContext* aCx, JS::Value* aRetval)
+{
+ ASSERT_VALID_EPHEMERAL;
+
+ *aRetval = JSD_GetValueWrappedJSVal(mCx, mValue);
+ if (!JS_WrapValue(aCx, aRetval)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdValue::GetScript(jsdIScript **_rval)
+{
+ ASSERT_VALID_EPHEMERAL;
+ JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
+ *_rval = jsdScript::FromPtr(mCx, script);
+ return NS_OK;
+}
+
+/******************************************************************************
+ * debugger service implementation
+ ******************************************************************************/
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(jsdService)
+ NS_INTERFACE_MAP_ENTRY(jsdIDebuggerService)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, jsdIDebuggerService)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_10(jsdService,
+ mErrorHook, mBreakpointHook, mDebugHook,
+ mDebuggerHook, mInterruptHook, mScriptHook,
+ mThrowHook, mTopLevelHook, mFunctionHook,
+ mActivationCallback)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(jsdService)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(jsdService)
+
+NS_IMETHODIMP
+jsdService::GetJSDContext(JSDContext **_rval)
+{
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetFlags (uint32_t *_rval)
+{
+ ASSERT_VALID_CONTEXT;
+ *_rval = JSD_GetContextFlags (mCx);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetFlags (uint32_t flags)
+{
+ ASSERT_VALID_CONTEXT;
+ JSD_SetContextFlags (mCx, flags);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetImplementationString(nsACString &aImplementationString)
+{
+ aImplementationString.AssignLiteral(implementationString);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetImplementationMajor(uint32_t *_rval)
+{
+ *_rval = JSDS_MAJOR_VERSION;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetImplementationMinor(uint32_t *_rval)
+{
+ *_rval = JSDS_MINOR_VERSION;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetIsOn (bool *_rval)
+{
+ *_rval = mOn;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::On (void)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ mActivationCallback = activationCallback;
+
+ return xpc->SetDebugModeWhenPossible(true, true);
+}
+
+NS_IMETHODIMP
+jsdService::RecompileForDebugMode (JSContext *cx, JSCompartment *comp, bool mode) {
+ NS_ASSERTION(NS_IsMainThread(), "wrong thread");
+ /* XPConnect now does this work itself, so this IDL entry point is no longer used. */
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+jsdService::DeactivateDebugger ()
+{
+ if (!mCx)
+ return NS_OK;
+
+ jsdContext::InvalidateAll();
+ jsdScript::InvalidateAll();
+ jsdValue::InvalidateAll();
+ jsdProperty::InvalidateAll();
+ jsdStackFrame::InvalidateAll();
+ ClearAllBreakpoints();
+
+ JSD_SetErrorReporter (mCx, NULL, NULL);
+ JSD_SetScriptHook (mCx, NULL, NULL);
+ JSD_ClearThrowHook (mCx);
+ JSD_ClearInterruptHook (mCx);
+ JSD_ClearDebuggerHook (mCx);
+ JSD_ClearDebugBreakHook (mCx);
+ JSD_ClearTopLevelHook (mCx);
+ JSD_ClearFunctionHook (mCx);
+
+ JSD_DebuggerOff (mCx);
+
+ mCx = nullptr;
+ mRuntime = nullptr;
+ mOn = false;
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+jsdService::ActivateDebugger (JSRuntime *rt)
+{
+ if (mOn)
+ return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
+
+ mRuntime = rt;
+
+ if (gPrevGCSliceCallback == jsds_GCSliceCallbackProc)
+ /* condition indicates that the callback proc has not been set yet */
+ gPrevGCSliceCallback = JS::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
+
+ mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
+ if (!mCx)
+ return NS_ERROR_FAILURE;
+
+ AutoSafeJSContext cx;
+ JS::RootedObject glob(cx, JSD_GetDefaultGlobal (mCx));
+ JSAutoCompartment ac(cx, glob);
+
+ /* init xpconnect on the debugger's context in case xpconnect tries to
+ * use it for stuff. */
+ nsresult rv;
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ xpc->InitClasses (cx, glob);
+
+ /* Start watching for script creation/destruction and manage jsdScript
+ * objects accordingly
+ */
+ JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
+
+ /* If any of these mFooHook objects are installed, do the required JSD
+ * hookup now. See also, jsdService::SetFooHook().
+ */
+ if (mErrorHook)
+ JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
+ if (mThrowHook)
+ JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
+ /* can't ignore script callbacks, as we need to |Release| the wrapper
+ * stored in private data when a script is deleted. */
+ if (mInterruptHook)
+ JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mDebuggerHook)
+ JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mDebugHook)
+ JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mTopLevelHook)
+ JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
+ else
+ JSD_ClearTopLevelHook (mCx);
+ if (mFunctionHook)
+ JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
+ else
+ JSD_ClearFunctionHook (mCx);
+ mOn = true;
+
+#ifdef DEBUG
+ printf ("+++ JavaScript debugging hooks installed.\n");
+#endif
+
+ nsCOMPtr<jsdIActivationCallback> activationCallback;
+ mActivationCallback.swap(activationCallback);
+ if (activationCallback)
+ return activationCallback->OnDebuggerActivated();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::Off (void)
+{
+ if (!mOn)
+ return NS_OK;
+
+ if (!mCx || !mRuntime)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ if (gDeadScripts) {
+ if (gGCRunning)
+ return NS_ERROR_NOT_AVAILABLE;
+
+ while (gDeadScripts)
+ jsds_NotifyPendingDeadScripts (JS_GetRuntime(nsContentUtils::GetSafeJSContext()));
+ }
+
+ DeactivateDebugger();
+
+#ifdef DEBUG
+ printf ("+++ JavaScript debugging hooks removed.\n");
+#endif
+
+ nsresult rv;
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ xpc->SetDebugModeWhenPossible(false, true);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetPauseDepth(uint32_t *_rval)
+{
+ NS_ENSURE_ARG_POINTER(_rval);
+ *_rval = mPauseLevel;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::Pause(uint32_t *_rval)
+{
+ return DoPause(_rval, false);
+}
+
+nsresult
+jsdService::DoPause(uint32_t *_rval, bool internalCall)
+{
+ if (!mCx)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ if (++mPauseLevel == 1) {
+ JSD_SetErrorReporter (mCx, NULL, NULL);
+ JSD_ClearThrowHook (mCx);
+ JSD_ClearInterruptHook (mCx);
+ JSD_ClearDebuggerHook (mCx);
+ JSD_ClearDebugBreakHook (mCx);
+ JSD_ClearTopLevelHook (mCx);
+ JSD_ClearFunctionHook (mCx);
+ JSD_DebuggerPause (mCx);
+
+ nsresult rv;
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ if (!internalCall) {
+ rv = xpc->SetDebugModeWhenPossible(false, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ if (_rval)
+ *_rval = mPauseLevel;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::UnPause(uint32_t *_rval)
+{
+ return DoUnPause(_rval, false);
+}
+
+nsresult
+jsdService::DoUnPause(uint32_t *_rval, bool internalCall)
+{
+ if (!mCx)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ if (mPauseLevel == 0)
+ return NS_ERROR_NOT_AVAILABLE;
+
+ /* check mOn before we muck with this stuff, it's possible the debugger
+ * was turned off while we were paused.
+ */
+ if (--mPauseLevel == 0 && mOn) {
+ JSD_DebuggerUnpause (mCx);
+ if (mErrorHook)
+ JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
+ if (mThrowHook)
+ JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mInterruptHook)
+ JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mDebuggerHook)
+ JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mDebugHook)
+ JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
+ if (mTopLevelHook)
+ JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
+ else
+ JSD_ClearTopLevelHook (mCx);
+ if (mFunctionHook)
+ JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
+ else
+ JSD_ClearFunctionHook (mCx);
+
+ nsresult rv;
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ if (!internalCall) {
+ rv = xpc->SetDebugModeWhenPossible(true, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ if (_rval)
+ *_rval = mPauseLevel;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
+{
+ ASSERT_VALID_CONTEXT;
+
+ if (!enumerator)
+ return NS_OK;
+
+ JSContext *iter = NULL;
+ JSContext *cx;
+
+ while ((cx = JS_ContextIterator (mRuntime, &iter)))
+ {
+ nsCOMPtr<jsdIContext> jsdicx =
+ getter_AddRefs(jsdContext::FromPtr(mCx, cx));
+ if (jsdicx)
+ {
+ if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
+ break;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
+{
+ ASSERT_VALID_CONTEXT;
+
+ JSDScript *script;
+ JSDScript *iter = NULL;
+ nsresult rv = NS_OK;
+
+ JSD_LockScriptSubsystem(mCx);
+ while((script = JSD_IterateScripts(mCx, &iter))) {
+ nsCOMPtr<jsdIScript> jsdis =
+ getter_AddRefs(jsdScript::FromPtr(mCx, script));
+ rv = enumerator->EnumerateScript (jsdis);
+ if (NS_FAILED(rv))
+ break;
+ }
+ JSD_UnlockScriptSubsystem(mCx);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+jsdService::GC (void)
+{
+ ASSERT_VALID_CONTEXT;
+ JSRuntime *rt = JSD_GetJSRuntime (mCx);
+ JS_GC(rt);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::DumpHeap(const nsACString &fileName)
+{
+ ASSERT_VALID_CONTEXT;
+#ifndef DEBUG
+ return NS_ERROR_NOT_IMPLEMENTED;
+#else
+ nsresult rv = NS_OK;
+ FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
+ if (!file) {
+ rv = NS_ERROR_FAILURE;
+ } else {
+ if (!JS_DumpHeap(JS_GetRuntime(nsContentUtils::GetSafeJSContext()), file, NULL, JSTRACE_OBJECT, NULL, (size_t)-1, NULL))
+ rv = NS_ERROR_FAILURE;
+ if (file != stdout)
+ fclose(file);
+ }
+ return rv;
+#endif
+}
+
+NS_IMETHODIMP
+jsdService::ClearProfileData ()
+{
+ ASSERT_VALID_CONTEXT;
+ JSD_ClearAllProfileData (mCx);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
+{
+ NS_ENSURE_ARG_POINTER (filter);
+ if (jsds_FindFilter (filter))
+ return NS_ERROR_INVALID_ARG;
+
+ FilterRecord *rec = PR_NEWZAP (FilterRecord);
+ if (!rec)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ if (!jsds_SyncFilter (rec, filter)) {
+ PR_Free (rec);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (gFilters) {
+ if (!after) {
+ /* insert at head of list */
+ PR_INSERT_LINK(&rec->links, &gFilters->links);
+ gFilters = rec;
+ } else {
+ /* insert somewhere in the list */
+ FilterRecord *afterRecord = jsds_FindFilter (after);
+ if (!afterRecord) {
+ jsds_FreeFilter(rec);
+ return NS_ERROR_INVALID_ARG;
+ }
+ PR_INSERT_AFTER(&rec->links, &afterRecord->links);
+ }
+ } else {
+ if (after) {
+ /* user asked to insert into the middle of an empty list, bail. */
+ jsds_FreeFilter(rec);
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ PR_INIT_CLIST(&rec->links);
+ gFilters = rec;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::AppendFilter (jsdIFilter *filter)
+{
+ NS_ENSURE_ARG_POINTER (filter);
+ if (jsds_FindFilter (filter))
+ return NS_ERROR_INVALID_ARG;
+ FilterRecord *rec = PR_NEWZAP (FilterRecord);
+
+ if (!jsds_SyncFilter (rec, filter)) {
+ PR_Free (rec);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (gFilters) {
+ PR_INSERT_BEFORE(&rec->links, &gFilters->links);
+ } else {
+ PR_INIT_CLIST(&rec->links);
+ gFilters = rec;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::RemoveFilter (jsdIFilter *filter)
+{
+ NS_ENSURE_ARG_POINTER(filter);
+ FilterRecord *rec = jsds_FindFilter (filter);
+ if (!rec)
+ return NS_ERROR_INVALID_ARG;
+
+ if (gFilters == rec) {
+ gFilters = reinterpret_cast<FilterRecord *>
+ (PR_NEXT_LINK(&rec->links));
+ /* If we're the only filter left, null out the list head. */
+ if (gFilters == rec)
+ gFilters = nullptr;
+ }
+
+
+ PR_REMOVE_LINK(&rec->links);
+ jsds_FreeFilter (rec);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
+{
+ NS_ENSURE_ARG_POINTER(filter_a);
+ NS_ENSURE_ARG_POINTER(filter_b);
+
+ FilterRecord *rec_a = jsds_FindFilter (filter_a);
+ if (!rec_a)
+ return NS_ERROR_INVALID_ARG;
+
+ if (filter_a == filter_b) {
+ /* just a refresh */
+ if (!jsds_SyncFilter (rec_a, filter_a))
+ return NS_ERROR_FAILURE;
+ return NS_OK;
+ }
+
+ FilterRecord *rec_b = jsds_FindFilter (filter_b);
+ if (!rec_b) {
+ /* filter_b is not in the list, replace filter_a with filter_b. */
+ if (!jsds_SyncFilter (rec_a, filter_b))
+ return NS_ERROR_FAILURE;
+ } else {
+ /* both filters are in the list, swap. */
+ if (!jsds_SyncFilter (rec_a, filter_b))
+ return NS_ERROR_FAILURE;
+ if (!jsds_SyncFilter (rec_b, filter_a))
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator)
+{
+ if (!gFilters)
+ return NS_OK;
+
+ FilterRecord *current = gFilters;
+ do {
+ jsds_SyncFilter (current, current->filterObject);
+ /* SyncFilter failure would be bad, but what would we do about it? */
+ if (enumerator) {
+ nsresult rv = enumerator->EnumerateFilter (current->filterObject);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+ current = reinterpret_cast<FilterRecord *>
+ (PR_NEXT_LINK (&current->links));
+ } while (current != gFilters);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::RefreshFilters ()
+{
+ return EnumerateFilters(nullptr);
+}
+
+NS_IMETHODIMP
+jsdService::ClearFilters ()
+{
+ if (!gFilters)
+ return NS_OK;
+
+ FilterRecord *current = reinterpret_cast<FilterRecord *>
+ (PR_NEXT_LINK (&gFilters->links));
+ do {
+ FilterRecord *next = reinterpret_cast<FilterRecord *>
+ (PR_NEXT_LINK (&current->links));
+ PR_REMOVE_AND_INIT_LINK(&current->links);
+ jsds_FreeFilter(current);
+ current = next;
+ } while (current != gFilters);
+
+ jsds_FreeFilter(current);
+ gFilters = nullptr;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::ClearAllBreakpoints (void)
+{
+ ASSERT_VALID_CONTEXT;
+
+ JSD_LockScriptSubsystem(mCx);
+ JSD_ClearAllExecutionHooks (mCx);
+ JSD_UnlockScriptSubsystem(mCx);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::WrapValue(const JS::Value &value, jsdIValue **_rval)
+{
+ ASSERT_VALID_CONTEXT;
+ JSDValue *jsdv = JSD_NewValue(mCx, value);
+ if (!jsdv)
+ return NS_ERROR_FAILURE;
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+jsdService::EnterNestedEventLoop (jsdINestCallback *callback, uint32_t *_rval)
+{
+ // Nesting event queues is a thing of the past. Now, we just spin the
+ // current event loop.
+ nsresult rv = NS_OK;
+ nsCxPusher pusher;
+ pusher.PushNull();
+ uint32_t nestLevel = ++mNestedLoopLevel;
+ nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
+
+ if (callback) {
+ DoPause(nullptr, true);
+ rv = callback->OnNest();
+ DoUnPause(nullptr, true);
+ }
+
+ while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
+ if (!NS_ProcessNextEvent(thread))
+ rv = NS_ERROR_UNEXPECTED;
+ }
+
+ NS_ASSERTION (mNestedLoopLevel <= nestLevel,
+ "nested event didn't unwind properly");
+ if (mNestedLoopLevel == nestLevel)
+ --mNestedLoopLevel;
+
+ *_rval = mNestedLoopLevel;
+ return rv;
+}
+
+NS_IMETHODIMP
+jsdService::ExitNestedEventLoop (uint32_t *_rval)
+{
+ if (mNestedLoopLevel > 0)
+ --mNestedLoopLevel;
+ else
+ return NS_ERROR_FAILURE;
+
+ *_rval = mNestedLoopLevel;
+ return NS_OK;
+}
+
+/* hook attribute get/set functions */
+
+NS_IMETHODIMP
+jsdService::SetErrorHook (jsdIErrorHook *aHook)
+{
+ mErrorHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
+ else
+ JSD_SetErrorReporter (mCx, NULL, NULL);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetErrorHook (jsdIErrorHook **aHook)
+{
+ *aHook = mErrorHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
+{
+ mBreakpointHook = aHook;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
+{
+ *aHook = mBreakpointHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetDebugHook (jsdIExecutionHook *aHook)
+{
+ mDebugHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
+ else
+ JSD_ClearDebugBreakHook (mCx);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetDebugHook (jsdIExecutionHook **aHook)
+{
+ *aHook = mDebugHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
+{
+ mDebuggerHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
+ else
+ JSD_ClearDebuggerHook (mCx);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
+{
+ *aHook = mDebuggerHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
+{
+ mInterruptHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
+ else
+ JSD_ClearInterruptHook (mCx);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
+{
+ *aHook = mInterruptHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetScriptHook (jsdIScriptHook *aHook)
+{
+ mScriptHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
+ /* we can't unset it if !aHook, because we still need to see script
+ * deletes in order to Release the jsdIScripts held in JSDScript
+ * private data. */
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetScriptHook (jsdIScriptHook **aHook)
+{
+ *aHook = mScriptHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetThrowHook (jsdIExecutionHook *aHook)
+{
+ mThrowHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
+ else
+ JSD_ClearThrowHook (mCx);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetThrowHook (jsdIExecutionHook **aHook)
+{
+ *aHook = mThrowHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetTopLevelHook (jsdICallHook *aHook)
+{
+ mTopLevelHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
+ else
+ JSD_ClearTopLevelHook (mCx);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetTopLevelHook (jsdICallHook **aHook)
+{
+ *aHook = mTopLevelHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::SetFunctionHook (jsdICallHook *aHook)
+{
+ mFunctionHook = aHook;
+
+ /* if the debugger isn't initialized, that's all we can do for now. The
+ * ActivateDebugger() method will do the rest when the coast is clear.
+ */
+ if (!mCx || mPauseLevel)
+ return NS_OK;
+
+ if (aHook)
+ JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
+ else
+ JSD_ClearFunctionHook (mCx);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdService::GetFunctionHook (jsdICallHook **aHook)
+{
+ *aHook = mFunctionHook;
+ NS_IF_ADDREF(*aHook);
+
+ return NS_OK;
+}
+
+/* virtual */
+jsdService::~jsdService()
+{
+ ClearFilters();
+ mErrorHook = nullptr;
+ mBreakpointHook = nullptr;
+ mDebugHook = nullptr;
+ mDebuggerHook = nullptr;
+ mInterruptHook = nullptr;
+ mScriptHook = nullptr;
+ mThrowHook = nullptr;
+ mTopLevelHook = nullptr;
+ mFunctionHook = nullptr;
+ Off();
+ gJsds = nullptr;
+}
+
+jsdService *
+jsdService::GetService ()
+{
+ if (!gJsds)
+ gJsds = new jsdService();
+
+ NS_IF_ADDREF(gJsds);
+ return gJsds;
+}
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
+
+/* app-start observer. turns on the debugger at app-start. this is inserted
+ * and/or removed from the app-start category by the jsdService::initAtStartup
+ * property.
+ */
+class jsdASObserver MOZ_FINAL : public nsIObserver
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ jsdASObserver () {}
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
+
+NS_IMETHODIMP
+jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
+ const PRUnichar *aData)
+{
+ nsresult rv;
+
+ // Hmm. Why is the app-startup observer called multiple times?
+ //NS_ASSERTION(!gJsds, "app startup observer called twice");
+ nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ bool on;
+ rv = jsds->GetIsOn(&on);
+ if (NS_FAILED(rv) || on)
+ return rv;
+
+ nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ JSRuntime *rt;
+ rts->GetRuntime (&rt);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = jsds->ActivateDebugger(rt);
+ if (NS_FAILED(rv))
+ return rv;
+
+ return NS_OK;
+}
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
+NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
+NS_DEFINE_NAMED_CID(JSDASO_CID);
+
+static const mozilla::Module::CIDEntry kJSDCIDs[] = {
+ { &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor },
+ { &kJSDASO_CID, false, NULL, jsdASObserverConstructor },
+ { NULL }
+};
+
+static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
+ { jsdServiceCtrID, &kJSDSERVICE_CID },
+ { jsdARObserverCtrID, &kJSDASO_CID },
+ { NULL }
+};
+
+static const mozilla::Module kJSDModule = {
+ mozilla::Module::kVersion,
+ kJSDCIDs,
+ kJSDContracts
+};
+
+NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
+
+void
+global_finalize(JSFreeOp *aFop, JSObject *aObj)
+{
+ nsIScriptObjectPrincipal *sop =
+ static_cast<nsIScriptObjectPrincipal *>(js::GetObjectPrivate(aObj));
+ MOZ_ASSERT(sop);
+ static_cast<SandboxPrivate *>(sop)->ForgetGlobalObject();
+ NS_IF_RELEASE(sop);
+}
+
+JSObject *
+CreateJSDGlobal(JSContext *aCx, JSClass *aClasp)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrincipal> nullPrin = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ JSPrincipals *jsPrin = nsJSPrincipals::get(nullPrin);
+ JSObject *global = JS_NewGlobalObject(aCx, aClasp, jsPrin);
+ NS_ENSURE_TRUE(global, nullptr);
+
+ // We have created a new global let's attach a private to it
+ // that implements nsIGlobalObject.
+ nsCOMPtr<nsIScriptObjectPrincipal> sbp =
+ new SandboxPrivate(nullPrin, global);
+ JS_SetPrivate(global, sbp.forget().get());
+
+ return global;
+}
+
+/********************************************************************************
+ ********************************************************************************
+ * graveyard
+ */
+
+#if 0
+/* Thread States */
+NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState);
+
+NS_IMETHODIMP
+jsdThreadState::GetJSDContext(JSDContext **_rval)
+{
+ *_rval = mCx;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
+{
+ *_rval = mThreadState;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdThreadState::GetFrameCount (uint32_t *_rval)
+{
+ *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
+{
+ JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
+
+ *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdThreadState::GetPendingException(jsdIValue **_rval)
+{
+ JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
+
+ *_rval = jsdValue::FromPtr (mCx, jsdv);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdThreadState::SetPendingException(jsdIValue *aException)
+{
+ JSDValue *jsdv;
+
+ nsresult rv = aException->GetJSDValue (&jsdv);
+ if (NS_FAILED(rv))
+ return NS_ERROR_FAILURE;
+
+ if (!JSD_SetException (mCx, mThreadState, jsdv))
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+#endif
diff --git a/js/jsd/jsd_xpc.h b/js/jsd/jsd_xpc.h
new file mode 100644
index 0000000..4dbfe7c
--- /dev/null
+++ b/js/jsd/jsd_xpc.h
@@ -0,0 +1,372 @@
+/* -*- 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 JSDSERVICE_H___
+#define JSDSERVICE_H___
+
+#include "jsdIDebuggerService.h"
+#include "jsdebug.h"
+#include "nsString.h"
+#include "nsCOMPtr.h"
+#include "nspr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "mozilla/Attributes.h"
+
+// #if defined(DEBUG_rginda_l)
+// # define DEBUG_verbose
+// #endif
+
+struct LiveEphemeral {
+ /* link in a chain of live values list */
+ PRCList links;
+ jsdIEphemeral *value;
+ void *key;
+};
+
+struct PCMapEntry {
+ uint32_t pc, line;
+};
+
+/*******************************************************************************
+ * reflected jsd data structures
+ *******************************************************************************/
+
+class jsdObject MOZ_FINAL : public jsdIObject
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDIOBJECT
+
+ /* you'll normally use use FromPtr() instead of directly constructing one */
+ jsdObject (JSDContext *aCx, JSDObject *aObject) :
+ mCx(aCx), mObject(aObject)
+ {
+ }
+
+ static jsdIObject *FromPtr (JSDContext *aCx,
+ JSDObject *aObject)
+ {
+ if (!aObject)
+ return nullptr;
+
+ jsdIObject *rv = new jsdObject (aCx, aObject);
+ NS_IF_ADDREF(rv);
+ return rv;
+ }
+
+ private:
+ jsdObject(); /* no implementation */
+ jsdObject(const jsdObject&); /* no implementation */
+
+ JSDContext *mCx;
+ JSDObject *mObject;
+};
+
+
+class jsdProperty : public jsdIProperty
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDIPROPERTY
+ NS_DECL_JSDIEPHEMERAL
+
+ jsdProperty (JSDContext *aCx, JSDProperty *aProperty);
+ virtual ~jsdProperty ();
+
+ static jsdIProperty *FromPtr (JSDContext *aCx,
+ JSDProperty *aProperty)
+ {
+ if (!aProperty)
+ return nullptr;
+
+ jsdIProperty *rv = new jsdProperty (aCx, aProperty);
+ NS_IF_ADDREF(rv);
+ return rv;
+ }
+
+ static void InvalidateAll();
+
+ private:
+ jsdProperty(); /* no implementation */
+ jsdProperty(const jsdProperty&); /* no implementation */
+
+ bool mValid;
+ LiveEphemeral mLiveListEntry;
+ JSDContext *mCx;
+ JSDProperty *mProperty;
+};
+
+class jsdScript : public jsdIScript
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDISCRIPT
+ NS_DECL_JSDIEPHEMERAL
+
+ /* you'll normally use use FromPtr() instead of directly constructing one */
+ jsdScript (JSDContext *aCx, JSDScript *aScript);
+ virtual ~jsdScript();
+
+ static jsdIScript *FromPtr (JSDContext *aCx, JSDScript *aScript)
+ {
+ if (!aScript)
+ return nullptr;
+
+ void *data = JSD_GetScriptPrivate (aScript);
+ jsdIScript *rv;
+
+ if (data) {
+ rv = static_cast<jsdIScript *>(data);
+ } else {
+ rv = new jsdScript (aCx, aScript);
+ NS_IF_ADDREF(rv); /* addref for the SetScriptPrivate, released in
+ * Invalidate() */
+ JSD_SetScriptPrivate (aScript, static_cast<void *>(rv));
+ }
+
+ NS_IF_ADDREF(rv); /* addref for return value */
+ return rv;
+ }
+
+ static void InvalidateAll();
+
+ private:
+ static uint32_t LastTag;
+
+ jsdScript(); /* no implementation */
+ jsdScript (const jsdScript&); /* no implementation */
+ PCMapEntry* CreatePPLineMap();
+ uint32_t PPPcToLine(uint32_t aPC);
+ uint32_t PPLineToPc(uint32_t aLine);
+
+ bool mValid;
+ uint32_t mTag;
+ JSDContext *mCx;
+ JSDScript *mScript;
+ nsCString *mFileName;
+ nsCString *mFunctionName;
+ uint32_t mBaseLineNumber, mLineExtent;
+ PCMapEntry *mPPLineMap;
+ uint32_t mPCMapSize;
+ uintptr_t mFirstPC;
+};
+
+uint32_t jsdScript::LastTag = 0;
+
+class jsdContext : public jsdIContext
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDICONTEXT
+ NS_DECL_JSDIEPHEMERAL
+
+ jsdContext (JSDContext *aJSDCx, JSContext *aJSCx, nsISupports *aISCx);
+ virtual ~jsdContext();
+
+ static void InvalidateAll();
+ static jsdIContext *FromPtr (JSDContext *aJSDCx, JSContext *aJSCx);
+ private:
+ static uint32_t LastTag;
+
+ jsdContext (); /* no implementation */
+ jsdContext (const jsdContext&); /* no implementation */
+
+ bool mValid;
+ LiveEphemeral mLiveListEntry;
+ uint32_t mTag;
+ JSDContext *mJSDCx;
+ JSContext *mJSCx;
+ nsCOMPtr<nsISupports> mISCx;
+};
+
+uint32_t jsdContext::LastTag = 0;
+
+class jsdStackFrame : public jsdIStackFrame
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDISTACKFRAME
+ NS_DECL_JSDIEPHEMERAL
+
+ /* you'll normally use use FromPtr() instead of directly constructing one */
+ jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
+ JSDStackFrameInfo *aStackFrameInfo);
+ virtual ~jsdStackFrame();
+
+ static void InvalidateAll();
+ static jsdIStackFrame* FromPtr (JSDContext *aCx,
+ JSDThreadState *aThreadState,
+ JSDStackFrameInfo *aStackFrameInfo);
+
+ private:
+ jsdStackFrame(); /* no implementation */
+ jsdStackFrame(const jsdStackFrame&); /* no implementation */
+
+ bool mValid;
+ LiveEphemeral mLiveListEntry;
+ JSDContext *mCx;
+ JSDThreadState *mThreadState;
+ JSDStackFrameInfo *mStackFrameInfo;
+};
+
+class jsdValue : public jsdIValue
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDIVALUE
+ NS_DECL_JSDIEPHEMERAL
+
+ /* you'll normally use use FromPtr() instead of directly constructing one */
+ jsdValue (JSDContext *aCx, JSDValue *aValue);
+ virtual ~jsdValue();
+
+ static jsdIValue *FromPtr (JSDContext *aCx, JSDValue *aValue);
+ static void InvalidateAll();
+
+ private:
+ jsdValue(); /* no implementation */
+ jsdValue (const jsdScript&); /* no implementation */
+
+ bool mValid;
+ LiveEphemeral mLiveListEntry;
+ JSDContext *mCx;
+ JSDValue *mValue;
+};
+
+/******************************************************************************
+ * debugger service
+ ******************************************************************************/
+
+class jsdService : public jsdIDebuggerService
+{
+ public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_JSDIDEBUGGERSERVICE
+
+ NS_DECL_CYCLE_COLLECTION_CLASS(jsdService)
+
+ jsdService() : mOn(false), mPauseLevel(0),
+ mNestedLoopLevel(0), mCx(0), mRuntime(0), mErrorHook(0),
+ mBreakpointHook(0), mDebugHook(0), mDebuggerHook(0),
+ mInterruptHook(0), mScriptHook(0), mThrowHook(0),
+ mTopLevelHook(0), mFunctionHook(0)
+ {
+ }
+
+ virtual ~jsdService();
+
+ static jsdService *GetService ();
+
+ bool CheckInterruptHook() { return !!mInterruptHook; }
+
+ nsresult DoPause(uint32_t *_rval, bool internalCall);
+ nsresult DoUnPause(uint32_t *_rval, bool internalCall);
+
+ private:
+ bool mOn;
+ uint32_t mPauseLevel;
+ uint32_t mNestedLoopLevel;
+ JSDContext *mCx;
+ JSRuntime *mRuntime;
+
+ nsCOMPtr<jsdIErrorHook> mErrorHook;
+ nsCOMPtr<jsdIExecutionHook> mBreakpointHook;
+ nsCOMPtr<jsdIExecutionHook> mDebugHook;
+ nsCOMPtr<jsdIExecutionHook> mDebuggerHook;
+ nsCOMPtr<jsdIExecutionHook> mInterruptHook;
+ nsCOMPtr<jsdIScriptHook> mScriptHook;
+ nsCOMPtr<jsdIExecutionHook> mThrowHook;
+ nsCOMPtr<jsdICallHook> mTopLevelHook;
+ nsCOMPtr<jsdICallHook> mFunctionHook;
+ nsCOMPtr<jsdIActivationCallback> mActivationCallback;
+};
+
+#endif /* JSDSERVICE_H___ */
+
+
+/* graveyard */
+
+#if 0
+
+class jsdContext : public jsdIContext
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDICONTEXT
+
+ /* you'll normally use use FromPtr() instead of directly constructing one */
+ jsdContext (JSDContext *aCx) : mCx(aCx)
+ {
+ printf ("++++++ jsdContext\n");
+ }
+
+ static jsdIContext *FromPtr (JSDContext *aCx)
+ {
+ if (!aCx)
+ return nullptr;
+
+ void *data = JSD_GetContextPrivate (aCx);
+ jsdIContext *rv;
+
+ if (data) {
+ rv = static_cast<jsdIContext *>(data);
+ } else {
+ rv = new jsdContext (aCx);
+ NS_IF_ADDREF(rv); // addref for the SetContextPrivate
+ JSD_SetContextPrivate (aCx, static_cast<void *>(rv));
+ }
+
+ NS_IF_ADDREF(rv); // addref for the return value
+ return rv;
+ }
+
+ virtual ~jsdContext() { printf ("------ ~jsdContext\n"); }
+ private:
+ jsdContext(); /* no implementation */
+ jsdContext(const jsdContext&); /* no implementation */
+
+ JSDContext *mCx;
+};
+
+class jsdThreadState : public jsdIThreadState
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_JSDITHREADSTATE
+
+ /* you'll normally use use FromPtr() instead of directly constructing one */
+ jsdThreadState (JSDContext *aCx, JSDThreadState *aThreadState) :
+ mCx(aCx), mThreadState(aThreadState)
+ {
+ }
+
+ /* XXX These things are only valid for a short period of time, they reflect
+ * state in the js engine that will go away after stepping past wherever
+ * we were stopped at when this was created. We could keep a list of every
+ * instance of this we've created, and "invalidate" them before we let the
+ * engine continue. The next time we need a threadstate, we can search the
+ * list to find an invalidated one, and just reuse it.
+ */
+ static jsdIThreadState *FromPtr (JSDContext *aCx,
+ JSDThreadState *aThreadState)
+ {
+ if (!aThreadState)
+ return nullptr;
+
+ jsdIThreadState *rv = new jsdThreadState (aCx, aThreadState);
+ NS_IF_ADDREF(rv);
+ return rv;
+ }
+
+ private:
+ jsdThreadState(); /* no implementation */
+ jsdThreadState(const jsdThreadState&); /* no implementation */
+
+ JSDContext *mCx;
+ JSDThreadState *mThreadState;
+};
+
+#endif
diff --git a/js/jsd/jsdebug.cpp b/js/jsd/jsdebug.cpp
new file mode 100644
index 0000000..0355ca3
--- /dev/null
+++ b/js/jsd/jsdebug.cpp
@@ -0,0 +1,1371 @@
+/* -*- 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/. */
+
+/*
+ * JavaScript Debugging support - All public functions
+ */
+
+#include "jsd.h"
+
+/***************************************************************************/
+/* High Level calls */
+
+JSD_PUBLIC_API(JSDContext*)
+JSD_DebuggerOnForUser(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user)
+{
+ return jsd_DebuggerOnForUser(jsrt, callbacks, user, NULL);
+}
+
+JSD_PUBLIC_API(JSDContext*)
+JSD_DebuggerOn(void)
+{
+ return jsd_DebuggerOn();
+}
+
+JSD_PUBLIC_API(void)
+JSD_DebuggerOff(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_DebuggerOff(jsdc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_DebuggerPause(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_DebuggerPause(jsdc, JS_FALSE);
+}
+
+JSD_PUBLIC_API(void)
+JSD_DebuggerUnpause(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_DebuggerUnpause(jsdc);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetMajorVersion(void)
+{
+ return JSD_MAJOR_VERSION;
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetMinorVersion(void)
+{
+ return JSD_MINOR_VERSION;
+}
+
+JSD_PUBLIC_API(JSObject*)
+JSD_GetDefaultGlobal(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsdc->glob;
+}
+
+JSD_PUBLIC_API(JSRuntime*)
+JSD_GetJSRuntime(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsdc->jsrt;
+}
+
+JSD_PUBLIC_API(void)
+JSD_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
+{
+ jsd_SetUserCallbacks(jsrt, callbacks, user);
+}
+
+JSD_PUBLIC_API(void)
+JSD_JSContextInUse(JSDContext* jsdc, JSContext* context)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ /* we no longer need this information - may need it again in the future */
+}
+
+JSD_PUBLIC_API(void *)
+JSD_SetContextPrivate(JSDContext *jsdc, void *data)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetContextPrivate (jsdc, data);
+}
+
+JSD_PUBLIC_API(void *)
+JSD_GetContextPrivate(JSDContext *jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetContextPrivate (jsdc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_ClearAllProfileData(JSDContext *jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_ClearAllProfileData(jsdc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_SetContextFlags(JSDContext *jsdc, uint32_t flags)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsdc->flags = flags;
+ if (flags & JSD_COLLECT_PROFILE_DATA) {
+ /* Need to reenable our call hooks now */
+ JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
+ JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
+ }
+}
+
+JSD_PUBLIC_API(uint32_t)
+JSD_GetContextFlags(JSDContext *jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsdc->flags;
+}
+
+JSD_PUBLIC_API(JSDContext*)
+JSD_JSDContextForJSContext(JSContext* context)
+{
+ return jsd_JSDContextForJSContext(context);
+}
+
+/***************************************************************************/
+/* Script functions */
+
+JSD_PUBLIC_API(void)
+JSD_LockScriptSubsystem(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_LOCK_SCRIPTS(jsdc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_UnlockScriptSubsystem(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_UNLOCK_SCRIPTS(jsdc);
+}
+
+JSD_PUBLIC_API(JSDScript*)
+JSD_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_IterateScripts(jsdc, iterp);
+}
+
+JSD_PUBLIC_API(uint32_t)
+JSD_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptFlags(jsdc, script);
+}
+
+JSD_PUBLIC_API(void)
+JSD_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_SetScriptFlags(jsdc, script, flags);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptCallCount(jsdc, script);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptMaxRecurseDepth(jsdc, script);
+}
+
+
+JSD_PUBLIC_API(double)
+JSD_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptMinExecutionTime(jsdc, script);
+}
+
+JSD_PUBLIC_API(double)
+JSD_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptMaxExecutionTime(jsdc, script);
+}
+
+JSD_PUBLIC_API(double)
+JSD_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptTotalExecutionTime(jsdc, script);
+}
+
+JSD_PUBLIC_API(double)
+JSD_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptMinOwnExecutionTime(jsdc, script);
+}
+
+JSD_PUBLIC_API(double)
+JSD_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptMaxOwnExecutionTime(jsdc, script);
+}
+
+JSD_PUBLIC_API(double)
+JSD_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptTotalOwnExecutionTime(jsdc, script);
+}
+
+JSD_PUBLIC_API(void)
+JSD_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_ClearScriptProfileData(jsdc, script);
+}
+
+JSD_PUBLIC_API(JSScript*)
+JSD_GetJSScript(JSDContext* jsdc, JSDScript *script)
+{
+ return jsd_GetJSScript(jsdc, script);
+}
+
+JSD_PUBLIC_API(JSFunction*)
+JSD_GetJSFunction(JSDContext* jsdc, JSDScript *script)
+{
+ return jsd_GetJSFunction (jsdc, script);
+}
+
+JSD_PUBLIC_API(void *)
+JSD_SetScriptPrivate(JSDScript *jsdscript, void *data)
+{
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_SetScriptPrivate (jsdscript, data);
+}
+
+JSD_PUBLIC_API(void *)
+JSD_GetScriptPrivate(JSDScript *jsdscript)
+{
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetScriptPrivate (jsdscript);
+}
+
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_IsActiveScript(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(const char*)
+JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetScriptFilename(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(JSString *)
+JSD_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetScriptFunctionId(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetScriptLineExtent(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetScriptHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(uintptr_t)
+JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetClosestPC(jsdc, jsdscript, line);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetClosestLine(jsdc, jsdscript, pc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned startLine, unsigned maxLines,
+ unsigned* count, unsigned** lines, uintptr_t** pcs)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_GetLinePCs(jsdc, jsdscript, startLine, maxLines, count, lines, pcs);
+}
+
+JSD_PUBLIC_API(void)
+JSD_ScriptCreated(JSDContext* jsdc,
+ JSContext *cx,
+ const char *filename, /* URL this script loads from */
+ unsigned lineno, /* line where this script starts */
+ JSScript *script,
+ JSFunction *fun)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_ScriptCreated(jsdc, cx, filename, lineno, script, fun);
+}
+
+JSD_PUBLIC_API(void)
+JSD_ScriptDestroyed(JSDContext* jsdc,
+ JSFreeOp *fop,
+ JSScript *script)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_ScriptDestroyed(jsdc, fop, script);
+}
+
+/***************************************************************************/
+/* Source Text functions */
+
+JSD_PUBLIC_API(void)
+JSD_LockSourceTextSubsystem(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_LOCK_SOURCE_TEXT(jsdc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_UnlockSourceTextSubsystem(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_UNLOCK_SOURCE_TEXT(jsdc);
+}
+
+JSD_PUBLIC_API(JSDSourceText*)
+JSD_IterateSources(JSDContext* jsdc, JSDSourceText **iterp)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_IterateSources(jsdc, iterp);
+}
+
+JSD_PUBLIC_API(JSDSourceText*)
+JSD_FindSourceForURL(JSDContext* jsdc, const char* url)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(url);
+ return jsd_FindSourceForURL(jsdc, url);
+}
+
+JSD_PUBLIC_API(const char*)
+JSD_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_GetSourceURL(jsdc,jsdsrc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
+ const char** ppBuf, int* pLen)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ JS_ASSERT(ppBuf);
+ JS_ASSERT(pLen);
+ return jsd_GetSourceText(jsdc, jsdsrc, ppBuf, pLen);
+}
+
+JSD_PUBLIC_API(void)
+JSD_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ jsd_ClearSourceText(jsdc, jsdsrc);
+}
+
+
+JSD_PUBLIC_API(JSDSourceStatus)
+JSD_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_GetSourceStatus(jsdc, jsdsrc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_IsSourceDirty(jsdc, jsdsrc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ jsd_SetSourceDirty(jsdc, jsdsrc, dirty);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_GetSourceAlterCount(jsdc, jsdsrc);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_IncrementSourceAlterCount(jsdc, jsdsrc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_DestroyAllSources( JSDContext* jsdc )
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ jsd_DestroyAllSources(jsdc);
+}
+
+JSD_PUBLIC_API(JSDSourceText*)
+JSD_NewSourceText(JSDContext* jsdc, const char* url)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(url);
+ return jsd_NewSourceText(jsdc, url);
+}
+
+JSD_PUBLIC_API(JSDSourceText*)
+JSD_AppendSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_AppendSourceText(jsdc, jsdsrc, text, length, status);
+}
+
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSD_AppendUCSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const jschar* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsd_AppendUCSourceText(jsdc, jsdsrc, text, length, status);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_AddFullSourceText(JSDContext* jsdc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ const char* url)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(url);
+ return jsd_AddFullSourceText(jsdc, text, length, url);
+}
+
+/***************************************************************************/
+/* Execution/Interrupt Hook functions */
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_SetExecutionHook(jsdc, jsdscript, pc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_ClearExecutionHook(jsdc, jsdscript, pc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearAllExecutionHooks(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearAllExecutionHooks(jsdc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetInterruptHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetInterruptHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsd_EnableSingleStepInterrupts(jsdc, jsdscript, enable);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearInterruptHook(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearInterruptHook(jsdc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetDebugBreakHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetDebugBreakHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearDebugBreakHook(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearDebugBreakHook(jsdc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetDebuggerHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetDebuggerHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearDebuggerHook(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearDebuggerHook(jsdc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetThrowHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetThrowHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearThrowHook(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearThrowHook(jsdc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetTopLevelHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetTopLevelHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearTopLevelHook(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearTopLevelHook(jsdc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetFunctionHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetFunctionHook(jsdc, hook, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_ClearFunctionHook(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ClearFunctionHook(jsdc);
+}
+
+/***************************************************************************/
+/* Stack Frame functions */
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetCountOfStackFrames(jsdc, jsdthreadstate);
+}
+
+JSD_PUBLIC_API(JSDStackFrameInfo*)
+JSD_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetStackFrame(jsdc, jsdthreadstate);
+}
+
+JSD_PUBLIC_API(JSContext*)
+JSD_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetJSContext(jsdc, jsdthreadstate);
+}
+
+JSD_PUBLIC_API(JSDStackFrameInfo*)
+JSD_GetCallingStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetCallingStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSDScript*)
+JSD_GetScriptForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptForStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(uintptr_t)
+JSD_GetPCForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetPCForStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetCallObjectForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetCallObjectForStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetScopeChainForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScopeChainForStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetThisForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetThisForStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSString *)
+JSD_GetIdForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetIdForStackFrame(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsStackFrameDebugger(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_IsStackFrameDebugger(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsStackFrameConstructing(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_IsStackFrameConstructing(jsdc, jsdthreadstate, jsdframe);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const jschar *bytes, unsigned length,
+ const char *filename, unsigned lineno, JS::MutableHandleValue rval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(bytes);
+ JS_ASSERT(length);
+ JS_ASSERT(filename);
+
+ return jsd_EvaluateUCScriptInStackFrame(jsdc, jsdthreadstate,jsdframe,
+ bytes, length, filename, lineno,
+ JS_TRUE, rval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_AttemptUCScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const jschar *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JS::MutableHandleValue rval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(bytes);
+ JS_ASSERT(length);
+ JS_ASSERT(filename);
+
+ return jsd_EvaluateUCScriptInStackFrame(jsdc, jsdthreadstate,jsdframe,
+ bytes, length, filename, lineno,
+ JS_FALSE, rval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_EvaluateScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const char *bytes, unsigned length,
+ const char *filename, unsigned lineno, JS::MutableHandleValue rval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(bytes);
+ JS_ASSERT(length);
+ JS_ASSERT(filename);
+
+ return jsd_EvaluateScriptInStackFrame(jsdc, jsdthreadstate,jsdframe,
+ bytes, length,
+ filename, lineno, JS_TRUE, rval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_AttemptScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const char *bytes, unsigned length,
+ const char *filename, unsigned lineno, JS::MutableHandleValue rval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(bytes);
+ JS_ASSERT(length);
+ JS_ASSERT(filename);
+
+ return jsd_EvaluateScriptInStackFrame(jsdc, jsdthreadstate,jsdframe,
+ bytes, length,
+ filename, lineno, JS_FALSE, rval);
+}
+
+JSD_PUBLIC_API(JSString*)
+JSD_ValToStringInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ jsval val)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_ValToStringInStackFrame(jsdc, jsdthreadstate, jsdframe, val);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetException(jsdc, jsdthreadstate);
+}
+
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
+ JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetException(jsdc, jsdthreadstate, jsdval);
+}
+
+/***************************************************************************/
+
+JSD_PUBLIC_API(JSBool)
+JSD_SetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter reporter,
+ void* callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_SetErrorReporter(jsdc, reporter, callerdata);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_GetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter* reporter,
+ void** callerdata)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetErrorReporter(jsdc, reporter, callerdata);
+}
+
+/***************************************************************************/
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsLockingAndThreadIdSupported()
+{
+#ifdef JSD_THREADSAFE
+ return JS_TRUE;
+#else
+ return JS_FALSE;
+#endif
+}
+
+JSD_PUBLIC_API(JSDStaticLock*)
+JSD_CreateLock()
+{
+#ifdef JSD_THREADSAFE
+ return jsd_CreateLock();
+#else
+ return (void*)1;
+#endif
+}
+
+JSD_PUBLIC_API(void)
+JSD_Lock(JSDStaticLock* lock)
+{
+#ifdef JSD_THREADSAFE
+ jsd_Lock(lock);
+#endif
+}
+
+JSD_PUBLIC_API(void)
+JSD_Unlock(JSDStaticLock* lock)
+{
+#ifdef JSD_THREADSAFE
+ jsd_Unlock(lock);
+#endif
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsLocked(JSDStaticLock* lock)
+{
+#if defined(JSD_THREADSAFE) && defined(DEBUG)
+ return jsd_IsLocked(lock);
+#else
+ return JS_TRUE;
+#endif
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsUnlocked(JSDStaticLock* lock)
+{
+#if defined(JSD_THREADSAFE) && defined(DEBUG)
+ return ! jsd_IsLocked(lock);
+#else
+ return JS_TRUE;
+#endif
+}
+
+JSD_PUBLIC_API(void*)
+JSD_CurrentThread()
+{
+ return JSD_CURRENT_THREAD();
+}
+
+/***************************************************************************/
+/* Value and Property Functions */
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_NewValue(JSDContext* jsdc, jsval val)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_NewValue(jsdc, val);
+}
+
+JSD_PUBLIC_API(void)
+JSD_DropValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ jsd_DropValue(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(jsval)
+JSD_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueWrappedJSVal(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(void)
+JSD_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ jsd_RefreshValue(jsdc, jsdval);
+}
+
+/**************************************************/
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueObject(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueNumber(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueInt(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueDouble(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueString(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueBoolean(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueNull(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueVoid(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValuePrimitive(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueFunction(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSD_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_IsValueNative(jsdc, jsdval);
+}
+
+/**************************************************/
+
+JSD_PUBLIC_API(JSBool)
+JSD_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueBoolean(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(int32_t)
+JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueInt(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(double)
+JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueDouble(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSString*)
+JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueString(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSString *)
+JSD_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueFunctionId(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSFunction*)
+JSD_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueFunction(jsdc, jsdval);
+}
+
+/**************************************************/
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetCountOfProperties(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSDProperty*)
+JSD_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ JS_ASSERT(iterp);
+ return jsd_IterateProperties(jsdc, jsdval, iterp);
+}
+
+JSD_PUBLIC_API(JSDProperty*)
+JSD_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ JS_ASSERT(name);
+ return jsd_GetValueProperty(jsdc, jsdval, name);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValuePrototype(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueParent(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueConstructor(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(const char*)
+JSD_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetValueClassName(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSDScript*)
+JSD_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_GetScriptForValue(jsdc, jsdval);
+}
+/**************************************************/
+
+JSD_PUBLIC_API(void)
+JSD_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_PROPERTY(jsdprop);
+ jsd_DropProperty(jsdc, jsdprop);
+}
+
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_PROPERTY(jsdprop);
+ return jsd_GetPropertyName(jsdc, jsdprop);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_PROPERTY(jsdprop);
+ return jsd_GetPropertyValue(jsdc, jsdprop);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_PROPERTY(jsdprop);
+ return jsd_GetPropertyAlias(jsdc, jsdprop);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_PROPERTY(jsdprop);
+ return jsd_GetPropertyFlags(jsdc, jsdprop);
+}
+
+/**************************************************/
+/* Object Functions */
+
+JSD_PUBLIC_API(void)
+JSD_LockObjectSubsystem(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_LOCK_OBJECTS(jsdc);
+}
+
+JSD_PUBLIC_API(void)
+JSD_UnlockObjectSubsystem(JSDContext* jsdc)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_UNLOCK_OBJECTS(jsdc);
+}
+
+JSD_PUBLIC_API(JSDObject*)
+JSD_IterateObjects(JSDContext* jsdc, JSDObject** iterp)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ return jsd_IterateObjects(jsdc, iterp);
+}
+
+JSD_PUBLIC_API(JSObject*)
+JSD_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetWrappedObject(jsdc, jsdobj);
+
+}
+
+JSD_PUBLIC_API(const char*)
+JSD_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetObjectNewURL(jsdc, jsdobj);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetObjectNewLineNumber(jsdc, jsdobj);
+}
+
+JSD_PUBLIC_API(const char*)
+JSD_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetObjectConstructorURL(jsdc, jsdobj);
+}
+
+JSD_PUBLIC_API(unsigned)
+JSD_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetObjectConstructorLineNumber(jsdc, jsdobj);
+}
+
+JSD_PUBLIC_API(const char*)
+JSD_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetObjectConstructorName(jsdc, jsdobj);
+}
+
+JSD_PUBLIC_API(JSDObject*)
+JSD_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(jsobj);
+ return jsd_GetJSDObjectForJSObject(jsdc, jsobj);
+}
+
+JSD_PUBLIC_API(JSDObject*)
+JSD_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_VALUE(jsdval);
+ return jsd_GetObjectForValue(jsdc, jsdval);
+}
+
+JSD_PUBLIC_API(JSDValue*)
+JSD_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_OBJECT(jsdobj);
+ return jsd_GetValueForObject(jsdc, jsdobj);
+}
+
+/***************************************************************************/
+/* Livewire specific API */
+#ifdef LIVEWIRE
+
+JSD_PUBLIC_API(LWDBGScript*)
+JSDLW_GetLWScript(JSDContext* jsdc, JSDScript* jsdscript)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsdlw_GetLWScript(jsdc, jsdscript);
+}
+
+JSD_PUBLIC_API(JSDSourceText*)
+JSDLW_PreLoadSource( JSDContext* jsdc, LWDBGApp* app,
+ const char* filename, JSBool clear )
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JS_ASSERT(app);
+ JS_ASSERT(filename);
+ return jsdlw_PreLoadSource(jsdc, app, filename, clear);
+}
+
+JSD_PUBLIC_API(JSDSourceText*)
+JSDLW_ForceLoadSource( JSDContext* jsdc, JSDSourceText* jsdsrc )
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc);
+ return jsdlw_ForceLoadSource(jsdc, jsdsrc);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSDLW_RawToProcessedLineNumber(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned lineIn, unsigned* lineOut)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, lineIn, lineOut);
+}
+
+JSD_PUBLIC_API(JSBool)
+JSDLW_ProcessedToRawLineNumber(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned lineIn, unsigned* lineOut)
+{
+ JSD_ASSERT_VALID_CONTEXT(jsdc);
+ JSD_ASSERT_VALID_SCRIPT(jsdscript);
+ return jsdlw_ProcessedToRawLineNumber(jsdc, jsdscript, lineIn, lineOut);
+}
+
+#endif
+/***************************************************************************/
diff --git a/js/jsd/jsdebug.h b/js/jsd/jsdebug.h
new file mode 100644
index 0000000..ddb2fa0
--- /dev/null
+++ b/js/jsd/jsdebug.h
@@ -0,0 +1,1564 @@
+/* -*- 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/. */
+
+/*
+ * Header for JavaScript Debugging support - All public functions
+ */
+
+#ifndef jsdebug_h___
+#define jsdebug_h___
+
+/* Get jstypes.h included first. After that we can use PR macros for doing
+* this extern "C" stuff!
+*/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "jstypes.h"
+#ifdef __cplusplus
+}
+#endif
+
+#include "jsapi.h"
+#include "jsdbgapi.h"
+#ifdef LIVEWIRE
+#include "lwdbgapi.h"
+#endif
+
+JS_BEGIN_EXTERN_C
+
+/*
+ * The linkage of JSD API functions differs depending on whether the file is
+ * used within the JSD library or not. Any source file within the JSD
+ * libraray should define EXPORT_JSD_API whereas any client of the library
+ * should not.
+ */
+#ifdef EXPORT_JSD_API
+#define JSD_PUBLIC_API(t) JS_EXPORT_API(t)
+#define JSD_PUBLIC_DATA(t) JS_EXPORT_DATA(t)
+#else
+#define JSD_PUBLIC_API(t) JS_IMPORT_API(t)
+#define JSD_PUBLIC_DATA(t) JS_IMPORT_DATA(t)
+#endif
+
+#define JSD_FRIEND_API(t) JSD_PUBLIC_API(t)
+#define JSD_FRIEND_DATA(t) JSD_PUBLIC_DATA(t)
+
+/***************************************************************************/
+/* Opaque typedefs for handles */
+
+typedef struct JSDContext JSDContext;
+typedef struct JSDScript JSDScript;
+typedef struct JSDSourceText JSDSourceText;
+typedef struct JSDThreadState JSDThreadState;
+typedef struct JSDStackFrameInfo JSDStackFrameInfo;
+typedef struct JSDValue JSDValue;
+typedef struct JSDProperty JSDProperty;
+typedef struct JSDObject JSDObject;
+
+/***************************************************************************/
+/* High Level calls */
+
+/*
+* callback stuff for calls in EXE to be accessed by this code
+* when it lives in an explicitly loaded DLL
+*/
+
+/*
+* This callback allows JSD to inform the embedding when JSD has been
+* turned on or off. This is especially useful in the Java-based debugging
+* system used in mozilla because the debugger applet controls starting
+* up the JSD system.
+*/
+typedef void
+(* JSD_SetContextProc)(JSDContext* jsdc, void* user);
+
+/* This struct could have more fields in future versions */
+typedef struct
+{
+ unsigned size; /* size of this struct (init before use)*/
+ JSD_SetContextProc setContext;
+} JSD_UserCallbacks;
+
+/*
+* Used by an embedding to tell JSD what JSRuntime to use and to set
+* callbacks without starting up JSD. This assumes only one JSRuntime
+* will be used. This exists to support the mozilla Java-based debugger
+* system.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_SetUserCallbacks(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user);
+
+/*
+* Startup JSD.
+* This version of the init function requires that JSD_SetUserCallbacks()
+* has been previously called (with a non-NULL callback struct pointer)
+*/
+extern JSD_PUBLIC_API(JSDContext*)
+JSD_DebuggerOn(void);
+
+/*
+* Startup JSD on a particular JSRuntime with (optional) callbacks
+*/
+extern JSD_PUBLIC_API(JSDContext*)
+JSD_DebuggerOnForUser(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user);
+
+/*
+ * Startup JSD in an application that uses compartments. Debugger
+ * objects will be allocated in the same compartment as scopeobj.
+ */
+extern JSD_PUBLIC_API(JSDContext*)
+JSD_DebuggerOnForUserWithCompartment(JSRuntime* jsrt,
+ JSD_UserCallbacks* callbacks,
+ void* user,
+ JSObject* scopeobj);
+
+/*
+* Shutdown JSD for this JSDContext
+*/
+extern JSD_PUBLIC_API(void)
+JSD_DebuggerOff(JSDContext* jsdc);
+
+/*
+ * Pause JSD for this JSDContext
+ */
+extern JSD_PUBLIC_API(void)
+JSD_DebuggerPause(JSDContext* jsdc);
+
+/*
+ * Unpause JSD for this JSDContext
+ */
+extern JSD_PUBLIC_API(void)
+JSD_DebuggerUnpause(JSDContext* jsdc);
+
+/*
+* Get the Major Version (initial JSD release used major version = 1)
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetMajorVersion(void);
+
+/*
+* Get the Minor Version (initial JSD release used minor version = 0)
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetMinorVersion(void);
+
+/*
+* Returns the default JSD global associated with a given JSDContext.
+*/
+extern JSD_PUBLIC_API(JSObject*)
+JSD_GetDefaultGlobal(JSDContext* jsdc);
+
+/*
+* Returns a JSRuntime this context is associated with
+*/
+extern JSD_PUBLIC_API(JSRuntime*)
+JSD_GetJSRuntime(JSDContext* jsdc);
+
+/*
+* Set the private data for this context, returns previous value
+*/
+extern JSD_PUBLIC_API(void *)
+JSD_SetContextPrivate(JSDContext *jsdc, void *data);
+
+/*
+* Get the private data for this context
+*/
+extern JSD_PUBLIC_API(void *)
+JSD_GetContextPrivate(JSDContext *jsdc);
+
+/*
+* Clear profile data for all scripts
+*/
+extern JSD_PUBLIC_API(void)
+JSD_ClearAllProfileData(JSDContext* jsdc);
+
+/*
+* Context flags.
+*/
+
+/* Include native frames in JSDThreadStates. */
+#define JSD_INCLUDE_NATIVE_FRAMES 0x01
+/*
+* Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in
+* profile data, otherwise it is not profiled. Setting the JSD_PROFILE_WHEN_SET
+* flag reverses this convention.
+*/
+#define JSD_PROFILE_WHEN_SET 0x02
+/*
+* Normally, when the script in the top frame of a thread state has a 1 in
+* JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the
+* JSD_DEBUG_WHEN_SET flag reverses this convention.
+*/
+#define JSD_DEBUG_WHEN_SET 0x04
+/*
+* When this flag is set the internal call hook will collect profile data.
+*/
+#define JSD_COLLECT_PROFILE_DATA 0x08
+/*
+* When this flag is set, stack frames that are disabled for debugging
+* will not appear in the call stack chain.
+*/
+#define JSD_HIDE_DISABLED_FRAMES 0x10
+/*
+* When this flag is set, the debugger will only check the
+* JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This
+* makes it possible to stop in an enabled frame which was called from
+* a stack that contains a disabled frame.
+*
+* When this flag is *not* set, any stack that contains a disabled frame
+* will not be debugged (the execution hook will not be invoked.)
+*
+* This only applies when the reason for calling the hook would have
+* been JSD_HOOK_INTERRUPTED or JSD_HOOK_THROW. JSD_HOOK_BREAKPOINT,
+* JSD_HOOK_DEBUG_REQUESTED, and JSD_HOOK_DEBUGGER_KEYWORD always stop,
+* regardless of this setting, as long as the top frame is not disabled.
+*
+* If JSD_HIDE_DISABLED_FRAMES is set, this is effectively set as well.
+*/
+#define JSD_MASK_TOP_FRAME_ONLY 0x20
+
+/*
+* 0x40 was formerly used to hook into object creation.
+*/
+#define JSD_DISABLE_OBJECT_TRACE_RETIRED 0x40
+
+
+extern JSD_PUBLIC_API(void)
+JSD_SetContextFlags (JSDContext* jsdc, uint32_t flags);
+
+extern JSD_PUBLIC_API(uint32_t)
+JSD_GetContextFlags (JSDContext* jsdc);
+
+/*
+* Notify JSD that this JSContext is 'in use'. This allows JSD to hook the
+* ErrorReporter. For the most part this is done automatically whenever
+* events like script loading happen. But, it is a good idea to call this
+* from the embedding when new contexts come into use.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_JSContextInUse(JSDContext* jsdc, JSContext* context);
+
+/*
+* Find the JSDContext (if any) associated with the JSRuntime of a
+* given JSContext.
+*/
+extern JSD_PUBLIC_API(JSDContext*)
+JSD_JSDContextForJSContext(JSContext* context);
+
+/***************************************************************************/
+/* Script functions */
+
+/*
+* Lock the entire script subsystem. This grabs a highlevel lock that
+* protects the JSD internal information about scripts. It is important
+* to wrap script related calls in this lock in multithreaded situations
+* -- i.e. where the debugger is running on a different thread than the
+* interpreter -- or when multiple debugger threads may be accessing this
+* subsystem. It is safe (and best) to use this locking even if the
+* environment might not be multi-threaded. Safely nestable.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_LockScriptSubsystem(JSDContext* jsdc);
+
+/*
+* Unlock the entire script subsystem -- see JSD_LockScriptSubsystem
+*/
+extern JSD_PUBLIC_API(void)
+JSD_UnlockScriptSubsystem(JSDContext* jsdc);
+
+/*
+* Iterate through all the active scripts for this JSDContext.
+* NOTE: must initialize iterp to NULL to start iteration.
+* NOTE: must lock and unlock the subsystem
+* example:
+*
+* JSDScript jsdscript;
+* JSDScript iter = NULL;
+*
+* JSD_LockScriptSubsystem(jsdc);
+* while((jsdscript = JSD_IterateScripts(jsdc, &iter)) != NULL) {
+* *** use jsdscript here ***
+* }
+* JSD_UnlockScriptSubsystem(jsdc);
+*/
+extern JSD_PUBLIC_API(JSDScript*)
+JSD_IterateScripts(JSDContext* jsdc, JSDScript **iterp);
+
+/*
+* Get the number of times this script has been called.
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetScriptCallCount(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the max number of times this script called itself, directly or indirectly.
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the shortest execution time recorded.
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the longest execution time recorded.
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the total amount of time spent in this script.
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the shortest execution time recorded, excluding time spent in called
+* functions.
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the longest execution time recorded, excluding time spent in called
+* functions.
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the total amount of time spent in this script, excluding time spent
+* in called functions.
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Clear profile data for this script.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the JSScript for a JSDScript
+*/
+extern JSD_PUBLIC_API(JSScript*)
+JSD_GetJSScript(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Get the JSFunction for a JSDScript
+*/
+extern JSD_PUBLIC_API(JSFunction*)
+JSD_GetJSFunction(JSDContext* jsdc, JSDScript *script);
+
+/*
+* Determines whether or not to collect profile information for this
+* script. The context flag JSD_PROFILE_WHEN_SET decides the logic.
+*/
+#define JSD_SCRIPT_PROFILE_BIT 0x01
+/*
+* Determines whether or not to ignore breakpoints, etc. in this script.
+* The context flag JSD_DEBUG_WHEN_SET decides the logic.
+*/
+#define JSD_SCRIPT_DEBUG_BIT 0x02
+/*
+ * Determines whether to invoke the onScriptDestroy callback for this
+ * script. The default is for this to be true if the onScriptCreated
+ * callback was invoked for this script.
+ */
+#define JSD_SCRIPT_CALL_DESTROY_HOOK_BIT 0x04
+
+extern JSD_PUBLIC_API(uint32_t)
+JSD_GetScriptFlags(JSDContext *jsdc, JSDScript* jsdscript);
+
+extern JSD_PUBLIC_API(void)
+JSD_SetScriptFlags(JSDContext *jsdc, JSDScript* jsdscript, uint32_t flags);
+
+/*
+* Set the private data for this script, returns previous value
+*/
+extern JSD_PUBLIC_API(void *)
+JSD_SetScriptPrivate(JSDScript* jsdscript, void *data);
+
+/*
+* Get the private data for this script
+*/
+extern JSD_PUBLIC_API(void *)
+JSD_GetScriptPrivate(JSDScript* jsdscript);
+
+/*
+* Determine if this script is still loaded in the interpreter
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript);
+
+/*
+* Get the filename associated with this script
+*/
+extern JSD_PUBLIC_API(const char*)
+JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript);
+
+/*
+* Get the function name associated with this script (NULL if not a function).
+* If the function does not have a name the result is the string "anonymous".
+* *** new for gecko 2.0 ****
+*/
+extern JSD_PUBLIC_API(JSString *)
+JSD_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript);
+
+/*
+* Get the base linenumber of the sourcefile from which this script was loaded.
+* This is one-based -- i.e. the first line of a file is line '1'. This may
+* return 0 if this infomation is unknown.
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript);
+
+/*
+* Get the count of source lines associated with this script (1 or greater)
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript);
+
+/*
+* Declaration of callback for notification of script creation and destruction.
+* 'creating' is JS_TRUE if creating new script, JS_FALSE if destroying existing
+* script (callback called just before actual destruction).
+* 'callerdata' is what was passed to JSD_SetScriptHook to set the hook.
+*/
+typedef void
+(* JSD_ScriptHookProc)(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ JSBool creating,
+ void* callerdata);
+
+/*
+* Set a hook to be called when scripts are created or destroyed (loaded or
+* unloaded).
+* 'callerdata' can be whatever you want it to be.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
+
+/*
+* Get the current script hook.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata);
+
+/*
+* Get a 'Program Counter' value for a given line. This represents the location
+* of the first bit of executable code for this line of source. This 'pc' should
+* be considered an opaque handle.
+* 0 is returned for invalid scripts, or lines that lie outside the script.
+* If no code is on the given line, then the returned pc represents the first
+* code within the script (if any) after the given line.
+* This function can be used to set breakpoints -- see JSD_SetExecutionHook
+*/
+extern JSD_PUBLIC_API(uintptr_t)
+JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line);
+
+/*
+* Get the source line number for a given 'Program Counter' location.
+* Returns 0 if no source line information is appropriate (or available) for
+* the given pc.
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc);
+
+/*
+ * Get a list of lines and the corresponding earliest PC for each (see
+ * JSD_GetClosestPC). Lines with no PCs associated will not be returned. NULL
+ * may be passed for either lines or pcs to avoid filling anything in for that
+ * argument.
+ */
+extern JSD_PUBLIC_API(JSBool)
+JSD_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned startLine, unsigned maxLines,
+ unsigned* count, unsigned** lines, uintptr_t** pcs);
+
+/* these are only used in cases where scripts are created outside of JS*/
+
+/*
+* Direct call to notify JSD that a script has been created.
+* Embeddings that use the normal jsapi script functions need not call this.
+* Any embedding that follows the (discouraged!) practice of contructing script
+* structures manually should call this function to inform JSD. (older ssjs
+* systems do this).
+*/
+extern JSD_PUBLIC_API(void)
+JSD_ScriptCreated(JSDContext* jsdc,
+ JSContext *cx,
+ const char *filename, /* URL this script loads from */
+ unsigned lineno, /* line where this script starts */
+ JSScript *script,
+ JSFunction *fun);
+
+/*
+* see JSD_ScriptCreated
+*/
+extern JSD_PUBLIC_API(void)
+JSD_ScriptDestroyed(JSDContext* jsdc,
+ JSFreeOp *fop,
+ JSScript *script);
+
+/***************************************************************************/
+/* Source Text functions */
+
+/*
+* In some embeddings (e.g. mozilla) JavaScript source code from a 'file' may be
+* execute before the entire 'file' has even been loaded. This system supports
+* access to such incrmentally loaded source. It also allows for the possibility
+* that source loading may fail or be aborted (though the source that did load
+* may still be usable). Remember that this source is the entire 'file'
+* contents and that the JavaScript code may only be part of that source.
+*
+* For any given URL there can only be one source text item (the most recently
+* loaded).
+*/
+
+/* these coorespond to netscape.jsdebug.SourceTextItem.java values -
+* change in both places if anywhere
+*/
+
+typedef enum
+{
+ JSD_SOURCE_INITED = 0, /* initialized, but contains no source yet */
+ JSD_SOURCE_PARTIAL = 1, /* some source loaded, more expected */
+ JSD_SOURCE_COMPLETED = 2, /* all source finished loading */
+ JSD_SOURCE_ABORTED = 3, /* user aborted loading, some may be loaded */
+ JSD_SOURCE_FAILED = 4, /* loading failed, some may be loaded */
+ JSD_SOURCE_CLEARED = 5 /* text has been cleared by debugger */
+} JSDSourceStatus;
+
+/*
+* Lock the entire source text subsystem. This grabs a highlevel lock that
+* protects the JSD internal information about sources. It is important to
+* wrap source text related calls in this lock in multithreaded situations
+* -- i.e. where the debugger is running on a different thread than the
+* interpreter (or the loader of sources) -- or when multiple debugger
+* threads may be accessing this subsystem. It is safe (and best) to use
+* this locking even if the environment might not be multi-threaded.
+* Safely Nestable.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_LockSourceTextSubsystem(JSDContext* jsdc);
+
+/*
+* Unlock the entire source text subsystem. see JSD_LockSourceTextSubsystem.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_UnlockSourceTextSubsystem(JSDContext* jsdc);
+
+/*
+* Iterate the source test items. Use the same pattern of calls shown in
+* the example for JSD_IterateScripts - NOTE that the SourceTextSubsystem.
+* must be locked before and unlocked after iterating.
+*/
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSD_IterateSources(JSDContext* jsdc, JSDSourceText **iterp);
+
+/*
+* Find the source text item for the given URL (or filename - or whatever
+* string the given embedding uses to describe source locations).
+* Returns NULL is not found.
+*/
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSD_FindSourceForURL(JSDContext* jsdc, const char* url);
+
+/*
+* Get the URL string associated with the given source text item
+*/
+extern JSD_PUBLIC_API(const char*)
+JSD_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+/*
+* Get the actual source text. This gives access to the actual storage of
+* the source - it sHould *not* be written to.
+* The buffer is NOT zero terminated (nor is it guaranteed to have space to
+* hold a zero terminating char).
+* XXX this is 8-bit character data. Unicode source is not yet supported.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc,
+ const char** ppBuf, int* pLen);
+
+/*
+* Clear the text -- delete the text and set the status to JSD_SOURCE_CLEARED.
+* This is useful if source is done loading and the debugger wishes to store
+* the text data itself (e.g. in a Java String). This allows avoidance of
+* storing the same text in multiple places.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+/*
+* Return the status of the source text item. see JSDSourceStatus enum.
+*/
+extern JSD_PUBLIC_API(JSDSourceStatus)
+JSD_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+/*
+* Has the source been altered since the last call to JSD_SetSourceDirty?
+* Use of JSD_IsSourceDirty and JSD_SetSourceDirty is still supported, but
+* discouraged in favor of the JSD_GetSourceAlterCount system. This dirty
+* scheme ASSUMES that there is only one consumer of the data.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+/*
+* Clear the dirty flag
+*/
+extern JSD_PUBLIC_API(void)
+JSD_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty);
+
+/*
+* Each time a source text item is altered this value is incremented. Any
+* consumer can store this value when they retieve other data about the
+* source text item and then check later to see if the current value is
+* different from their stored value. Thus they can know if they have stale
+* data or not. NOTE: this value is not gauranteed to start at any given number.
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+/*
+* Force an increment in the alter count for a source text item. This is
+* normally automatic when the item changes, but a give consumer may want to
+* force this to amke an item appear to have changed even if it has not.
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+/*
+* Destroy *all* the source text items
+* (new for server-side USE WITH CARE)
+*/
+extern JSD_PUBLIC_API(void)
+JSD_DestroyAllSources( JSDContext* jsdc );
+
+/* functions for adding source items */
+
+/*
+* Add a new item for a given URL. If an iten already exists for the given URL
+* then the old item is removed.
+* 'url' may not be NULL.
+*
+* ifdef LIVEWIRE url is treated as a char* and ownership is claimed by jsd
+*/
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSD_NewSourceText(JSDContext* jsdc, const char* url);
+
+/*
+* Append text (or change status -- e.g. set completed) for a source text
+* item. Text need not be zero terminated. Callers should consider the returned
+* JSDSourceText to be the 'current' item for future use. This may return NULL
+* if called after this item has been replaced by a call to JSD_NewSourceText.
+*/
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSD_AppendSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status);
+
+/*
+* Unicode varient of JSD_AppendSourceText.
+*
+* NOTE: At this point text is stored in 8bit ASCII so this function just
+* extracts the bottom 8bits from each jschar. At some future point we may
+* switch to storing and exposing 16bit Unicode.
+*/
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSD_AppendUCSourceText(JSDContext* jsdc,
+ JSDSourceText* jsdsrc,
+ const jschar* text, /* *not* zero terminated */
+ size_t length,
+ JSDSourceStatus status);
+/*
+ * Convienence function for adding complete source of url in one call.
+ * same as:
+ * JSDSourceText* jsdsrc;
+ * JSD_LOCK_SOURCE_TEXT(jsdc);
+ * jsdsrc = jsd_NewSourceText(jsdc, url);
+ * if(jsdsrc)
+ * jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
+ * text, length, JSD_SOURCE_PARTIAL);
+ * if(jsdsrc)
+ * jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc,
+ * NULL, 0, JSD_SOURCE_COMPLETED);
+ * JSD_UNLOCK_SOURCE_TEXT(jsdc);
+ * return jsdsrc ? JS_TRUE : JS_FALSE;
+ */
+extern JSD_PUBLIC_API(JSBool)
+JSD_AddFullSourceText(JSDContext* jsdc,
+ const char* text, /* *not* zero terminated */
+ size_t length,
+ const char* url);
+
+/***************************************************************************/
+/* Execution/Interrupt Hook functions */
+
+/* possible 'type' params for JSD_ExecutionHookProc */
+#define JSD_HOOK_INTERRUPTED 0
+#define JSD_HOOK_BREAKPOINT 1
+#define JSD_HOOK_DEBUG_REQUESTED 2
+#define JSD_HOOK_DEBUGGER_KEYWORD 3
+#define JSD_HOOK_THROW 4
+
+/* legal return values for JSD_ExecutionHookProc */
+#define JSD_HOOK_RETURN_HOOK_ERROR 0
+#define JSD_HOOK_RETURN_CONTINUE 1
+#define JSD_HOOK_RETURN_ABORT 2
+#define JSD_HOOK_RETURN_RET_WITH_VAL 3
+#define JSD_HOOK_RETURN_THROW_WITH_VAL 4
+#define JSD_HOOK_RETURN_CONTINUE_THROW 5
+
+/*
+* Implement a callback of this form in order to hook execution.
+*/
+typedef unsigned
+(* JSD_ExecutionHookProc)(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ unsigned type,
+ void* callerdata,
+ jsval* rval);
+
+/* possible 'type' params for JSD_CallHookProc */
+#define JSD_HOOK_TOPLEVEL_START 0 /* about to evaluate top level script */
+#define JSD_HOOK_TOPLEVEL_END 1 /* done evaluting top level script */
+#define JSD_HOOK_FUNCTION_CALL 2 /* about to call a function */
+#define JSD_HOOK_FUNCTION_RETURN 3 /* done calling function */
+
+/*
+* Implement a callback of this form in order to hook function call/returns.
+* Return JS_TRUE from a TOPLEVEL_START or FUNCTION_CALL type call hook if you
+* want to hear about the TOPLEVEL_END or FUNCTION_RETURN too. Return value is
+* ignored to TOPLEVEL_END and FUNCTION_RETURN type hooks.
+*/
+typedef JSBool
+(* JSD_CallHookProc)(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ unsigned type,
+ void* callerdata);
+
+/*
+* Set Hook to be called whenever the given pc is about to be executed --
+* i.e. for 'trap' or 'breakpoint'
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+/*
+* Clear the hook for this pc
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearExecutionHook(JSDContext* jsdc,
+ JSDScript* jsdscript,
+ uintptr_t pc);
+
+/*
+* Clear all the pc specific hooks for this script
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript);
+
+/*
+* Clear all the pc specific hooks for the entire JSRuntime associated with
+* this JSDContext
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearAllExecutionHooks(JSDContext* jsdc);
+
+/*
+* Set a hook to be called before the next instruction is executed. Depending
+* on the threading situation and whether or not an JS code is currently
+* executing the hook might be called before this call returns, or at some
+* future time. The hook will continue to be called as each instruction
+* executes until cleared.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetInterruptHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+/*
+* Call the interrupt hook at least once per source line
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript *jsdscript, JSBool enable);
+
+/*
+* Clear the current interrupt hook.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearInterruptHook(JSDContext* jsdc);
+
+/*
+* Set the hook that should be called whenever a JSD_ErrorReporter hook
+* returns JSD_ERROR_REPORTER_DEBUG.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetDebugBreakHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+/*
+* Clear the debug break hook
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearDebugBreakHook(JSDContext* jsdc);
+
+/*
+* Set the hook that should be called when the 'debugger' keyword is
+* encountered by the JavaScript interpreter during execution.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetDebuggerHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+
+/*
+* Clear the 'debugger' keyword hook
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearDebuggerHook(JSDContext* jsdc);
+
+/*
+* Set the hook that should be called when a JS exception is thrown.
+* NOTE: the 'do default' return value is: JSD_HOOK_RETURN_CONTINUE_THROW
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetThrowHook(JSDContext* jsdc,
+ JSD_ExecutionHookProc hook,
+ void* callerdata);
+/*
+* Clear the throw hook
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearThrowHook(JSDContext* jsdc);
+
+/*
+* Set the hook that should be called when a toplevel script begins or completes.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetTopLevelHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata);
+/*
+* Clear the toplevel call hook
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearTopLevelHook(JSDContext* jsdc);
+
+/*
+* Set the hook that should be called when a function call or return happens.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetFunctionHook(JSDContext* jsdc,
+ JSD_CallHookProc hook,
+ void* callerdata);
+/*
+* Clear the function call hook
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_ClearFunctionHook(JSDContext* jsdc);
+
+/***************************************************************************/
+/* Stack Frame functions */
+
+/*
+* Get the count of call stack frames for the given JSDThreadState
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+/*
+* Get the 'current' call stack frame for the given JSDThreadState
+*/
+extern JSD_PUBLIC_API(JSDStackFrameInfo*)
+JSD_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+/*
+* Get the JSContext for the given JSDThreadState
+*/
+extern JSD_PUBLIC_API(JSContext*)
+JSD_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+/*
+* Get the calling call stack frame for the given frame
+*/
+extern JSD_PUBLIC_API(JSDStackFrameInfo*)
+JSD_GetCallingStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Get the script for the given call stack frame
+*/
+extern JSD_PUBLIC_API(JSDScript*)
+JSD_GetScriptForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Get the 'Program Counter' for the given call stack frame
+*/
+extern JSD_PUBLIC_API(uintptr_t)
+JSD_GetPCForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Get the JavaScript Call Object for the given call stack frame.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetCallObjectForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Get the head of the scope chain for the given call stack frame.
+* the chain can be traversed using JSD_GetValueParent.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetScopeChainForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Get the 'this' Object for the given call stack frame.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetThisForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Get the name of the function executing in this stack frame. Especially useful
+* for native frames (without script objects.)
+* *** new for gecko 2.0 ****
+*/
+extern JSD_PUBLIC_API(JSString *)
+JSD_GetIdForStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* True if stack frame represents a frame created as a result of a debugger
+* evaluation.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsStackFrameDebugger(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* True if stack frame is constructing a new object.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsStackFrameConstructing(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe);
+
+/*
+* Evaluate the given unicode source code in the context of the given stack frame.
+* returns JS_TRUE and puts result in rval on success, JS_FALSE on failure.
+* NOTE: The ErrorReporter hook might be called if this fails.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const jschar *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JS::MutableHandleValue rval);
+
+/*
+* Same as above, but does not eat exceptions.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_AttemptUCScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const jschar *bytes, unsigned length,
+ const char *filename, unsigned lineno,
+ JS::MutableHandleValue rval);
+
+/* single byte character version of JSD_EvaluateUCScriptInStackFrame */
+extern JSD_PUBLIC_API(JSBool)
+JSD_EvaluateScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const char *bytes, unsigned length,
+ const char *filename, unsigned lineno, JS::MutableHandleValue rval);
+
+/*
+* Same as above, but does not eat exceptions.
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_AttemptScriptInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ const char *bytes, unsigned length,
+ const char *filename, unsigned lineno, JS::MutableHandleValue rval);
+
+/*
+* Convert the given jsval to a string
+* NOTE: The ErrorReporter hook might be called if this fails.
+*/
+extern JSD_PUBLIC_API(JSString*)
+JSD_ValToStringInStackFrame(JSDContext* jsdc,
+ JSDThreadState* jsdthreadstate,
+ JSDStackFrameInfo* jsdframe,
+ jsval val);
+
+/*
+* Get the JSDValue currently being thrown as an exception (may be NULL).
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate);
+
+/*
+* Set the JSDValue currently being thrown as an exception.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
+ JSDValue* jsdval);
+
+/***************************************************************************/
+/* Error Reporter functions */
+
+/*
+* XXX The ErrorReporter Hook scheme is going to change soon to more
+* Fully support exceptions.
+*/
+
+/* legal return values for JSD_ErrorReporter */
+#define JSD_ERROR_REPORTER_PASS_ALONG 0 /* pass along to regular reporter */
+#define JSD_ERROR_REPORTER_RETURN 1 /* don't pass to error reporter */
+#define JSD_ERROR_REPORTER_DEBUG 2 /* force call to DebugBreakHook */
+#define JSD_ERROR_REPORTER_CLEAR_RETURN 3 /* clear exception and don't pass */
+
+/*
+* Implement a callback of this form in order to hook the ErrorReporter
+*/
+typedef unsigned
+(* JSD_ErrorReporter)(JSDContext* jsdc,
+ JSContext* cx,
+ const char* message,
+ JSErrorReport* report,
+ void* callerdata);
+
+/* Set ErrorReporter hook */
+extern JSD_PUBLIC_API(JSBool)
+JSD_SetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter reporter,
+ void* callerdata);
+
+/* Get Current ErrorReporter hook */
+extern JSD_PUBLIC_API(JSBool)
+JSD_GetErrorReporter(JSDContext* jsdc,
+ JSD_ErrorReporter* reporter,
+ void** callerdata);
+
+/***************************************************************************/
+/* Generic locks that callers can use for their own purposes */
+
+struct JSDStaticLock;
+
+/*
+* Is Locking and GetThread supported in this build?
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsLockingAndThreadIdSupported();
+
+/*
+* Create a reentrant/nestable lock
+*/
+extern JSD_PUBLIC_API(JSDStaticLock*)
+JSD_CreateLock();
+
+/*
+* Aquire lock for this thread (or block until available). Increments a
+* counter if this thread already owns the lock.
+*/
+extern JSD_PUBLIC_API(void)
+JSD_Lock(JSDStaticLock* lock);
+
+/*
+* Release lock for this thread (or decrement the counter if JSD_Lock
+* was previous called more than once).
+*/
+extern JSD_PUBLIC_API(void)
+JSD_Unlock(JSDStaticLock* lock);
+
+/*
+* For debugging only if not (JS_THREADSAFE AND DEBUG) then returns JS_TRUE
+* So JSD_IsLocked(lock) may not equal !JSD_IsUnlocked(lock)
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsLocked(JSDStaticLock* lock);
+
+/*
+* See above...
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsUnlocked(JSDStaticLock* lock);
+
+/*
+* return an ID uniquely identifying this thread.
+*/
+extern JSD_PUBLIC_API(void*)
+JSD_CurrentThread();
+
+/***************************************************************************/
+/* Value and Property Functions --- All NEW for 1.1 --- */
+
+/*
+* NOTE: JSDValue and JSDProperty objects are reference counted. This allows
+* for rooting these objects AND any underlying garbage collected jsvals.
+* ALL JSDValue and JSDProperty objects returned by the functions below
+* MUST eventually be released using the appropriate JSD_Dropxxx function.
+*/
+
+/*
+* Create a new JSDValue to wrap the given jsval
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_NewValue(JSDContext* jsdc, jsval val);
+
+/*
+* Release the JSDValue. After this call the object MUST not be referenced again!
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(void)
+JSD_DropValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Get the jsval wrapped by this JSDValue
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(jsval)
+JSD_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Clear all property and association information about the given JSDValue.
+* Such information will be lazily regenerated when later accessed. This
+* function must be called to make changes to the properties of an object
+* visible to the accessor functions below (if the properties et.al. have
+* changed since a previous call to those accessors).
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(void)
+JSD_RefreshValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+/*
+* Does the JSDValue wrap a JSObject?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueObject(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a number (int or double)?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap an int?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueInt(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a double?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a JSString?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueString(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a JSBool?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a JSVAL_NULL?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueNull(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a JSVAL_VOID?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a primative (not a JSObject)?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a function?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Does the JSDValue wrap a native function?
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_IsValueNative(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+/*
+* Return JSBool value (does NOT do conversion).
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSBool)
+JSD_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Return int32_t value (does NOT do conversion).
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(int32_t)
+JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Return double value (does NOT do conversion).
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(double)
+JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Return JSString value (DOES do conversion if necessary).
+* NOTE that the JSString returned is not protected from garbage
+* collection. It should be immediately read or wrapped using
+* JSD_NewValue(jsdc,STRING_TO_JSVAL(str)) if necessary.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSString*)
+JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Return name of function IFF JSDValue represents a function.
+* *** new for gecko 2.0 ****
+*/
+extern JSD_PUBLIC_API(JSString *)
+JSD_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Return function object IFF JSDValue represents a function or an object
+* wrapping a function.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSFunction*)
+JSD_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+/*
+* Return the number of properties for the JSDValue.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Iterate through the properties of the JSDValue.
+* Use form similar to that shown for JSD_IterateScripts (no locking required).
+* NOTE: each JSDProperty returned must eventually be released by calling
+* JSD_DropProperty.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDProperty*)
+JSD_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp);
+
+/*
+* Get the JSDProperty for the property of this JSDVal with this name.
+* NOTE: must eventually release by calling JSD_DropProperty (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDProperty*)
+JSD_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name);
+
+/*
+* Get the prototype object for this JSDValue.
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Get the parent object for this JSDValue.
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetValueParent(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Get the ctor object for this JSDValue (or likely its prototype's ctor).
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Get the name of the class for this object.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(const char*)
+JSD_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Get the script for the given value if the given value represents a
+* scripted function. Otherwise, return null.
+*/
+extern JSD_PUBLIC_API(JSDScript*)
+JSD_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/**************************************************/
+
+/* possible or'd together bitflags returned by JSD_GetPropertyFlags
+ *
+ * XXX these must stay the same as the JSPD_ flags in jsdbgapi.h
+ */
+#define JSDPD_ENUMERATE JSPD_ENUMERATE /* visible to for/in loop */
+#define JSDPD_READONLY JSPD_READONLY /* assignment is error */
+#define JSDPD_PERMANENT JSPD_PERMANENT /* property cannot be deleted */
+#define JSDPD_ALIAS JSPD_ALIAS /* property has an alias id */
+#define JSDPD_EXCEPTION JSPD_EXCEPTION /* exception occurred looking up */
+ /* proprety, value is exception */
+#define JSDPD_ERROR JSPD_ERROR /* native getter returned JS_FALSE */
+ /* without throwing an exception */
+/* this is not one of the JSPD_ flags in jsdbgapi.h - careful not to overlap*/
+#define JSDPD_HINTED 0x800 /* found via explicit lookup */
+
+/*
+* Release this JSDProperty
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(void)
+JSD_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop);
+
+/*
+* Get the JSDValue represeting the name of this property (int or string)
+* NOTE: must eventually release by calling JSD_DropValue
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop);
+
+/*
+* Get the JSDValue represeting the current value of this property
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop);
+
+/*
+* Get the JSDValue represeting the alias of this property (if JSDPD_ALIAS set)
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop);
+
+/*
+* Get the flags for this property
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop);
+
+/***************************************************************************/
+/* Object Functions --- All NEW for 1.1 --- */
+
+/*
+* JSDObjects exist to allow a means of iterating through all JSObjects in the
+* engine. They are created and destroyed as the wrapped JSObjects are created
+* and destroyed in the engine. JSDObjects additionally track the location in
+* the JavaScript source where their wrapped JSObjects were created and the name
+* and location of the (non-native) constructor used.
+*
+* NOTE: JSDObjects are NOT reference counted. The have only weak links to
+* jsObjects - thus they do not inhibit garbage collection of JSObjects. If
+* you need a JSDObject to safely persist then wrap it in a JSDValue (using
+* jsd_GetValueForObject).
+*/
+
+/*
+* Lock the entire Object subsystem -- see JSD_UnlockObjectSubsystem
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(void)
+JSD_LockObjectSubsystem(JSDContext* jsdc);
+
+/*
+* Unlock the entire Object subsystem -- see JSD_LockObjectSubsystem
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(void)
+JSD_UnlockObjectSubsystem(JSDContext* jsdc);
+
+/*
+* Iterate through the known objects
+* Use form similar to that shown for JSD_IterateScripts.
+* NOTE: the ObjectSubsystem must be locked before and unlocked after iterating.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDObject*)
+JSD_IterateObjects(JSDContext* jsdc, JSDObject** iterp);
+
+/*
+* Get the JSObject represented by this JSDObject
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSObject*)
+JSD_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj);
+
+/*
+* Get the URL of the line of source that caused this object to be created.
+* May be NULL.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(const char*)
+JSD_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj);
+
+/*
+* Get the line number of the line of source that caused this object to be
+* created. May be 0 indicating that the line number is unknown.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj);
+
+/*
+* Get the URL of the line of source of the constructor for this object.
+* May be NULL.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(const char*)
+JSD_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj);
+
+/*
+* Get the line number of the line of source of the constructor for this object.
+* created. May be 0 indicating that the line number is unknown.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(unsigned)
+JSD_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj);
+
+/*
+* Get the name of the constructor for this object.
+* May be NULL.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(const char*)
+JSD_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj);
+
+/*
+* Get JSDObject representing this JSObject.
+* May return NULL.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDObject*)
+JSD_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj);
+
+/*
+* Get JSDObject representing this JSDValue.
+* May return NULL.
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDObject*)
+JSD_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval);
+
+/*
+* Create a JSDValue to wrap (and root) this JSDObject.
+* NOTE: must eventually release by calling JSD_DropValue (if not NULL)
+* *** new for version 1.1 ****
+*/
+extern JSD_PUBLIC_API(JSDValue*)
+JSD_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj);
+
+/***************************************************************************/
+/* Livewire specific API */
+#ifdef LIVEWIRE
+
+extern JSD_PUBLIC_API(LWDBGScript*)
+JSDLW_GetLWScript(JSDContext* jsdc, JSDScript* jsdscript);
+
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSDLW_PreLoadSource(JSDContext* jsdc, LWDBGApp* app,
+ const char* filename, JSBool clear);
+
+extern JSD_PUBLIC_API(JSDSourceText*)
+JSDLW_ForceLoadSource(JSDContext* jsdc, JSDSourceText* jsdsrc);
+
+extern JSD_PUBLIC_API(JSBool)
+JSDLW_RawToProcessedLineNumber(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned lineIn, unsigned* lineOut);
+
+extern JSD_PUBLIC_API(JSBool)
+JSDLW_ProcessedToRawLineNumber(JSDContext* jsdc, JSDScript* jsdscript,
+ unsigned lineIn, unsigned* lineOut);
+
+#endif
+/***************************************************************************/
+
+JS_END_EXTERN_C
+
+#endif /* jsdebug_h___ */
diff --git a/js/jsd/jsdstubs.cpp b/js/jsd/jsdstubs.cpp
new file mode 100644
index 0000000..2242041
--- /dev/null
+++ b/js/jsd/jsdstubs.cpp
@@ -0,0 +1,18 @@
+/* -*- 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/. */
+
+/* this is all going away... replaced by code in js/jsd/java */
+
+#if 0
+
+#include "_stubs/netscape_jsdebug_Script.c"
+#include "_stubs/netscape_jsdebug_DebugController.c"
+#include "_stubs/netscape_jsdebug_JSThreadState.c"
+#include "_stubs/netscape_jsdebug_JSStackFrameInfo.c"
+#include "_stubs/netscape_jsdebug_JSPC.c"
+#include "_stubs/netscape_jsdebug_JSSourceTextProvider.c"
+
+#endif
diff --git a/js/jsd/jshash.cpp b/js/jsd/jshash.cpp
new file mode 100644
index 0000000..d4caf2c
--- /dev/null
+++ b/js/jsd/jshash.cpp
@@ -0,0 +1,444 @@
+/* -*- 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/. */
+
+/*
+ * PR hash table package.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h"
+#include "jshash.h"
+
+using namespace js;
+
+/* Compute the number of buckets in ht */
+#define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift)
+
+/* The smallest table has 16 buckets */
+#define MINBUCKETSLOG2 4
+#define MINBUCKETS JS_BIT(MINBUCKETSLOG2)
+
+/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
+#define OVERLOADED(n) ((n) - ((n) >> 3))
+
+/* Compute the number of entries below which we shrink the table by half */
+#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
+
+/*
+** Stubs for default hash allocator ops.
+*/
+static void *
+DefaultAllocTable(void *pool, size_t size)
+{
+ return js_malloc(size);
+}
+
+static void
+DefaultFreeTable(void *pool, void *item, size_t size)
+{
+ js_free(item);
+}
+
+static JSHashEntry *
+DefaultAllocEntry(void *pool, const void *key)
+{
+ return (JSHashEntry*) js_malloc(sizeof(JSHashEntry));
+}
+
+static void
+DefaultFreeEntry(void *pool, JSHashEntry *he, unsigned flag)
+{
+ if (flag == HT_FREE_ENTRY)
+ js_free(he);
+}
+
+static JSHashAllocOps defaultHashAllocOps = {
+ DefaultAllocTable, DefaultFreeTable,
+ DefaultAllocEntry, DefaultFreeEntry
+};
+
+JSHashTable *
+JS_NewHashTable(uint32_t n, JSHashFunction keyHash,
+ JSHashComparator keyCompare, JSHashComparator valueCompare,
+ JSHashAllocOps *allocOps, void *allocPriv)
+{
+ JSHashTable *ht;
+ size_t nb;
+
+ if (n <= MINBUCKETS) {
+ n = MINBUCKETSLOG2;
+ } else {
+ n = JS_CEILING_LOG2W(n);
+ if (int32_t(n) < 0)
+ return NULL;
+ }
+
+ if (!allocOps) allocOps = &defaultHashAllocOps;
+
+ ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht);
+ if (!ht)
+ return NULL;
+ memset(ht, 0, sizeof *ht);
+ ht->shift = JS_HASH_BITS - n;
+ n = JS_BIT(n);
+ nb = n * sizeof(JSHashEntry *);
+ ht->buckets = (JSHashEntry**) allocOps->allocTable(allocPriv, nb);
+ if (!ht->buckets) {
+ allocOps->freeTable(allocPriv, ht, nb);
+ return NULL;
+ }
+ memset(ht->buckets, 0, nb);
+
+ ht->keyHash = keyHash;
+ ht->keyCompare = keyCompare;
+ ht->valueCompare = valueCompare;
+ ht->allocOps = allocOps;
+ ht->allocPriv = allocPriv;
+ return ht;
+}
+
+void
+JS_HashTableDestroy(JSHashTable *ht)
+{
+ uint32_t i, n;
+ JSHashEntry *he, **hep;
+ JSHashAllocOps *allocOps = ht->allocOps;
+ void *allocPriv = ht->allocPriv;
+
+ n = NBUCKETS(ht);
+ for (i = 0; i < n; i++) {
+ hep = &ht->buckets[i];
+ while ((he = *hep) != NULL) {
+ *hep = he->next;
+ allocOps->freeEntry(allocPriv, he, HT_FREE_ENTRY);
+ }
+ }
+#ifdef DEBUG
+ memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
+#endif
+ allocOps->freeTable(allocPriv, ht->buckets, n * sizeof ht->buckets[0]);
+#ifdef DEBUG
+ memset(ht, 0xDB, sizeof *ht);
+#endif
+ allocOps->freeTable(allocPriv, ht, sizeof *ht);
+}
+
+/*
+ * Multiplicative hash, from Knuth 6.4.
+ */
+#define BUCKET_HEAD(ht, keyHash) \
+ (&(ht)->buckets[((keyHash) * JS_GOLDEN_RATIO) >> (ht)->shift])
+
+JSHashEntry **
+JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key)
+{
+ JSHashEntry *he, **hep, **hep0;
+
+#ifdef JS_HASHMETER
+ ht->nlookups++;
+#endif
+ hep = hep0 = BUCKET_HEAD(ht, keyHash);
+ while ((he = *hep) != NULL) {
+ if (he->keyHash == keyHash && ht->keyCompare(key, he->key)) {
+ /* Move to front of chain if not already there */
+ if (hep != hep0) {
+ *hep = he->next;
+ he->next = *hep0;
+ *hep0 = he;
+ }
+ return hep0;
+ }
+ hep = &he->next;
+#ifdef JS_HASHMETER
+ ht->nsteps++;
+#endif
+ }
+ return hep;
+}
+
+static JSBool
+Resize(JSHashTable *ht, uint32_t newshift)
+{
+ size_t nb, nentries, i;
+ JSHashEntry **oldbuckets, *he, *next, **hep;
+ size_t nold = NBUCKETS(ht);
+
+ JS_ASSERT(newshift < JS_HASH_BITS);
+
+ nb = (size_t)1 << (JS_HASH_BITS - newshift);
+
+ /* Integer overflow protection. */
+ if (nb > (size_t)-1 / sizeof(JSHashEntry*))
+ return JS_FALSE;
+ nb *= sizeof(JSHashEntry*);
+
+ oldbuckets = ht->buckets;
+ ht->buckets = (JSHashEntry**)ht->allocOps->allocTable(ht->allocPriv, nb);
+ if (!ht->buckets) {
+ ht->buckets = oldbuckets;
+ return JS_FALSE;
+ }
+ memset(ht->buckets, 0, nb);
+
+ ht->shift = newshift;
+ nentries = ht->nentries;
+
+ for (i = 0; nentries != 0; i++) {
+ for (he = oldbuckets[i]; he; he = next) {
+ JS_ASSERT(nentries != 0);
+ --nentries;
+ next = he->next;
+ hep = BUCKET_HEAD(ht, he->keyHash);
+
+ /*
+ * We do not require unique entries, instead appending he to the
+ * chain starting at hep.
+ */
+ while (*hep)
+ hep = &(*hep)->next;
+ he->next = NULL;
+ *hep = he;
+ }
+ }
+#ifdef DEBUG
+ memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]);
+#endif
+ ht->allocOps->freeTable(ht->allocPriv, oldbuckets,
+ nold * sizeof oldbuckets[0]);
+ return JS_TRUE;
+}
+
+JSHashEntry *
+JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep,
+ JSHashNumber keyHash, const void *key, void *value)
+{
+ uint32_t n;
+ JSHashEntry *he;
+
+ /* Grow the table if it is overloaded */
+ n = NBUCKETS(ht);
+ if (ht->nentries >= OVERLOADED(n)) {
+ if (!Resize(ht, ht->shift - 1))
+ return NULL;
+#ifdef JS_HASHMETER
+ ht->ngrows++;
+#endif
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ }
+
+ /* Make a new key value entry */
+ he = ht->allocOps->allocEntry(ht->allocPriv, key);
+ if (!he)
+ return NULL;
+ he->keyHash = keyHash;
+ he->key = key;
+ he->value = value;
+ he->next = *hep;
+ *hep = he;
+ ht->nentries++;
+ return he;
+}
+
+JSHashEntry *
+JS_HashTableAdd(JSHashTable *ht, const void *key, void *value)
+{
+ JSHashNumber keyHash;
+ JSHashEntry *he, **hep;
+
+ keyHash = ht->keyHash(key);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ if ((he = *hep) != NULL) {
+ /* Hit; see if values match */
+ if (ht->valueCompare(he->value, value)) {
+ /* key,value pair is already present in table */
+ return he;
+ }
+ if (he->value)
+ ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_VALUE);
+ he->value = value;
+ return he;
+ }
+ return JS_HashTableRawAdd(ht, hep, keyHash, key, value);
+}
+
+void
+JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he)
+{
+ uint32_t n;
+
+ *hep = he->next;
+ ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY);
+
+ /* Shrink table if it's underloaded */
+ n = NBUCKETS(ht);
+ if (--ht->nentries < UNDERLOADED(n)) {
+ Resize(ht, ht->shift + 1);
+#ifdef JS_HASHMETER
+ ht->nshrinks++;
+#endif
+ }
+}
+
+JSBool
+JS_HashTableRemove(JSHashTable *ht, const void *key)
+{
+ JSHashNumber keyHash;
+ JSHashEntry *he, **hep;
+
+ keyHash = ht->keyHash(key);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ if ((he = *hep) == NULL)
+ return JS_FALSE;
+
+ /* Hit; remove element */
+ JS_HashTableRawRemove(ht, hep, he);
+ return JS_TRUE;
+}
+
+void *
+JS_HashTableLookup(JSHashTable *ht, const void *key)
+{
+ JSHashNumber keyHash;
+ JSHashEntry *he, **hep;
+
+ keyHash = ht->keyHash(key);
+ hep = JS_HashTableRawLookup(ht, keyHash, key);
+ if ((he = *hep) != NULL) {
+ return he->value;
+ }
+ return NULL;
+}
+
+/*
+** Iterate over the entries in the hash table calling func for each
+** entry found. Stop if "f" says to (return value & JS_ENUMERATE_STOP).
+** Return a count of the number of elements scanned.
+*/
+int
+JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg)
+{
+ JSHashEntry *he, **hep, **bucket;
+ uint32_t nlimit, n, nbuckets, newlog2;
+ int rv;
+
+ nlimit = ht->nentries;
+ n = 0;
+ for (bucket = ht->buckets; n != nlimit; ++bucket) {
+ hep = bucket;
+ while ((he = *hep) != NULL) {
+ JS_ASSERT(n < nlimit);
+ rv = f(he, n, arg);
+ n++;
+ if (rv & HT_ENUMERATE_REMOVE) {
+ *hep = he->next;
+ ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY);
+ --ht->nentries;
+ } else {
+ hep = &he->next;
+ }
+ if (rv & HT_ENUMERATE_STOP) {
+ goto out;
+ }
+ }
+ }
+
+out:
+ /* Shrink table if removal of entries made it underloaded */
+ if (ht->nentries != nlimit) {
+ JS_ASSERT(ht->nentries < nlimit);
+ nbuckets = NBUCKETS(ht);
+ if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) {
+ newlog2 = JS_CEILING_LOG2W(ht->nentries);
+ if (newlog2 < MINBUCKETSLOG2)
+ newlog2 = MINBUCKETSLOG2;
+
+ /* Check that we really shrink the table. */
+ JS_ASSERT(JS_HASH_BITS - ht->shift > newlog2);
+ Resize(ht, JS_HASH_BITS - newlog2);
+ }
+ }
+ return (int)n;
+}
+
+#ifdef JS_HASHMETER
+#include <stdio.h>
+
+void
+JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
+{
+ double sqsum, mean, sigma;
+ uint32_t nchains, nbuckets;
+ uint32_t i, n, maxChain, maxChainLen;
+ JSHashEntry *he;
+
+ sqsum = 0;
+ nchains = 0;
+ maxChain = maxChainLen = 0;
+ nbuckets = NBUCKETS(ht);
+ for (i = 0; i < nbuckets; i++) {
+ he = ht->buckets[i];
+ if (!he)
+ continue;
+ nchains++;
+ for (n = 0; he; he = he->next)
+ n++;
+ sqsum += n * n;
+ if (n > maxChainLen) {
+ maxChainLen = n;
+ maxChain = i;
+ }
+ }
+
+ mean = JS_MeanAndStdDev(nchains, ht->nentries, sqsum, &sigma);
+
+ fprintf(fp, "\nHash table statistics:\n");
+ fprintf(fp, " number of lookups: %u\n", ht->nlookups);
+ fprintf(fp, " number of entries: %u\n", ht->nentries);
+ fprintf(fp, " number of grows: %u\n", ht->ngrows);
+ fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
+ fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
+ / ht->nlookups);
+ fprintf(fp, "mean hash chain length: %g\n", mean);
+ fprintf(fp, " standard deviation: %g\n", sigma);
+ fprintf(fp, " max hash chain length: %u\n", maxChainLen);
+ fprintf(fp, " max hash chain: [%u]\n", maxChain);
+
+ for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
+ if (dump(he, i, fp) != HT_ENUMERATE_NEXT)
+ break;
+}
+#endif /* JS_HASHMETER */
+
+int
+JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
+{
+ int count;
+
+ count = JS_HashTableEnumerateEntries(ht, dump, fp);
+#ifdef JS_HASHMETER
+ JS_HashTableDumpMeter(ht, dump, fp);
+#endif
+ return count;
+}
+
+JSHashNumber
+JS_HashString(const void *key)
+{
+ JSHashNumber h;
+ const unsigned char *s;
+
+ h = 0;
+ for (s = (const unsigned char *)key; *s; s++)
+ h = JS_ROTATE_LEFT32(h, 4) ^ *s;
+ return h;
+}
+
+int
+JS_CompareValues(const void *v1, const void *v2)
+{
+ return v1 == v2;
+}
diff --git a/js/jsd/jshash.h b/js/jsd/jshash.h
new file mode 100644
index 0000000..e21c7b7
--- /dev/null
+++ b/js/jsd/jshash.h
@@ -0,0 +1,120 @@
+/* -*- 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 jshash_h___
+#define jshash_h___
+
+/*
+ * API to portable hash table code.
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include "jstypes.h"
+
+JS_BEGIN_EXTERN_C
+
+typedef uint32_t JSHashNumber;
+typedef struct JSHashEntry JSHashEntry;
+typedef struct JSHashTable JSHashTable;
+
+#define JS_HASH_BITS 32
+#define JS_GOLDEN_RATIO 0x9E3779B9U
+
+typedef JSHashNumber (* JSHashFunction)(const void *key);
+typedef int (* JSHashComparator)(const void *v1, const void *v2);
+typedef int (* JSHashEnumerator)(JSHashEntry *he, int i, void *arg);
+
+/* Flag bits in JSHashEnumerator's return value */
+#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */
+#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */
+#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */
+
+typedef struct JSHashAllocOps {
+ void * (*allocTable)(void *pool, size_t size);
+ void (*freeTable)(void *pool, void *item, size_t size);
+ JSHashEntry * (*allocEntry)(void *pool, const void *key);
+ void (*freeEntry)(void *pool, JSHashEntry *he, unsigned flag);
+} JSHashAllocOps;
+
+#define HT_FREE_VALUE 0 /* just free the entry's value */
+#define HT_FREE_ENTRY 1 /* free value and entire entry */
+
+struct JSHashEntry {
+ JSHashEntry *next; /* hash chain linkage */
+ JSHashNumber keyHash; /* key hash function result */
+ const void *key; /* ptr to opaque key */
+ void *value; /* ptr to opaque value */
+};
+
+struct JSHashTable {
+ JSHashEntry **buckets; /* vector of hash buckets */
+ uint32_t nentries; /* number of entries in table */
+ uint32_t shift; /* multiplicative hash shift */
+ JSHashFunction keyHash; /* key hash function */
+ JSHashComparator keyCompare; /* key comparison function */
+ JSHashComparator valueCompare; /* value comparison function */
+ JSHashAllocOps *allocOps; /* allocation operations */
+ void *allocPriv; /* allocation private data */
+#ifdef JS_HASHMETER
+ uint32_t nlookups; /* total number of lookups */
+ uint32_t nsteps; /* number of hash chains traversed */
+ uint32_t ngrows; /* number of table expansions */
+ uint32_t nshrinks; /* number of table contractions */
+#endif
+};
+
+/*
+ * Create a new hash table.
+ * If allocOps is null, use default allocator ops built on top of malloc().
+ */
+extern JSHashTable *
+JS_NewHashTable(uint32_t n, JSHashFunction keyHash,
+ JSHashComparator keyCompare, JSHashComparator valueCompare,
+ JSHashAllocOps *allocOps, void *allocPriv);
+
+extern void
+JS_HashTableDestroy(JSHashTable *ht);
+
+/* Low level access methods */
+extern JSHashEntry **
+JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key);
+
+#ifdef __cplusplus
+extern JSHashEntry *
+JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, JSHashNumber keyHash,
+ const void *key, void *value);
+#endif
+
+extern void
+JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he);
+
+/* Higher level access methods */
+extern JSHashEntry *
+JS_HashTableAdd(JSHashTable *ht, const void *key, void *value);
+
+extern JSBool
+JS_HashTableRemove(JSHashTable *ht, const void *key);
+
+extern int
+JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg);
+
+extern void *
+JS_HashTableLookup(JSHashTable *ht, const void *key);
+
+extern int
+JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp);
+
+/* General-purpose C string hash function. */
+extern JSHashNumber
+JS_HashString(const void *key);
+
+/* Stub function just returns v1 == v2 */
+extern int
+JS_CompareValues(const void *v1, const void *v2);
+
+JS_END_EXTERN_C
+
+#endif /* jshash_h___ */
diff --git a/js/jsd/mkshell.bat b/js/jsd/mkshell.bat
new file mode 100755
index 0000000..a00f468
--- /dev/null
+++ b/js/jsd/mkshell.bat
@@ -0,0 +1,8 @@
+@echo off
+REM This Source Code Form is subject to the terms of the Mozilla Public
+REM License, v. 2.0. If a copy of the MPL was not distributed with this
+REM file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+REM nmake -f jsdshell.mak JSDEBUGGER_JAVA_UI=1 %1 %2 %3 %4 %5
+@echo on
+nmake -f jsdshell.mak JSDEBUGGER_JAVA_UI=1 %1 %2 %3 %4 %5
diff --git a/js/jsd/moz.build b/js/jsd/moz.build
new file mode 100644
index 0000000..1cb5e02
--- /dev/null
+++ b/js/jsd/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += ['idl']
+TEST_TOOL_DIRS += ['test']
+
+MODULE = 'jsdebug'
+
+EXPORTS += [
+ 'jsdebug.h',
+]
+
+XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
+
+CPP_SOURCES += [
+ 'jsd_atom.cpp',
+ 'jsd_high.cpp',
+ 'jsd_hook.cpp',
+ 'jsd_lock.cpp',
+ 'jsd_obj.cpp',
+ 'jsd_scpt.cpp',
+ 'jsd_stak.cpp',
+ 'jsd_step.cpp',
+ 'jsd_text.cpp',
+ 'jsd_val.cpp',
+ 'jsd_xpc.cpp',
+ 'jsdebug.cpp',
+ 'jshash.cpp',
+]
+
+LIBRARY_NAME = 'jsd'
+
diff --git a/js/jsd/resource.h b/js/jsd/resource.h
new file mode 100644
index 0000000..69874fe
--- /dev/null
+++ b/js/jsd/resource.h
@@ -0,0 +1,21 @@
+/* -*- 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/. */
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by jsd3240.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/js/jsd/test/Makefile.in b/js/jsd/test/Makefile.in
new file mode 100644
index 0000000..bf3273d
--- /dev/null
+++ b/js/jsd/test/Makefile.in
@@ -0,0 +1,19 @@
+#
+# 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/.
+
+DEPTH = @DEPTH@
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MOCHITEST_FILES = test_bug507448.html bug507448.js \
+ test_bug617870-callhooks.html test-bug617870-callhooks.js jsd-test.js \
+ test_bug638178-execlines.html test-bug638178-execlines.js \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/js/jsd/test/bug507448.js b/js/jsd/test/bug507448.js
new file mode 100644
index 0000000..9ef2241
--- /dev/null
+++ b/js/jsd/test/bug507448.js
@@ -0,0 +1,25 @@
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+function f() {}
+function g(a,b) {}
+function h(me, too, here) { var x = 1; }
+function annoying(a, b, a, b, b, a) {}
+function manyLocals(a, b, c, d, e, f, g, h, i, j, k, l, m) {
+ var n, o, p, q, r, s, t, u, v, w, x, y, z;
+}
+
+assertArraysEqual(jsd.wrapValue(f).script.getParameterNames(), []);
+assertArraysEqual(jsd.wrapValue(g).script.getParameterNames(), ["a", "b"]);
+assertArraysEqual(jsd.wrapValue(h).script.getParameterNames(), ["me", "too", "here"]);
+assertArraysEqual(jsd.wrapValue(annoying).script.getParameterNames(),
+ ["a", "b", "a", "b", "b", "a"]);
+assertArraysEqual(jsd.wrapValue(manyLocals).script.getParameterNames(),
+ "abcdefghijklm".split(""));
+
+if (!jsdOnAtStart) {
+ // turn JSD off if it wasn't on when this test started
+ jsd.off();
+ ok(!jsd.isOn, "JSD shouldn't be running at the end of this test.");
+}
+
+SimpleTest.finish(); \ No newline at end of file
diff --git a/js/jsd/test/jsd-test.js b/js/jsd/test/jsd-test.js
new file mode 100644
index 0000000..cb6480c
--- /dev/null
+++ b/js/jsd/test/jsd-test.js
@@ -0,0 +1,119 @@
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const RETURN_CONTINUE = Ci.jsdIExecutionHook.RETURN_CONTINUE;
+const DebuggerService = Cc["@mozilla.org/js/jsd/debugger-service;1"];
+
+var jsd = Components.classes['@mozilla.org/js/jsd/debugger-service;1']
+ .getService(Ci.jsdIDebuggerService);
+var jsdOnAtStart = false;
+
+function setupJSD(test) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ jsdOnAtStart = jsd.isOn;
+ if (jsdOnAtStart) {
+ runTest();
+ } else {
+ jsd.asyncOn({ onDebuggerActivated: function() { runTest(); } });
+ }
+}
+
+// Ugly workaround: when you turn the debugger on, it will only see scripts
+// compiled after that point. And it may be turned on asynchronously. So
+// we put the debugged code into a separate script that gets loaded after
+// the debugger is on.
+function loadScript(url, element) {
+ var script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = url;
+ script.defer = false;
+ element.appendChild(script);
+}
+
+function findScriptByFunction(name) {
+ var script;
+ jsd.enumerateScripts({ enumerateScript:
+ function(script_) {
+ if (script_.functionName === name) {
+ script = script_;
+ }
+ }
+ });
+
+ if (typeof(script) === "undefined") {
+ throw("Cannot find function named '" + name + "'");
+ }
+
+ return script;
+}
+
+// Pass in a JSD script
+function breakOnAllLines(script) {
+ // Map each line to a PC, and collect that set of PCs (removing
+ // duplicates.)
+ var pcs = {};
+ for (i = 0; i < script.lineExtent; i++) {
+ var jsdLine = script.baseLineNumber + i;
+ var pc = script.lineToPc(jsdLine, Ci.jsdIScript.PCMAP_SOURCETEXT);
+ pcs[pc] = 1;
+ }
+
+ // Set a breakpoint on each of those PCs.
+ for (pc in pcs) {
+ try {
+ script.setBreakpoint(pc);
+ } catch(e) {
+ alert("Error setting breakpoint: " + e);
+ }
+ }
+}
+
+// Set a breakpoint on a script, where lineno is relative to the beginning
+// of the script (NOT the absolute line number within the file).
+function breakOnLine(script, lineno) {
+ breakOnAbsoluteLine(script, script.baseLineNumber + lineno);
+}
+
+function breakOnAbsoluteLine(script, lineno) {
+ var pc = script.lineToPc(lineno, Ci.jsdIScript.PCMAP_SOURCETEXT);
+ script.setBreakpoint(pc);
+}
+
+function loadPage(page) {
+ var url;
+ if (page.match(/^\w+:/)) {
+ // Full URI, so just use it
+ url = page;
+ } else {
+ // Treat as relative to previous page
+ url = document.location.href.replace(/\/[^\/]*$/, "/" + page);
+ }
+
+ dump("Switching to URL " + url + "\n");
+
+ gURLBar.value = url;
+ gURLBar.handleCommand();
+}
+
+function breakpointObserver(lines, interesting, callback) {
+ jsd.breakpointHook = { onExecute: function(frame, type, rv) {
+ breakpoints_hit.push(frame.line);
+ if (frame.line in interesting) {
+ return callback(frame, type, breakpoints_hit);
+ } else {
+ return RETURN_CONTINUE;
+ }
+ } };
+}
+
+function dumpStack(frame, msg) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ dump(msg + ":\n");
+ while(frame) {
+ var callee = frame.callee;
+ if (callee !== null)
+ callee = callee.jsClassName;
+ dump(" " + frame.script.fileName + ":" + frame.line + " func=" + frame.script.functionName + " ffunc=" + frame.functionName + " callee=" + callee + " pc=" + frame.pc + "\n");
+ frame = frame.callingFrame;
+ }
+}
diff --git a/js/jsd/test/moz.build b/js/jsd/test/moz.build
new file mode 100644
index 0000000..219f3f3
--- /dev/null
+++ b/js/jsd/test/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+MODULE = 'jsdebug'
+
diff --git a/js/jsd/test/test-bug617870-callhooks.js b/js/jsd/test/test-bug617870-callhooks.js
new file mode 100644
index 0000000..bfe97a3
--- /dev/null
+++ b/js/jsd/test/test-bug617870-callhooks.js
@@ -0,0 +1,52 @@
+g = { 'global noneval': 1 };
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+eval("g['global eval'] = 1");
+
+// Function to step through and set breakpoints on
+function f1() {
+ g['function noneval'] = 1;
+ eval("g['function eval'] = 1");
+
+ x = 1;
+ for (y = 0; y < 10; y++) {
+ x++;
+ }
+ for (y = 0; y < 3; y++) {
+ x++;
+ }
+ z = 3;
+}
+
+var f2 = new Function("g['function noneval'] = 2; eval(\"g['function eval'] = 2\")");
+
+function testJSD(jsd) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ ok(jsd.isOn, "JSD needs to be running for this test.");
+
+ var numBreakpoints = 0;
+
+ f1();
+ f2();
+ jsd.topLevelHook = null;
+ jsd.functionHook = null;
+ dump("numGlobalNonevals="+numGlobalNonevals+"\n");
+ dump("numFunctionNonevals="+numFunctionNonevals+"\n");
+ dump("numGlobalEvals="+numGlobalEvals+"\n");
+ dump("numFunctionEvals="+numFunctionEvals+"\n");
+
+ ok(numFunctionNonevals == 3, "(fn) Should have hit f1(), testJSD(), and f2(); hit " + hits.fn);
+ ok(numGlobalNonevals == 1, "(gn) Overall script, hit " + hits.gn);
+ ok(numGlobalEvals == 1, "(ge) Eval in global area, hit " + hits.ge);
+ ok(numFunctionEvals == 2, "(fe) Evals within f1() and f2(), hit " + hits.fe);
+
+ if (!jsdOnAtStart) {
+ // turn JSD off if it wasn't on when this test started
+ jsd.off();
+ ok(!jsd.isOn, "JSD shouldn't be running at the end of this test.");
+ }
+
+ SimpleTest.finish();
+}
+
+testJSD(jsd);
diff --git a/js/jsd/test/test-bug638178-execlines.js b/js/jsd/test/test-bug638178-execlines.js
new file mode 100644
index 0000000..a35811d
--- /dev/null
+++ b/js/jsd/test/test-bug638178-execlines.js
@@ -0,0 +1,95 @@
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+var jsdIScript = Components.interfaces.jsdIScript;
+
+function f1() {
+ var x;
+}
+
+function f2() {
+
+
+ var x; var y; x = 1;
+}
+
+function f3() {
+
+
+ var x;
+
+ var y; var y2; y = 1;
+ var z;
+
+}
+
+var jsdIFilter = Components.interfaces.jsdIFilter;
+
+function testJSD(jsd) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ ok(jsd.isOn, "JSD needs to be running for this test.");
+
+ jsd.functionHook = ({
+ onCall: function(frame, type) {
+ //console.log("Got " + type);
+ console.log("Got " + frame.script.fileName);
+ }
+ });
+
+ console.log("Triggering functions");
+ f1();
+ f2();
+ f3();
+ console.log("Done with functions");
+
+ var linemap = {};
+ var firsts = {};
+ var rests = {};
+ var startlines = {};
+ jsd.enumerateScripts({
+ enumerateScript: function(script) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ if (/execlines\.js$/.test(script.fileName)) {
+ console.log("script: " + script.fileName + " " + script.functionName);
+ var execLines = script.getExecutableLines(jsdIScript.PCMAP_SOURCETEXT, 0, 10000);
+ console.log(execLines.toSource());
+ linemap[script.functionName] = execLines;
+ startlines[script.functionName] = script.baseLineNumber;
+
+ execLines = script.getExecutableLines(jsdIScript.PCMAP_SOURCETEXT, 0, 1);
+ firsts[script.functionName] = execLines;
+ execLines = script.getExecutableLines(jsdIScript.PCMAP_SOURCETEXT, execLines[0]+1, 10000);
+ rests[script.functionName] = execLines;
+ }
+ }
+ });
+
+ var checklines = function (funcname, linemap, rellines) {
+ var base = startlines[funcname];
+ var b = [];
+ for (var i = 0; i < rellines.length; ++i) {
+ b[i] = rellines[i] + base;
+ }
+ is(linemap[funcname].toSource(), b.toSource(), funcname + " lines");
+ };
+
+ checklines('f1', linemap, [ 1 ]);
+ checklines('f2', linemap, [ 3 ]);
+ checklines('f3', linemap, [ 3, 5, 6 ]);
+
+ checklines('f1', firsts, [ 1 ]);
+ checklines('f1', rests, []);
+ checklines('f3', firsts, [ 3 ]);
+ checklines('f3', rests, [ 5, 6 ]);
+
+ jsd.functionHook = null;
+
+ if (!jsdOnAtStart) {
+ // turn JSD off if it wasn't on when this test started
+ jsd.off();
+ ok(!jsd.isOn, "JSD shouldn't be running at the end of this test.");
+ }
+
+ SimpleTest.finish();
+}
+
+testJSD(jsd);
diff --git a/js/jsd/test/test_bug507448.html b/js/jsd/test/test_bug507448.html
new file mode 100644
index 0000000..1df24fd
--- /dev/null
+++ b/js/jsd/test/test_bug507448.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=507448
+-->
+<head>
+ <title>Test for Bug 507448</title>
+ <script type="application/javascript" src="/MochiKit/Base.js"></script>
+ <script type="application/javascript" src="/MochiKit/Async.js"></script>
+ <script type="application/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=507448">Mozilla Bug 507448</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+function f() {}
+function g(a,b) {}
+function h(me, too, here) { var x = 1; }
+function annoying(a, b, a, b, b, a) {}
+function manyLocals(a, b, c, d, e, f, g, h, i, j, k, l, m) {
+ var n, o, p, q, r, s, t, u, v, w, x, y, z;
+}
+</script>
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function loadScript(url) {
+ var d = new MochiKit.Async.Deferred();
+ var head = document.getElementsByTagName("head")[0];
+ var script = MochiKit.DOM.createDOM("script", { type: "text/javascript", src: url });
+ script.onload = function() {
+ script.onload = null;
+ script.onerror = null;
+ script.onreadystatechange = null;
+ d.callback();
+ };
+ script.onerror = function(msg) {
+ script.onload = null;
+ script.onerror = null;
+ script.onreadystatechange = null;
+ msg = "Failed to load script at " + url + ": " + msg;
+ d.errback(new URIError(msg, url));
+ }
+ script.onreadystatechange = function() {
+ if (script.readyState == "loaded" || script.readyState == "complete") {
+ script.onload();
+ } else {
+ // IE doesn't bother to report errors...
+ MochiKit.Async.callLater(10, script.onerror, "Script loading timed out")
+ }
+ };
+ head.appendChild(script);
+ return d;
+}
+
+/** Test for Bug 507448 **/
+function assertArraysEqual(arr1, arr2) {
+ is(arr1.length, arr2.length, "Lengths not equal");
+ for (var i = 0 ; i < arr1.length; ++i) {
+ is(arr1[i], arr2[i], "Element " + i + " not equal");
+ }
+}
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
+var jsd = Components.classes['@mozilla.org/js/jsd/debugger-service;1']
+ .getService(jsdIDebuggerService);
+var jsdOnAtStart = false;
+
+function setupJSD() {
+ // This is somewhat unfortunate: jsd only deals with scripts that have a
+ // nonzero line number, so we can't just createElement a script here.
+ // So break the test up into three <script>s, of which the middle one has our test functions.
+
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+ jsdOnAtStart = jsd.isOn;
+ if (jsdOnAtStart) {
+ testJSD();
+ } else {
+ jsd.asyncOn(
+ {
+ onDebuggerActivated: function() {
+ testJSD();
+ }
+ }
+ );
+ }
+}
+
+addLoadEvent(setupJSD);
+
+</script>
+<script>
+function testJSD() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+ ok(jsd.isOn, "JSD needs to be running for this test.");
+
+ var deferred = loadScript("bug507448.js");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/js/jsd/test/test_bug617870-callhooks.html b/js/jsd/test/test_bug617870-callhooks.html
new file mode 100644
index 0000000..e9f5b2e
--- /dev/null
+++ b/js/jsd/test/test_bug617870-callhooks.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <!-- The bug number is pulled from the test URL -->
+ <title>JSD Test for Bug AUTOFILLED</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="jsd-test.js"></script>
+ <script type="application/javascript">
+var BUG = 617870;
+var TEST_SCRIPT = "test-bug617870-callhooks.js";
+document.getElementsByTagName("title")[0].innerHTML = "JSD Test for Bug " + BUG;
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+SimpleTest.waitForExplicitFinish();
+
+var hits = { gn: [], ge: [], fn: [], fe: [] };
+var numGlobalNonevals = 0;
+var numFunctionNonevals = 0;
+var numGlobalEvals = 0;
+var numFunctionEvals = 0;
+function runTest() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ jsd.topLevelHook = {
+ onCall: function(frame,type) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ if (frame.script.fileName.indexOf(TEST_SCRIPT) != -1) {
+ var desc = frame.script.fileName + ":" + frame.line + " (" + frame.functionName + ")";
+ if (type == Ci.jsdICallHook.TYPE_TOPLEVEL_START) {
+ if (frame.callingFrame === null) {
+ numGlobalNonevals++;
+ hits.gn.push(desc);
+ } else if (frame.callee === null) {
+ numGlobalEvals++;
+ hits.ge.push(desc);
+ } else {
+ numFunctionEvals++;
+ hits.fe.push(desc);
+ }
+ }
+ dumpStack(frame, "TOPLEVEL(" + type + ")");
+ }
+ }
+ };
+ jsd.functionHook = {
+ onCall: function(frame,type) {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ if (frame.script.fileName.indexOf(TEST_SCRIPT) != -1) {
+ if (type == Ci.jsdICallHook.TYPE_FUNCTION_CALL) {
+ var desc = frame.script.fileName + ":" + frame.line + " (" + frame.functionName + ")";
+ numFunctionNonevals++;
+ hits.fn.push(desc);
+ }
+ dumpStack(frame, "FUNCTION(" + type + ")");
+ }
+ }
+ };
+ loadScript(TEST_SCRIPT, document.getElementById("test"));
+}
+
+function setupTest() {
+ var buglink = document.getElementById("buglink");
+ buglink.href = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + BUG;
+ buglink.innerHTML = "Mozilla Bug " + BUG;
+}
+ </script>
+</head>
+<body onLoad='setupTest(); setupJSD();'>
+
+<a id="buglink" target="_blank"></a>
+<p id="display"></p>
+
+<div id="content" style="display: none">
+ <pre id='test'>
+ </pre>
+</div>
+
+<div id='test-output'>
+</div>
+
+</body>
+</html>
diff --git a/js/jsd/test/test_bug638178-execlines.html b/js/jsd/test/test_bug638178-execlines.html
new file mode 100644
index 0000000..75cd1b0
--- /dev/null
+++ b/js/jsd/test/test_bug638178-execlines.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <!-- The bug number is pulled from the test URL -->
+ <title>JSD Test for Bug AUTOFILLED</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="jsd-test.js"></script>
+ <script type="application/javascript">
+var BUG = 638178;
+var TEST_SCRIPT = "test-bug638178-execlines.js";
+document.getElementsByTagName("title")[0].innerHTML = "JSD Test for Bug " + BUG;
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ console.log("start of runTest, loading script");
+ loadScript(TEST_SCRIPT, document.getElementById("test"));
+ console.log("end of runTest");
+}
+
+function setupTest() {
+ var buglink = document.getElementById("buglink");
+ buglink.href = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + BUG;
+ buglink.innerHTML = "Mozilla Bug " + BUG;
+}
+ </script>
+</head>
+<body onLoad='setupTest(); setupJSD();'>
+
+<a id="buglink" target="_blank"></a>
+<p id="display"></p>
+
+<div id="content" style="display: none">
+ <pre id='test'>
+ </pre>
+</div>
+
+<div id='test-output'>
+</div>
+
+</body>
+</html>
diff --git a/js/jsd/test/test_evalCached.js b/js/jsd/test/test_evalCached.js
new file mode 100644
index 0000000..4c56ef2
--- /dev/null
+++ b/js/jsd/test/test_evalCached.js
@@ -0,0 +1,23 @@
+// This test must be run with debugging already enabled
+
+function run_test() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const DebuggerService = Cc["@mozilla.org/js/jsd/debugger-service;1"];
+ const jsdIDebuggerService = Ci.jsdIDebuggerService;
+ var jsd = DebuggerService.getService(jsdIDebuggerService);
+
+ do_check_true(jsd.isOn);
+
+ jsd.scriptHook = {
+ onScriptCreated: function(script) {
+ // Just the presence of this will trigger the script to be handed
+ // to JSD and trigger the crash
+ },
+ onScriptDestroyed: function(script) {
+ }
+ }
+
+ eval("4+4");
+ eval("4+4"); // Will be found in the eval cache
+}
diff --git a/js/jsd/test/test_jsval_retval.js b/js/jsd/test/test_jsval_retval.js
new file mode 100644
index 0000000..a2ddba8
--- /dev/null
+++ b/js/jsd/test/test_jsval_retval.js
@@ -0,0 +1,42 @@
+// Bug 689101 - if the binary layout of jsval does not match between C and C++
+// code, then calls to functions returning jsval may get compiled differently
+// than the callee, resulting in parameters being shifted over by one.
+//
+// An example is where on Windows, calling jsdValue.getWrappedValue() will
+// return a random floating point number instead of an object.
+//
+// This test must be run with debugging already enabled
+
+function run_test() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const DebuggerService = Cc["@mozilla.org/js/jsd/debugger-service;1"];
+ const jsdIDebuggerService = Ci.jsdIDebuggerService;
+ var jsd = DebuggerService.getService(jsdIDebuggerService);
+
+ do_check_true(jsd.isOn);
+
+ var n = 0;
+ function f() {
+ n++;
+ }
+
+ jsd.enumerateScripts({ enumerateScript: function(script) {
+ script.setBreakpoint(0);
+ } });
+
+ jsd.breakpointHook = function(frame, type, dummy) {
+ var scope = frame.scope;
+ var parent = scope.jsParent; // Probably does not need to be called
+ var wrapped = scope.getWrappedValue();
+ // Do not try to print 'wrapped'; it may be an internal Call object
+ // that will crash when you toString it. Different bug.
+ do_check_eq(typeof(wrapped), "object");
+ return Ci.jsdIExecutionHook.RETURN_CONTINUE;
+ };
+
+ f();
+
+ jsd.breakpointHook = null;
+ jsd = null;
+}
diff --git a/js/jsd/test/xpcshell.ini b/js/jsd/test/xpcshell.ini
new file mode 100644
index 0000000..4681adf
--- /dev/null
+++ b/js/jsd/test/xpcshell.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+head =
+tail =
+
+[test_jsval_retval.js]
+debug = 1
+
+[test_evalCached.js]
+debug = 1