diff --git a/CLOBBER b/CLOBBER index 091c0155fc6d..533560686519 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,6 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Clobber to make sure any residual damage from bug 975011 is gone. +Bug 800200: Removing the old JavaScript debugging API, js/jsd. I'm advised +that our build system doesn't cope well with deletions, and that a spoonful +of clobber helps the medicine go down (in a most delightful way). diff --git a/browser/components/loop/content/shared/js/models.js b/browser/components/loop/content/shared/js/models.js index b589d05cf833..ddc5d0bbd6e0 100644 --- a/browser/components/loop/content/shared/js/models.js +++ b/browser/components/loop/content/shared/js/models.js @@ -139,7 +139,6 @@ loop.shared.models = (function() { throw new Error("Can't start session as it's not ready"); } this.session = this.sdk.initSession(this.get("sessionId")); - this.listenTo(this.session, "sessionConnected", this._sessionConnected); this.listenTo(this.session, "streamCreated", this._streamCreated); this.listenTo(this.session, "connectionDestroyed", this._connectionDestroyed); @@ -147,7 +146,8 @@ loop.shared.models = (function() { this._sessionDisconnected); this.listenTo(this.session, "networkDisconnected", this._networkDisconnected); - this.session.connect(this.get("apiKey"), this.get("sessionToken")); + this.session.connect(this.get("apiKey"), this.get("sessionToken"), + this._onConnectCompletion.bind(this)); }, /** @@ -160,14 +160,22 @@ loop.shared.models = (function() { }, /** - * Session is created. + * Manages connection status + * triggers apropriate event for connection error/success + * http://tokbox.com/opentok/tutorials/connect-session/js/ + * http://tokbox.com/opentok/tutorials/hello-world/js/ * http://tokbox.com/opentok/libraries/client/js/reference/SessionConnectEvent.html * - * @param {SessionConnectEvent} event + * @param {error|null} error */ - _sessionConnected: function(event) { - this.trigger("session:connected", event); - this.set("ongoing", true); + _onConnectCompletion: function(error) { + if (error) { + this.trigger("session:connection-error", error); + this.endSession(); + } else { + this.trigger("session:connected"); + this.set("ongoing", true); + } }, /** diff --git a/browser/components/loop/content/shared/js/router.js b/browser/components/loop/content/shared/js/router.js index f81bde593ab3..8664b3d69ece 100644 --- a/browser/components/loop/content/shared/js/router.js +++ b/browser/components/loop/content/shared/js/router.js @@ -103,10 +103,22 @@ loop.shared.router = (function(l10n) { this._onPeerHungup); this.listenTo(this._conversation, "session:network-disconnected", this._onNetworkDisconnected); + this.listenTo(this._conversation, "session:connection-error", + this._notifyError); BaseRouter.apply(this, arguments); }, + /** + * Notify the user that the connection was not possible + * @param {{code: number, message: string}} error + */ + _notifyError: function(error) { + console.log(error); + this._notifier.errorL10n("connection_error_see_console_notification"); + this.endCall(); + }, + /** * Starts the call. This method should be overriden. */ diff --git a/browser/components/loop/standalone/content/l10n/data.ini b/browser/components/loop/standalone/content/l10n/data.ini index 328caaf0bbd5..2ca84f09338c 100644 --- a/browser/components/loop/standalone/content/l10n/data.ini +++ b/browser/components/loop/standalone/content/l10n/data.ini @@ -13,6 +13,7 @@ use_latest_firefox.innerHTML=To use Loop, please use the latest version of pathBuilder = CreatePathBuilder(); - ArcToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry), 0, Float(2*M_PI), false); + EllipseToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry)); return pathBuilder->Finish(); } diff --git a/dom/base/moz.build b/dom/base/moz.build index 4f50656fcc7a..3639bdcdc1e9 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -182,7 +182,7 @@ LOCAL_INCLUDES += [ '/js/xpconnect/wrappers', ] -for var in ('MOZ_JSDEBUGGER', 'MOZ_B2G_RIL', 'MOZ_B2G_FM'): +for var in ('MOZ_B2G_RIL', 'MOZ_B2G_FM'): if CONFIG[var]: DEFINES[var] = True diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 0535f5528460..97c8bb1bf8f8 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -230,10 +230,6 @@ #include "mozilla/dom/SpeechSynthesis.h" #endif -#ifdef MOZ_JSDEBUGGER -#include "jsdIDebuggerService.h" -#endif - #ifdef MOZ_B2G #include "nsPISocketTransportService.h" #endif @@ -10881,7 +10877,6 @@ nsGlobalWindow::ShowSlowScriptDialog() // Prioritize the SlowScriptDebug interface over JSD1. nsCOMPtr debugCallback; - bool oldDebugPossible = false; if (hasFrame) { const char *debugCID = "@mozilla.org/dom/slow-script-debug;1"; @@ -10889,33 +10884,9 @@ nsGlobalWindow::ShowSlowScriptDialog() if (NS_SUCCEEDED(rv)) { debugService->GetActivationHandler(getter_AddRefs(debugCallback)); } - - if (!debugCallback) { - oldDebugPossible = js::CanCallContextDebugHandler(cx); -#ifdef MOZ_JSDEBUGGER - // Get the debugger service if necessary. - if (oldDebugPossible) { - bool jsds_IsOn = false; - const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1"; - nsCOMPtr jsdHook; - nsCOMPtr jsds = do_GetService(jsdServiceCtrID, &rv); - - // Check if there's a user for the debugger service that's 'on' for us - if (NS_SUCCEEDED(rv)) { - jsds->GetDebuggerHook(getter_AddRefs(jsdHook)); - jsds->GetIsOn(&jsds_IsOn); - } - - // If there is a debug handler registered for this runtime AND - // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs))) - // then something useful will be done with our request to debug. - oldDebugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn); - } -#endif - } } - bool showDebugButton = debugCallback || oldDebugPossible; + bool showDebugButton = !!debugCallback; // Get localizable strings nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg; @@ -11024,10 +10995,6 @@ nsGlobalWindow::ShowSlowScriptDialog() rv = debugCallback->HandleSlowScriptDebug(this); return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript; } - - if (oldDebugPossible) { - return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript; - } } JS_ClearPendingException(cx); return KillSlowScript; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 556ea67b3dad..a373f9d106cd 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -70,9 +70,6 @@ #endif #include "AccessCheck.h" -#ifdef MOZ_JSDEBUGGER -#include "jsdIDebuggerService.h" -#endif #ifdef MOZ_LOGGING // Force PR_LOGGING so we can get JS strict warnings even in release builds #define FORCE_PR_LOG 1 diff --git a/dom/camera/CameraPreferences.cpp b/dom/camera/CameraPreferences.cpp index a4df3fee3545..1014e4372041 100644 --- a/dom/camera/CameraPreferences.cpp +++ b/dom/camera/CameraPreferences.cpp @@ -129,13 +129,9 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure) return; } -#ifdef DEBUG if (NS_FAILED(rv)) { - nsCString msg; - msg.AppendPrintf("Failed to update pref '%s' (0x%x)\n", aPref, rv); - NS_WARNING(msg.get()); + DOM_CAMERA_LOGE("Failed to get pref '%s' (0x%x)\n", aPref, rv); } -#endif } /* static */ diff --git a/dom/events/EventListenerService.cpp b/dom/events/EventListenerService.cpp index 22fe980edaec..f3179d4274ee 100644 --- a/dom/events/EventListenerService.cpp +++ b/dom/events/EventListenerService.cpp @@ -4,9 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "EventListenerService.h" -#ifdef MOZ_JSDEBUGGER -#include "jsdIDebuggerService.h" -#endif #include "mozilla/BasicEvents.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" @@ -131,35 +128,6 @@ EventListenerInfo::ToSource(nsAString& aResult) return NS_OK; } -NS_IMETHODIMP -EventListenerInfo::GetDebugObject(nsISupports** aRetVal) -{ - *aRetVal = nullptr; - -#ifdef MOZ_JSDEBUGGER - nsresult rv = NS_OK; - nsCOMPtr jsd = - do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv); - NS_ENSURE_SUCCESS(rv, NS_OK); - - bool isOn = false; - jsd->GetIsOn(&isOn); - NS_ENSURE_TRUE(isOn, NS_OK); - - AutoSafeJSContext cx; - Maybe ac; - JS::Rooted v(cx); - if (GetJSVal(cx, ac, &v)) { - nsCOMPtr jsdValue; - rv = jsd->WrapValue(v, getter_AddRefs(jsdValue)); - NS_ENSURE_SUCCESS(rv, rv); - jsdValue.forget(aRetVal); - } -#endif - - return NS_OK; -} - NS_IMETHODIMP EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget, uint32_t* aCount, diff --git a/dom/events/moz.build b/dom/events/moz.build index a4b3ff772323..729db7e0eb8a 100644 --- a/dom/events/moz.build +++ b/dom/events/moz.build @@ -144,6 +144,3 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': LOCAL_INCLUDES += [ '/dom/wifi', ] - -if CONFIG['MOZ_JSDEBUGGER']: - DEFINES['MOZ_JSDEBUGGER'] = True diff --git a/dom/events/nsIEventListenerService.idl b/dom/events/nsIEventListenerService.idl index 8c03cb0f95e4..ab85b98472a0 100644 --- a/dom/events/nsIEventListenerService.idl +++ b/dom/events/nsIEventListenerService.idl @@ -12,7 +12,7 @@ interface nsIDOMEventTarget; * An instance of this interface describes how an event listener * was added to an event target. */ -[scriptable, uuid(c4776eb7-05bc-49ce-a0ca-6213a346d53a)] +[scriptable, uuid(11ba5fd7-8db2-4b1a-9f67-342cfa11afad)] interface nsIEventListenerInfo : nsISupports { /** @@ -37,12 +37,6 @@ interface nsIEventListenerInfo : nsISupports * (for example with C++ listeners). */ AString toSource(); - - /** - * If jsdIDebuggerService is active and the listener is implemented in JS, - * this returns the listener as a jsdIValue. Otherwise null. - */ - nsISupports getDebugObject(); }; [scriptable, uuid(f6964bfb-dabe-4cab-9733-be0ee2bf8171)] diff --git a/dom/events/test/test_bug448602.html b/dom/events/test/test_bug448602.html index 27d8563b659f..5055209eee7c 100644 --- a/dom/events/test/test_bug448602.html +++ b/dom/events/test/test_bug448602.html @@ -22,12 +22,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448602 var els, root, l2, l3; function runTests() { -/* - Disabled due to lack of present support for JSD in JM - var jsdIDebuggerService = SpecialPowers.Ci.jsdIDebuggerService; - var jsd = SpecialPowers.Components.classes['@mozilla.org/js/jsd/debugger-service;1'] - .getService(jsdIDebuggerService); -*/ els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"] .getService(SpecialPowers.Ci.nsIEventListenerService); @@ -48,18 +42,6 @@ function runTests() { is(SpecialPowers.unwrap(infos[0].listenerObject), root.onclick, "Should have the right listener object (1)"); -/* - var jsdOn = jsd.isOn; - if (!jsdOn) { - is(infos[0].getDebugObject(), null, - "If JSD isn't running, getDebugObject() should return null.") - jsd.on(); - ok(jsd.isOn, "JSD should be running."); - } - var jsdvalue = infos[0].getDebugObject().QueryInterface(SpecialPowers.Ci.jsdIValue); - is(jsdvalue.jsType, 3, "Event listener should be a function! (1)"); -*/ - root.removeAttribute("onclick"); root.setAttribute("onclick", "...invalid script..."); SimpleTest.expectUncaughtException(true); @@ -84,12 +66,6 @@ function runTests() { is(infos[0].allowsUntrusted, true, "Should allow untrusted events (2)"); is(SpecialPowers.unwrap(infos[0].listenerObject), l, "Should have the right listener object (2)"); -/* - jsdvalue = infos[0].getDebugObject().QueryInterface(SpecialPowers.Ci.jsdIValue); - is(jsdvalue.jsType, 3, "Event listener should be a function!(2)"); - is(jsdvalue.getWrappedValue(), l, "Wrong JS value! (1)"); -*/ - is(infos[1].toSource(), "(function (e) { alert(e); })", "Unexpected serialization (3)"); is(infos[1].type, "foo", "Wrong type (3)"); @@ -98,11 +74,6 @@ function runTests() { is(SpecialPowers.unwrap(infos[1].listenerObject), l, "Should have the right listener object (3)"); -/* - jsdvalue2 = infos[1].getDebugObject().QueryInterface(SpecialPowers.Ci.jsdIValue); - is(jsdvalue2.jsType, 3, "Event listener should be a function! (3)"); - is(jsdvalue2.getWrappedValue(), l, "Wrong JS value! (2)"); -*/ root.removeEventListener("foo", l, true); root.removeEventListener("foo", l, false); infos = els.getListenerInfoFor(root, {}); @@ -142,12 +113,6 @@ function runTests() { ok(hasDocumentInChain, "Should have document in event target chain!"); ok(hasWindowInChain, "Should have window in event target chain!"); -/* - if (!jsdOn) { - jsd.off(); - ok(!jsd.isOn, "JSD shouldn't be running anymore."); - } -*/ try { els.getListenerInfoFor(null, {}); diff --git a/dom/media/tests/mochitest/blacksilence.js b/dom/media/tests/mochitest/blacksilence.js index 632388b2d2bd..39f3045a8168 100644 --- a/dom/media/tests/mochitest/blacksilence.js +++ b/dom/media/tests/mochitest/blacksilence.js @@ -24,19 +24,31 @@ } function periodicCheck(type, checkFunc, successMessage, done) { - var interval = setInterval(function periodic() { + var num = 0; + var timeout; + function periodic() { if (checkFunc()) { ok(true, type + ' is ' + successMessage); - clearInterval(interval); - interval = null; done(); + } else { + setupNext(); } - }, 200); + } + function setupNext() { + // exponential backoff on the timer + // on a very slow system (like the b2g emulator) a long timeout is + // necessary, but we want to run fast if we can + timeout = setTimeout(periodic, 200 << num); + num++; + } + + setupNext(); + return function cancel() { - if (interval) { + if (timeout) { ok(false, type + ' (' + successMessage + ')' + ' failed after waiting full duration'); - clearInterval(interval); + clearTimeout(timeout); done(); } }; @@ -59,16 +71,22 @@ var silent = check(constraintApplied, isSilence(view), 'be silence for audio'); return sampleCount > 0 && silent; } + function disconnect() { + source.disconnect(); + analyser.disconnect(); + done(); + } return periodicCheck('audio', testAudio, - (constraintApplied ? '' : 'not ') + 'silent', done); + (constraintApplied ? '' : 'not ') + 'silent', disconnect); } function mkElement(type) { - var display = document.getElementById('display'); + // this makes an unattached element + // it's not rendered to save the cycles that costs on b2g emulator + // and it gets droped (and GC'd) when the test is done var e = document.createElement(type); e.width = 32; e.height = 24; - display.appendChild(e); return e; } diff --git a/dom/media/tests/mochitest/templates.js b/dom/media/tests/mochitest/templates.js index d2ec11646632..03dc05786de0 100644 --- a/dom/media/tests/mochitest/templates.js +++ b/dom/media/tests/mochitest/templates.js @@ -187,6 +187,50 @@ var commandsPeerConnection = [ }); } ], + [ + 'PC_REMOTE_CHECK_FOR_DUPLICATED_PORTS_IN_SDP', + function (test) { + var re = /a=candidate.* (UDP|TCP) [\d]+ ([\d\.]+) ([\d]+) typ host/g; + + function _sdpCandidatesIntoArray(sdp) { + var regexArray = []; + var resultArray = []; + while ((regexArray = re.exec(sdp)) !== null) { + info("regexArray: " + regexArray); + if ((regexArray[1] === "TCP") && (regexArray[3] === "9")) { + // As both sides can advertise TCP active connection on port 9 lets + // ignore them all together + info("Ignoring TCP candidate on port 9"); + continue; + } + const triple = regexArray[1] + ":" + regexArray[2] + ":" + regexArray[3]; + info("triple: " + triple); + if (resultArray.indexOf(triple) !== -1) { + dump("SDP: " + sdp.replace(/[\r]/g, '') + "\n"); + ok(false, "This Transport:IP:Port " + triple + " appears twice in the SDP above!"); + } + resultArray.push(triple); + } + return resultArray; + } + + const offerTriples = _sdpCandidatesIntoArray(test._local_offer.sdp); + info("Offer ICE host candidates: " + JSON.stringify(offerTriples)); + + const answerTriples = _sdpCandidatesIntoArray(test.pcRemote._last_answer.sdp); + info("Answer ICE host candidates: " + JSON.stringify(answerTriples)); + + for (var i=0; i< offerTriples.length; i++) { + if (answerTriples.indexOf(offerTriples[i]) !== -1) { + dump("SDP offer: " + test._local_offer.sdp.replace(/[\r]/g, '') + "\n"); + dump("SDP answer: " + test.pcRemote._last_answer.sdp.replace(/[\r]/g, '') + "\n"); + ok(false, "This IP:Port " + offerTriples[i] + " appears in SDP offer and answer!"); + } + } + + test.next(); + } + ], [ 'PC_REMOTE_SET_LOCAL_DESCRIPTION', function (test) { diff --git a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html index 6a4ae702bb1a..84b170b71333 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html +++ b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html @@ -36,8 +36,8 @@ function theTest() { } var cancelAudioCheck = audioIsSilence(withConstraint, stream, checkDone); var cancelVideoCheck = videoIsBlack(withConstraint, stream, checkDone); - setTimeout(cancelAudioCheck, 20000); - setTimeout(cancelVideoCheck, 20000); + setTimeout(cancelAudioCheck, 3*60*1000); + setTimeout(cancelVideoCheck, 3*60*1000); }, function(e) { ok(false, 'gUM error: ' + e); }); diff --git a/dom/workers/MessagePort.cpp b/dom/workers/MessagePort.cpp index 1079383c54d9..d01b1da83446 100644 --- a/dom/workers/MessagePort.cpp +++ b/dom/workers/MessagePort.cpp @@ -7,6 +7,7 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/ScriptSettings.h" #include "nsIDOMEvent.h" #include "SharedWorker.h" @@ -17,6 +18,7 @@ using mozilla::dom::EventHandlerNonNull; using mozilla::dom::MessagePortBase; using mozilla::dom::Optional; using mozilla::dom::Sequence; +using mozilla::dom::AutoNoJSAPI; using namespace mozilla; USING_WORKERS_NAMESPACE @@ -42,6 +44,28 @@ public: mEvents.SwapElements(aEvents); } + bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + { + if (mBehavior == WorkerThreadModifyBusyCount) { + return aWorkerPrivate->ModifyBusyCount(aCx, true); + } + + return true; + } + + void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) + { + if (!aDispatchResult) { + if (mBehavior == WorkerThreadModifyBusyCount) { + aWorkerPrivate->ModifyBusyCount(aCx, false); + } + if (aCx) { + JS_ReportPendingException(aCx); + } + } + } + bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate); }; @@ -281,6 +305,8 @@ DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) mMessagePort->AssertCorrectThread(); MOZ_ASSERT(mEvents.Length()); + AutoNoJSAPI nojsapi; + bool ignored; for (uint32_t i = 0; i < mEvents.Length(); i++) { mMessagePort->DispatchEvent(mEvents[i], &ignored); diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index 36c74a812ff3..ee0ae487ecbb 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -11,20 +11,242 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/DOMError.h" + #include "nsContentUtils.h" #include "nsCxPusher.h" #include "nsNetUtil.h" +#include "nsProxyRelease.h" #include "nsTArray.h" #include "RuntimeService.h" #include "ServiceWorker.h" #include "WorkerInlines.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" using namespace mozilla; using namespace mozilla::dom; BEGIN_WORKERS_NAMESPACE +NS_IMPL_ISUPPORTS0(ServiceWorkerRegistration) + +UpdatePromise::UpdatePromise() + : mState(Pending) +{ + MOZ_COUNT_CTOR(UpdatePromise); +} + +UpdatePromise::~UpdatePromise() +{ + MOZ_COUNT_DTOR(UpdatePromise); +} + +void +UpdatePromise::AddPromise(Promise* aPromise) +{ + MOZ_ASSERT(mState == Pending); + mPromises.AppendElement(aPromise); +} + +void +UpdatePromise::ResolveAllPromises(const nsACString& aScriptSpec, const nsACString& aScope) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(mState == Pending); + mState = Resolved; + RuntimeService* rs = RuntimeService::GetOrCreateService(); + MOZ_ASSERT(rs); + + nsTArray> array; + array.SwapElements(mPromises); + for (uint32_t i = 0; i < array.Length(); ++i) { + nsTWeakRef& pendingPromise = array.ElementAt(i); + if (pendingPromise) { + nsCOMPtr go = + do_QueryInterface(pendingPromise->GetParentObject()); + MOZ_ASSERT(go); + + AutoSafeJSContext cx; + JS::Rooted global(cx, go->GetGlobalJSObject()); + JSAutoCompartment ac(cx, global); + + GlobalObject domGlobal(cx, global); + + nsRefPtr serviceWorker; + nsresult rv = rs->CreateServiceWorker(domGlobal, + NS_ConvertUTF8toUTF16(aScriptSpec), + aScope, + getter_AddRefs(serviceWorker)); + if (NS_WARN_IF(NS_FAILED(rv))) { + pendingPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + continue; + } + + pendingPromise->MaybeResolve(serviceWorker); + } + } +} + +void +UpdatePromise::RejectAllPromises(nsresult aRv) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(mState == Pending); + mState = Rejected; + + nsTArray> array; + array.SwapElements(mPromises); + for (uint32_t i = 0; i < array.Length(); ++i) { + nsTWeakRef& pendingPromise = array.ElementAt(i); + if (pendingPromise) { + // Since ServiceWorkerContainer is only exposed to windows we can be + // certain about this cast. + nsCOMPtr window = + do_QueryInterface(pendingPromise->GetParentObject()); + MOZ_ASSERT(window); + nsRefPtr domError = new DOMError(window, aRv); + pendingPromise->MaybeRejectBrokenly(domError); + } + } +} + +class FinishFetchOnMainThreadRunnable : public nsRunnable +{ + nsMainThreadPtrHandle mUpdateInstance; +public: + FinishFetchOnMainThreadRunnable + (const nsMainThreadPtrHandle& aUpdateInstance) + : mUpdateInstance(aUpdateInstance) + { } + + NS_IMETHOD + Run() MOZ_OVERRIDE; +}; + +class FinishSuccessfulFetchWorkerRunnable : public WorkerRunnable +{ + nsMainThreadPtrHandle mUpdateInstance; +public: + FinishSuccessfulFetchWorkerRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aUpdateInstance) + : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount), + mUpdateInstance(aUpdateInstance) + { + AssertIsOnMainThread(); + } + + bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + { + aWorkerPrivate->AssertIsOnWorkerThread(); + if (!aWorkerPrivate->WorkerScriptExecutedSuccessfully()) { + return true; + } + + nsRefPtr r = + new FinishFetchOnMainThreadRunnable(mUpdateInstance); + NS_DispatchToMainThread(r); + return true; + } +}; + +// Allows newer calls to Update() to 'abort' older calls. +// Each call to Update() creates the instance which handles creating the +// worker and queues up a runnable to resolve the update promise once the +// worker has successfully been parsed. +class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports +{ + // Owner of this instance. + ServiceWorkerRegistration* mRegistration; + nsCString mScriptSpec; + nsCOMPtr mWindow; + + bool mAborted; +public: + NS_DECL_ISUPPORTS + + ServiceWorkerUpdateInstance(ServiceWorkerRegistration *aRegistration, + nsPIDOMWindow* aWindow) + : mRegistration(aRegistration), + // Capture the current script spec in case register() gets called. + mScriptSpec(aRegistration->mScriptSpec), + mWindow(aWindow), + mAborted(false) + { + AssertIsOnMainThread(); + } + + void + Abort() + { + MOZ_ASSERT(!mAborted); + mAborted = true; + } + + void + Update() + { + AssertIsOnMainThread(); + nsRefPtr swm = ServiceWorkerManager::GetInstance(); + MOZ_ASSERT(swm); + + nsRefPtr serviceWorker; + nsresult rv = swm->CreateServiceWorkerForWindow(mWindow, + mScriptSpec, + mRegistration->mScope, + getter_AddRefs(serviceWorker)); + if (NS_WARN_IF(NS_FAILED(rv))) { + swm->RejectUpdatePromiseObservers(mRegistration, rv); + return; + } + + nsMainThreadPtrHandle handle = + new nsMainThreadPtrHolder(this); + // FIXME(nsm): Deal with error case (worker failed to download, redirect, + // parse) in error handler patch. + nsRefPtr r = + new FinishSuccessfulFetchWorkerRunnable(serviceWorker->GetWorkerPrivate(), handle); + + AutoSafeJSContext cx; + if (!r->Dispatch(cx)) { + swm->RejectUpdatePromiseObservers(mRegistration, NS_ERROR_FAILURE); + } + } + + void + FetchDone() + { + AssertIsOnMainThread(); + if (mAborted) { + return; + } + + nsRefPtr swm = ServiceWorkerManager::GetInstance(); + MOZ_ASSERT(swm); + swm->FinishFetch(mRegistration, mWindow); + } +}; + +NS_IMPL_ISUPPORTS0(ServiceWorkerUpdateInstance) + +NS_IMETHODIMP +FinishFetchOnMainThreadRunnable::Run() +{ + AssertIsOnMainThread(); + mUpdateInstance->FetchDone(); + return NS_OK; +} + +ServiceWorkerRegistration::ServiceWorkerRegistration(const nsACString& aScope) + : mScope(aScope), + mPendingUninstall(false) +{ } + +ServiceWorkerRegistration::~ServiceWorkerRegistration() +{ } + ////////////////////////// // ServiceWorkerManager // ////////////////////////// @@ -89,13 +311,15 @@ public: nsRefPtr swm = ServiceWorkerManager::GetInstance(); ServiceWorkerManager::ServiceWorkerDomainInfo* domainInfo = swm->mDomainMap.Get(domain); - // FIXME(nsm): Refactor this pattern. + // XXXnsm: This pattern can be refactored if we end up using it + // often enough. if (!swm->mDomainMap.Get(domain, &domainInfo)) { domainInfo = new ServiceWorkerManager::ServiceWorkerDomainInfo; swm->mDomainMap.Put(domain, domainInfo); } - nsRefPtr registration = domainInfo->GetRegistration(mScope); + nsRefPtr registration = + domainInfo->GetRegistration(mScope); nsCString spec; rv = mScriptURI->GetSpec(spec); @@ -107,9 +331,6 @@ public: if (registration) { registration->mPendingUninstall = false; if (spec.Equals(registration->mScriptSpec)) { - // FIXME(nsm): Force update on Shift+Reload. Algorithm not specified for - // that yet. - // There is an existing update in progress. Resolve with whatever it // results in. if (registration->HasUpdatePromise()) { @@ -117,8 +338,8 @@ public: return NS_OK; } - // There is no update in progress and since SW updating is upto the UA, we - // will not update right now. Simply resolve with whatever worker we + // There is no update in progress and since SW updating is upto the UA, + // we will not update right now. Simply resolve with whatever worker we // have. ServiceWorkerInfo info = registration->Newest(); if (info.IsValid()) { @@ -143,10 +364,16 @@ public: registration->mScriptSpec = spec; - // FIXME(nsm): Call Update. Same bug, different patch. - // For now if the registration reaches this spot, the promise remains - // unresolved. - return NS_OK; + rv = swm->Update(registration, mWindow); + MOZ_ASSERT(registration->HasUpdatePromise()); + + // We append this register() call's promise after calling Update() because + // we don't want this one to be aborted when the others (existing updates + // for the same registration) are aborted. Update() sets a new + // UpdatePromise on the registration. + registration->mUpdatePromise->AddPromise(mPromise); + + return rv; } }; @@ -154,7 +381,8 @@ public: // automatically reject the Promise. NS_IMETHODIMP ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope, - const nsAString& aScriptURL, nsISupports** aPromise) + const nsAString& aScriptURL, + nsISupports** aPromise) { AssertIsOnMainThread(); MOZ_ASSERT(aWindow); @@ -206,10 +434,9 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope, return rv; } - // https://github.com/slightlyoff/ServiceWorker/issues/262 - // allowIfInheritsPrincipal: allow data: URLs for now. + // Data URLs are not allowed. rv = documentPrincipal->CheckMayLoad(scriptURI, true /* report */, - true /* allowIfInheritsPrincipal */); + false /* allowIfInheritsPrincipal */); if (NS_FAILED(rv)) { return NS_ERROR_DOM_SECURITY_ERR; } @@ -238,11 +465,51 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope, return NS_DispatchToCurrentThread(registerRunnable); } +void +ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration, + nsresult aRv) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aRegistration->HasUpdatePromise()); + aRegistration->mUpdatePromise->RejectAllPromises(aRv); + aRegistration->mUpdatePromise = nullptr; +} + +/* + * Update() does not return the Promise that the spec says it should. Callers + * may access the registration's (new) Promise after calling this method. + */ NS_IMETHODIMP ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration, nsPIDOMWindow* aWindow) { - // FIXME(nsm): Same bug, different patch. + if (aRegistration->HasUpdatePromise()) { + NS_WARNING("Already had a UpdatePromise. Aborting that one!"); + RejectUpdatePromiseObservers(aRegistration, NS_ERROR_DOM_ABORT_ERR); + MOZ_ASSERT(aRegistration->mUpdateInstance); + aRegistration->mUpdateInstance->Abort(); + aRegistration->mUpdateInstance = nullptr; + } + + if (aRegistration->mInstallingWorker.IsValid()) { + // FIXME(nsm): Terminate the worker. We still haven't figured out worker + // instance ownership when not associated with a window, so let's wait on + // this. + // FIXME(nsm): We should be setting the state on the actual worker + // instance. + // FIXME(nsm): Fire "statechange" on installing worker instance. + aRegistration->mInstallingWorker.Invalidate(); + } + + aRegistration->mUpdatePromise = new UpdatePromise(); + // FIXME(nsm): Bug 931249. If we don't need to fetch & install, resolve + // promise and skip this. + // FIXME(nsm): Bug 931249. Force cache update if > 1 day. + + aRegistration->mUpdateInstance = + new ServiceWorkerUpdateInstance(aRegistration, aWindow); + aRegistration->mUpdateInstance->Update(); + return NS_OK; } @@ -266,11 +533,69 @@ ServiceWorkerManager::Unregister(nsIDOMWindow* aWindow, const nsAString& aScope, already_AddRefed ServiceWorkerManager::GetInstance() { - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); + nsCOMPtr swm = + do_GetService(SERVICEWORKERMANAGER_CONTRACTID); nsRefPtr concrete = do_QueryObject(swm); return concrete.forget(); } +void +ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration, + const nsACString& aWorkerScriptSpec) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aRegistration->HasUpdatePromise()); + if (aRegistration->mUpdatePromise->IsRejected()) { + aRegistration->mUpdatePromise = nullptr; + return; + } + + aRegistration->mUpdatePromise->ResolveAllPromises(aWorkerScriptSpec, + aRegistration->mScope); + aRegistration->mUpdatePromise = nullptr; +} + +// Must NS_Free() aString +void +ServiceWorkerManager::FinishFetch(ServiceWorkerRegistration* aRegistration, + nsPIDOMWindow* aWindow) +{ + AssertIsOnMainThread(); + + MOZ_ASSERT(aRegistration->HasUpdatePromise()); + MOZ_ASSERT(aRegistration->mUpdateInstance); + aRegistration->mUpdateInstance = nullptr; + if (aRegistration->mUpdatePromise->IsRejected()) { + aRegistration->mUpdatePromise = nullptr; + return; + } + + // We have skipped Steps 3-8.3 of the Update algorithm here! + + nsRefPtr worker; + nsresult rv = CreateServiceWorkerForWindow(aWindow, + aRegistration->mScriptSpec, + aRegistration->mScope, + getter_AddRefs(worker)); + + if (NS_WARN_IF(NS_FAILED(rv))) { + RejectUpdatePromiseObservers(aRegistration, rv); + return; + } + + ResolveRegisterPromises(aRegistration, aRegistration->mScriptSpec); + + ServiceWorkerInfo info(aRegistration->mScriptSpec); + Install(aRegistration, info); +} + +void +ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration, + ServiceWorkerInfo aServiceWorkerInfo) +{ + // FIXME(nsm): Same bug, different patch. +} + NS_IMETHODIMP ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow, const nsACString& aScriptSpec, diff --git a/dom/workers/ServiceWorkerManager.h b/dom/workers/ServiceWorkerManager.h index c6191c5afbbd..293a5ae7d77a 100644 --- a/dom/workers/ServiceWorkerManager.h +++ b/dom/workers/ServiceWorkerManager.h @@ -23,6 +23,44 @@ namespace dom { namespace workers { class ServiceWorker; +class ServiceWorkerUpdateInstance; + +/** + * UpdatePromise is a utility class that sort of imitates Promise, but not + * completely. Using DOM Promise from C++ is a pain when we know the precise types + * we're dealing with since it involves dealing with JSAPI. In this case we + * also don't (yet) need the 'thenables added after resolution should trigger + * immediately' support and other things like that. All we want is something + * that works reasonably Promise like and can resolve real DOM Promises added + * pre-emptively. + */ +class UpdatePromise MOZ_FINAL +{ +public: + UpdatePromise(); + ~UpdatePromise(); + + void AddPromise(Promise* aPromise); + void ResolveAllPromises(const nsACString& aScriptSpec, const nsACString& aScope); + void RejectAllPromises(nsresult aRv); + + bool + IsRejected() const + { + return mState == Rejected; + } + +private: + enum { + Pending, + Resolved, + Rejected + } mState; + + // XXXnsm: Right now we don't need to support AddPromise() after + // already being resolved (i.e. true Promise-like behaviour). + nsTArray> mPromises; +}; /* * Wherever the spec treats a worker instance and a description of said worker @@ -32,7 +70,7 @@ class ServiceWorker; */ class ServiceWorkerInfo { - const nsCString mScriptSpec; + nsCString mScriptSpec; public: bool @@ -41,6 +79,12 @@ public: return !mScriptSpec.IsVoid(); } + void + Invalidate() + { + mScriptSpec.SetIsVoid(true); + } + const nsCString& GetScriptSpec() const { @@ -49,19 +93,23 @@ public: } ServiceWorkerInfo() - { } + { + Invalidate(); + } explicit ServiceWorkerInfo(const nsACString& aScriptSpec) : mScriptSpec(aScriptSpec) { } }; -class ServiceWorkerRegistration +// Needs to inherit from nsISupports because NS_ProxyRelease() does not support +// non-ISupports classes. +class ServiceWorkerRegistration MOZ_FINAL : public nsISupports { -private: - ~ServiceWorkerRegistration() {} + virtual ~ServiceWorkerRegistration(); + public: - NS_INLINE_DECL_REFCOUNTING(ServiceWorkerRegistration) + NS_DECL_ISUPPORTS nsCString mScope; // The scriptURL for the registration. This may be completely different from @@ -72,18 +120,20 @@ public: ServiceWorkerInfo mWaitingWorker; ServiceWorkerInfo mInstallingWorker; - bool mHasUpdatePromise; + nsAutoPtr mUpdatePromise; + nsRefPtr mUpdateInstance; void AddUpdatePromiseObserver(Promise* aPromise) { - // FIXME(nsm): Same bug, different patch. + MOZ_ASSERT(HasUpdatePromise()); + mUpdatePromise->AddPromise(aPromise); } bool HasUpdatePromise() { - return mHasUpdatePromise; + return mUpdatePromise; } // When unregister() is called on a registration, it is not immediately @@ -91,11 +141,7 @@ public: // pendingUninstall and when all controlling documents go away, removed. bool mPendingUninstall; - explicit ServiceWorkerRegistration(const nsACString& aScope) - : mScope(aScope), - mHasUpdatePromise(false), - mPendingUninstall(false) - { } + explicit ServiceWorkerRegistration(const nsACString& aScope); ServiceWorkerInfo Newest() const @@ -126,6 +172,8 @@ public: class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager { friend class RegisterRunnable; + friend class CallInstallRunnable; + friend class ServiceWorkerUpdateInstance; public: NS_DECL_ISUPPORTS @@ -174,12 +222,17 @@ public: nsClassHashtable mDomainMap; - // FIXME(nsm): What do we do if a page calls for register("/foo_worker.js", { scope: "/*" - // }) and then another page calls register("/bar_worker.js", { scope: "/*" }) - // while the install is in progress. The async install steps for register - // bar_worker.js could finish before foo_worker.js, but bar_worker still has - // to be the winning controller. - // FIXME(nsm): Move this into per domain? + void + ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration, + const nsACString& aWorkerScriptSpec); + + void + RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration, + nsresult aResult); + + void + FinishFetch(ServiceWorkerRegistration* aRegistration, + nsPIDOMWindow* aWindow); static already_AddRefed GetInstance(); @@ -191,6 +244,10 @@ private: NS_IMETHOD Update(ServiceWorkerRegistration* aRegistration, nsPIDOMWindow* aWindow); + void + Install(ServiceWorkerRegistration* aRegistration, + ServiceWorkerInfo aServiceWorkerInfo); + NS_IMETHODIMP CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow, const nsACString& aScriptSpec, diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp index 9c524169a985..fae33fa9dad0 100644 --- a/dom/workers/SharedWorker.cpp +++ b/dom/workers/SharedWorker.cpp @@ -40,6 +40,7 @@ SharedWorker::SharedWorker(nsPIDOMWindow* aWindow, SharedWorker::~SharedWorker() { AssertIsOnMainThread(); + Close(); MOZ_ASSERT(!mWorkerPrivate); } diff --git a/dom/workers/test/bug998474_worker.js b/dom/workers/test/bug998474_worker.js new file mode 100644 index 000000000000..a14ed281052d --- /dev/null +++ b/dom/workers/test/bug998474_worker.js @@ -0,0 +1,6 @@ +self.addEventListener("connect", function(e) { + var port = e.ports[0]; + port.onmessage = function(e) { + port.postMessage(eval(e.data)); + }; +}); diff --git a/dom/workers/test/mochitest.ini b/dom/workers/test/mochitest.ini index 4c58b7546e3d..5ab2ff8bcb0c 100644 --- a/dom/workers/test/mochitest.ini +++ b/dom/workers/test/mochitest.ini @@ -7,6 +7,7 @@ support-files = bug1014466_worker.js bug1020226_worker.js bug1020226_frame.html + bug998474_worker.js clearTimeouts_worker.js closeOnGC_server.sjs closeOnGC_worker.js @@ -81,10 +82,12 @@ support-files = [test_atob.html] [test_blobConstructor.html] [test_blobWorkers.html] +[test_bug1002702.html] [test_bug949946.html] [test_bug1010784.html] [test_bug1014466.html] [test_bug1020226.html] +[test_bug998474.html] [test_chromeWorker.html] [test_clearTimeouts.html] [test_close.html] @@ -121,6 +124,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure [test_onLine.html] skip-if = (toolkit == 'gonk' && debug) #debug-only failure [test_promise.html] +[test_promise_resolved_with_string.html] [test_recursion.html] [test_recursiveOnerror.html] [test_relativeLoad.html] diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index f7b5b7d5690a..1ba39eb1fb13 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -1,2 +1,8 @@ +[DEFAULT] +support-files = + worker.js + worker2.js + worker3.js + [test_installation_simple.html] [test_navigator.html] diff --git a/dom/workers/test/serviceworkers/test_installation_simple.html b/dom/workers/test/serviceworkers/test_installation_simple.html index 97a0a9394d79..cf84bd80abec 100644 --- a/dom/workers/test/serviceworkers/test_installation_simple.html +++ b/dom/workers/test/serviceworkers/test_installation_simple.html @@ -16,7 +16,7 @@ + + + +

+ +

+
+
+
+
+
diff --git a/dom/workers/test/test_bug998474.html b/dom/workers/test/test_bug998474.html
new file mode 100644
index 000000000000..39e5aca0df3f
--- /dev/null
+++ b/dom/workers/test/test_bug998474.html
@@ -0,0 +1,39 @@
+
+
+
+
+  Test for bug 998474
+  
+  
+
+
+

+ +

+
+
+
+
diff --git a/dom/workers/test/test_promise_resolved_with_string.html b/dom/workers/test/test_promise_resolved_with_string.html
new file mode 100644
index 000000000000..b63ddb900d7a
--- /dev/null
+++ b/dom/workers/test/test_promise_resolved_with_string.html
@@ -0,0 +1,41 @@
+
+
+
+
+  
+  Test for Bug 1027221
+  
+  
+  
+
+
+
Mozilla Bug 1027221 +

+ +
+
+ + diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 3e9766edce0f..99355aa0d713 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -620,6 +620,8 @@ public: DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {} virtual ~DrawTarget() {} + virtual DrawTargetType GetType() const = 0; + virtual BackendType GetBackendType() const = 0; /** * Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget. diff --git a/gfx/2d/DrawTargetCG.cpp b/gfx/2d/DrawTargetCG.cpp index 104841c88f47..9477a0b760b7 100644 --- a/gfx/2d/DrawTargetCG.cpp +++ b/gfx/2d/DrawTargetCG.cpp @@ -155,6 +155,13 @@ DrawTargetCG::~DrawTargetCG() CGContextRelease(mCg); } +DrawTargetType +DrawTargetCG::GetType() const +{ + return GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED ? + DrawTargetType::HARDWARE_RASTER : DrawTargetType::SOFTWARE_RASTER; +} + BackendType DrawTargetCG::GetBackendType() const { diff --git a/gfx/2d/DrawTargetCG.h b/gfx/2d/DrawTargetCG.h index a25f12dfb076..4284c495d2dc 100644 --- a/gfx/2d/DrawTargetCG.h +++ b/gfx/2d/DrawTargetCG.h @@ -100,6 +100,7 @@ public: DrawTargetCG(); virtual ~DrawTargetCG(); + virtual DrawTargetType GetType() const MOZ_OVERRIDE; virtual BackendType GetBackendType() const; virtual TemporaryRef Snapshot(); diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index 2e1ce7add2da..57eb3de59ab8 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -372,6 +372,56 @@ DrawTargetCairo::~DrawTargetCairo() MOZ_ASSERT(!mLockedBits); } +DrawTargetType +DrawTargetCairo::GetType() const +{ + if (mContext) { + cairo_surface_type_t type = cairo_surface_get_type(mSurface); + if (type == CAIRO_SURFACE_TYPE_TEE) { + type = cairo_surface_get_type(cairo_tee_surface_index(mSurface, 0)); + MOZ_ASSERT(type != CAIRO_SURFACE_TYPE_TEE, "C'mon!"); + MOZ_ASSERT(type == cairo_surface_get_type(cairo_tee_surface_index(mSurface, 1)), + "What should we do here?"); + } + switch (type) { + case CAIRO_SURFACE_TYPE_PDF: + case CAIRO_SURFACE_TYPE_PS: + case CAIRO_SURFACE_TYPE_SVG: + case CAIRO_SURFACE_TYPE_WIN32_PRINTING: + case CAIRO_SURFACE_TYPE_XML: + return DrawTargetType::VECTOR; + + case CAIRO_SURFACE_TYPE_VG: + case CAIRO_SURFACE_TYPE_GL: + case CAIRO_SURFACE_TYPE_GLITZ: + case CAIRO_SURFACE_TYPE_QUARTZ: + case CAIRO_SURFACE_TYPE_DIRECTFB: + return DrawTargetType::HARDWARE_RASTER; + + case CAIRO_SURFACE_TYPE_SKIA: + case CAIRO_SURFACE_TYPE_QT: + MOZ_ASSERT(false, "Can't determine actual DrawTargetType for DrawTargetCairo - assuming SOFTWARE_RASTER"); + // fallthrough + case CAIRO_SURFACE_TYPE_IMAGE: + case CAIRO_SURFACE_TYPE_XLIB: + case CAIRO_SURFACE_TYPE_XCB: + case CAIRO_SURFACE_TYPE_WIN32: + case CAIRO_SURFACE_TYPE_BEOS: + case CAIRO_SURFACE_TYPE_OS2: + case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: + case CAIRO_SURFACE_TYPE_SCRIPT: + case CAIRO_SURFACE_TYPE_RECORDING: + case CAIRO_SURFACE_TYPE_DRM: + case CAIRO_SURFACE_TYPE_SUBSURFACE: + case CAIRO_SURFACE_TYPE_D2D: + case CAIRO_SURFACE_TYPE_TEE: // included to silence warning about unhandled enum value + return DrawTargetType::SOFTWARE_RASTER; + } + } + MOZ_ASSERT(false, "Could not determine DrawTargetType for DrawTargetCairo"); + return DrawTargetType::SOFTWARE_RASTER; +} + IntSize DrawTargetCairo::GetSize() { diff --git a/gfx/2d/DrawTargetCairo.h b/gfx/2d/DrawTargetCairo.h index 6294daf72a82..46ad2902ee4b 100644 --- a/gfx/2d/DrawTargetCairo.h +++ b/gfx/2d/DrawTargetCairo.h @@ -58,6 +58,7 @@ public: DrawTargetCairo(); virtual ~DrawTargetCairo(); + virtual DrawTargetType GetType() const MOZ_OVERRIDE; virtual BackendType GetBackendType() const { return BackendType::CAIRO; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize(); diff --git a/gfx/2d/DrawTargetD2D.h b/gfx/2d/DrawTargetD2D.h index 65ab34c4b492..9c39001c3c24 100644 --- a/gfx/2d/DrawTargetD2D.h +++ b/gfx/2d/DrawTargetD2D.h @@ -47,6 +47,7 @@ public: DrawTargetD2D(); virtual ~DrawTargetD2D(); + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return DrawTargetType::HARDWARE_RASTER; } virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize() { return mSize; } diff --git a/gfx/2d/DrawTargetD2D1.h b/gfx/2d/DrawTargetD2D1.h index 81afe217ce64..eac56c97d176 100644 --- a/gfx/2d/DrawTargetD2D1.h +++ b/gfx/2d/DrawTargetD2D1.h @@ -39,6 +39,7 @@ public: DrawTargetD2D1(); virtual ~DrawTargetD2D1(); + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return DrawTargetType::HARDWARE_RASTER; } virtual BackendType GetBackendType() const { return BackendType::DIRECT2D1_1; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize() { return mSize; } diff --git a/gfx/2d/DrawTargetDual.h b/gfx/2d/DrawTargetDual.h index 3954150a950c..097bfeddca16 100644 --- a/gfx/2d/DrawTargetDual.h +++ b/gfx/2d/DrawTargetDual.h @@ -43,6 +43,7 @@ public: mFormat = aA->GetFormat(); } + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mA->GetType(); } virtual BackendType GetBackendType() const { return mA->GetBackendType(); } virtual TemporaryRef Snapshot() { return new SourceSurfaceDual(mA, mB); } virtual IntSize GetSize() { return mA->GetSize(); } diff --git a/gfx/2d/DrawTargetRecording.h b/gfx/2d/DrawTargetRecording.h index 4386353ef6f3..9bb8836d1590 100644 --- a/gfx/2d/DrawTargetRecording.h +++ b/gfx/2d/DrawTargetRecording.h @@ -19,6 +19,7 @@ public: DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT, bool aHasData = false); ~DrawTargetRecording(); + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mFinalDT->GetType(); } virtual BackendType GetBackendType() const { return mFinalDT->GetBackendType(); } virtual TemporaryRef Snapshot(); diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 80c102398c24..7a8ba66636bd 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -277,12 +277,12 @@ struct AutoPaintSetup { mPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode); SkPaint temp; temp.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); - temp.setAlpha(U8CPU(aOptions.mAlpha*255+0.5)); + temp.setAlpha(ColorFloatToByte(aOptions.mAlpha)); //TODO: Get a rect here mCanvas->saveLayer(nullptr, &temp); mNeedsRestore = true; } else { - mPaint.setAlpha(U8CPU(aOptions.mAlpha*255.0+0.5)); + mPaint.setAlpha(ColorFloatToByte(aOptions.mAlpha)); mAlpha = aOptions.mAlpha; } mPaint.setFilterLevel(SkPaint::kLow_FilterLevel); @@ -339,6 +339,17 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface, mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint); } +DrawTargetType +DrawTargetSkia::GetType() const +{ +#ifdef USE_SKIA_GPU + if (mGrContext) { + return DrawTargetType::HARDWARE_RASTER; + } +#endif + return DrawTargetType::SOFTWARE_RASTER; +} + void DrawTargetSkia::DrawFilter(FilterNode *aNode, const Rect &aSourceRect, diff --git a/gfx/2d/DrawTargetSkia.h b/gfx/2d/DrawTargetSkia.h index 1c727f3d620f..d4505c44de9a 100644 --- a/gfx/2d/DrawTargetSkia.h +++ b/gfx/2d/DrawTargetSkia.h @@ -31,6 +31,7 @@ public: DrawTargetSkia(); virtual ~DrawTargetSkia(); + virtual DrawTargetType GetType() const MOZ_OVERRIDE; virtual BackendType GetBackendType() const { return BackendType::SKIA; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize() { return mSize; } diff --git a/gfx/2d/DrawTargetTiled.h b/gfx/2d/DrawTargetTiled.h index a0e2320302da..280113ed8985 100644 --- a/gfx/2d/DrawTargetTiled.h +++ b/gfx/2d/DrawTargetTiled.h @@ -21,6 +21,7 @@ public: bool Init(const TileSet& mTiles); + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mTiles[0].mDrawTarget->GetType(); } virtual BackendType GetBackendType() const { return mTiles[0].mDrawTarget->GetBackendType(); } virtual TemporaryRef Snapshot(); virtual IntSize GetSize() { return IntSize(mRect.XMost(), mRect.YMost()); } diff --git a/gfx/2d/HelpersSkia.h b/gfx/2d/HelpersSkia.h index bc77c126e129..10df270213cd 100644 --- a/gfx/2d/HelpersSkia.h +++ b/gfx/2d/HelpersSkia.h @@ -235,11 +235,20 @@ GfxOpToSkiaOp(CompositionOp op) } } -static inline SkColor ColorToSkColor(const Color &color, Float aAlpha) +/* There's quite a bit of inconsistency about + * whether float colors should be rounded with .5f. + * We choose to do it to match cairo which also + * happens to match the Direct3D specs */ +static inline U8CPU ColorFloatToByte(Float color) { //XXX: do a better job converting to int - return SkColorSetARGB(U8CPU(color.a*aAlpha*255.0), U8CPU(color.r*255.0), - U8CPU(color.g*255.0), U8CPU(color.b*255.0)); + return U8CPU(color*255.f + .5f); +}; + +static inline SkColor ColorToSkColor(const Color &color, Float aAlpha) +{ + return SkColorSetARGB(ColorFloatToByte(color.a*aAlpha), ColorFloatToByte(color.r), + ColorFloatToByte(color.g), ColorFloatToByte(color.b)); } static inline SkRect diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 822339bfed1f..56d493e4d315 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -83,6 +83,51 @@ void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius, } } +/* This is basically the ArcToBezier with the parameters for drawing a circle + * inlined which vastly simplifies it and avoids a bunch of transcedental function + * calls which should make it faster. */ +template +void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius) +{ + Point startPoint(aOrigin.x + aRadius.width, + aOrigin.y); + + aSink->LineTo(startPoint); + + // Calculate kappa constant for partial curve. The sign of angle in the + // tangent will actually ensure this is negative for a counter clockwise + // sweep, so changing signs later isn't needed. + Float kappaFactor = (4.0f / 3.0f) * tan((M_PI/2.0f) / 4.0f); + Float kappaX = kappaFactor * aRadius.width; + Float kappaY = kappaFactor * aRadius.height; + Float cosStartAngle = 1; + Float sinStartAngle = 0; + for (int i = 0; i < 4; i++) { + // We guarantee here the current point is the start point of the next + // curve segment. + Point currentStartPoint(aOrigin.x + cosStartAngle * aRadius.width, + aOrigin.y + sinStartAngle * aRadius.height); + Point currentEndPoint(aOrigin.x + -sinStartAngle * aRadius.width, + aOrigin.y + cosStartAngle * aRadius.height); + + Point tangentStart(-sinStartAngle, cosStartAngle); + Point cp1 = currentStartPoint; + cp1 += Point(tangentStart.x * kappaX, tangentStart.y * kappaY); + + Point revTangentEnd(cosStartAngle, sinStartAngle); + Point cp2 = currentEndPoint; + cp2 += Point(revTangentEnd.x * kappaX, revTangentEnd.y * kappaY); + + aSink->BezierTo(cp1, cp2, currentEndPoint); + + // cos(x+pi/2) == -sin(x) + // sin(x+pi/2) == cos(x) + Float tmp = cosStartAngle; + cosStartAngle = -sinStartAngle; + sinStartAngle = tmp; + } +} + /** * Appends a path represending a rounded rectangle to the path being built by * aPathBuilder. diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h index c26ad4e584a8..2a5a5dcd07de 100644 --- a/gfx/2d/Types.h +++ b/gfx/2d/Types.h @@ -72,6 +72,12 @@ MOZ_BEGIN_ENUM_CLASS(FilterType, int8_t) UNPREMULTIPLY MOZ_END_ENUM_CLASS(FilterType) +MOZ_BEGIN_ENUM_CLASS(DrawTargetType, int8_t) + SOFTWARE_RASTER = 0, + HARDWARE_RASTER, + VECTOR +MOZ_END_ENUM_CLASS(DrawTargetType) + MOZ_BEGIN_ENUM_CLASS(BackendType, int8_t) NONE = 0, DIRECT2D, diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 97c8805c9c81..882e043e6c22 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -14,7 +14,6 @@ #include "LayerSorter.h" // for SortLayersBy3DZOrder #include "LayersLogging.h" // for AppendToString #include "ReadbackLayer.h" // for ReadbackLayer -#include "gfxImageSurface.h" #include "gfxPlatform.h" // for gfxPlatform #include "gfxUtils.h" // for gfxUtils, etc #include "gfx2DGlue.h" @@ -1232,18 +1231,13 @@ void WriteSnapshotLinkToDumpFile(T* aObj, std::stringstream& aStream) template void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf) { - nsRefPtr deprecatedSurf = - new gfxImageSurface(aSurf->GetData(), - ThebesIntSize(aSurf->GetSize()), - aSurf->Stride(), - SurfaceFormatToImageFormat(aSurf->GetFormat())); nsCString string(aObj->Name()); string.Append('-'); string.AppendInt((uint64_t)aObj); if (gfxUtils::sDumpPaintFile) { fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading()); } - deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile); + gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile); if (gfxUtils::sDumpPaintFile) { fprintf_stderr(gfxUtils::sDumpPaintFile, "\";"); } diff --git a/gfx/layers/client/CompositableClient.cpp b/gfx/layers/client/CompositableClient.cpp index 70f031e6280b..a4eabd7b404d 100644 --- a/gfx/layers/client/CompositableClient.cpp +++ b/gfx/layers/client/CompositableClient.cpp @@ -55,6 +55,17 @@ public: uint64_t mAsyncID; }; +void +RemoveTextureFromCompositableTracker::ReleaseTextureClient() +{ + if (mTextureClient) { + TextureClientReleaseTask* task = new TextureClientReleaseTask(mTextureClient); + RefPtr allocator = mTextureClient->GetAllocator(); + mTextureClient = nullptr; + allocator->GetMessageLoop()->PostTask(FROM_HERE, task); + } +} + /* static */ void CompositableClient::TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId) { diff --git a/gfx/layers/client/CompositableClient.h b/gfx/layers/client/CompositableClient.h index 5308ca1fd5cd..6db2ad9e235a 100644 --- a/gfx/layers/client/CompositableClient.h +++ b/gfx/layers/client/CompositableClient.h @@ -42,22 +42,22 @@ public: ~RemoveTextureFromCompositableTracker() { MOZ_COUNT_DTOR(RemoveTextureFromCompositableTracker); + ReleaseTextureClient(); } virtual void Complete() MOZ_OVERRIDE { - // The TextureClient's recycling is postponed until the transaction - // complete. - mTextureClient = nullptr; + ReleaseTextureClient(); } virtual void Cancel() MOZ_OVERRIDE { - mTextureClient = nullptr; + ReleaseTextureClient(); } virtual void SetTextureClient(TextureClient* aTextureClient) MOZ_OVERRIDE { + ReleaseTextureClient(); mTextureClient = aTextureClient; } @@ -68,6 +68,9 @@ public: } } +protected: + void ReleaseTextureClient(); + private: RefPtr mTextureClient; }; diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 58c03e494ff7..cf5a96468b91 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -203,6 +203,7 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) MOZ_ASSERT(mActor); mActor->mForwarder = aForwarder; mActor->mTextureClient = this; + mAllocator = aForwarder; mShared = true; return mActor->IPCOpen(); } diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 4f5c23a8e938..14f16236c968 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -364,7 +364,13 @@ protected: mFlags |= aFlags; } + ISurfaceAllocator* GetAllocator() + { + return mAllocator; + } + RefPtr mActor; + RefPtr mAllocator; TextureFlags mFlags; bool mShared; bool mValid; @@ -372,10 +378,30 @@ protected: FenceHandle mAcquireFenceHandle; friend class TextureChild; + friend class RemoveTextureFromCompositableTracker; friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*); friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&); }; +/** + * Task that releases TextureClient pointer on a specified thread. + */ +class TextureClientReleaseTask : public Task +{ +public: + TextureClientReleaseTask(TextureClient* aClient) + : mTextureClient(aClient) { + } + + virtual void Run() MOZ_OVERRIDE + { + mTextureClient = nullptr; + } + +private: + mozilla::RefPtr mTextureClient; +}; + /** * TextureClient that wraps a random access buffer such as a Shmem or raw memory. * This class must be inherited to implement the memory allocation and access bits. diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index 9de4629eecb7..d42b309c5375 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -8,6 +8,7 @@ #include // for pair #include "ContentHost.h" // for ContentHostDoubleBuffered, etc #include "Effects.h" // for EffectMask, Effect, etc +#include "gfxUtils.h" #include "ImageHost.h" // for ImageHostBuffered, etc #include "TiledContentHost.h" // for TiledContentHost #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor @@ -227,12 +228,8 @@ CompositableHost::DumpTextureHost(std::stringstream& aStream, TextureHost* aText dSurf->GetSize(), dSurf->Stride(), dSurf->GetFormat()); - nsRefPtr surf = platform->GetThebesSurfaceForDrawTarget(dt); - if (!surf) { - return; - } // TODO stream surface - surf->DumpAsDataURL(stderr); + gfxUtils::DumpAsDataURI(dt, stderr); } #endif diff --git a/gfx/layers/ipc/ISurfaceAllocator.h b/gfx/layers/ipc/ISurfaceAllocator.h index ea50fddb3b6c..bad7be7cc80d 100644 --- a/gfx/layers/ipc/ISurfaceAllocator.h +++ b/gfx/layers/ipc/ISurfaceAllocator.h @@ -85,7 +85,9 @@ class ISurfaceAllocator : public AtomicRefCountedWithFinalize { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator) - ISurfaceAllocator() {} + ISurfaceAllocator() + : mDefaultMessageLoop(MessageLoop::current()) + {} void Finalize(); @@ -163,6 +165,11 @@ public: virtual bool IPCOpen() const { return true; } virtual bool IsSameProcess() const = 0; + virtual MessageLoop * GetMessageLoop() const + { + return mDefaultMessageLoop; + } + // Returns true if aSurface wraps a Shmem. static bool IsShmem(SurfaceDescriptor* aSurface); @@ -177,6 +184,8 @@ protected: // This is used to implement an extremely simple & naive heap allocator. std::vector mUsedShmems; + MessageLoop* mDefaultMessageLoop; + friend class AtomicRefCountedWithFinalize; }; diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 2f7ee5e19be8..124c9f773c4f 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -170,7 +170,7 @@ public: * * Can be called from any thread. */ - MessageLoop * GetMessageLoop() const; + virtual MessageLoop * GetMessageLoop() const MOZ_OVERRIDE; PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) MOZ_OVERRIDE; bool DeallocPCompositableChild(PCompositableChild* aActor) MOZ_OVERRIDE; diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index c4eb95c6264b..40920d559c23 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -261,7 +261,7 @@ ImageBridgeParent::RecvChildAsyncMessages(const InfallibleTArray imgsurf = GetAsImageSurface(); - nsIntSize size; - - // FIXME/bug 831898: hack r5g6b5 for now. - if (!imgsurf || imgsurf->Format() == gfxImageFormat::RGB16_565) { - size = GetSize(); - if (size.width == -1 && size.height == -1) { - printf("Could not determine surface size\n"); - return; - } - - imgsurf = - new gfxImageSurface(nsIntSize(size.width, size.height), - gfxImageFormat::ARGB32); - - if (!imgsurf || imgsurf->CairoStatus()) { - printf("Could not allocate image surface\n"); - return; - } - - nsRefPtr ctx = new gfxContext(imgsurf); - if (!ctx || ctx->HasError()) { - printf("Could not allocate image context\n"); - return; - } - - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(this, gfxPoint(0, 0)); - ctx->Paint(); - } - size = imgsurf->GetSize(); - - nsCOMPtr encoder = - do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png"); - if (!encoder) { - int32_t w = std::min(size.width, 8); - int32_t h = std::min(size.height, 8); - printf("Could not create encoder. Printing %dx%d pixels.\n", w, h); - for (int32_t y = 0; y < h; ++y) { - for (int32_t x = 0; x < w; ++x) { - printf("%x ", reinterpret_cast(imgsurf->Data())[y*imgsurf->Stride()+ x]); - } - } - return; - } - - nsresult rv = encoder->InitFromData(imgsurf->Data(), - size.width * size.height * 4, - size.width, - size.height, - imgsurf->Stride(), - imgIEncoder::INPUT_FORMAT_HOSTARGB, - NS_LITERAL_STRING("")); - if (NS_FAILED(rv)) - return; - - nsCOMPtr imgStream; - CallQueryInterface(encoder.get(), getter_AddRefs(imgStream)); - if (!imgStream) - return; - - uint64_t bufSize64; - rv = imgStream->Available(&bufSize64); - if (NS_FAILED(rv)) - return; - - if (bufSize64 > UINT32_MAX - 16) - return; - - uint32_t bufSize = (uint32_t)bufSize64; - - // ...leave a little extra room so we can call read again and make sure we - // got everything. 16 bytes for better padding (maybe) - bufSize += 16; - uint32_t imgSize = 0; - char* imgData = (char*)moz_malloc(bufSize); - if (!imgData) - return; - uint32_t numReadThisTime = 0; - while ((rv = imgStream->Read(&imgData[imgSize], - bufSize - imgSize, - &numReadThisTime)) == NS_OK && numReadThisTime > 0) - { - imgSize += numReadThisTime; - if (imgSize == bufSize) { - // need a bigger buffer, just double - bufSize *= 2; - char* newImgData = (char*)moz_realloc(imgData, bufSize); - if (!newImgData) { - moz_free(imgData); - return; - } - imgData = newImgData; - } - } - - if (aBinary) { - if (aFile) { - fwrite(imgData, 1, imgSize, aFile); - } else { - NS_WARNING("Can't write binary image data without a file!"); - } - return; - } - - // base 64, result will be null-terminated - nsCString encodedImg; - rv = Base64Encode(Substring(imgData, imgSize), encodedImg); - moz_free(imgData); - if (NS_FAILED(rv)) // not sure why this would fail - return; - - nsCString string("data:image/png;base64,"); - string.Append(encodedImg); - - if (aFile) { -#ifdef ANDROID - if (aFile == stdout || aFile == stderr) { - // ADB logcat cuts off long strings so we will break it down - const char* cStr = string.BeginReading(); - size_t len = strlen(cStr); - while (true) { - printf_stderr("IMG: %.140s\n", cStr); - if (len <= 140) - break; - len -= 140; - cStr += 140; - } - } -#endif - fprintf_stderr(aFile, "%s", string.BeginReading()); - } else { - nsCOMPtr clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv)); - if (clipboard) { - clipboard->CopyString(NS_ConvertASCIItoUTF16(string), nullptr); - } - } - - return; -} - void gfxASurface::SetOpaqueRect(const gfxRect& aRect) { diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index b8d7324c2419..3b3506dbb388 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -175,27 +175,6 @@ public: virtual const nsIntSize GetSize() const; - /** - * Debug functions to encode the current image as a PNG and export it. - */ - - /** - * Writes a binary PNG file. - */ - void WriteAsPNG(const char* aFile); - - /** - * Write as a PNG encoded Data URL to a file. - */ - void DumpAsDataURL(FILE* aOutput = stdout); - - /** - * Copy a PNG encoded Data URL to the clipboard. - */ - void CopyAsDataURL(); - - void WriteAsPNG_internal(FILE* aFile, bool aBinary); - void SetOpaqueRect(const gfxRect& aRect); const gfxRect& GetOpaqueRect() { diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index 19fc44b5eacb..16b3c9411f57 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -16,6 +16,7 @@ #include "gfxColor.h" #include "gfxMatrix.h" +#include "gfxUtils.h" #include "gfxASurface.h" #include "gfxPattern.h" #include "gfxPlatform.h" @@ -1957,34 +1958,31 @@ gfxContext::RoundedRectangle(const gfxRect& rect, #ifdef MOZ_DUMP_PAINTING void gfxContext::WriteAsPNG(const char* aFile) -{ - nsRefPtr surf = CurrentSurface(); - if (surf) { - surf->WriteAsPNG(aFile); +{ + if (mDT) { + gfxUtils::WriteAsPNG(mDT, aFile); } else { - NS_WARNING("No surface found!"); + NS_WARNING("No DrawTarget found!"); } } void -gfxContext::DumpAsDataURL() -{ - nsRefPtr surf = CurrentSurface(); - if (surf) { - surf->DumpAsDataURL(); +gfxContext::DumpAsDataURI() +{ + if (mDT) { + gfxUtils::DumpAsDataURI(mDT); } else { - NS_WARNING("No surface found!"); + NS_WARNING("No DrawTarget found!"); } } void -gfxContext::CopyAsDataURL() -{ - nsRefPtr surf = CurrentSurface(); - if (surf) { - surf->CopyAsDataURL(); +gfxContext::CopyAsDataURI() +{ + if (mDT) { + gfxUtils::CopyAsDataURI(mDT); } else { - NS_WARNING("No surface found!"); + NS_WARNING("No DrawTarget found!"); } } #endif diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index c551b369e780..02d540d1bd91 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -707,12 +707,12 @@ public: /** * Write as a PNG encoded Data URL to stdout. */ - void DumpAsDataURL(); + void DumpAsDataURI(); /** * Copy a PNG encoded Data URL to the clipboard. */ - void CopyAsDataURL(); + void CopyAsDataURI(); #endif static mozilla::gfx::UserDataKey sDontUseAsSourceKey; diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 9547a4e46f3b..b446bd8748e2 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -9,6 +9,7 @@ #include "mozilla/dom/ContentChild.h" #include "gfxAndroidPlatform.h" #include "mozilla/Omnijar.h" +#include "nsAutoPtr.h" #include "nsIInputStream.h" #include "nsNetUtil.h" #define gfxToolkitPlatform gfxAndroidPlatform @@ -1084,7 +1085,8 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive, uint32_t bufSize = item->RealSize(); // We use fallible allocation here; if there's not enough RAM, we'll simply // ignore the bundled fonts and fall back to the device's installed fonts. - nsAutoPtr buf(static_cast(moz_malloc(bufSize))); + static const fallible_t fallible = fallible_t(); + nsAutoArrayPtr buf(new (fallible) uint8_t[bufSize]); if (!buf) { return; } diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index 8fbc908b7c52..487efac812b7 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -876,16 +876,32 @@ gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject, return NS_OK; } +static bool +IgnorePrincipal(nsIURI *aURI) +{ + nsresult rv; + bool inherits = false; + rv = NS_URIChainHasFlags(aURI, + nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, + &inherits); + return NS_SUCCEEDED(rv) && inherits; +} + bool gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const { - bool equal; - if (NS_FAILED(mURI->Equals(aKey->mURI, &equal)) || !equal) { + bool result; + if (NS_FAILED(mURI->Equals(aKey->mURI, &result)) || !result) { return false; } - if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &equal)) || !equal) { - return false; + // For data: URIs, we don't care about the principal; otherwise, check it. + if (!IgnorePrincipal(mURI)) { + NS_ASSERTION(mPrincipal && aKey->mPrincipal, + "only data: URIs are allowed to omit the principal"); + if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &result)) || !result) { + return false; + } } if (mPrivate != aKey->mPrivate) { @@ -925,7 +941,16 @@ gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry) } gfxUserFontData *data = aFontEntry->mUserFontData; - sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry, + // For data: URIs, the principal is ignored; anyone who has the same + // data: URI is able to load it and get an equivalent font. + // Otherwise, the principal is used as part of the cache key. + nsIPrincipal *principal; + if (IgnorePrincipal(data->mURI)) { + principal = nullptr; + } else { + principal = data->mPrincipal; + } + sUserFonts->PutEntry(Key(data->mURI, principal, aFontEntry, data->mPrivate)); #ifdef DEBUG_USERFONT_CACHE @@ -965,7 +990,15 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI *aSrcURI, return nullptr; } - Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy, + // Ignore principal when looking up a data: URI. + nsIPrincipal *principal; + if (IgnorePrincipal(aSrcURI)) { + principal = nullptr; + } else { + principal = aPrincipal; + } + + Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, principal, aProxy, aPrivate)); if (entry) { return entry->GetFontEntry(); @@ -990,20 +1023,21 @@ gfxUserFontSet::UserFontCache::Entry::DumpEntry(Entry* aEntry, void* aUserData) { nsresult rv; - nsAutoCString principalURISpec; - - nsCOMPtr principalURI; - rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI)); - if (NS_SUCCEEDED(rv)) { - principalURI->GetSpec(principalURISpec); - } - + nsAutoCString principalURISpec("(null)"); bool setDomain = false; - nsCOMPtr domainURI; - aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI)); - if (domainURI) { - setDomain = true; + if (aEntry->mPrincipal) { + nsCOMPtr principalURI; + rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI)); + if (NS_SUCCEEDED(rv)) { + principalURI->GetSpec(principalURISpec); + } + + nsCOMPtr domainURI; + aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI)); + if (domainURI) { + setDomain = true; + } } NS_ASSERTION(aEntry->mURI, "null URI in userfont cache entry"); diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index f5068a8c4dbb..446e236ee88b 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -294,7 +294,7 @@ public: // entry and the corresponding "real" font entry. struct Key { nsCOMPtr mURI; - nsCOMPtr mPrincipal; + nsCOMPtr mPrincipal; // use nullptr with data: URLs gfxFontEntry *mFontEntry; bool mPrivate; @@ -333,8 +333,10 @@ public: static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } static PLDHashNumber HashKey(const KeyTypePointer aKey) { - uint32_t principalHash; - aKey->mPrincipal->GetHashValue(&principalHash); + uint32_t principalHash = 0; + if (aKey->mPrincipal) { + aKey->mPrincipal->GetHashValue(&principalHash); + } return mozilla::HashGeneric(principalHash + int(aKey->mPrivate), nsURIHashKey::HashKey(aKey->mURI), HashFeatures(aKey->mFontEntry->mFeatureSettings), @@ -365,7 +367,7 @@ public: } nsCOMPtr mURI; - nsCOMPtr mPrincipal; + nsCOMPtr mPrincipal; // or nullptr for data: URLs // The "real" font entry corresponding to this downloaded font. // The font entry MUST notify the cache when it is destroyed diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 78637a85940a..7e45e7a61288 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -10,9 +10,19 @@ #include "gfxImageSurface.h" #include "gfxPlatform.h" #include "gfxDrawable.h" +#include "imgIEncoder.h" +#include "mozilla/Base64.h" #include "mozilla/gfx/2D.h" +#include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/RefPtr.h" +#include "mozilla/Vector.h" +#include "nsComponentManagerUtils.h" +#include "nsIClipboardHelper.h" +#include "nsIFile.h" +#include "nsIPresShell.h" +#include "nsPresContext.h" #include "nsRegion.h" +#include "nsServiceManagerUtils.h" #include "yuv_convert.h" #include "ycbcr_to_rgb565.h" #include "GeckoProfiler.h" @@ -1105,83 +1115,258 @@ gfxUtils::GetColorForFrameNumber(uint64_t aFrameNumber) return colors[aFrameNumber % sNumFrameColors]; } -#ifdef MOZ_DUMP_PAINTING +/* static */ nsresult +gfxUtils::EncodeSourceSurface(SourceSurface* aSurface, + const nsACString& aMimeType, + const nsAString& aOutputOptions, + BinaryOrData aBinaryOrData, + FILE* aFile) +{ + MOZ_ASSERT(aBinaryOrData == eDataURIEncode || aFile, + "Copying binary encoding to clipboard not currently supported"); + + const IntSize size = aSurface->GetSize(); + if (size.IsEmpty()) { + return NS_ERROR_INVALID_ARG; + } + const Size floatSize(size.width, size.height); + + RefPtr dataSurface; + if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { + // FIXME bug 995807 (B8G8R8X8), bug 831898 (R5G6B5) + dataSurface = + CopySurfaceToDataSourceSurfaceWithFormat(aSurface, + SurfaceFormat::B8G8R8A8); + } else { + dataSurface = aSurface->GetDataSurface(); + } + if (!dataSurface) { + return NS_ERROR_FAILURE; + } + + DataSourceSurface::MappedSurface map; + if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) { + return NS_ERROR_FAILURE; + } + + nsAutoCString encoderCID( + NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType); + nsCOMPtr encoder = do_CreateInstance(encoderCID.get()); + if (!encoder) { +#ifdef DEBUG + int32_t w = std::min(size.width, 8); + int32_t h = std::min(size.height, 8); + printf("Could not create encoder. Top-left %dx%d pixels contain:\n", w, h); + for (int32_t y = 0; y < h; ++y) { + for (int32_t x = 0; x < w; ++x) { + printf("%x ", reinterpret_cast(map.mData)[y*map.mStride+x]); + } + } +#endif + dataSurface->Unmap(); + return NS_ERROR_FAILURE; + } + + nsresult rv = encoder->InitFromData(map.mData, + BufferSizeFromStrideAndHeight(map.mStride, size.height), + size.width, + size.height, + map.mStride, + imgIEncoder::INPUT_FORMAT_HOSTARGB, + aOutputOptions); + dataSurface->Unmap(); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr imgStream; + CallQueryInterface(encoder.get(), getter_AddRefs(imgStream)); + if (!imgStream) { + return NS_ERROR_FAILURE; + } + + uint64_t bufSize64; + rv = imgStream->Available(&bufSize64); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ENSURE_TRUE(bufSize64 < UINT32_MAX - 16, NS_ERROR_FAILURE); + + uint32_t bufSize = (uint32_t)bufSize64; + + // ...leave a little extra room so we can call read again and make sure we + // got everything. 16 bytes for better padding (maybe) + bufSize += 16; + uint32_t imgSize = 0; + Vector imgData; + if (!imgData.initCapacity(bufSize)) { + return NS_ERROR_OUT_OF_MEMORY; + } + uint32_t numReadThisTime = 0; + while ((rv = imgStream->Read(imgData.begin() + imgSize, + bufSize - imgSize, + &numReadThisTime)) == NS_OK && numReadThisTime > 0) + { + imgSize += numReadThisTime; + if (imgSize == bufSize) { + // need a bigger buffer, just double + bufSize *= 2; + if (!imgData.resizeUninitialized(bufSize)) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + } + + if (aBinaryOrData == eBinaryEncode) { + if (aFile) { + fwrite(imgData.begin(), 1, imgSize, aFile); + } + return NS_OK; + } + + // base 64, result will be null-terminated + nsCString encodedImg; + rv = Base64Encode(Substring(imgData.begin(), imgSize), encodedImg); + NS_ENSURE_SUCCESS(rv, rv); + + nsCString string("data:"); + string.Append(aMimeType); + string.Append(";base64,"); + string.Append(encodedImg); + + if (aFile) { +#ifdef ANDROID + if (aFile == stdout || aFile == stderr) { + // ADB logcat cuts off long strings so we will break it down + const char* cStr = string.BeginReading(); + size_t len = strlen(cStr); + while (true) { + printf_stderr("IMG: %.140s\n", cStr); + if (len <= 140) + break; + len -= 140; + cStr += 140; + } + } +#endif + fprintf(aFile, "%s", string.BeginReading()); + } else { + nsCOMPtr clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv)); + if (clipboard) { + clipboard->CopyString(NS_ConvertASCIItoUTF16(string), nullptr); + } + } + return NS_OK; +} + +/* static */ void +gfxUtils::WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile) +{ + WriteAsPNG(aSurface, NS_ConvertUTF16toUTF8(aFile).get()); +} + +/* static */ void +gfxUtils::WriteAsPNG(SourceSurface* aSurface, const char* aFile) +{ + FILE* file = fopen(aFile, "wb"); + + if (!file) { + // Maybe the directory doesn't exist; try creating it, then fopen again. + nsresult rv = NS_ERROR_FAILURE; + nsCOMPtr comFile = do_CreateInstance("@mozilla.org/file/local;1"); + if (comFile) { + NS_ConvertUTF8toUTF16 utf16path((nsDependentCString(aFile))); + rv = comFile->InitWithPath(utf16path); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr dirPath; + comFile->GetParent(getter_AddRefs(dirPath)); + if (dirPath) { + rv = dirPath->Create(nsIFile::DIRECTORY_TYPE, 0777); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_FILE_ALREADY_EXISTS) { + file = fopen(aFile, "wb"); + } + } + } + } + if (!file) { + NS_WARNING("Failed to open file to create PNG!\n"); + return; + } + } + + EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"), + EmptyString(), eBinaryEncode, file); + fclose(file); +} + +/* static */ void +gfxUtils::WriteAsPNG(DrawTarget* aDT, const nsAString& aFile) +{ + WriteAsPNG(aDT, NS_ConvertUTF16toUTF8(aFile).get()); +} + /* static */ void gfxUtils::WriteAsPNG(DrawTarget* aDT, const char* aFile) { - aDT->Flush(); - nsRefPtr surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT); - if (surf) { - surf->WriteAsPNG(aFile); + RefPtr surface = aDT->Snapshot(); + if (surface) { + WriteAsPNG(surface, aFile); } else { - NS_WARNING("Failed to get Thebes surface!"); + NS_WARNING("Failed to get surface!"); } } /* static */ void -gfxUtils::DumpAsDataURL(DrawTarget* aDT) +gfxUtils::WriteAsPNG(nsIPresShell* aShell, const char* aFile) { - aDT->Flush(); - nsRefPtr surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT); - if (surf) { - surf->DumpAsDataURL(); + int32_t width = 1000, height = 1000; + nsRect r(0, 0, aShell->GetPresContext()->DevPixelsToAppUnits(width), + aShell->GetPresContext()->DevPixelsToAppUnits(height)); + + RefPtr dt = gfxPlatform::GetPlatform()-> + CreateOffscreenContentDrawTarget(IntSize(width, height), + SurfaceFormat::B8G8R8A8); + NS_ENSURE_TRUE(dt, /*void*/); + + nsRefPtr context = new gfxContext(dt); + aShell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context); + WriteAsPNG(dt.get(), aFile); +} + +/* static */ void +gfxUtils::DumpAsDataURI(SourceSurface* aSurface, FILE* aFile) +{ + EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"), + EmptyString(), eDataURIEncode, aFile); +} + +/* static */ void +gfxUtils::DumpAsDataURI(DrawTarget* aDT, FILE* aFile) +{ + RefPtr surface = aDT->Snapshot(); + if (surface) { + DumpAsDataURI(surface, aFile); } else { - NS_WARNING("Failed to get Thebes surface!"); + NS_WARNING("Failed to get surface!"); } } /* static */ void -gfxUtils::CopyAsDataURL(DrawTarget* aDT) +gfxUtils::CopyAsDataURI(SourceSurface* aSurface) { - aDT->Flush(); - nsRefPtr surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT); - if (surf) { - surf->CopyAsDataURL(); + EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"), + EmptyString(), eDataURIEncode, nullptr); +} + +/* static */ void +gfxUtils::CopyAsDataURI(DrawTarget* aDT) +{ + RefPtr surface = aDT->Snapshot(); + if (surface) { + CopyAsDataURI(surface); } else { - NS_WARNING("Failed to get Thebes surface!"); + NS_WARNING("Failed to get surface!"); } } -/* static */ void -gfxUtils::WriteAsPNG(gfx::SourceSurface* aSourceSurface, const char* aFile) -{ - RefPtr dataSurface = aSourceSurface->GetDataSurface(); - RefPtr dt - = gfxPlatform::GetPlatform() - ->CreateDrawTargetForData(dataSurface->GetData(), - dataSurface->GetSize(), - dataSurface->Stride(), - aSourceSurface->GetFormat()); - gfxUtils::WriteAsPNG(dt.get(), aFile); -} - -/* static */ void -gfxUtils::DumpAsDataURL(gfx::SourceSurface* aSourceSurface) -{ - RefPtr dataSurface = aSourceSurface->GetDataSurface(); - RefPtr dt - = gfxPlatform::GetPlatform() - ->CreateDrawTargetForData(dataSurface->GetData(), - dataSurface->GetSize(), - dataSurface->Stride(), - aSourceSurface->GetFormat()); - gfxUtils::DumpAsDataURL(dt.get()); -} - -/* static */ void -gfxUtils::CopyAsDataURL(gfx::SourceSurface* aSourceSurface) -{ - RefPtr dataSurface = aSourceSurface->GetDataSurface(); - RefPtr dt - = gfxPlatform::GetPlatform() - ->CreateDrawTargetForData(dataSurface->GetData(), - dataSurface->GetSize(), - dataSurface->Stride(), - aSourceSurface->GetFormat()); - - gfxUtils::CopyAsDataURL(dt.get()); -} - +#ifdef MOZ_DUMP_PAINTING static bool sDumpPaintList = getenv("MOZ_DUMP_PAINT_LIST") != 0; /* static */ bool diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 222347121e7e..8b823bb84dc5 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -16,6 +16,8 @@ class gfxASurface; class gfxDrawable; class nsIntRegion; +class nsIPresShell; + struct nsIntRect; namespace mozilla { @@ -27,6 +29,7 @@ struct PlanarYCbCrData; class gfxUtils { public: typedef mozilla::gfx::DataSourceSurface DataSourceSurface; + typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::IntPoint IntPoint; typedef mozilla::gfx::Matrix Matrix; typedef mozilla::gfx::SourceSurface SourceSurface; @@ -228,45 +231,78 @@ public: static const mozilla::gfx::Color& GetColorForFrameNumber(uint64_t aFrameNumber); static const uint32_t sNumFrameColors; + + enum BinaryOrData { + eBinaryEncode, + eDataURIEncode + }; + + /** + * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder. + * + * @param aMimeType The MIME-type of the image type that the surface is to + * be encoded to. Used to create an appropriate imgIEncoder instance to + * do the encoding. + * + * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as + * the value of the |outputOptions| parameter. Callers are responsible + * for making sure that this is a sane value for the passed MIME-type + * (i.e. for the type of encoder that will be created). + * + * @aBinaryOrData Flag used to determine if the surface is simply encoded + * to the requested binary image format, or if the binary image is + * further converted to base-64 and written out as a 'data:' URI. + * + * @aFile If specified, the encoded data is written out to aFile, otherwise + * it is copied to the clipboard. + * + * TODO: Copying to the clipboard as a binary file is not currently + * supported. + */ + static nsresult + EncodeSourceSurface(SourceSurface* aSurface, + const nsACString& aMimeType, + const nsAString& aOutputOptions, + BinaryOrData aBinaryOrData, + FILE* aFile); + + /** + * Write as a PNG file to the path aFile. + */ + static void WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile); + static void WriteAsPNG(SourceSurface* aSurface, const char* aFile); + static void WriteAsPNG(DrawTarget* aDT, const nsAString& aFile); + static void WriteAsPNG(DrawTarget* aDT, const char* aFile); + static void WriteAsPNG(nsIPresShell* aShell, const char* aFile); + + /** + * Dump as a PNG encoded Data URL to a FILE stream (using stdout by + * default). + * + * Rather than giving aFile a default argument we have separate functions + * to make them easier to use from a debugger. + */ + static void DumpAsDataURI(SourceSurface* aSourceSurface, FILE* aFile); + static inline void DumpAsDataURI(SourceSurface* aSourceSurface) { + DumpAsDataURI(aSourceSurface, stdout); + } + static void DumpAsDataURI(DrawTarget* aDT, FILE* aFile); + static inline void DumpAsDataURI(DrawTarget* aDT) { + DumpAsDataURI(aDT, stdout); + } + + /** + * Copy to the clipboard as a PNG encoded Data URL. + */ + static void CopyAsDataURI(SourceSurface* aSourceSurface); + static void CopyAsDataURI(DrawTarget* aDT); + #ifdef MOZ_DUMP_PAINTING - /** - * Writes a binary PNG file. - */ - static void WriteAsPNG(mozilla::gfx::DrawTarget* aDT, const char* aFile); - - /** - * Write as a PNG encoded Data URL to stdout. - */ - static void DumpAsDataURL(mozilla::gfx::DrawTarget* aDT); - - /** - * Copy a PNG encoded Data URL to the clipboard. - */ - static void CopyAsDataURL(mozilla::gfx::DrawTarget* aDT); - static bool DumpPaintList(); static bool sDumpPainting; static bool sDumpPaintingToFile; static FILE* sDumpPaintFile; - - /** - * Writes a binary PNG file. - * Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads - */ - static void WriteAsPNG(mozilla::gfx::SourceSurface* aSourceSurface, const char* aFile); - - /** - * Write as a PNG encoded Data URL to stdout. - * Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads - */ - static void DumpAsDataURL(mozilla::gfx::SourceSurface* aSourceSurface); - - /** - * Copy a PNG encoded Data URL to the clipboard. - * Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads - */ - static void CopyAsDataURL(mozilla::gfx::SourceSurface* aSourceSurface); #endif }; diff --git a/js/jsd/README b/js/jsd/README deleted file mode 100644 index 25295a8a14b3..000000000000 --- a/js/jsd/README +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 4c5b22304856..000000000000 --- a/js/jsd/idl/jsdIDebuggerService.idl +++ /dev/null @@ -1,1233 +0,0 @@ -/* -*- 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. - * - * Note that all the APIs in this file are deprecated. All consumers of - * these interfaces should switch to using the new Debugger API, documented - * here: https://wiki.mozilla.org/Debugger - */ -[scriptable, uuid(39609752-2d73-4019-a324-a374dee16d3c)] -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); - - /** - * Suppress console warnings about using JSD, which is a deprecated API. - * - * This applies only to the next call to asyncOn; any subsequent calls - * will elicit the warning, unless you call 'acknowledgeDeprecation' - * before each of them, too. This arrangement ensures that one add-on's - * acknowledgement doesn't suppress warnings for other add-ons. - */ - void acknowledgeDeprecation(); -}; - -/* 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 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 deleted file mode 100644 index 9127dba1bad7..000000000000 --- a/js/jsd/idl/moz.build +++ /dev/null @@ -1,12 +0,0 @@ -# -*- 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' - diff --git a/js/jsd/jsd.h b/js/jsd/jsd.h deleted file mode 100644 index 10fadec9e2ef..000000000000 --- a/js/jsd/jsd.h +++ /dev/null @@ -1,1054 +0,0 @@ -/* -*- 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 "jsapi.h" -#include "jshash.h" -#include "jsclist.h" -#include "jsdebug.h" -#include "js/OldDebugAPI.h" -#include "jsd_lock.h" - -#include -#include -#include - -#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 */ - bool 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; - JS::Heap 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; -}; - -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; - bool dirty; - JSDSourceStatus status; - unsigned alterCount; - bool 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 -{ - JS::Heap val; - int nref; - JSCList props; - JS::Heap string; - JS::Heap 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, bool 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 bool -jsd_SetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter reporter, - void* callerdata); - -extern bool -jsd_GetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter* reporter, - void** callerdata); - -/***************************************************************************/ -/* Script functions */ - -extern bool -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 bool -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 bool -jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata); - -extern bool -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 bool -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 bool -jsd_SetExecutionHook(JSDContext* jsdc, - JSDScript* jsdscript, - uintptr_t pc, - JSD_ExecutionHookProc hook, - void* callerdata); - -extern bool -jsd_ClearExecutionHook(JSDContext* jsdc, - JSDScript* jsdscript, - uintptr_t pc); - -extern bool -jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript); - -extern bool -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 bool -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 bool -jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc); - -extern void -jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, bool 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 bool -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 bool -jsd_SetInterruptHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); - -extern bool -jsd_ClearInterruptHook(JSDContext* jsdc); - -extern bool -jsd_EnableSingleStepInterrupts(JSDContext* jsdc, - JSDScript* jsdscript, - bool enable); - -extern bool -jsd_SetDebugBreakHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); - -extern bool -jsd_ClearDebugBreakHook(JSDContext* jsdc); - -extern bool -jsd_SetDebuggerHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); - -extern bool -jsd_ClearDebuggerHook(JSDContext* jsdc); - -extern JSTrapStatus -jsd_CallExecutionHook(JSDContext* jsdc, - JSContext* cx, - unsigned type, - JSD_ExecutionHookProc hook, - void* hookData, - jsval* rval); - -extern bool -jsd_CallCallHook (JSDContext* jsdc, - JSContext* cx, - unsigned type, - JSD_CallHookProc hook, - void* hookData); - -extern bool -jsd_SetThrowHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); -extern bool -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 bool -jsd_SetFunctionHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata); - -extern bool -jsd_ClearFunctionHook(JSDContext* jsdc); - -extern bool -jsd_SetTopLevelHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata); - -extern bool -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 bool -jsd_IsStackFrameDebugger(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe); - -extern bool -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 bool -jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe, - const jschar *bytes, unsigned length, - const char *filename, unsigned lineno, - bool eatExceptions, JS::MutableHandleValue rval); - -extern bool -jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe, - const char *bytes, unsigned length, - const char *filename, unsigned lineno, - bool eatExceptions, JS::MutableHandleValue rval); - -extern JSString* -jsd_ValToStringInStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe, - jsval val); - -extern bool -jsd_IsValidThreadState(JSDContext* jsdc, - JSDThreadState* jsdthreadstate); - -extern bool -jsd_IsValidFrameInThreadState(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe); - -extern JSDValue* -jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate); - -extern bool -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(); \ - MOZ_ASSERT(_jsd_global_lock); \ - jsd_Lock(_jsd_global_lock); \ - JS_END_MACRO - -#define JSD_UNLOCK() \ - JS_BEGIN_MACRO \ - MOZ_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) \ - ( (nullptr != (jsdc->scriptsLock = jsd_CreateLock())) && \ - (nullptr != (jsdc->sourceTextLock = jsd_CreateLock())) && \ - (nullptr != (jsdc->atomsLock = jsd_CreateLock())) && \ - (nullptr != (jsdc->objectsLock = jsd_CreateLock())) && \ - (nullptr != (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 bool -jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval); - -extern bool -jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval); - -/**************************************************/ - -extern bool -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, - bool before, bool *ok, void *closure); - -extern void * -jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, - bool before, bool *ok, void *closure); - -/**************************************************/ -/* Object Functions */ - -extern bool -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 bool -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; -}; - -#endif /* jsd_h___ */ diff --git a/js/jsd/jsd1640.def b/js/jsd/jsd1640.def deleted file mode 100644 index 48af380c898f..000000000000 --- a/js/jsd/jsd1640.def +++ /dev/null @@ -1,77 +0,0 @@ -; -*- 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 deleted file mode 100644 index 7c3cf55a2936..000000000000 --- a/js/jsd/jsd1640.rc +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- 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 - -#include - - - -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 deleted file mode 100644 index 5b2bc342eaab..000000000000 --- a/js/jsd/jsd3240.rc +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- 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 deleted file mode 100644 index a68ebbb25a99..000000000000 --- a/js/jsd/jsd_atom.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- 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) -{ - MOZ_ASSERT(he); - MOZ_ASSERT(he->value); - MOZ_ASSERT(((JSDAtom*)(he->value))->str); - - free(((JSDAtom*)(he->value))->str); - free(he->value); - he->value = nullptr; - he->key = nullptr; - 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); -} - - -bool -jsd_CreateAtomTable(JSDContext* jsdc) -{ - jsdc->atoms = JS_NewHashTable(256, JS_HashString, - _compareAtomKeys, _compareAtoms, - nullptr, nullptr); -#ifdef TEST_ATOMS - _testAtoms(jsdc); -#endif - return !!jsdc->atoms; -} - -void -jsd_DestroyAtomTable(JSDContext* jsdc) -{ - if( jsdc->atoms ) - { - JS_HashTableEnumerateEntries(jsdc->atoms, _atom_smasher, nullptr); - JS_HashTableDestroy(jsdc->atoms); - jsdc->atoms = nullptr; - } -} - -JSDAtom* -jsd_AddAtom(JSDContext* jsdc, const char* str) -{ - JSDAtom* atom; - - if(!str) - { - MOZ_ASSERT(0); - return nullptr; - } - - 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 = nullptr; - } - } - } - - 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 deleted file mode 100644 index ed156389eb5a..000000000000 --- a/js/jsd/jsd_high.cpp +++ /dev/null @@ -1,415 +0,0 @@ -/* -*- 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" - -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 = nullptr; -static JSRuntime* _jsrt = nullptr; - -#ifdef JSD_HAS_DANGEROUS_THREAD -static void* _dangerousThread = nullptr; -#endif - -#ifdef JSD_THREADSAFE -JSDStaticLock* _jsd_global_lock = nullptr; -#endif - -#ifdef DEBUG -void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc) -{ - MOZ_ASSERT(jsdc->inited); - MOZ_ASSERT(jsdc->jsrt); - MOZ_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, const JSClass *clasp); - -/***************************************************************************/ - - -static const 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, - nullptr, nullptr, nullptr, - JS_GlobalObjectTraceHook -}; - -static bool -_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 = nullptr; - bool ok = true; - AutoSafeJSContext cx; - - if( ! jsrt ) - return nullptr; - - if( ! _validateUserCallbacks(callbacks) ) - return nullptr; - - 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; - - { - JS::RootedObject global(cx, CreateJSDGlobal(cx, &global_class)); - if( ! global ) - goto label_newJSDContext_failure; - - jsdc->glob = global; - - JSAutoCompartment ac(cx, jsdc->glob); - ok = JS::AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") && - JS_InitStandardClasses(cx, global); - } - if( ! ok ) - goto label_newJSDContext_failure; - - jsdc->data = nullptr; - jsdc->inited = 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 nullptr; -} - -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 = 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 nullptr; - - /* - * 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); - - if( jsdc->userCallbacks.setContext ) - jsdc->userCallbacks.setContext(jsdc, jsdc->user); - return jsdc; -} - -JSDContext* -jsd_DebuggerOn(void) -{ - MOZ_ASSERT(_jsrt); - MOZ_ASSERT(_validateUserCallbacks(&_callbacks)); - return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, nullptr); -} - -void -jsd_DebuggerOff(JSDContext* jsdc) -{ - jsd_DebuggerPause(jsdc, true); - /* clear hooks here */ - JS_SetNewScriptHookProc(jsdc->jsrt, nullptr, nullptr); - JS_SetDestroyScriptHookProc(jsdc->jsrt, nullptr, nullptr); - - /* clean up */ - JSD_LockScriptSubsystem(jsdc); - jsd_DestroyScriptManager(jsdc); - JSD_UnlockScriptSubsystem(jsdc); - jsd_DestroyAllSources(jsdc); - - _destroyJSDContext(jsdc); - - if( jsdc->userCallbacks.setContext ) - jsdc->userCallbacks.setContext(nullptr, jsdc->user); -} - -void -jsd_DebuggerPause(JSDContext* jsdc, bool forceAllHooksOff) -{ - JS_SetDebuggerHandler(jsdc->jsrt, nullptr, nullptr); - if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) { - JS_SetExecuteHook(jsdc->jsrt, nullptr, nullptr); - JS_SetCallHook(jsdc->jsrt, nullptr, nullptr); - } - JS_SetThrowHook(jsdc->jsrt, nullptr, nullptr); - JS_SetDebugErrorHook(jsdc->jsrt, nullptr, nullptr); -} - -static bool -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 = nullptr; - 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 bool -jsd_DebugErrorHook(JSContext *cx, const char *message, - JSErrorReport *report, void *closure) -{ - JSDContext* jsdc = (JSDContext*) closure; - JSD_ErrorReporter errorReporter; - void* errorReporterData; - - if( ! jsdc ) - { - MOZ_ASSERT(0); - return true; - } - if( JSD_IS_DANGEROUS_THREAD(jsdc) ) - return true; - - /* local in case hook gets cleared on another thread */ - JSD_LOCK(); - errorReporter = jsdc->errorReporter; - errorReporterData = jsdc->errorReporterData; - JSD_UNLOCK(); - - if(!errorReporter) - return true; - - switch(errorReporter(jsdc, cx, message, report, errorReporterData)) - { - case JSD_ERROR_REPORTER_PASS_ALONG: - return true; - case JSD_ERROR_REPORTER_RETURN: - return false; - case JSD_ERROR_REPORTER_DEBUG: - { - JS::RootedValue rval(cx); - 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.address()); - /* XXX Should make this dependent on ExecutionHook retval */ - return true; - } - case JSD_ERROR_REPORTER_CLEAR_RETURN: - if(report && JSREPORT_IS_EXCEPTION(report->flags)) - JS_ClearPendingException(cx); - return false; - default: - MOZ_ASSERT(0); - break; - } - return true; -} - -bool -jsd_SetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter reporter, - void* callerdata) -{ - JSD_LOCK(); - jsdc->errorReporter = reporter; - jsdc->errorReporterData = callerdata; - JSD_UNLOCK(); - return true; -} - -bool -jsd_GetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter* reporter, - void** callerdata) -{ - JSD_LOCK(); - if( reporter ) - *reporter = jsdc->errorReporter; - if( callerdata ) - *callerdata = jsdc->errorReporterData; - JSD_UNLOCK(); - return true; -} diff --git a/js/jsd/jsd_hook.cpp b/js/jsd/jsd_hook.cpp deleted file mode 100644 index d7157e4b7bdc..000000000000 --- a/js/jsd/jsd_hook.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* -*- 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; - - 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 *rvalArg, 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::RootedValue rval(cx); - JS_GetPendingException(cx, &rval); - - JSTrapStatus result = jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_THROW, - hook, hookData, rval.address()); - *rvalArg = rval; - return result; -} - -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 && nullptr != (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) */ - MOZ_ASSERT(JSD_HOOK_THROW == type); - return JSTRAP_THROW; - default: - MOZ_ASSERT(0); - break; - } - return JSTRAP_CONTINUE; -} - -bool -jsd_CallCallHook (JSDContext* jsdc, - JSContext *cx, - unsigned type, - JSD_CallHookProc hook, - void* hookData) -{ - bool hookanswer; - JSDThreadState* jsdthreadstate; - - hookanswer = false; - if(hook && nullptr != (jsdthreadstate = jsd_NewThreadState(jsdc, cx))) - { - hookanswer = hook(jsdc, jsdthreadstate, type, hookData); - jsd_DestroyThreadState(jsdc, jsdthreadstate); - } - - return hookanswer; -} - -bool -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 true; -} - -bool -jsd_ClearInterruptHook(JSDContext* jsdc) -{ - JSD_LOCK(); - JS_ClearInterrupt(jsdc->jsrt, nullptr, nullptr); - jsdc->interruptHook = nullptr; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_SetDebugBreakHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_LOCK(); - jsdc->debugBreakHookData = callerdata; - jsdc->debugBreakHook = hook; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_ClearDebugBreakHook(JSDContext* jsdc) -{ - JSD_LOCK(); - jsdc->debugBreakHook = nullptr; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_SetDebuggerHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_LOCK(); - jsdc->debuggerHookData = callerdata; - jsdc->debuggerHook = hook; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_ClearDebuggerHook(JSDContext* jsdc) -{ - JSD_LOCK(); - jsdc->debuggerHook = nullptr; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_SetThrowHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_LOCK(); - jsdc->throwHookData = callerdata; - jsdc->throwHook = hook; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_ClearThrowHook(JSDContext* jsdc) -{ - JSD_LOCK(); - jsdc->throwHook = nullptr; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_SetFunctionHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata) -{ - JSD_LOCK(); - jsdc->functionHookData = callerdata; - jsdc->functionHook = hook; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_ClearFunctionHook(JSDContext* jsdc) -{ - JSD_LOCK(); - jsdc->functionHook = nullptr; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_SetTopLevelHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata) -{ - JSD_LOCK(); - jsdc->toplevelHookData = callerdata; - jsdc->toplevelHook = hook; - JSD_UNLOCK(); - - return true; -} - -bool -jsd_ClearTopLevelHook(JSDContext* jsdc) -{ - JSD_LOCK(); - jsdc->toplevelHook = nullptr; - JSD_UNLOCK(); - - return true; -} - diff --git a/js/jsd/jsd_lock.cpp b/js/jsd/jsd_lock.cpp deleted file mode 100644 index decab79e3389..000000000000 --- a/js/jsd/jsd_lock.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- 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, \ - nullptr); \ - MOZ_ASSERT(out); \ -JS_END_MACRO -#else -#define _CURRENT_THREAD(out) \ -JS_BEGIN_MACRO \ - out = (void*) PR_GetCurrentThread(); \ - MOZ_ASSERT(out); \ -JS_END_MACRO -#endif - -#ifdef DEBUG -#define JSD_LOCK_SIG 0x10CC10CC -void ASSERT_VALID_LOCK(JSDStaticLock* lock) -{ - MOZ_ASSERT(lock); - MOZ_ASSERT(lock->lock); - MOZ_ASSERT(lock->count >= 0); - MOZ_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()) || - ! (lock->lock = PR_NewLock()) ) - { - if(lock) - { - free(lock); - lock = nullptr; - } - } -#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++; - MOZ_ASSERT(lock->count > 1); - } - else - { - PR_Lock(lock->lock); /* this can block... */ - MOZ_ASSERT(lock->owner == 0); - MOZ_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 */ - MOZ_ASSERT(lock->owner == me); - if(lock->owner != me) - return; - - if(--lock->count == 0) - { - lock->owner = nullptr; - PR_Unlock(lock->lock); - } -} - -#ifdef DEBUG -bool -jsd_IsLocked(JSDStaticLock* lock) -{ - void* me; - ASSERT_VALID_LOCK(lock); - _CURRENT_THREAD(me); - if (lock->owner != me) - return false; - MOZ_ASSERT(lock->count > 0); - return 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 -bool -jsd_IsLocked(void* lock) -{ - return 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 deleted file mode 100644 index 4b0ac0838d46..000000000000 --- a/js/jsd/jsd_lock.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- 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 bool -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 deleted file mode 100644 index 4de336720c10..000000000000 --- a/js/jsd/jsd_obj.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- 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) -{ - MOZ_ASSERT(jsdobj); - MOZ_ASSERT(!JS_CLIST_IS_EMPTY(&jsdobj->links)); - MOZ_ASSERT(jsdobj->obj); -} -#endif - - -static void -_destroyJSDObject(JSDContext* jsdc, JSDObject* jsdobj) -{ - MOZ_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(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 */ -} - -bool -jsd_InitObjectManager(JSDContext* jsdc) -{ - JS_INIT_CLIST(&jsdc->objectsList); - jsdc->objectsTable = JS_NewHashTable(256, _hash_root, - JS_CompareValues, JS_CompareValues, - nullptr, nullptr); - 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; - - MOZ_ASSERT(JSD_OBJECTS_LOCKED(jsdc)); - - if( !jsdobj ) - jsdobj = (JSDObject *)jsdc->objectsList.next; - if( jsdobj == (JSDObject *)&jsdc->objectsList ) - return nullptr; - *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 nullptr; -} - -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 nullptr; -} - -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 nullptr; -} - -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, jsdval->val.toObjectOrNull()); -} - -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 deleted file mode 100644 index 995ccbeb445e..000000000000 --- a/js/jsd/jsd_scpt.cpp +++ /dev/null @@ -1,883 +0,0 @@ -/* -*- 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) -{ - MOZ_ASSERT(jsdscript); - MOZ_ASSERT(jsdscript->script); -} -void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook) -{ - MOZ_ASSERT(jsdhook); - MOZ_ASSERT(jsdhook->hook); -} -#endif - -static JSDScript* -_newJSDScript(JSDContext* jsdc, - JSContext *cx, - JSScript *script_) -{ - JS::RootedScript script(cx, script_); - if ( JS_GetScriptIsSelfHosted(script) ) - return nullptr; - - JSDScript* jsdscript; - unsigned lineno; - const char* raw_filename; - - MOZ_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 nullptr; - - jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript)); - if( ! jsdscript ) - return nullptr; - - raw_filename = JS_GetScriptFilename(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 = nullptr; - jsdscript->url = (char*) jsd_BuildNormalizedURL(raw_filename); - - JS_INIT_CLIST(&jsdscript->hooks); - - return jsdscript; -} - -static void -_destroyJSDScript(JSDContext* jsdc, - JSDScript* jsdscript) -{ - MOZ_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, - MOZ_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 = nullptr; - JSDScript* jsdscript = nullptr; - - OutputDebugString( "*** JSDScriptDump\n" ); - while( nullptr != (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 const 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 - -bool -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 ) -{ - MOZ_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; - MOZ_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 = nullptr; - } -} - -JSScript * -jsd_GetJSScript (JSDContext *jsdc, JSDScript *script) -{ - return script->script; -} - -JSFunction * -jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script) -{ - AutoSafeJSContext cx; - return JS_GetScriptFunction(cx, script->script); -} - -JSDScript* -jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp) -{ - JSDScript *jsdscript = *iterp; - - MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); - - if( !jsdscript ) - jsdscript = (JSDScript *)jsdc->scripts.next; - if( jsdscript == (JSDScript *)&jsdc->scripts ) - return nullptr; - *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; -} - -bool -jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript) -{ - JSDScript *current; - - MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); - - for( current = (JSDScript *)jsdc->scripts.next; - current != (JSDScript *)&jsdc->scripts; - current = (JSDScript *)current->links.next ) - { - if(jsdscript == current) - return true; - } - return 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 nullptr; - 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; - - 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; - - return line; -} - -bool -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; - bool ok; - jsbytecode **pcs; - unsigned i; - - if (last < startLine) - return 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; -} - -bool -jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata) -{ - JSD_LOCK(); - jsdc->scriptHook = hook; - jsdc->scriptHookData = callerdata; - JSD_UNLOCK(); - return true; -} - -bool -jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata) -{ - JSD_LOCK(); - if( hook ) - *hook = jsdc->scriptHook; - if( callerdata ) - *callerdata = jsdc->scriptHookData; - JSD_UNLOCK(); - return true; -} - -bool -jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, bool enable) -{ - bool rv; - AutoSafeJSContext cx; - JS::RootedScript script(cx, jsdscript->script); - JSAutoCompartment ac(cx, script); - JSD_LOCK(); - rv = JS_SetSingleStepMode(cx, 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 = nullptr; - 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, true, hookData); -} - -void -jsd_DestroyScriptHookProc( - JSFreeOp *fop, - JSScript *script_, - void* callerdata ) -{ - JSDScript* jsdscript = nullptr; - 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 - : nullptr; - hookData = jsdc->scriptHookData; - JSD_UNLOCK(); - - if( hook ) - hook(jsdc, jsdscript, 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 nullptr; -} - -static bool -_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 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 true; - } - } - JSD_UNLOCK_SCRIPTS(jsdc); - return false; -} - - -JSTrapStatus -jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval, - jsval closure) -{ - JS::RootedScript script(cx, script_); - JSDExecHook* jsdhook = (JSDExecHook*) closure.toPrivate(); - JSD_ExecutionHookProc hook; - void* hookData; - JSDContext* jsdc; - - JSD_LOCK(); - - if( nullptr == (jsdc = jsd_JSDContextForJSContext(cx)) || - ! _isActiveHook(jsdc, script, jsdhook) ) - { - JSD_UNLOCK(); - return JSTRAP_CONTINUE; - } - - JSD_ASSERT_VALID_EXEC_HOOK(jsdhook); - MOZ_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc); - MOZ_ASSERT(jsdhook->jsdscript->script == script); - MOZ_ASSERT(jsdhook->jsdscript->jsdc == jsdc); - - hook = jsdhook->hook; - hookData = jsdhook->callerdata; - - /* 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; - - return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT, - hook, hookData, rval); -} - - - -bool -jsd_SetExecutionHook(JSDContext* jsdc, - JSDScript* jsdscript, - uintptr_t pc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSDExecHook* jsdhook; - bool rv; - - JSD_LOCK(); - if( ! hook ) - { - jsd_ClearExecutionHook(jsdc, jsdscript, pc); - JSD_UNLOCK(); - return true; - } - - jsdhook = _findHook(jsdc, jsdscript, pc); - if( jsdhook ) - { - jsdhook->hook = hook; - jsdhook->callerdata = callerdata; - JSD_UNLOCK(); - return true; - } - /* else... */ - - jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook)); - if( ! jsdhook ) { - JSD_UNLOCK(); - return false; - } - jsdhook->jsdscript = jsdscript; - jsdhook->pc = pc; - jsdhook->hook = hook; - jsdhook->callerdata = callerdata; - - { - AutoSafeJSContext cx; - JSAutoCompartment ac(cx, jsdscript->script); - JS::RootedScript script(cx, jsdscript->script); - JS::RootedValue hookValue(cx, PRIVATE_TO_JSVAL(jsdhook)); - rv = JS_SetTrap(cx, script, (jsbytecode*)pc, jsd_TrapHandler, hookValue); - } - - if ( ! rv ) { - free(jsdhook); - JSD_UNLOCK(); - return false; - } - - JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks); - JSD_UNLOCK(); - - return true; -} - -bool -jsd_ClearExecutionHook(JSDContext* jsdc, - JSDScript* jsdscript, - uintptr_t pc) -{ - JSDExecHook* jsdhook; - - JSD_LOCK(); - - jsdhook = _findHook(jsdc, jsdscript, pc); - if( ! jsdhook ) - { - JSD_UNLOCK(); - return false; - } - - { - AutoSafeJSContext cx; - JSAutoCompartment ac(cx, jsdscript->script); - JS_ClearTrap(cx, jsdscript->script, - (jsbytecode*)pc, nullptr, nullptr); - } - - JS_REMOVE_LINK(&jsdhook->links); - free(jsdhook); - - JSD_UNLOCK(); - return true; -} - -bool -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 true; -} - -bool -jsd_ClearAllExecutionHooks(JSDContext* jsdc) -{ - JSDScript* jsdscript; - JSDScript* iterp = nullptr; - - JSD_LOCK(); - while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) ) - jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript); - JSD_UNLOCK(); - return 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 deleted file mode 100644 index d07394fe453b..000000000000 --- a/js/jsd/jsd_stak.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/* -*- 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) -{ - MOZ_ASSERT(jsdthreadstate); - MOZ_ASSERT(jsdthreadstate->stackDepth > 0); -} - -void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe) -{ - MOZ_ASSERT(jsdframe); - MOZ_ASSERT(jsdframe->jsdthreadstate); -} -#endif - -static JSDStackFrameInfo* -_addNewFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSScript* script, - uintptr_t pc, - bool isConstructing, - JSAbstractFramePtr frame) -{ - JSDStackFrameInfo* jsdframe; - JSDScript* jsdscript = nullptr; - - 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 nullptr; - } - - if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)) - jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME; - - jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo)); - if( ! jsdframe ) - return nullptr; - - 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 nullptr; - - 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)frame.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 nullptr; - } - } - - ++iter; - } - JS_EndRequest(jsdthreadstate->context); - - if (jsdthreadstate->stackDepth == 0) - { - free(jsdthreadstate); - return nullptr; - } - - 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; - - MOZ_ASSERT(jsdthreadstate); - MOZ_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 = nullptr; - - 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 = nullptr; - - 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 = nullptr; - - 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 = nullptr; - - 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 = nullptr; - - JSD_LOCK_THREADSTATES(jsdc); - - if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) - { - AutoPushJSContext cx(jsdthreadstate->context); - obj = jsdframe->frame.callObject(cx); - 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 = nullptr; - - JSD_LOCK_THREADSTATES(jsdc); - - if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) - { - AutoPushJSContext cx(jsdthreadstate->context); - obj = jsdframe->frame.scopeChain(cx); - 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 = nullptr; - JSD_LOCK_THREADSTATES(jsdc); - - if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) - { - bool ok; - JS::RootedValue thisval(jsdthreadstate->context); - AutoPushJSContext cx(jsdthreadstate->context); - ok = jsdframe->frame.getThisValue(cx, &thisval); - if(ok) - jsdval = JSD_NewValue(jsdc, thisval); - } - - JSD_UNLOCK_THREADSTATES(jsdc); - return jsdval; -} - -JSString* -jsd_GetIdForStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - JSString *rv = nullptr; - - 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; -} - -bool -jsd_IsStackFrameDebugger(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - bool rv = true; - JSD_LOCK_THREADSTATES(jsdc); - - if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) - { - rv = jsdframe->frame.isDebuggerFrame(); - } - - JSD_UNLOCK_THREADSTATES(jsdc); - return rv; -} - -bool -jsd_IsStackFrameConstructing(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - bool rv = true; - JSD_LOCK_THREADSTATES(jsdc); - - if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) - { - rv = jsdframe->isConstructing; - } - - JSD_UNLOCK_THREADSTATES(jsdc); - return rv; -} - -bool -jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe, - const jschar *bytes, unsigned length, - const char *filename, unsigned lineno, - bool eatExceptions, JS::MutableHandleValue rval) -{ - bool retval; - bool valid; - JSExceptionState* exceptionState = nullptr; - - MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread); - - JSD_LOCK_THREADSTATES(jsdc); - valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); - JSD_UNLOCK_THREADSTATES(jsdc); - - if( ! valid ) - return false; - - AutoPushJSContext cx(jsdthreadstate->context); - MOZ_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; -} - -bool -jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe, - const char *bytes, unsigned length, - const char *filename, unsigned lineno, - bool eatExceptions, JS::MutableHandleValue rval) -{ - bool retval; - bool valid; - JSExceptionState* exceptionState = nullptr; - - MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread); - - JSD_LOCK_THREADSTATES(jsdc); - valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); - JSD_UNLOCK_THREADSTATES(jsdc); - - if (!valid) - return false; - - AutoPushJSContext cx(jsdthreadstate->context); - MOZ_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) -{ - bool valid; - JSString* retval; - JSExceptionState* exceptionState; - - JSD_LOCK_THREADSTATES(jsdc); - valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); - JSD_UNLOCK_THREADSTATES(jsdc); - - if( ! valid ) - return nullptr; - - AutoPushJSContext cx(jsdthreadstate->context); - - JS::RootedValue v(cx, val); - exceptionState = JS_SaveExceptionState(cx); - retval = JS::ToString(cx, v); - JS_RestoreExceptionState(cx, exceptionState); - - return retval; -} - -bool -jsd_IsValidThreadState(JSDContext* jsdc, - JSDThreadState* jsdthreadstate) -{ - JSDThreadState *cur; - - MOZ_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) ); - - for( cur = (JSDThreadState*)jsdc->threadsStates.next; - cur != (JSDThreadState*)&jsdc->threadsStates; - cur = (JSDThreadState*)cur->links.next ) - { - if( cur == jsdthreadstate ) - return true; - } - return false; -} - -bool -jsd_IsValidFrameInThreadState(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - MOZ_ASSERT(JSD_THREADSTATES_LOCKED(jsdc)); - - if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) ) - return false; - if( jsdframe->jsdthreadstate != jsdthreadstate ) - return false; - - JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate); - JSD_ASSERT_VALID_STACK_FRAME(jsdframe); - - return true; -} - -static JSContext* -_getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate) -{ - bool valid; - JSD_LOCK_THREADSTATES(jsdc); - valid = jsd_IsValidThreadState(jsdc, jsdthreadstate); - JSD_UNLOCK_THREADSTATES(jsdc); - if( valid ) - return jsdthreadstate->context; - return nullptr; -} - -JSDValue* -jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate) -{ - JSContext* cx; - if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate))) - return nullptr; - - JS::RootedValue val(cx); - if(JS_GetPendingException(cx, &val)) - return jsd_NewValue(jsdc, val); - return nullptr; -} - -bool -jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, - JSDValue* jsdval) -{ - JSContext* cx; - - if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate))) - return false; - - if(jsdval) { - JS::RootedValue exn(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval)); - JS_SetPendingException(cx, exn); - } else { - JS_ClearPendingException(cx); - } - return true; -} - diff --git a/js/jsd/jsd_step.cpp b/js/jsd/jsd_step.cpp deleted file mode 100644 index a6fa6b230db9..000000000000 --- a/js/jsd/jsd_step.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* -*- 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 = nullptr; - 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, bool before) -{ - JSDScript* jsdscript = nullptr; - JSScript * script; - static indent = 0; - JSString* funName = nullptr; - - 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(""); - } - printf("\n"); - MOZ_ASSERT(indent >= 0); -} -#endif - -bool -_callHook(JSDContext *jsdc, JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, - bool before, unsigned type, JSD_CallHookProc hook, void *hookData) -{ - JSDScript* jsdscript; - JSScript* jsscript; - bool hookresult = true; - - if (!jsdc || !jsdc->inited) - return 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 false; - jsd_Constructing(jsdc, cx, newObj.toObjectOrNull(), 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 = 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 = nullptr; - /* 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 = true; - } - } - } - -#ifdef JSD_TRACE - _interpreterTrace(jsdc, cx, frame, isConstructing, before); - return true; -#else - return hookresult; -#endif - -} - -void * -jsd_FunctionCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, - bool before, bool *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 nullptr; -} - -void * -jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, - bool before, bool *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 nullptr; - -} diff --git a/js/jsd/jsd_text.cpp b/js/jsd/jsd_text.cpp deleted file mode 100644 index 483873ba9739..000000000000 --- a/js/jsd/jsd_text.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* -*- 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 -#include "jsd.h" -#include "jsprf.h" - -#ifdef DEBUG -void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc) -{ - MOZ_ASSERT(jsdsrc); - MOZ_ASSERT(jsdsrc->url); -} -#endif - -/***************************************************************************/ -/* XXX add notification */ - -static void -_clearText(JSDContext* jsdc, JSDSourceText* jsdsrc) -{ - if( jsdsrc->text ) - free(jsdsrc->text); - jsdsrc->text = nullptr; - jsdsrc->textLength = 0; - jsdsrc->textSpace = 0; - jsdsrc->status = JSD_SOURCE_CLEARED; - jsdsrc->dirty = true; - jsdsrc->alterCount = jsdc->sourceAlterCount++ ; - jsdsrc->doingEval = false; -} - -static bool -_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 false; - } - } - - jsdsrc->text = newBuf; - jsdsrc->textSpace = iNewSize; - } - - memcpy(jsdsrc->text + jsdsrc->textLength, text, length); - jsdsrc->textLength += length; - return true; -} - -static JSDSourceText* -_newSource(JSDContext* jsdc, char* url) -{ - JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText)); - if( ! jsdsrc ) - return nullptr; - - jsdsrc->url = url; - jsdsrc->status = JSD_SOURCE_INITED; - jsdsrc->dirty = true; - jsdsrc->alterCount = jsdc->sourceAlterCount++ ; - - return jsdsrc; -} - -static void -_destroySource(JSDContext* jsdc, JSDSourceText* jsdsrc) -{ - MOZ_ASSERT(nullptr == 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 nullptr; - 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 bool -_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 true; - } - return 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 nullptr; - - 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 nullptr; - *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 nullptr; -} - -const char* -jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc) -{ - return jsdsrc->url; -} - -bool -jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, - const char** ppBuf, int* pLen ) -{ - *ppBuf = jsdsrc->text; - *pLen = jsdsrc->textLength; - return 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; -} - -bool -jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc) -{ - return jsdsrc->dirty; -} - -void -jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, bool 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 = nullptr; - JSDSourceText* jsdsrc = nullptr; - int dummy; - - while( nullptr != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) ) - { - const char* url; - const char* text; - int len; - bool dirty; - JSDStreamStatus status; - bool 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); - - new_url_string = jsd_BuildNormalizedURL(url); - - if( ! new_url_string ) - return nullptr; - - jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string); - - if( jsdsrc ) - { - if( jsdsrc->doingEval ) - { - free(new_url_string); - JSD_UNLOCK_SOURCE_TEXT(jsdc); - return nullptr; - } - 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 nullptr; - } - - if( ! _isSourceInSourceList( jsdc, jsdsrc ) ) - { - _removeSourceFromRemovedList( jsdc, jsdsrc ); - JSD_UNLOCK_SOURCE_TEXT(jsdc); - return nullptr; - } - - if( text && length && ! _appendText( jsdc, jsdsrc, text, length ) ) - { - jsdsrc->dirty = true; - jsdsrc->alterCount = jsdc->sourceAlterCount++ ; - jsdsrc->status = JSD_SOURCE_FAILED; - _moveSourceToRemovedList(jsdc, jsdsrc); - JSD_UNLOCK_SOURCE_TEXT(jsdc); - return nullptr; - } - - jsdsrc->dirty = 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 = nullptr; - int remaining = length; - - if(!text || !length) - return jsd_AppendSourceText(jsdc, jsdsrc, nullptr, 0, status); - - JSD_LOCK_SOURCE_TEXT(jsdc); - if(!buf) - { - buf = js_pod_malloc(UNICODE_TRUNCATE_BUF_SIZE); - if(!buf) - { - JSD_UNLOCK_SOURCE_TEXT(jsdc); - return nullptr; - } - } - 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, nullptr, 0, status); - - JSD_UNLOCK_SOURCE_TEXT(jsdc); - return jsdsrc; -} - -/* convienence function for adding complete source of url in one call */ -bool -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, - nullptr, 0, JSD_SOURCE_COMPLETED ); - - JSD_UNLOCK_SOURCE_TEXT(jsdc); - - return jsdsrc ? true : 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 - MOZ_ASSERT(! jsdsrc->doingEval); -#endif -#endif - jsdsrc->doingEval = 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!) - */ - MOZ_ASSERT(jsdsrc->doingEval); -#endif -#endif - jsdsrc->doingEval = false; - } - - JSD_UNLOCK_SOURCE_TEXT(jsdc); -} diff --git a/js/jsd/jsd_val.cpp b/js/jsd/jsd_val.cpp deleted file mode 100644 index da625eaf54d3..000000000000 --- a/js/jsd/jsd_val.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/* -*- 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) -{ - MOZ_ASSERT(jsdval); - MOZ_ASSERT(jsdval->nref > 0); - if(!JS_CLIST_IS_EMPTY(&jsdval->props)) - { - MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)); - MOZ_ASSERT(!jsdval->val.isPrimitive()); - } - - if(jsdval->proto) - { - MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)); - MOZ_ASSERT(jsdval->proto->nref > 0); - } - if(jsdval->parent) - { - MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)); - MOZ_ASSERT(jsdval->parent->nref > 0); - } - if(jsdval->ctor) - { - MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)); - MOZ_ASSERT(jsdval->ctor->nref > 0); - } -} - -void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop) -{ - MOZ_ASSERT(jsdprop); - MOZ_ASSERT(jsdprop->name); - MOZ_ASSERT(jsdprop->name->nref > 0); - MOZ_ASSERT(jsdprop->val); - MOZ_ASSERT(jsdprop->val->nref > 0); - if(jsdprop->alias) - MOZ_ASSERT(jsdprop->alias->nref > 0); -} -#endif - - -bool -jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval) -{ - return !jsdval->val.isPrimitive() || jsdval->val.isNull(); -} - -bool -jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isNumber(); -} - -bool -jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isInt32(); -} - -bool -jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isDouble(); -} - -bool -jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isString(); -} - -bool -jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isBoolean(); -} - -bool -jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isNull(); -} - -bool -jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isUndefined(); -} - -bool -jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval) -{ - return jsdval->val.isPrimitive(); -} - -bool -jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval) -{ - AutoSafeJSContext cx; // NB: Actually unused. - return !jsdval->val.isPrimitive() && - JS_ObjectIsCallable(cx, jsdval->val.toObjectOrNull()); -} - -bool -jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) -{ - AutoSafeJSContext cx; - JS::RootedFunction fun(cx); - - if(jsd_IsValueFunction(jsdc, jsdval)) - { - JSAutoCompartment ac(cx, jsdval->val.toObjectOrNull()); - AutoSaveExceptionState as(cx); - bool ok = false; - fun = JSD_GetValueFunction(jsdc, jsdval); - if(fun) - ok = JS_GetFunctionScript(cx, fun) ? false : true; - MOZ_ASSERT(fun); - return ok; - } - return !jsdval->val.isPrimitive(); -} - -/***************************************************************************/ - -bool -jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval) -{ - jsval val = jsdval->val; - if(!val.isBoolean()) - return false; - return val.toBoolean(); -} - -int32_t -jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) -{ - jsval val = jsdval->val; - if(!val.isInt32()) - return 0; - return val.toInt32(); -} - -double -jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) -{ - if(!jsdval->val.isDouble()) - return 0; - return jsdval->val.toDouble(); -} - -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(jsdval->val.isString()) { - jsdval->string = jsdval->val.toString(); - return jsdval->string; - } - - /* Objects call JS_ValueToString in their own compartment. */ - scopeObj = !jsdval->val.isPrimitive() ? jsdval->val.toObjectOrNull() : jsdc->glob; - { - JSAutoCompartment ac(cx, scopeObj); - AutoSaveExceptionState as(cx); - JS::RootedValue v(cx, jsdval->val); - string = JS::ToString(cx, v); - } - - JSAutoCompartment ac2(cx, jsdc->glob); - if(string) { - stringval = STRING_TO_JSVAL(string); - } - if(!string || !JS_WrapValue(cx, &stringval)) { - return nullptr; - } - - jsdval->string = stringval.toString(); - if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString")) - jsdval->string = nullptr; - - 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, jsdval->val.toObjectOrNull()); - AutoSaveExceptionState as(cx); - fun = JSD_GetValueFunction(jsdc, jsdval); - if(!fun) - return nullptr; - 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) -{ - JS::RootedValue val(jsdc->jsrt, value); - AutoSafeJSContext cx; - JSDValue* jsdval; - - if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) - return nullptr; - - if(val.isGCThing()) - { - bool ok; - JSAutoCompartment ac(cx, jsdc->glob); - - ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue"); - if(ok && val.isString()) { - if(!JS_WrapValue(cx, &val)) { - ok = false; - } - } - - if(!ok) - { - free(jsdval); - return nullptr; - } - } - jsdval->val = val; - jsdval->nref = 1; - JS_INIT_CLIST(&jsdval->props); - - return jsdval; -} - -void -jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) -{ - MOZ_ASSERT(jsdval->nref > 0); - if(0 == --jsdval->nref) - { - jsd_RefreshValue(jsdc, jsdval); - if(jsdval->val.isGCThing()) - { - AutoSafeJSContext cx; - JSAutoCompartment ac(cx, jsdc->glob); - JS::RemoveValueRoot(cx, &jsdval->val); - } - free(jsdval); - } -} - -jsval -jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval) -{ - AutoSafeJSContext cx; - JS::RootedValue val(cx, jsdval->val); - if (!val.isPrimitive()) { - JS::RootedObject obj(cx, &val.toObject()); - JSAutoCompartment ac(cx, obj); - obj = JS_ObjectToOuterObject(cx, obj); - if (!obj) - { - JS_ClearPendingException(cx); - val = JSVAL_NULL; - } - else - val = JS::ObjectValue(*obj); - } - - return val; -} - -static JSDProperty* _newProperty(JSDContext* jsdc, JS::HandleValue propId, - JS::HandleValue propValue, JS::HandleValue propAlias, - uint8_t propFlags, unsigned additionalFlags) -{ - JSDProperty* jsdprop; - - if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty)))) - return nullptr; - - JS_INIT_CLIST(&jsdprop->links); - jsdprop->nref = 1; - jsdprop->flags = propFlags | additionalFlags; - - if(!(jsdprop->name = jsd_NewValue(jsdc, propId))) - goto new_prop_fail; - - if(!(jsdprop->val = jsd_NewValue(jsdc, propValue))) - goto new_prop_fail; - - if((jsdprop->flags & JSDPD_ALIAS) && - !(jsdprop->alias = jsd_NewValue(jsdc, propAlias))) - goto new_prop_fail; - - return jsdprop; -new_prop_fail: - jsd_DropProperty(jsdc, jsdprop); - return nullptr; -} - -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); - } - MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); - CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS); -} - -static bool _buildProps(JSDContext* jsdc, JSDValue* jsdval) -{ - AutoSafeJSContext cx; - JS::RootedObject obj(cx); - JSPropertyDescArray pda; - unsigned i; - - MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); - MOZ_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))); - MOZ_ASSERT(!jsdval->val.isPrimitive()); - - if(jsdval->val.isPrimitive()) - return false; - - obj = jsdval->val.toObjectOrNull(); - - JSAutoCompartment ac(cx, obj); - - if(!JS_GetPropertyDescArray(cx, obj, &pda)) - { - return false; - } - - JS::RootedValue propId(cx); - JS::RootedValue propValue(cx); - JS::RootedValue propAlias(cx); - uint8_t propFlags; - for(i = 0; i < pda.length; i++) - { - propId = pda.array[i].id; - propValue = pda.array[i].value; - propAlias = pda.array[i].alias; - propFlags = pda.array[i].flags; - JSDProperty* prop = _newProperty(jsdc, propId, propValue, propAlias, propFlags, 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 = nullptr;} - -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(!jsdval->val.isString()) - { - JSAutoCompartment ac(cx, jsdc->glob); - JS::RemoveStringRoot(cx, &jsdval->string); - } - jsdval->string = nullptr; - } - - jsdval->funName = nullptr; - jsdval->className = nullptr; - 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))) - { - MOZ_ASSERT(!jsdprop); - if(!_buildProps(jsdc, jsdval)) - return nullptr; - } - - if(!jsdprop) - jsdprop = (JSDProperty*)jsdval->props.next; - if(jsdprop == (JSDProperty*)&jsdval->props) - return nullptr; - *iterp = (JSDProperty*)jsdprop->links.next; - - MOZ_ASSERT(jsdprop); - jsdprop->nref++; - return jsdprop; -} - -JSDProperty* -jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr) -{ - JS::RootedString name(jsdc->jsrt, nameStr); - AutoSafeJSContext cx; - JSAutoCompartment acBase(cx, jsdc->glob); - JSDProperty* jsdprop; - JSDProperty* iter = nullptr; - JS::RootedObject obj(cx); - JS::RootedValue val(cx), nameval(cx); - JS::RootedId nameid(cx); - JS::RootedValue propId(cx); - JS::RootedValue propValue(cx); - JS::RootedValue propAlias(cx); - uint8_t propFlags; - - if(!jsd_IsValueObject(jsdc, jsdval)) - return nullptr; - - /* If we already have the prop, then return it */ - while(nullptr != (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 */ - - nameval = STRING_TO_JSVAL(name); - if(!JS_ValueToId(cx, nameval, &nameid)) - return nullptr; - - if(!(obj = jsdval->val.toObjectOrNull())) - return nullptr; - - JS::Rooted desc(cx); - { - JSAutoCompartment ac(cx, obj); - JS::RootedId id(cx, nameid); - - if(!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) - return nullptr; - if(!desc.object()) - return nullptr; - - JS_ClearPendingException(cx); - - if(!JS_GetPropertyById(cx, obj, id, &val)) - { - if (JS_IsExceptionPending(cx)) - { - if (!JS_GetPendingException(cx, &propValue)) - { - return nullptr; - } - propFlags = JSPD_EXCEPTION; - } - else - { - propFlags = JSPD_ERROR; - propValue = JSVAL_VOID; - } - } - else - { - propValue = val; - } - } - - if (!JS_IdToValue(cx, nameid, &propId)) - return nullptr; - - propAlias = JSVAL_NULL; - propFlags |= desc.isEnumerable() ? JSPD_ENUMERATE : 0 - | desc.isReadonly() ? JSPD_READONLY : 0 - | desc.isPermanent() ? JSPD_PERMANENT : 0; - - return _newProperty(jsdc, propId, propValue, propAlias, propFlags, 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 (jsdval->val.isPrimitive()) - return nullptr; - - obj = js::UncheckedUnwrap(jsdval->val.toObjectOrNull()); - JSAutoCompartment ac(cx, obj); - JS::RootedValue funval(cx, JS::ObjectValue(*obj)); - fun = JS_ValueToFunction(cx, funval); - - 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); - MOZ_ASSERT(!jsdval->proto); - SET_BIT_FLAG(jsdval->flags, GOT_PROTO); - if(jsdval->val.isPrimitive()) - return nullptr; - obj = jsdval->val.toObjectOrNull(); - if(!JS_GetPrototype(cx, obj, &proto)) - return nullptr; - if(!proto) - return nullptr; - 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); - MOZ_ASSERT(!jsdval->parent); - SET_BIT_FLAG(jsdval->flags, GOT_PARENT); - if(jsdval->val.isPrimitive()) - return nullptr; - obj = jsdval->val.toObjectOrNull(); - { - JSAutoCompartment ac(cx, obj); - parent = JS_GetParentOrScopeChain(cx, obj); - } - if(!parent) - return nullptr; - 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); - MOZ_ASSERT(!jsdval->ctor); - SET_BIT_FLAG(jsdval->flags, GOT_CTOR); - if(jsdval->val.isPrimitive()) - return nullptr; - obj = jsdval->val.toObjectOrNull(); - if(!JS_GetPrototype(cx, obj, &proto)) - return nullptr; - if(!proto) - return nullptr; - { - JSAutoCompartment ac(cx, obj); - ctor = JS_GetConstructor(cx, proto); - } - if(!ctor) - return nullptr; - 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 && !val.isPrimitive()) - { - JS::RootedObject obj(jsdc->jsrt, val.toObjectOrNull()); - AutoSafeJSContext cx; - 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); - JS::RootedScript script(cx); - JSDScript* jsdscript; - - if (!jsd_IsValueFunction(jsdc, jsdval)) - return nullptr; - - { - JSAutoCompartment ac(cx, val.toObjectOrNull()); - AutoSaveExceptionState as(cx); - JS::RootedFunction fun(cx, JSD_GetValueFunction(jsdc, jsdval)); - if (fun) - script = JS_GetFunctionScript(cx, fun); - } - - if (!script) - return nullptr; - - 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) -{ - MOZ_ASSERT(jsdprop->nref > 0); - if(0 == --jsdprop->nref) - { - MOZ_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 deleted file mode 100644 index 4d13e9cfadb4..000000000000 --- a/js/jsd/jsd_xpc.cpp +++ /dev/null @@ -1,3495 +0,0 @@ -/* -*- 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 "jsfriendapi.h" -#include "jsd_xpc.h" -#include "xpcpublic.h" - -#include "js/GCAPI.h" -#include "js/OldDebugAPI.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 "nsIScriptError.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 "nsPIDOMWindow.h" -#include "nsDOMJSUtils.h" -#include "SandboxPrivate.h" -#include "nsJSPrincipals.h" -#include "nsContentUtils.h" -#include "mozilla/dom/ScriptSettings.h" - -using mozilla::AutoSafeJSContext; -using mozilla::AutoPushJSContext; -using mozilla::dom::AutoNoJSAPI; - -/* - * 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"; - -#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 -jsds_FindEphemeral (LiveEphemeral **listHead, void *key) -{ - if (!*listHead) - return nullptr; - - LiveEphemeral *lv_record = - reinterpret_cast - (PR_NEXT_LINK(&(*listHead)->links)); - do - { - if (lv_record->key == key) - { - nsCOMPtr ret = lv_record->value; - return ret.forget(); - } - lv_record = reinterpret_cast - (PR_NEXT_LINK(&lv_record->links)); - } - while (lv_record != *listHead); - - return nullptr; -} - -void -jsds_InvalidateAllEphemerals (LiveEphemeral **listHead) -{ - LiveEphemeral *lv_record = - reinterpret_cast - (PR_NEXT_LINK(&(*listHead)->links)); - do - { - LiveEphemeral *next = - reinterpret_cast - (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 - (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 - (PR_NEXT_LINK(¤t->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 - (PR_NEXT_LINK(¤tFilter->links)); - } while (currentFilter != gFilters); - - return true; - -} - -/******************************************************************************* - * c callbacks - *******************************************************************************/ - -static void -jsds_NotifyPendingDeadScripts (JSRuntime *rt) -{ - jsdService *jsds = gJsds; - - nsCOMPtr 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 - (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 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 val; - if (JS_IsExceptionPending(cx)) { - JS::RootedValue jv(cx); - JS_GetPendingException(cx, &jv); - JSDValue *jsdv = JSD_NewValue (jsdc, jv); - val = dont_AddRef(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 bool -jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate, - unsigned type, void* callerdata) -{ - nsCOMPtr 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 true; - - if (!jsds_FilterHook (jsdc, jsdthreadstate)) - return false; - - JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate); - nsCOMPtr frame = - dont_AddRef(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, native_frame)); - gJsds->DoPause(nullptr, true); - hook->OnCall(frame, type); - gJsds->DoUnPause(nullptr, true); - jsdStackFrame::InvalidateAll(); - - return true; -} - -static uint32_t -jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate, - unsigned type, void* callerdata, jsval* rval) -{ - nsCOMPtr hook(0); - uint32_t hook_rv = JSD_HOOK_RETURN_CONTINUE; - nsCOMPtr 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 = dont_AddRef(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 frame = - dont_AddRef(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, bool creating, - void* callerdata) -{ -#ifdef CAUTIOUS_SCRIPTHOOK - JSRuntime *rt = JS_GetRuntime(nsContentUtils::GetSafeJSContext()); -#endif - - if (creating) { - nsCOMPtr hook; - gJsds->GetScriptHook(getter_AddRefs(hook)); - - /* a script is being created */ - if (!hook) { - /* nobody cares, just exit */ - return; - } - - nsCOMPtr script = - dont_AddRef(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 jsdis = - static_cast(JSD_GetScriptPrivate(jsdscript)); - if (!jsdis) - return; - - jsdis->Invalidate(); - - if (!gGCRunning) { - nsCOMPtr 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_ISUPPORTS(jsdContext, jsdIContext, jsdIEphemeral); - -NS_IMETHODIMP -jsdContext::GetJSDContext(JSDContext **_rval) -{ - *_rval = mCx; - return NS_OK; -} -*/ - -/* Objects */ -NS_IMPL_ISUPPORTS(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_ISUPPORTS(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_ISUPPORTS(jsdScript, jsdIScript, jsdIEphemeral) - -static NS_IMETHODIMP -AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str_) -{ - if (!str_) { - x->SetLength(0); - return NS_OK; - } - JS::RootedString str(JSD_GetJSRuntime(aCx), str_); - 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, nullptr, JS::NullPtr(), JS::NullPtr())); - 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 kungFuDeathGrip(jsstr); - static const char *const argnames[] = { - "arg1", "arg2", "arg3", "arg4", - "arg5", "arg6", "arg7", "arg8", - "arg9", "arg10", "arg11", "arg12" - }; - JS::CompileOptions options(cx); - options.setFileAndLine("x-jsd:ppbuffer?type=function", 3); - fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars, - length, options); - 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 kungFuDeathGrip(jsstr); - JS::CompileOptions options(cx); - options.setFileAndLine("x-jsd:ppbuffer?type=script", 1); - script = JS_CompileUCScript(cx, obj, chars, length, options); - 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 - (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 - (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(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 - (JSD_GetScriptPrivate(mScript)); - NS_ASSERTION (script == this, "That's not my script!"); - NS_RELEASE(script); - JSD_SetScriptPrivate(mScript, nullptr); - return NS_OK; -} - -void -jsdScript::InvalidateAll () -{ - JSDContext *cx; - if (NS_FAILED(gJsds->GetJSDContext (&cx))) - return; - - JSDScript *script; - JSDScript *iter = nullptr; - - JSD_LockScriptSubsystem(cx); - while((script = JSD_IterateScripts(cx, &iter)) != nullptr) { - nsCOMPtr jsdis = - static_cast(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, char16_t*** 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; - } - - char16_t **ret = - static_cast(NS_Alloc(nargs * sizeof(char16_t*))); - 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) -{ - JS::RootedFunction fun(JSD_GetJSRuntime(mCx), 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 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(NS_Alloc((end - start + 1) * sizeof(uint32_t))); - if (!JSD_GetLinePCs(mCx, mScript, aStartLine, aMaxLines, aCount, aExecutableLines, - nullptr)) - return NS_ERROR_OUT_OF_MEMORY; - - return NS_OK; - } - - if (aPcmap == PCMAP_PRETTYPRINT) { - if (!mPPLineMap) { - if (!CreatePPLineMap()) - return NS_ERROR_OUT_OF_MEMORY; - } - - nsTArray 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(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, nullptr); - 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_ISUPPORTS(jsdContext, jsdIContext, jsdIEphemeral) - -jsdIContext * -jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx) -{ - if (!aJSDCx || !aJSCx) - return nullptr; - - nsCOMPtr jsdicx; - nsCOMPtr eph = - jsds_FindEphemeral (&gLiveContexts, static_cast(aJSCx)); - if (eph) - { - jsdicx = do_QueryInterface(eph); - } - else - { - nsCOMPtr iscx; - if (JS::ContextOptionsRef(aJSCx).privateIsNSISupports()) - iscx = static_cast(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), - mScriptDisabledForWindowWithID(0), - mTag(0), - mJSDCx(aJSDCx), - mJSCx(aJSCx), mISCx(aISCx) -{ - DEBUG_CREATE ("jsdContext", gContextCount); - mLiveListEntry.value = this; - mLiveListEntry.key = static_cast(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; -} - -/* Simulate the old options API in terms of the new one for backwards - * compatibility */ - -#define JSOPTION_EXTRA_WARNINGS JS_BIT(0) -#define JSOPTION_WERROR JS_BIT(1) -#define JSOPTION_VAROBJFIX JS_BIT(2) -#define JSOPTION_PRIVATE_IS_NSISUPPORTS JS_BIT(3) -#define JSOPTION_DONT_REPORT_UNCAUGHT JS_BIT(8) -#define JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT JS_BIT(11) -#define JSOPTION_NO_SCRIPT_RVAL JS_BIT(12) -#define JSOPTION_STRICT_MODE JS_BIT(17) -#define JSOPTION_MASK JS_BITMASK(20) - -NS_IMETHODIMP -jsdContext::GetOptions(uint32_t *_rval) -{ - ASSERT_VALID_EPHEMERAL; - *_rval = (JS::ContextOptionsRef(mJSCx).extraWarnings() ? JSOPTION_EXTRA_WARNINGS : 0) - | (JS::ContextOptionsRef(mJSCx).werror() ? JSOPTION_WERROR : 0) - | (JS::ContextOptionsRef(mJSCx).varObjFix() ? JSOPTION_VAROBJFIX : 0) - | (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() ? JSOPTION_PRIVATE_IS_NSISUPPORTS : 0) - | (JS::ContextOptionsRef(mJSCx).dontReportUncaught() ? JSOPTION_DONT_REPORT_UNCAUGHT : 0) - | (JS::ContextOptionsRef(mJSCx).noDefaultCompartmentObject() ? JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT : 0) - | (JS::ContextOptionsRef(mJSCx).noScriptRval() ? JSOPTION_NO_SCRIPT_RVAL : 0) - | (JS::ContextOptionsRef(mJSCx).strictMode() ? JSOPTION_STRICT_MODE : 0); - return NS_OK; -} - -NS_IMETHODIMP -jsdContext::SetOptions(uint32_t options) -{ - ASSERT_VALID_EPHEMERAL; - - /* don't let users change this option, they'd just be shooting themselves - * in the foot. */ - if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() != - !!(options & JSOPTION_PRIVATE_IS_NSISUPPORTS)) - return NS_ERROR_ILLEGAL_VALUE; - - JS::ContextOptionsRef(mJSCx).setExtraWarnings(options & JSOPTION_EXTRA_WARNINGS) - .setWerror(options & JSOPTION_WERROR) - .setVarObjFix(options & JSOPTION_VAROBJFIX) - .setDontReportUncaught(options & JSOPTION_DONT_REPORT_UNCAUGHT) - .setNoDefaultCompartmentObject(options & JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT) - .setNoScriptRval(options & JSOPTION_NO_SCRIPT_RVAL) - .setStrictMode(options & JSOPTION_STRICT_MODE); - return NS_OK; -} - -NS_IMETHODIMP -jsdContext::GetPrivateData(nsISupports **_rval) -{ - ASSERT_VALID_EPHEMERAL; - if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports()) - { - *_rval = static_cast(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 = GetDefaultScopeFromJSContext(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; - *_rval = IsScriptEnabled(); - return NS_OK; -} - -NS_IMETHODIMP -jsdContext::SetScriptsEnabled (bool _rval) -{ - ASSERT_VALID_EPHEMERAL; - if (_rval == IsScriptEnabled()) - return NS_OK; - - nsCOMPtr scx = do_QueryInterface(mISCx); - NS_ENSURE_TRUE(scx && scx->GetWindowProxy(), NS_ERROR_NO_INTERFACE); - nsCOMPtr piWin = do_QueryInterface(scx->GetGlobalObject()); - NS_ENSURE_TRUE(piWin, NS_ERROR_NO_INTERFACE); - uint64_t currentWindowID = piWin->WindowID(); - - if (_rval) { - if (mScriptDisabledForWindowWithID != currentWindowID) { - NS_WARNING("Please stop abusing JSD and fix your code!"); - return NS_ERROR_UNEXPECTED; - } - xpc::Scriptability::Get(scx->GetWindowProxy()).Unblock(); - piWin->ResumeTimeouts(); - mScriptDisabledForWindowWithID = 0; - } - else { - piWin->SuspendTimeouts(); - xpc::Scriptability::Get(scx->GetWindowProxy()).Block(); - mScriptDisabledForWindowWithID = currentWindowID; - } - - return NS_OK; -} - -/* Stack Frames */ -NS_IMPL_ISUPPORTS(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 frame; - - nsCOMPtr eph = - jsds_FindEphemeral (&gLiveStackFrames, - reinterpret_cast(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.AssignLiteral("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(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); - 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_ISUPPORTS(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; - JS::RootedValue val(JSD_GetJSRuntime(mCx), JSD_GetValueWrappedJSVal (mCx, mValue)); - - if (val.isNull()) - *_rval = TYPE_NULL; - else if (val.isBoolean()) - *_rval = TYPE_BOOLEAN; - else if (val.isDouble()) - *_rval = TYPE_DOUBLE; - else if (val.isInt32()) - *_rval = TYPE_INT; - else if (val.isString()) - *_rval = TYPE_STRING; - else if (val.isUndefined()) - *_rval = TYPE_VOID; - else if (JSD_IsValueFunction (mCx, mValue)) - *_rval = TYPE_FUNCTION; - else if (!val.isPrimitive()) - *_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 - (nsMemory::Alloc(sizeof (jsdIProperty *) * - prop_count)); - NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY); - - uint32_t i = 0; - JSDProperty *iter = nullptr; - 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::MutableHandle aRetval) -{ - ASSERT_VALID_EPHEMERAL; - - aRetval.set(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(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; - - // Warn that JSD is deprecated, unless the caller has told us - // that they know already. - if (mDeprecationAcknowledged) { - mDeprecationAcknowledged = false; - } else if (!mWarnedAboutDeprecation) { - // In any case, warn only once. - mWarnedAboutDeprecation = true; - - // Ignore errors: simply being unable to print the message - // shouldn't (effectively) disable JSD. - nsContentUtils::ReportToConsoleNonLocalized( - NS_LITERAL_STRING("\ -The jsdIDebuggerService and its associated interfaces are deprecated. \ -Please use Debugger, via IJSDebugger, instead."), - nsIScriptError::warningFlag, - NS_LITERAL_CSTRING("JSD"), - nullptr); - } - - nsCOMPtr 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, nullptr, nullptr); - JSD_SetScriptHook (mCx, nullptr, nullptr); - 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, nullptr, nullptr); - 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 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, nullptr); - - /* 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, nullptr); - if (mThrowHook) - JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr); - /* 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, nullptr); - if (mDebuggerHook) - JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr); - if (mDebugHook) - JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr); - if (mTopLevelHook) - JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr); - else - JSD_ClearTopLevelHook (mCx); - if (mFunctionHook) - JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr); - else - JSD_ClearFunctionHook (mCx); - mOn = true; - -#ifdef DEBUG - printf ("+++ JavaScript debugging hooks installed.\n"); -#endif - - nsCOMPtr 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 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, nullptr, nullptr); - JSD_ClearThrowHook (mCx); - JSD_ClearInterruptHook (mCx); - JSD_ClearDebuggerHook (mCx); - JSD_ClearDebugBreakHook (mCx); - JSD_ClearTopLevelHook (mCx); - JSD_ClearFunctionHook (mCx); - JSD_DebuggerPause (mCx); - - nsresult rv; - nsCOMPtr 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, nullptr); - if (mThrowHook) - JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr); - if (mInterruptHook) - JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr); - if (mDebuggerHook) - JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr); - if (mDebugHook) - JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr); - if (mTopLevelHook) - JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr); - else - JSD_ClearTopLevelHook (mCx); - if (mFunctionHook) - JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr); - else - JSD_ClearFunctionHook (mCx); - - nsresult rv; - nsCOMPtr 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 = nullptr; - JSContext *cx; - - while ((cx = JS_ContextIterator (mRuntime, &iter))) - { - nsCOMPtr jsdicx = - dont_AddRef(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 = nullptr; - nsresult rv = NS_OK; - - JSD_LockScriptSubsystem(mCx); - while((script = JSD_IterateScripts(mCx, &iter))) { - nsCOMPtr jsdis = - dont_AddRef(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, nullptr, JSTRACE_OBJECT, nullptr, (size_t)-1, nullptr)) - 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 - (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 - (PR_NEXT_LINK (¤t->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 - (PR_NEXT_LINK (&gFilters->links)); - do { - FilterRecord *next = reinterpret_cast - (PR_NEXT_LINK (¤t->links)); - PR_REMOVE_AND_INIT_LINK(¤t->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(JS::Handle 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; - AutoNoJSAPI nojsapi; - uint32_t nestLevel = ++mNestedLoopLevel; - nsCOMPtr 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; -} - -NS_IMETHODIMP -jsdService::AcknowledgeDeprecation() -{ - mDeprecationAcknowledged = true; - 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, nullptr); - else - JSD_SetErrorReporter (mCx, nullptr, nullptr); - - 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, nullptr); - 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, nullptr); - 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, nullptr); - 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, nullptr); - /* 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, nullptr); - 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, nullptr); - 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, nullptr); - 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 -{ - ~jsdASObserver () {} - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIOBSERVER - - jsdASObserver () {} -}; - -NS_IMPL_ISUPPORTS(jsdASObserver, nsIObserver) - -NS_IMETHODIMP -jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic, - const char16_t *aData) -{ - nsresult rv; - - // Hmm. Why is the app-startup observer called multiple times? - //NS_ASSERTION(!gJsds, "app startup observer called twice"); - nsCOMPtr 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 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, nullptr, jsdServiceConstructor }, - { &kJSDASO_CID, false, nullptr, jsdASObserverConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kJSDContracts[] = { - { jsdServiceCtrID, &kJSDSERVICE_CID }, - { jsdARObserverCtrID, &kJSDASO_CID }, - { nullptr } -}; - -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(js::GetObjectPrivate(aObj)); - MOZ_ASSERT(sop); - static_cast(sop)->ForgetGlobalObject(); - NS_IF_RELEASE(sop); -} - -JSObject * -CreateJSDGlobal(JSContext *aCx, const JSClass *aClasp) -{ - nsresult rv; - nsCOMPtr nullPrin = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); - NS_ENSURE_SUCCESS(rv, nullptr); - - JSPrincipals *jsPrin = nsJSPrincipals::get(nullPrin); - JS::RootedObject global(aCx, JS_NewGlobalObject(aCx, aClasp, jsPrin, JS::DontFireOnNewGlobalHook)); - NS_ENSURE_TRUE(global, nullptr); - - // We have created a new global let's attach a private to it - // that implements nsIGlobalObject. - nsCOMPtr sbp = - new SandboxPrivate(nullPrin, global); - JS_SetPrivate(global, sbp.forget().take()); - - JS_FireOnNewGlobalObject(aCx, global); - - return global; -} - -/******************************************************************************** - ******************************************************************************** - * graveyard - */ - -#if 0 -/* Thread States */ -NS_IMPL_ISUPPORTS(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 deleted file mode 100644 index e34f9e91a6e5..000000000000 --- a/js/jsd/jsd_xpc.h +++ /dev/null @@ -1,399 +0,0 @@ -/* -*- 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_THREADSAFE_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 */ - - ~jsdObject() {} - - JSDContext *mCx; - JSDObject *mObject; -}; - - -class jsdProperty : public jsdIProperty -{ - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_JSDIPROPERTY - NS_DECL_JSDIEPHEMERAL - - jsdProperty (JSDContext *aCx, JSDProperty *aProperty); - - 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 */ - - virtual ~jsdProperty (); - - bool mValid; - LiveEphemeral mLiveListEntry; - JSDContext *mCx; - JSDProperty *mProperty; -}; - -class jsdScript : public jsdIScript -{ - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_JSDISCRIPT - NS_DECL_JSDIEPHEMERAL - - /* you'll normally use use FromPtr() instead of directly constructing one */ - jsdScript (JSDContext *aCx, JSDScript *aScript); - - static jsdIScript *FromPtr (JSDContext *aCx, JSDScript *aScript) - { - if (!aScript) - return nullptr; - - void *data = JSD_GetScriptPrivate (aScript); - jsdIScript *rv; - - if (data) { - rv = static_cast(data); - } else { - rv = new jsdScript (aCx, aScript); - NS_IF_ADDREF(rv); /* addref for the SetScriptPrivate, released in - * Invalidate() */ - JSD_SetScriptPrivate (aScript, static_cast(rv)); - } - - NS_IF_ADDREF(rv); /* addref for return value */ - return rv; - } - - static void InvalidateAll(); - - private: - virtual ~jsdScript(); - - 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_THREADSAFE_ISUPPORTS - NS_DECL_JSDICONTEXT - NS_DECL_JSDIEPHEMERAL - - jsdContext (JSDContext *aJSDCx, JSContext *aJSCx, nsISupports *aISCx); - - static void InvalidateAll(); - static jsdIContext *FromPtr (JSDContext *aJSDCx, JSContext *aJSCx); - private: - static uint32_t LastTag; - - jsdContext (); /* no implementation */ - jsdContext (const jsdContext&); /* no implementation */ - - virtual ~jsdContext(); - - bool mValid; - // The API exposed by JSD here is problematic, because it allows for per- - // JSContext script disabling, which no longer exists in the platform. - // The only consumer here in practice is Firebug, which makes sure to re- - // enable any disabled script before navigation. But if some other consumer - // were to disable script, navigate, and try to re-enable it, we'd end up - // with an unmatched UnblockScript call, which violates platform invariants. - // So we make a half-hearted attempt to detect this by storing the Window ID - // of the scope for which we disabled script. - uint64_t mScriptDisabledForWindowWithID; - bool IsScriptEnabled() { return !mScriptDisabledForWindowWithID; } - LiveEphemeral mLiveListEntry; - uint32_t mTag; - JSDContext *mJSDCx; - JSContext *mJSCx; - nsCOMPtr mISCx; -}; - -uint32_t jsdContext::LastTag = 0; - -class jsdStackFrame : public jsdIStackFrame -{ - public: - NS_DECL_THREADSAFE_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); - - static void InvalidateAll(); - static jsdIStackFrame* FromPtr (JSDContext *aCx, - JSDThreadState *aThreadState, - JSDStackFrameInfo *aStackFrameInfo); - - private: - jsdStackFrame(); /* no implementation */ - jsdStackFrame(const jsdStackFrame&); /* no implementation */ - - virtual ~jsdStackFrame(); - - bool mValid; - LiveEphemeral mLiveListEntry; - JSDContext *mCx; - JSDThreadState *mThreadState; - JSDStackFrameInfo *mStackFrameInfo; -}; - -class jsdValue : public jsdIValue -{ - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_JSDIVALUE - NS_DECL_JSDIEPHEMERAL - - /* you'll normally use use FromPtr() instead of directly constructing one */ - jsdValue (JSDContext *aCx, JSDValue *aValue); - - static jsdIValue *FromPtr (JSDContext *aCx, JSDValue *aValue); - static void InvalidateAll(); - - private: - virtual ~jsdValue(); - - 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), - mWarnedAboutDeprecation(false), - mDeprecationAcknowledged(false) - { - } - - static jsdService *GetService (); - - bool CheckInterruptHook() { return !!mInterruptHook; } - - nsresult DoPause(uint32_t *_rval, bool internalCall); - nsresult DoUnPause(uint32_t *_rval, bool internalCall); - - private: - virtual ~jsdService(); - - bool mOn; - uint32_t mPauseLevel; - uint32_t mNestedLoopLevel; - JSDContext *mCx; - JSRuntime *mRuntime; - - nsCOMPtr mErrorHook; - nsCOMPtr mBreakpointHook; - nsCOMPtr mDebugHook; - nsCOMPtr mDebuggerHook; - nsCOMPtr mInterruptHook; - nsCOMPtr mScriptHook; - nsCOMPtr mThrowHook; - nsCOMPtr mTopLevelHook; - nsCOMPtr mFunctionHook; - nsCOMPtr mActivationCallback; - - // True if we have ever printed a warning about JSD being deprecated. - // We only ever print the warning once. - bool mWarnedAboutDeprecation; - - // True if the next call to asyncOn should not produce a warning, - // because the consumer called jsdIDebuggerService::acknowledgeDeprecation. - bool mDeprecationAcknowledged; -}; - -#endif /* JSDSERVICE_H___ */ - - -/* graveyard */ - -#if 0 - -class jsdContext : public jsdIContext -{ - public: - NS_DECL_THREADSAFE_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(data); - } else { - rv = new jsdContext (aCx); - NS_IF_ADDREF(rv); // addref for the SetContextPrivate - JSD_SetContextPrivate (aCx, static_cast(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_THREADSAFE_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 deleted file mode 100644 index 9c24aa5e496c..000000000000 --- a/js/jsd/jsdebug.cpp +++ /dev/null @@ -1,1320 +0,0 @@ -/* -*- 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, nullptr); -} - -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, 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(bool) -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(bool) -JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetScriptHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -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(bool) -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); - MOZ_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(bool) -JSD_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, - const char** ppBuf, int* pLen) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); - MOZ_ASSERT(ppBuf); - MOZ_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(bool) -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, bool 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); - MOZ_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(bool) -JSD_AddFullSourceText(JSDContext* jsdc, - const char* text, /* *not* zero terminated */ - size_t length, - const char* url) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - MOZ_ASSERT(url); - return jsd_AddFullSourceText(jsdc, text, length, url); -} - -/***************************************************************************/ -/* Execution/Interrupt Hook functions */ - -JSD_PUBLIC_API(bool) -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(bool) -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(bool) -JSD_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_SCRIPT(jsdscript); - return jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript); -} - -JSD_PUBLIC_API(bool) -JSD_ClearAllExecutionHooks(JSDContext* jsdc) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_ClearAllExecutionHooks(jsdc); -} - -JSD_PUBLIC_API(bool) -JSD_SetInterruptHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetInterruptHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, bool enable) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_SCRIPT(jsdscript); - return jsd_EnableSingleStepInterrupts(jsdc, jsdscript, enable); -} - -JSD_PUBLIC_API(bool) -JSD_ClearInterruptHook(JSDContext* jsdc) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_ClearInterruptHook(jsdc); -} - -JSD_PUBLIC_API(bool) -JSD_SetDebugBreakHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetDebugBreakHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -JSD_ClearDebugBreakHook(JSDContext* jsdc) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_ClearDebugBreakHook(jsdc); -} - -JSD_PUBLIC_API(bool) -JSD_SetDebuggerHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetDebuggerHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -JSD_ClearDebuggerHook(JSDContext* jsdc) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_ClearDebuggerHook(jsdc); -} - -JSD_PUBLIC_API(bool) -JSD_SetThrowHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetThrowHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -JSD_ClearThrowHook(JSDContext* jsdc) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_ClearThrowHook(jsdc); -} - -JSD_PUBLIC_API(bool) -JSD_SetTopLevelHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetTopLevelHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -JSD_ClearTopLevelHook(JSDContext* jsdc) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_ClearTopLevelHook(jsdc); -} - -JSD_PUBLIC_API(bool) -JSD_SetFunctionHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetFunctionHook(jsdc, hook, callerdata); -} - -JSD_PUBLIC_API(bool) -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(bool) -JSD_IsStackFrameDebugger(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_IsStackFrameDebugger(jsdc, jsdthreadstate, jsdframe); -} - -JSD_PUBLIC_API(bool) -JSD_IsStackFrameConstructing(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_IsStackFrameConstructing(jsdc, jsdthreadstate, jsdframe); -} - -JSD_PUBLIC_API(bool) -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); - MOZ_ASSERT(bytes); - MOZ_ASSERT(length); - MOZ_ASSERT(filename); - - return jsd_EvaluateUCScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, - bytes, length, filename, lineno, - true, rval); -} - -JSD_PUBLIC_API(bool) -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); - MOZ_ASSERT(bytes); - MOZ_ASSERT(length); - MOZ_ASSERT(filename); - - return jsd_EvaluateUCScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, - bytes, length, filename, lineno, - false, rval); -} - -JSD_PUBLIC_API(bool) -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); - MOZ_ASSERT(bytes); - MOZ_ASSERT(length); - MOZ_ASSERT(filename); - - return jsd_EvaluateScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, - bytes, length, - filename, lineno, true, rval); -} - -JSD_PUBLIC_API(bool) -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); - MOZ_ASSERT(bytes); - MOZ_ASSERT(length); - MOZ_ASSERT(filename); - - return jsd_EvaluateScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, - bytes, length, - filename, lineno, 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(bool) -JSD_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, - JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetException(jsdc, jsdthreadstate, jsdval); -} - -/***************************************************************************/ - -JSD_PUBLIC_API(bool) -JSD_SetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter reporter, - void* callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_SetErrorReporter(jsdc, reporter, callerdata); -} - -JSD_PUBLIC_API(bool) -JSD_GetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter* reporter, - void** callerdata) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - return jsd_GetErrorReporter(jsdc, reporter, callerdata); -} - -/***************************************************************************/ - -JSD_PUBLIC_API(bool) -JSD_IsLockingAndThreadIdSupported() -{ -#ifdef JSD_THREADSAFE - return true; -#else - return 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(bool) -JSD_IsLocked(JSDStaticLock* lock) -{ -#if defined(JSD_THREADSAFE) && defined(DEBUG) - return jsd_IsLocked(lock); -#else - return true; -#endif -} - -JSD_PUBLIC_API(bool) -JSD_IsUnlocked(JSDStaticLock* lock) -{ -#if defined(JSD_THREADSAFE) && defined(DEBUG) - return ! jsd_IsLocked(lock); -#else - return 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(bool) -JSD_IsValueObject(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueObject(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueNumber(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueInt(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueInt(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueDouble(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueString(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueString(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueBoolean(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueNull(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueNull(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueVoid(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValuePrimitive(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueFunction(jsdc, jsdval); -} - -JSD_PUBLIC_API(bool) -JSD_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) -{ - JSD_ASSERT_VALID_CONTEXT(jsdc); - JSD_ASSERT_VALID_VALUE(jsdval); - return jsd_IsValueNative(jsdc, jsdval); -} - -/**************************************************/ - -JSD_PUBLIC_API(bool) -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); - MOZ_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); - MOZ_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); - MOZ_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); -} diff --git a/js/jsd/jsdebug.h b/js/jsd/jsdebug.h deleted file mode 100644 index 4f81a55f8053..000000000000 --- a/js/jsd/jsdebug.h +++ /dev/null @@ -1,1524 +0,0 @@ -/* -*- 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___ - -#include "jstypes.h" -#include "js/TypeDecls.h" - -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-nullptr 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 nullptr to start iteration. -* NOTE: must lock and unlock the subsystem -* example: -* -* JSDScript jsdscript; -* JSDScript iter = nullptr; -* -* JSD_LockScriptSubsystem(jsdc); -* while((jsdscript = JSD_IterateScripts(jsdc, &iter)) != nullptr) { -* *** 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(bool) -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 (nullptr 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 true if creating new script, 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, - bool 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(bool) -JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata); - -/* -* Get the current script hook. -*/ -extern JSD_PUBLIC_API(bool) -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. - * nullptr may be passed for either lines or pcs to avoid filling anything in - * for that argument. - */ -extern JSD_PUBLIC_API(bool) -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 nullptr if 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(bool) -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(bool) -JSD_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc); - -/* -* Clear the dirty flag -*/ -extern JSD_PUBLIC_API(void) -JSD_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, bool 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 item already exists for the given URL -* then the old item is removed. -* 'url' may not be nullptr. -*/ -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 -* nullptr 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, - * nullptr, 0, JSD_SOURCE_COMPLETED); - * JSD_UNLOCK_SOURCE_TEXT(jsdc); - * return jsdsrc ? true : false; - */ -extern JSD_PUBLIC_API(bool) -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, - JS::Value* 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 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 bool -(* 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(bool) -JSD_SetExecutionHook(JSDContext* jsdc, - JSDScript* jsdscript, - uintptr_t pc, - JSD_ExecutionHookProc hook, - void* callerdata); - -/* -* Clear the hook for this pc -*/ -extern JSD_PUBLIC_API(bool) -JSD_ClearExecutionHook(JSDContext* jsdc, - JSDScript* jsdscript, - uintptr_t pc); - -/* -* Clear all the pc specific hooks for this script -*/ -extern JSD_PUBLIC_API(bool) -JSD_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript); - -/* -* Clear all the pc specific hooks for the entire JSRuntime associated with -* this JSDContext -*/ -extern JSD_PUBLIC_API(bool) -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(bool) -JSD_SetInterruptHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); - -/* -* Call the interrupt hook at least once per source line -*/ -extern JSD_PUBLIC_API(bool) -JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript *jsdscript, bool enable); - -/* -* Clear the current interrupt hook. -*/ -extern JSD_PUBLIC_API(bool) -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(bool) -JSD_SetDebugBreakHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); - -/* -* Clear the debug break hook -*/ -extern JSD_PUBLIC_API(bool) -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(bool) -JSD_SetDebuggerHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); - -/* -* Clear the 'debugger' keyword hook -*/ -extern JSD_PUBLIC_API(bool) -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(bool) -JSD_SetThrowHook(JSDContext* jsdc, - JSD_ExecutionHookProc hook, - void* callerdata); -/* -* Clear the throw hook -*/ -extern JSD_PUBLIC_API(bool) -JSD_ClearThrowHook(JSDContext* jsdc); - -/* -* Set the hook that should be called when a toplevel script begins or completes. -*/ -extern JSD_PUBLIC_API(bool) -JSD_SetTopLevelHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata); -/* -* Clear the toplevel call hook -*/ -extern JSD_PUBLIC_API(bool) -JSD_ClearTopLevelHook(JSDContext* jsdc); - -/* -* Set the hook that should be called when a function call or return happens. -*/ -extern JSD_PUBLIC_API(bool) -JSD_SetFunctionHook(JSDContext* jsdc, - JSD_CallHookProc hook, - void* callerdata); -/* -* Clear the function call hook -*/ -extern JSD_PUBLIC_API(bool) -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(bool) -JSD_IsStackFrameDebugger(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe); - -/* -* True if stack frame is constructing a new object. -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsStackFrameConstructing(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe); - -/* -* Evaluate the given unicode source code in the context of the given stack frame. -* returns true and puts result in rval on success, false on failure. -* NOTE: The ErrorReporter hook might be called if this fails. -*/ -extern JSD_PUBLIC_API(bool) -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(bool) -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(bool) -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(bool) -JSD_AttemptScriptInStackFrame(JSDContext* jsdc, - JSDThreadState* jsdthreadstate, - JSDStackFrameInfo* jsdframe, - const char *bytes, unsigned length, - const char *filename, unsigned lineno, JS::MutableHandleValue rval); - -/* -* Convert the given JS::Value 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, - JS::Value val); - -/* -* Get the JSDValue currently being thrown as an exception (may be nullptr). -* NOTE: must eventually release by calling JSD_DropValue (if not nullptr) -* *** 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(bool) -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(bool) -JSD_SetErrorReporter(JSDContext* jsdc, - JSD_ErrorReporter reporter, - void* callerdata); - -/* Get Current ErrorReporter hook */ -extern JSD_PUBLIC_API(bool) -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(bool) -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 true -* So JSD_IsLocked(lock) may not equal !JSD_IsUnlocked(lock) -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsLocked(JSDStaticLock* lock); - -/* -* See above... -*/ -extern JSD_PUBLIC_API(bool) -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 JS::Values. -* 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 JS::Value -* NOTE: must eventually release by calling JSD_DropValue (if not nullptr) -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(JSDValue*) -JSD_NewValue(JSDContext* jsdc, JS::Value 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 JS::Value wrapped by this JSDValue -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(JS::Value) -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(bool) -JSD_IsValueObject(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a number (int or double)? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap an int? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueInt(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a double? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a JSString? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueString(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a bool? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a JSVAL_NULL? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueNull(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a JSVAL_VOID? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a primative (not a JSObject)? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a function? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval); - -/* -* Does the JSDValue wrap a native function? -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -JSD_IsValueNative(JSDContext* jsdc, JSDValue* jsdval); - -/**************************************************/ - -/* -* Return bool value (does NOT do conversion). -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(bool) -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 nullptr) -* *** 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 nullptr) -* *** 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 nullptr) -* *** 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 nullptr) -* *** 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 js/OldDebugAPI.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 false */ - /* without throwing an exception */ -/* this is not one of the JSPD_ flags in js/OldDebugAPI.h - don't 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 nullptr) -* *** 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 nullptr) -* *** 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 nullptr. -* *** 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 nullptr. -* *** 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 nullptr. -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(const char*) -JSD_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj); - -/* -* Get JSDObject representing this JSObject. -* May return nullptr. -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(JSDObject*) -JSD_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj); - -/* -* Get JSDObject representing this JSDValue. -* May return nullptr. -* *** 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 nullptr) -* *** new for version 1.1 **** -*/ -extern JSD_PUBLIC_API(JSDValue*) -JSD_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj); - -} // extern "C" - -#endif /* jsdebug_h___ */ diff --git a/js/jsd/jsdstubs.cpp b/js/jsd/jsdstubs.cpp deleted file mode 100644 index 22420410251c..000000000000 --- a/js/jsd/jsdstubs.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- 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 deleted file mode 100644 index fac1bade28c2..000000000000 --- a/js/jsd/jshash.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/* -*- 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 "jshash.h" - -#include "mozilla/MathAlgorithms.h" - -#include -#include - -#include "jstypes.h" - -#include "js/Utility.h" - -using namespace js; - -using mozilla::CeilingLog2Size; -using mozilla::RotateLeft; - -/* 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 const JSHashAllocOps defaultHashAllocOps = { - DefaultAllocTable, DefaultFreeTable, - DefaultAllocEntry, DefaultFreeEntry -}; - -JSHashTable * -JS_NewHashTable(uint32_t n, JSHashFunction keyHash, - JSHashComparator keyCompare, JSHashComparator valueCompare, - const JSHashAllocOps *allocOps, void *allocPriv) -{ - JSHashTable *ht; - size_t nb; - - if (n <= MINBUCKETS) { - n = MINBUCKETSLOG2; - } else { - n = CeilingLog2Size(n); - if (int32_t(n) < 0) - return nullptr; - } - - if (!allocOps) allocOps = &defaultHashAllocOps; - - ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht); - if (!ht) - return nullptr; - 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 nullptr; - } - 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; - const JSHashAllocOps *allocOps = ht->allocOps; - void *allocPriv = ht->allocPriv; - - n = NBUCKETS(ht); - for (i = 0; i < n; i++) { - hep = &ht->buckets[i]; - while ((he = *hep) != nullptr) { - *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) != nullptr) { - 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 bool -Resize(JSHashTable *ht, uint32_t newshift) -{ - size_t nb, nentries, i; - JSHashEntry **oldbuckets, *he, *next, **hep; - size_t nold = NBUCKETS(ht); - - MOZ_ASSERT(newshift < JS_HASH_BITS); - - nb = (size_t)1 << (JS_HASH_BITS - newshift); - - /* Integer overflow protection. */ - if (nb > (size_t)-1 / sizeof(JSHashEntry*)) - return false; - nb *= sizeof(JSHashEntry*); - - oldbuckets = ht->buckets; - ht->buckets = (JSHashEntry**)ht->allocOps->allocTable(ht->allocPriv, nb); - if (!ht->buckets) { - ht->buckets = oldbuckets; - return 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) { - MOZ_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 = nullptr; - *hep = he; - } - } -#ifdef DEBUG - memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]); -#endif - ht->allocOps->freeTable(ht->allocPriv, oldbuckets, - nold * sizeof oldbuckets[0]); - return 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 nullptr; -#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 nullptr; - 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) != nullptr) { - /* 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 - } -} - -bool -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) == nullptr) - return false; - - /* Hit; remove element */ - JS_HashTableRawRemove(ht, hep, he); - return 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) != nullptr) { - return he->value; - } - return nullptr; -} - -/* -** 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) != nullptr) { - MOZ_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) { - MOZ_ASSERT(ht->nentries < nlimit); - nbuckets = NBUCKETS(ht); - if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) { - newlog2 = CeilingLog2Size(ht->nentries); - if (newlog2 < MINBUCKETSLOG2) - newlog2 = MINBUCKETSLOG2; - - /* Check that we really shrink the table. */ - MOZ_ASSERT(JS_HASH_BITS - ht->shift > newlog2); - Resize(ht, JS_HASH_BITS - newlog2); - } - } - return (int)n; -} - -#ifdef JS_HASHMETER -#include - -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 = RotateLeft(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 deleted file mode 100644 index 76077977eec0..000000000000 --- a/js/jsd/jshash.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- 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 -#include -#include - -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 */ - const 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, - const 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); - -extern JSHashEntry * -JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, JSHashNumber keyHash, - const void *key, void *value); - -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 bool -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); - -} // extern "C" - -#endif /* jshash_h___ */ diff --git a/js/jsd/mkshell.bat b/js/jsd/mkshell.bat deleted file mode 100755 index a00f46822ca3..000000000000 --- a/js/jsd/mkshell.bat +++ /dev/null @@ -1,8 +0,0 @@ -@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 deleted file mode 100644 index 2d800f469783..000000000000 --- a/js/jsd/moz.build +++ /dev/null @@ -1,39 +0,0 @@ -# -*- 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'] - -EXPORTS += [ - 'jsdebug.h', -] - -XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini'] - -UNIFIED_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', -] - -DEFINES['EXPORT_JSD_API'] = True - -if CONFIG['JS_THREADSAFE']: - DEFINES['JS_THREADSAFE'] = True - -FINAL_LIBRARY = 'xul' - -FAIL_ON_WARNINGS = True diff --git a/js/jsd/resource.h b/js/jsd/resource.h deleted file mode 100644 index 69874fe0ff30..000000000000 --- a/js/jsd/resource.h +++ /dev/null @@ -1,21 +0,0 @@ -/* -*- 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/bug507448.js b/js/jsd/test/bug507448.js deleted file mode 100644 index 9f7c2a61e712..000000000000 --- a/js/jsd/test/bug507448.js +++ /dev/null @@ -1,24 +0,0 @@ - -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 deleted file mode 100644 index 91c7ce980a43..000000000000 --- a/js/jsd/test/jsd-test.js +++ /dev/null @@ -1,117 +0,0 @@ -const Cc = SpecialPowers.Cc; -const Ci = SpecialPowers.Ci; -const RETURN_CONTINUE = Ci.jsdIExecutionHook.RETURN_CONTINUE; -const DebuggerService = Cc["@mozilla.org/js/jsd/debugger-service;1"]; - -var jsd = Cc['@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) { - 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/mochitest.ini b/js/jsd/test/mochitest.ini deleted file mode 100644 index a0c2a0251093..000000000000 --- a/js/jsd/test/mochitest.ini +++ /dev/null @@ -1,13 +0,0 @@ -[DEFAULT] -skip-if = buildapp == 'b2g' -support-files = - bug507448.js - jsd-test.js - test-bug617870-callhooks.js - test-bug638178-execlines.js - -[test_bug507448.html] -skip-if = toolkit == 'android' #TIMED_OUT -[test_bug617870-callhooks.html] -skip-if = toolkit == 'android' #TIMED_OUT -[test_bug638178-execlines.html] diff --git a/js/jsd/test/moz.build b/js/jsd/test/moz.build deleted file mode 100644 index 3cf16eb0cfe8..000000000000 --- a/js/jsd/test/moz.build +++ /dev/null @@ -1,8 +0,0 @@ -# -*- 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/. - -MOCHITEST_MANIFESTS += ['mochitest.ini'] - diff --git a/js/jsd/test/test-bug617870-callhooks.js b/js/jsd/test/test-bug617870-callhooks.js deleted file mode 100644 index a3d3b91448c4..000000000000 --- a/js/jsd/test/test-bug617870-callhooks.js +++ /dev/null @@ -1,50 +0,0 @@ -g = { 'global noneval': 1 }; - -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) { - 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 deleted file mode 100644 index a4024bac434c..000000000000 --- a/js/jsd/test/test-bug638178-execlines.js +++ /dev/null @@ -1,92 +0,0 @@ - -var jsdIScript = SpecialPowers.Ci.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 = SpecialPowers.Ci.jsdIFilter; - -function testJSD(jsd) { - 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) { - 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 deleted file mode 100644 index 7ffffb3dff5f..000000000000 --- a/js/jsd/test/test_bug507448.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - Test for Bug 507448 - - - - - - - -Mozilla Bug 507448 -

- -
-
-
-
-
- - diff --git a/js/jsd/test/test_bug617870-callhooks.html b/js/jsd/test/test_bug617870-callhooks.html deleted file mode 100644 index 7b868e5dd29e..000000000000 --- a/js/jsd/test/test_bug617870-callhooks.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - JSD Test for Bug AUTOFILLED - - - - - - - - -

- - - -
-
- - - diff --git a/js/jsd/test/test_bug638178-execlines.html b/js/jsd/test/test_bug638178-execlines.html deleted file mode 100644 index 6b66ef176c8b..000000000000 --- a/js/jsd/test/test_bug638178-execlines.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - JSD Test for Bug AUTOFILLED - - - - - - - - -

- - - -
-
- - - diff --git a/js/jsd/test/test_evalCached.js b/js/jsd/test/test_evalCached.js deleted file mode 100644 index 4c56ef2eaf8d..000000000000 --- a/js/jsd/test/test_evalCached.js +++ /dev/null @@ -1,23 +0,0 @@ -// 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 deleted file mode 100644 index a2ddba866568..000000000000 --- a/js/jsd/test/test_jsval_retval.js +++ /dev/null @@ -1,42 +0,0 @@ -// 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 deleted file mode 100644 index c4e7d43471aa..000000000000 --- a/js/jsd/test/xpcshell.ini +++ /dev/null @@ -1,17 +0,0 @@ -[DEFAULT] -head = -tail = -support-files = - bug507448.js - jsd-test.js - test-bug617870-callhooks.js - test-bug638178-execlines.js - test_bug507448.html - test_bug617870-callhooks.html - test_bug638178-execlines.html - -[test_jsval_retval.js] -debug = 1 - -[test_evalCached.js] -debug = 1 diff --git a/js/public/HashTable.h b/js/public/HashTable.h index a64a5286ac52..d2759722aae2 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -479,6 +479,13 @@ class HashSet impl.rekeyAndMaybeRehash(p, new_lookup, new_value); } + // Infallibly rekey one entry with a new key that is equivalent. + void rekeyInPlace(Ptr p, const T &new_value) + { + MOZ_ASSERT(HashPolicy::match(*p, new_value)); + impl.rekeyInPlace(p, new_value); + } + // HashSet is movable HashSet(HashSet &&rhs) : impl(mozilla::Move(rhs.impl)) {} void operator=(HashSet &&rhs) { @@ -1629,6 +1636,14 @@ class HashTable : private AllocPolicy checkOverRemoved(); } + void rekeyInPlace(Ptr p, const Key &k) + { + MOZ_ASSERT(table); + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(p.found()); + HashPolicy::rekey(const_cast(*p), const_cast(k)); + } + #undef METER }; diff --git a/js/src/jit-test/etc/generate-nosuchproperty-tests.js b/js/src/jit-test/etc/generate-nosuchproperty-tests.js new file mode 100644 index 000000000000..7eaec2ae60e2 --- /dev/null +++ b/js/src/jit-test/etc/generate-nosuchproperty-tests.js @@ -0,0 +1,78 @@ + +// This code generates the test cases jit-test/tests/baseline/no-such-property-getprop.js +// +// In particular, it generates the testChain__() and runChain__() functions +// at the tail of the file. + +var TEST_CASE_FUNCS = []; +function runChain_NNNN_DDDD(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_NNNN_DDDD() { + var obj = createTower(NNNN); + assertEq(runChain_NNNN_DDDD(obj), NaN); + updateChain(obj, DDDD, 'foo', 9); + assertEq(runChain_NNNN_DDDD(obj), 900); +} +function generateTestCase(n, d) { + var runFuncName = "runChain_" + n + "_" + d; + var testFuncName = "testChain_" + n + "_" + d; + TEST_CASE_FUNCS.push(testFuncName); + + print("//// Test chain of length " + n + " with late-property-addition at depth " + d); + print(uneval(runChain_NNNN_DDDD).replace(/NNNN/g, ''+n).replace(/DDDD/g, ''+d)); + print(uneval(testChain_NNNN_DDDD).replace(/NNNN/g, ''+n).replace(/DDDD/g, ''+d)); + print(""); +} + +// Helper function to create an object with a proto-chain of length N. +function createTower(n) { + var result = Object.create(null); + for (var i = 0; i < n; i++) + result = Object.create(result); + return result; +} + +function updateChain(obj, depth, prop, value) { + // Walk down the proto chain |depth| iterations and set |prop| to |value|. + var cur = obj; + for (var i = 0; i < depth; i++) + cur = Object.getPrototypeOf(cur); + + var desc = {value:value, writable:true, configurable:true, enumerable:true}; + Object.defineProperty(cur, prop, desc); +} + +print("/////////////////////////////////////////"); +print("// This is a generated file!"); +print("// See jit-tests/etc/generate-nosuchproperty-tests.js for the code"); +print("// that generated this code!"); +print("/////////////////////////////////////////"); +print(""); +print("/////////////////////////////////////////"); +print("// PRELUDE //"); +print("/////////////////////////////////////////"); +print(""); +print(createTower); +print(updateChain); +print(""); +print("/////////////////////////////////////////"); +print("// TEST CASES //"); +print("/////////////////////////////////////////"); +print(""); +for (var n = 0; n <= 10; n++) { + for (var d = 0; d <= n; d++) { + generateTestCase(n, d); + } +} + +print(""); +print("/////////////////////////////////////////"); +print("// RUNNER //"); +print("/////////////////////////////////////////"); +print(""); +for (var i = 0; i < TEST_CASE_FUNCS.length; i++) + print(TEST_CASE_FUNCS[i] + "();"); diff --git a/js/src/jit-test/tests/baseline/no-such-property-getprop.js b/js/src/jit-test/tests/baseline/no-such-property-getprop.js new file mode 100644 index 000000000000..72303d266066 --- /dev/null +++ b/js/src/jit-test/tests/baseline/no-such-property-getprop.js @@ -0,0 +1,1025 @@ +///////////////////////////////////////// +// This is a generated file! +// See jit-tests/etc/generate-nosuchproperty-tests.js for the code +// that generated this code! +///////////////////////////////////////// + +///////////////////////////////////////// +// PRELUDE // +///////////////////////////////////////// + +function createTower(n) { + var result = Object.create(null); + for (var i = 0; i < n; i++) + result = Object.create(result); + return result; +} +function updateChain(obj, depth, prop, value) { + // Walk down the proto chain |depth| iterations and set |prop| to |value|. + var cur = obj; + for (var i = 0; i < depth; i++) + cur = Object.getPrototypeOf(cur); + + var desc = {value:value, writable:true, configurable:true, enumerable:true}; + Object.defineProperty(cur, prop, desc); +} + +///////////////////////////////////////// +// TEST CASES // +///////////////////////////////////////// + +//// Test chain of length 0 with late-property-addition at depth 0 +function runChain_0_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_0_0() { + var obj = createTower(0); + assertEq(runChain_0_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_0_0(obj), 900); +} + +//// Test chain of length 1 with late-property-addition at depth 0 +function runChain_1_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_1_0() { + var obj = createTower(1); + assertEq(runChain_1_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_1_0(obj), 900); +} + +//// Test chain of length 1 with late-property-addition at depth 1 +function runChain_1_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_1_1() { + var obj = createTower(1); + assertEq(runChain_1_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_1_1(obj), 900); +} + +//// Test chain of length 2 with late-property-addition at depth 0 +function runChain_2_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_2_0() { + var obj = createTower(2); + assertEq(runChain_2_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_2_0(obj), 900); +} + +//// Test chain of length 2 with late-property-addition at depth 1 +function runChain_2_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_2_1() { + var obj = createTower(2); + assertEq(runChain_2_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_2_1(obj), 900); +} + +//// Test chain of length 2 with late-property-addition at depth 2 +function runChain_2_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_2_2() { + var obj = createTower(2); + assertEq(runChain_2_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_2_2(obj), 900); +} + +//// Test chain of length 3 with late-property-addition at depth 0 +function runChain_3_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_3_0() { + var obj = createTower(3); + assertEq(runChain_3_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_3_0(obj), 900); +} + +//// Test chain of length 3 with late-property-addition at depth 1 +function runChain_3_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_3_1() { + var obj = createTower(3); + assertEq(runChain_3_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_3_1(obj), 900); +} + +//// Test chain of length 3 with late-property-addition at depth 2 +function runChain_3_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_3_2() { + var obj = createTower(3); + assertEq(runChain_3_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_3_2(obj), 900); +} + +//// Test chain of length 3 with late-property-addition at depth 3 +function runChain_3_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_3_3() { + var obj = createTower(3); + assertEq(runChain_3_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_3_3(obj), 900); +} + +//// Test chain of length 4 with late-property-addition at depth 0 +function runChain_4_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_4_0() { + var obj = createTower(4); + assertEq(runChain_4_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_4_0(obj), 900); +} + +//// Test chain of length 4 with late-property-addition at depth 1 +function runChain_4_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_4_1() { + var obj = createTower(4); + assertEq(runChain_4_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_4_1(obj), 900); +} + +//// Test chain of length 4 with late-property-addition at depth 2 +function runChain_4_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_4_2() { + var obj = createTower(4); + assertEq(runChain_4_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_4_2(obj), 900); +} + +//// Test chain of length 4 with late-property-addition at depth 3 +function runChain_4_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_4_3() { + var obj = createTower(4); + assertEq(runChain_4_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_4_3(obj), 900); +} + +//// Test chain of length 4 with late-property-addition at depth 4 +function runChain_4_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_4_4() { + var obj = createTower(4); + assertEq(runChain_4_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_4_4(obj), 900); +} + +//// Test chain of length 5 with late-property-addition at depth 0 +function runChain_5_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_5_0() { + var obj = createTower(5); + assertEq(runChain_5_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_5_0(obj), 900); +} + +//// Test chain of length 5 with late-property-addition at depth 1 +function runChain_5_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_5_1() { + var obj = createTower(5); + assertEq(runChain_5_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_5_1(obj), 900); +} + +//// Test chain of length 5 with late-property-addition at depth 2 +function runChain_5_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_5_2() { + var obj = createTower(5); + assertEq(runChain_5_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_5_2(obj), 900); +} + +//// Test chain of length 5 with late-property-addition at depth 3 +function runChain_5_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_5_3() { + var obj = createTower(5); + assertEq(runChain_5_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_5_3(obj), 900); +} + +//// Test chain of length 5 with late-property-addition at depth 4 +function runChain_5_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_5_4() { + var obj = createTower(5); + assertEq(runChain_5_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_5_4(obj), 900); +} + +//// Test chain of length 5 with late-property-addition at depth 5 +function runChain_5_5(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_5_5() { + var obj = createTower(5); + assertEq(runChain_5_5(obj), NaN); + updateChain(obj, 5, 'foo', 9); + assertEq(runChain_5_5(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 0 +function runChain_6_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_0() { + var obj = createTower(6); + assertEq(runChain_6_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_6_0(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 1 +function runChain_6_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_1() { + var obj = createTower(6); + assertEq(runChain_6_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_6_1(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 2 +function runChain_6_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_2() { + var obj = createTower(6); + assertEq(runChain_6_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_6_2(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 3 +function runChain_6_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_3() { + var obj = createTower(6); + assertEq(runChain_6_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_6_3(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 4 +function runChain_6_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_4() { + var obj = createTower(6); + assertEq(runChain_6_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_6_4(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 5 +function runChain_6_5(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_5() { + var obj = createTower(6); + assertEq(runChain_6_5(obj), NaN); + updateChain(obj, 5, 'foo', 9); + assertEq(runChain_6_5(obj), 900); +} + +//// Test chain of length 6 with late-property-addition at depth 6 +function runChain_6_6(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_6_6() { + var obj = createTower(6); + assertEq(runChain_6_6(obj), NaN); + updateChain(obj, 6, 'foo', 9); + assertEq(runChain_6_6(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 0 +function runChain_7_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_0() { + var obj = createTower(7); + assertEq(runChain_7_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_7_0(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 1 +function runChain_7_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_1() { + var obj = createTower(7); + assertEq(runChain_7_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_7_1(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 2 +function runChain_7_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_2() { + var obj = createTower(7); + assertEq(runChain_7_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_7_2(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 3 +function runChain_7_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_3() { + var obj = createTower(7); + assertEq(runChain_7_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_7_3(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 4 +function runChain_7_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_4() { + var obj = createTower(7); + assertEq(runChain_7_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_7_4(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 5 +function runChain_7_5(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_5() { + var obj = createTower(7); + assertEq(runChain_7_5(obj), NaN); + updateChain(obj, 5, 'foo', 9); + assertEq(runChain_7_5(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 6 +function runChain_7_6(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_6() { + var obj = createTower(7); + assertEq(runChain_7_6(obj), NaN); + updateChain(obj, 6, 'foo', 9); + assertEq(runChain_7_6(obj), 900); +} + +//// Test chain of length 7 with late-property-addition at depth 7 +function runChain_7_7(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_7_7() { + var obj = createTower(7); + assertEq(runChain_7_7(obj), NaN); + updateChain(obj, 7, 'foo', 9); + assertEq(runChain_7_7(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 0 +function runChain_8_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_0() { + var obj = createTower(8); + assertEq(runChain_8_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_8_0(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 1 +function runChain_8_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_1() { + var obj = createTower(8); + assertEq(runChain_8_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_8_1(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 2 +function runChain_8_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_2() { + var obj = createTower(8); + assertEq(runChain_8_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_8_2(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 3 +function runChain_8_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_3() { + var obj = createTower(8); + assertEq(runChain_8_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_8_3(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 4 +function runChain_8_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_4() { + var obj = createTower(8); + assertEq(runChain_8_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_8_4(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 5 +function runChain_8_5(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_5() { + var obj = createTower(8); + assertEq(runChain_8_5(obj), NaN); + updateChain(obj, 5, 'foo', 9); + assertEq(runChain_8_5(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 6 +function runChain_8_6(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_6() { + var obj = createTower(8); + assertEq(runChain_8_6(obj), NaN); + updateChain(obj, 6, 'foo', 9); + assertEq(runChain_8_6(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 7 +function runChain_8_7(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_7() { + var obj = createTower(8); + assertEq(runChain_8_7(obj), NaN); + updateChain(obj, 7, 'foo', 9); + assertEq(runChain_8_7(obj), 900); +} + +//// Test chain of length 8 with late-property-addition at depth 8 +function runChain_8_8(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_8_8() { + var obj = createTower(8); + assertEq(runChain_8_8(obj), NaN); + updateChain(obj, 8, 'foo', 9); + assertEq(runChain_8_8(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 0 +function runChain_9_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_0() { + var obj = createTower(9); + assertEq(runChain_9_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_9_0(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 1 +function runChain_9_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_1() { + var obj = createTower(9); + assertEq(runChain_9_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_9_1(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 2 +function runChain_9_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_2() { + var obj = createTower(9); + assertEq(runChain_9_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_9_2(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 3 +function runChain_9_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_3() { + var obj = createTower(9); + assertEq(runChain_9_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_9_3(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 4 +function runChain_9_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_4() { + var obj = createTower(9); + assertEq(runChain_9_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_9_4(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 5 +function runChain_9_5(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_5() { + var obj = createTower(9); + assertEq(runChain_9_5(obj), NaN); + updateChain(obj, 5, 'foo', 9); + assertEq(runChain_9_5(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 6 +function runChain_9_6(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_6() { + var obj = createTower(9); + assertEq(runChain_9_6(obj), NaN); + updateChain(obj, 6, 'foo', 9); + assertEq(runChain_9_6(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 7 +function runChain_9_7(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_7() { + var obj = createTower(9); + assertEq(runChain_9_7(obj), NaN); + updateChain(obj, 7, 'foo', 9); + assertEq(runChain_9_7(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 8 +function runChain_9_8(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_8() { + var obj = createTower(9); + assertEq(runChain_9_8(obj), NaN); + updateChain(obj, 8, 'foo', 9); + assertEq(runChain_9_8(obj), 900); +} + +//// Test chain of length 9 with late-property-addition at depth 9 +function runChain_9_9(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_9_9() { + var obj = createTower(9); + assertEq(runChain_9_9(obj), NaN); + updateChain(obj, 9, 'foo', 9); + assertEq(runChain_9_9(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 0 +function runChain_10_0(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_0() { + var obj = createTower(10); + assertEq(runChain_10_0(obj), NaN); + updateChain(obj, 0, 'foo', 9); + assertEq(runChain_10_0(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 1 +function runChain_10_1(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_1() { + var obj = createTower(10); + assertEq(runChain_10_1(obj), NaN); + updateChain(obj, 1, 'foo', 9); + assertEq(runChain_10_1(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 2 +function runChain_10_2(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_2() { + var obj = createTower(10); + assertEq(runChain_10_2(obj), NaN); + updateChain(obj, 2, 'foo', 9); + assertEq(runChain_10_2(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 3 +function runChain_10_3(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_3() { + var obj = createTower(10); + assertEq(runChain_10_3(obj), NaN); + updateChain(obj, 3, 'foo', 9); + assertEq(runChain_10_3(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 4 +function runChain_10_4(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_4() { + var obj = createTower(10); + assertEq(runChain_10_4(obj), NaN); + updateChain(obj, 4, 'foo', 9); + assertEq(runChain_10_4(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 5 +function runChain_10_5(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_5() { + var obj = createTower(10); + assertEq(runChain_10_5(obj), NaN); + updateChain(obj, 5, 'foo', 9); + assertEq(runChain_10_5(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 6 +function runChain_10_6(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_6() { + var obj = createTower(10); + assertEq(runChain_10_6(obj), NaN); + updateChain(obj, 6, 'foo', 9); + assertEq(runChain_10_6(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 7 +function runChain_10_7(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_7() { + var obj = createTower(10); + assertEq(runChain_10_7(obj), NaN); + updateChain(obj, 7, 'foo', 9); + assertEq(runChain_10_7(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 8 +function runChain_10_8(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_8() { + var obj = createTower(10); + assertEq(runChain_10_8(obj), NaN); + updateChain(obj, 8, 'foo', 9); + assertEq(runChain_10_8(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 9 +function runChain_10_9(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_9() { + var obj = createTower(10); + assertEq(runChain_10_9(obj), NaN); + updateChain(obj, 9, 'foo', 9); + assertEq(runChain_10_9(obj), 900); +} + +//// Test chain of length 10 with late-property-addition at depth 10 +function runChain_10_10(obj) { + var sum = 0; + for (var i = 0; i < 100; i++) + sum += obj.foo; + return sum; +} +function testChain_10_10() { + var obj = createTower(10); + assertEq(runChain_10_10(obj), NaN); + updateChain(obj, 10, 'foo', 9); + assertEq(runChain_10_10(obj), 900); +} + + +///////////////////////////////////////// +// RUNNER // +///////////////////////////////////////// + +testChain_0_0(); +testChain_1_0(); +testChain_1_1(); +testChain_2_0(); +testChain_2_1(); +testChain_2_2(); +testChain_3_0(); +testChain_3_1(); +testChain_3_2(); +testChain_3_3(); +testChain_4_0(); +testChain_4_1(); +testChain_4_2(); +testChain_4_3(); +testChain_4_4(); +testChain_5_0(); +testChain_5_1(); +testChain_5_2(); +testChain_5_3(); +testChain_5_4(); +testChain_5_5(); +testChain_6_0(); +testChain_6_1(); +testChain_6_2(); +testChain_6_3(); +testChain_6_4(); +testChain_6_5(); +testChain_6_6(); +testChain_7_0(); +testChain_7_1(); +testChain_7_2(); +testChain_7_3(); +testChain_7_4(); +testChain_7_5(); +testChain_7_6(); +testChain_7_7(); +testChain_8_0(); +testChain_8_1(); +testChain_8_2(); +testChain_8_3(); +testChain_8_4(); +testChain_8_5(); +testChain_8_6(); +testChain_8_7(); +testChain_8_8(); +testChain_9_0(); +testChain_9_1(); +testChain_9_2(); +testChain_9_3(); +testChain_9_4(); +testChain_9_5(); +testChain_9_6(); +testChain_9_7(); +testChain_9_8(); +testChain_9_9(); +testChain_10_0(); +testChain_10_1(); +testChain_10_2(); +testChain_10_3(); +testChain_10_4(); +testChain_10_5(); +testChain_10_6(); +testChain_10_7(); +testChain_10_8(); +testChain_10_9(); +testChain_10_10(); diff --git a/js/src/jit/AliasAnalysis.cpp b/js/src/jit/AliasAnalysis.cpp index 9af26acce844..79abbdb47d49 100644 --- a/js/src/jit/AliasAnalysis.cpp +++ b/js/src/jit/AliasAnalysis.cpp @@ -177,8 +177,7 @@ AliasAnalysis::analyze() // Type analysis may have inserted new instructions. Since this pass depends // on the instruction number ordering, all instructions are renumbered. - // We start with 1 because some passes use 0 to denote failure. - uint32_t newId = 1; + uint32_t newId = 0; for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { if (mir->shouldCancel("Alias Analysis (main loop)")) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 8e1d10f576e9..8365a29097b3 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -335,6 +335,23 @@ ICStub::trace(JSTracer *trc) MarkShape(trc, &propStub->holderShape(), "baseline-getpropnativeproto-stub-holdershape"); break; } + case ICStub::GetProp_NativeDoesNotExist: { + ICGetProp_NativeDoesNotExist *propStub = toGetProp_NativeDoesNotExist(); + JS_STATIC_ASSERT(ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8); + switch (propStub->protoChainDepth()) { + case 0: propStub->toImpl<0>()->traceShapes(trc); break; + case 1: propStub->toImpl<1>()->traceShapes(trc); break; + case 2: propStub->toImpl<2>()->traceShapes(trc); break; + case 3: propStub->toImpl<3>()->traceShapes(trc); break; + case 4: propStub->toImpl<4>()->traceShapes(trc); break; + case 5: propStub->toImpl<5>()->traceShapes(trc); break; + case 6: propStub->toImpl<6>()->traceShapes(trc); break; + case 7: propStub->toImpl<7>()->traceShapes(trc); break; + case 8: propStub->toImpl<8>()->traceShapes(trc); break; + default: MOZ_ASSUME_UNREACHABLE("Invalid proto stub."); + } + break; + } case ICStub::GetProp_CallDOMProxyNative: case ICStub::GetProp_CallDOMProxyWithGenerationNative: { ICGetPropCallDOMProxyNativeStub *propStub; @@ -3340,6 +3357,35 @@ EffectlesslyLookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName n return true; } +static bool +CheckHasNoSuchProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, + MutableHandleObject lastProto, size_t *protoChainDepthOut) +{ + MOZ_ASSERT(protoChainDepthOut != nullptr); + + size_t depth = 0; + RootedObject curObj(cx, obj); + while (curObj) { + if (!curObj->isNative()) + return false; + + Shape *shape = curObj->nativeLookup(cx, NameToId(name)); + if (shape) + return false; + + JSObject *proto = curObj->getTaggedProto().toObjectOrNull(); + if (!proto) + break; + + curObj = proto; + depth++; + } + + lastProto.set(curObj); + *protoChainDepthOut = depth; + return true; +} + static bool IsCacheableProtoChain(JSObject *obj, JSObject *holder, bool isDOMProxy=false) { @@ -6335,6 +6381,48 @@ TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc return true; } +static bool +TryAttachNativeDoesNotExistStub(JSContext *cx, HandleScript script, jsbytecode *pc, + ICGetProp_Fallback *stub, HandlePropertyName name, + HandleValue val, bool *attached) +{ + MOZ_ASSERT(!*attached); + + if (!val.isObject()) + return true; + + RootedObject obj(cx, &val.toObject()); + + // Don't attach stubs for CALLPROP since those need NoSuchMethod handling. + if (JSOp(*pc) == JSOP_CALLPROP) + return true; + + // Check if does-not-exist can be confirmed on property. + RootedObject lastProto(cx); + size_t protoChainDepth = SIZE_MAX; + if (!CheckHasNoSuchProperty(cx, obj, name, &lastProto, &protoChainDepth)) + return true; + MOZ_ASSERT(protoChainDepth < SIZE_MAX); + + if (protoChainDepth > ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH) + return true; + + ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); + RootedShape objShape(cx, obj->lastProperty()); + RootedShape lastShape(cx, lastProto->lastProperty()); + + // Confirmed no-such-property. Add stub. + IonSpew(IonSpew_BaselineIC, " Generating GetProp_NativeDoesNotExist stub"); + ICGetPropNativeDoesNotExistCompiler compiler(cx, monitorStub, obj, protoChainDepth); + ICStub *newStub = compiler.getStub(compiler.getStubSpace(script)); + if (!newStub) + return false; + + stub->addNewStub(newStub); + *attached = true; + return true; +} + static bool DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_, MutableHandleValue val, MutableHandleValue res) @@ -6423,6 +6511,14 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_ return true; } + if (res.isUndefined()) { + // Try attaching property-not-found optimized stub for undefined results. + if (!TryAttachNativeDoesNotExistStub(cx, script, pc, stub, name, val, &attached)) + return false; + if (attached) + return true; + } + JS_ASSERT(!attached); stub->noteUnoptimizableAccess(); @@ -6680,6 +6776,87 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler &masm) return true; } +ICStub * +ICGetPropNativeDoesNotExistCompiler::getStub(ICStubSpace *space) +{ + AutoShapeVector shapes(cx); + if (!shapes.append(obj_->lastProperty())) + return nullptr; + + if (!GetProtoShapes(obj_, protoChainDepth_, &shapes)) + return nullptr; + + JS_STATIC_ASSERT(ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8); + + ICStub *stub = nullptr; + switch(protoChainDepth_) { + case 0: stub = getStubSpecific<0>(space, &shapes); break; + case 1: stub = getStubSpecific<1>(space, &shapes); break; + case 2: stub = getStubSpecific<2>(space, &shapes); break; + case 3: stub = getStubSpecific<3>(space, &shapes); break; + case 4: stub = getStubSpecific<4>(space, &shapes); break; + case 5: stub = getStubSpecific<5>(space, &shapes); break; + case 6: stub = getStubSpecific<6>(space, &shapes); break; + case 7: stub = getStubSpecific<7>(space, &shapes); break; + case 8: stub = getStubSpecific<8>(space, &shapes); break; + default: MOZ_ASSUME_UNREACHABLE("ProtoChainDepth too high."); + } + if (!stub) + return nullptr; + return stub; +} + +bool +ICGetPropNativeDoesNotExistCompiler::generateStubCode(MacroAssembler &masm) +{ + Label failure; + + GeneralRegisterSet regs(availableGeneralRegs(1)); + Register scratch = regs.takeAny(); + +#ifdef DEBUG + // Ensure that protoChainDepth_ matches the protoChainDepth stored on the stub. + { + Label ok; + masm.load16ZeroExtend(Address(BaselineStubReg, ICStub::offsetOfExtra()), scratch); + masm.branch32(Assembler::Equal, scratch, Imm32(protoChainDepth_), &ok); + masm.assumeUnreachable("Non-matching proto chain depth on stub."); + masm.bind(&ok); + } +#endif // DEBUG + + // Guard input is an object. + masm.branchTestObject(Assembler::NotEqual, R0, &failure); + + // Unbox and guard against old shape. + Register objReg = masm.extractObject(R0, ExtractTemp0); + masm.loadPtr(Address(BaselineStubReg, ICGetProp_NativeDoesNotExist::offsetOfShape(0)), + scratch); + masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure); + + Register protoReg = regs.takeAny(); + // Check the proto chain. + for (size_t i = 0; i < protoChainDepth_; i++) { + masm.loadObjProto(i == 0 ? objReg : protoReg, protoReg); + masm.branchTestPtr(Assembler::Zero, protoReg, protoReg, &failure); + size_t shapeOffset = ICGetProp_NativeDoesNotExistImpl<0>::offsetOfShape(i + 1); + masm.loadPtr(Address(BaselineStubReg, shapeOffset), scratch); + masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratch, &failure); + } + + // Shape and type checks succeeded, ok to proceed. + masm.moveValue(UndefinedValue(), R0); + + // Normally for this op, the result would have to be monitored by TI. + // However, since this stub ALWAYS returns UndefinedValue(), and we can be sure + // that undefined is already registered with the type-set, this can be avoided. + EmitReturnFromIC(masm); + + masm.bind(&failure); + EmitStubGuardFailure(masm); + return true; +} + bool ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm) { @@ -10125,6 +10302,43 @@ ICGetProp_NativePrototype::Clone(JSContext *cx, ICStubSpace *space, ICStub *firs holder, holderShape); } +ICGetProp_NativeDoesNotExist::ICGetProp_NativeDoesNotExist( + JitCode *stubCode, ICStub *firstMonitorStub, size_t protoChainDepth) + : ICMonitoredStub(GetProp_NativeDoesNotExist, stubCode, firstMonitorStub) +{ + MOZ_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH); + extra_ = protoChainDepth; +} + +/* static */ size_t +ICGetProp_NativeDoesNotExist::offsetOfShape(size_t idx) +{ + MOZ_ASSERT(ICGetProp_NativeDoesNotExistImpl<0>::offsetOfShape(idx) == + ICGetProp_NativeDoesNotExistImpl< + ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH>::offsetOfShape(idx)); + return ICGetProp_NativeDoesNotExistImpl<0>::offsetOfShape(idx); +} + +template +ICGetProp_NativeDoesNotExistImpl::ICGetProp_NativeDoesNotExistImpl( + JitCode *stubCode, ICStub *firstMonitorStub, const AutoShapeVector *shapes) + : ICGetProp_NativeDoesNotExist(stubCode, firstMonitorStub, ProtoChainDepth) +{ + MOZ_ASSERT(shapes->length() == NumShapes); + for (size_t i = 0; i < NumShapes; i++) + shapes_[i].init((*shapes)[i]); +} + +ICGetPropNativeDoesNotExistCompiler::ICGetPropNativeDoesNotExistCompiler( + JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, size_t protoChainDepth) + : ICStubCompiler(cx, ICStub::GetProp_NativeDoesNotExist), + firstMonitorStub_(firstMonitorStub), + obj_(cx, obj), + protoChainDepth_(protoChainDepth) +{ + MOZ_ASSERT(protoChainDepth_ <= ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH); +} + ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, HandleObject holder, HandleShape holderShape, HandleFunction getter, uint32_t pcOffset) diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index f6e1ec1aeb50..0551ea9840ec 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -414,6 +414,7 @@ class ICEntry _(GetProp_Primitive) \ _(GetProp_StringLength) \ _(GetProp_Native) \ + _(GetProp_NativeDoesNotExist) \ _(GetProp_NativePrototype) \ _(GetProp_CallScripted) \ _(GetProp_CallNative) \ @@ -4412,6 +4413,104 @@ class ICGetPropNativeCompiler : public ICStubCompiler } }; +template class ICGetProp_NativeDoesNotExistImpl; + +class ICGetProp_NativeDoesNotExist : public ICMonitoredStub +{ + friend class ICStubSpace; + public: + static const size_t MAX_PROTO_CHAIN_DEPTH = 8; + + protected: + ICGetProp_NativeDoesNotExist(JitCode *stubCode, ICStub *firstMonitorStub, + size_t protoChainDepth); + + public: + static inline ICGetProp_NativeDoesNotExist *New(ICStubSpace *space, JitCode *code, + ICStub *firstMonitorStub, + size_t protoChainDepth) + { + if (!code) + return nullptr; + return space->allocate(code, firstMonitorStub, + protoChainDepth); + } + + size_t protoChainDepth() const { + MOZ_ASSERT(extra_ <= MAX_PROTO_CHAIN_DEPTH); + return extra_; + } + + template + ICGetProp_NativeDoesNotExistImpl *toImpl() { + MOZ_ASSERT(ProtoChainDepth == protoChainDepth()); + return static_cast *>(this); + } + + static size_t offsetOfShape(size_t idx); +}; + +template +class ICGetProp_NativeDoesNotExistImpl : public ICGetProp_NativeDoesNotExist +{ + friend class ICStubSpace; + public: + static const size_t MAX_PROTO_CHAIN_DEPTH = 8; + static const size_t NumShapes = ProtoChainDepth + 1; + + private: + mozilla::Array shapes_; + + ICGetProp_NativeDoesNotExistImpl(JitCode *stubCode, ICStub *firstMonitorStub, + const AutoShapeVector *shapes); + + public: + static inline ICGetProp_NativeDoesNotExistImpl *New( + ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, + const AutoShapeVector *shapes) + { + if (!code) + return nullptr; + return space->allocate>( + code, firstMonitorStub, shapes); + } + + void traceShapes(JSTracer *trc) { + for (size_t i = 0; i < NumShapes; i++) + MarkShape(trc, &shapes_[i], "baseline-getpropnativedoesnotexist-stub-shape"); + } + + static size_t offsetOfShape(size_t idx) { + return offsetof(ICGetProp_NativeDoesNotExistImpl, shapes_) + (idx * sizeof(HeapPtrShape)); + } +}; + +class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler +{ + ICStub *firstMonitorStub_; + RootedObject obj_; + size_t protoChainDepth_; + + protected: + virtual int32_t getKey() const { + return static_cast(kind) | (static_cast(protoChainDepth_) << 16); + } + + bool generateStubCode(MacroAssembler &masm); + + public: + ICGetPropNativeDoesNotExistCompiler(JSContext *cx, ICStub *firstMonitorStub, + HandleObject obj, size_t protoChainDepth); + + template + ICStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes) { + return ICGetProp_NativeDoesNotExistImpl::New(space, getStubCode(), + firstMonitorStub_, shapes); + } + + ICStub *getStub(ICStubSpace *space); +}; + class ICGetPropCallGetter : public ICMonitoredStub { friend class ICStubSpace; @@ -5155,7 +5254,8 @@ class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd } }; -class ICSetPropNativeAddCompiler : public ICStubCompiler { +class ICSetPropNativeAddCompiler : public ICStubCompiler +{ RootedObject obj_; RootedShape oldShape_; size_t protoChainDepth_; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index da8f27ebe223..8c6d8ad4ad9d 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3340,7 +3340,10 @@ CodeGenerator::generateBody() // blocks are created to split critical edges, and if we didn't end up // putting any instructions in them, we can skip them. if (current->isTrivial()) - continue; + continue; + + IonSpew(IonSpew_Codegen, "# block%lu%s:", i, + current->mir()->isLoopHeader() ? " (loop header)" : ""); masm.bind(current->label()); diff --git a/js/src/jit/EdgeCaseAnalysis.cpp b/js/src/jit/EdgeCaseAnalysis.cpp index 2fd418446863..30a18249639d 100644 --- a/js/src/jit/EdgeCaseAnalysis.cpp +++ b/js/src/jit/EdgeCaseAnalysis.cpp @@ -21,7 +21,7 @@ bool EdgeCaseAnalysis::analyzeLate() { // Renumber definitions for NeedNegativeZeroCheck under analyzeEdgeCasesBackward. - uint32_t nextId = 1; + uint32_t nextId = 0; for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) { if (mir->shouldCancel("Analyze Late (first loop)")) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 7c7820caf5e9..66b2c9b9654c 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1395,8 +1395,8 @@ OptimizeMIR(MIRGenerator *mir) if (mir->optimizationInfo().gvnEnabled()) { AutoTraceLog log(logger, TraceLogger::GVN); - ValueNumberer gvn(mir, graph, mir->optimizationInfo().gvnKind() == GVN_Optimistic); - if (!gvn.analyze()) + ValueNumberer gvn(mir, graph); + if (!gvn.run(ValueNumberer::UpdateAliasAnalysis)) return false; IonSpewPass("GVN"); AssertExtendedGraphCoherency(graph); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 8508443b7f19..e2e801a87072 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -6,6 +6,7 @@ #include "jit/IonAnalysis.h" +#include "jit/AliasAnalysis.h" #include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/Ion.h" @@ -1091,6 +1092,59 @@ jit::RenumberBlocks(MIRGraph &graph) return true; } +// A utility for code which deletes blocks. Renumber the remaining blocks, +// recompute dominators, and optionally recompute AliasAnalysis dependencies. +bool +jit::AccountForCFGChanges(MIRGenerator *mir, MIRGraph &graph, bool updateAliasAnalysis) +{ + // Renumber the blocks and clear out the old dominator info. + size_t id = 0; + for (ReversePostorderIterator i(graph.rpoBegin()), e(graph.rpoEnd()); i != e; ++i) { + i->clearDominatorInfo(); + i->setId(id++); + } + + // Recompute dominator info. + if (!BuildDominatorTree(graph)) + return false; + + // If needed, update alias analysis dependencies. + if (updateAliasAnalysis) { + if (!AliasAnalysis(mir, graph).analyze()) + return false; + } + + AssertExtendedGraphCoherency(graph); + return true; +} + +// Remove all blocks not marked with isMarked(). Unmark all remaining blocks. +// Alias analysis dependencies may be invalid after calling this function. +bool +jit::RemoveUnmarkedBlocks(MIRGenerator *mir, MIRGraph &graph, uint32_t numMarkedBlocks) +{ + // If all blocks are marked, the CFG is unmodified. Just clear the marks. + if (numMarkedBlocks == graph.numBlocks()) { + graph.unmarkBlocks(); + return true; + } + + for (ReversePostorderIterator iter(graph.rpoBegin()); iter != graph.rpoEnd();) { + MBasicBlock *block = *iter++; + + if (block->isMarked()) { + block->unmark(); + continue; + } + + for (size_t i = 0, e = block->numSuccessors(); i != e; ++i) + block->getSuccessor(i)->removePredecessor(block); + graph.removeBlockIncludingPhis(block); + } + + return AccountForCFGChanges(mir, graph, /*updateAliasAnalysis=*/false); +} + // A Simple, Fast Dominance Algorithm by Cooper et al. // Modified to support empty intersections for OSR, and in RPO. static MBasicBlock * @@ -1559,7 +1613,13 @@ BoundsCheckHashIgnoreOffset(MBoundsCheck *check) static MBoundsCheck * FindDominatingBoundsCheck(BoundsCheckMap &checks, MBoundsCheck *check, size_t index) { - // See the comment in ValueNumberer::findDominatingDef. + // Since we are traversing the dominator tree in pre-order, when we + // are looking at the |index|-th block, the next numDominated() blocks + // we traverse are precisely the set of blocks that are dominated. + // + // So, this value is visible in all blocks if: + // index <= index + ins->block->numDominated() + // and becomes invalid after that. HashNumber hash = BoundsCheckHashIgnoreOffset(check); BoundsCheckMap::Ptr p = checks.lookup(hash); if (!p || index >= p->value().validEnd) { diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index 397327c9cb75..a843fa55ff23 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -55,6 +55,12 @@ MakeMRegExpHoistable(MIRGraph &graph); bool RenumberBlocks(MIRGraph &graph); +bool +AccountForCFGChanges(MIRGenerator *mir, MIRGraph &graph, bool updateAliasAnalysis); + +bool +RemoveUnmarkedBlocks(MIRGenerator *mir, MIRGraph &graph, uint32_t numMarkedBlocks); + bool BuildDominatorTree(MIRGraph &graph); diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 0a290ded7c0e..957de5b71a2f 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1344,7 +1344,10 @@ MacroAssembler::assumeUnreachable(const char *output) static void Printf0_(const char *output) { - printf("%s", output); + // Use stderr instead of stdout because this is only used for debug + // output. stderr is less likely to interfere with the program's normal + // output, and it's always unbuffered. + fprintf(stderr, "%s", output); } void @@ -1366,7 +1369,7 @@ MacroAssembler::printf(const char *output) static void Printf1_(const char *output, uintptr_t value) { char *line = JS_sprintf_append(nullptr, output, value); - printf("%s", line); + fprintf(stderr, "%s", line); js_free(line); } diff --git a/js/src/jit/IonOptimizationLevels.cpp b/js/src/jit/IonOptimizationLevels.cpp index aad2045a501e..d53c7297d23e 100644 --- a/js/src/jit/IonOptimizationLevels.cpp +++ b/js/src/jit/IonOptimizationLevels.cpp @@ -29,7 +29,6 @@ OptimizationInfo::initNormalOptimizationInfo() inlineInterpreted_ = true; inlineNative_ = true; gvn_ = true; - gvnKind_ = GVN_Optimistic; licm_ = true; uce_ = true; rangeAnalysis_ = true; diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h index 75c45aa9560a..bd0827e54c02 100644 --- a/js/src/jit/IonOptimizationLevels.h +++ b/js/src/jit/IonOptimizationLevels.h @@ -66,9 +66,6 @@ class OptimizationInfo // Toggles whether global value numbering is used. bool gvn_; - // Toggles whether global value numbering is optimistic or pessimistic. - IonGvnKind gvnKind_; - // Toggles whether loop invariant code motion is performed. bool licm_; @@ -162,12 +159,6 @@ class OptimizationInfo return eliminateRedundantChecks_; } - IonGvnKind gvnKind() const { - if (!js_JitOptions.forceGvnKind) - return gvnKind_; - return js_JitOptions.forcedGvnKind; - } - IonRegisterAllocator registerAllocator() const { if (!js_JitOptions.forceRegisterAllocator) return registerAllocator_; diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index 8b442dd3b648..807cf4b230c2 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -66,11 +66,6 @@ JitOptions::JitOptions() forceDefaultIonUsesBeforeCompile = false; forcedDefaultIonUsesBeforeCompile = 1000; - // Force the GVN kind to be optimistic or pessimistic instead of letting - // the optimization pass decide. - forceGvnKind = false; - forcedGvnKind = GVN_Optimistic; - // Force the used register allocator instead of letting the // optimization pass decide. forceRegisterAllocator = false; diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index da3922994341..7aaba05f2163 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -28,11 +28,6 @@ enum IonRegisterAllocator { RegisterAllocator_Stupid }; -enum IonGvnKind { - GVN_Optimistic, - GVN_Pessimistic -}; - struct JitOptions { bool checkGraphConsistency; @@ -51,8 +46,6 @@ struct JitOptions bool eagerCompilation; bool forceDefaultIonUsesBeforeCompile; uint32_t forcedDefaultIonUsesBeforeCompile; - bool forceGvnKind; - IonGvnKind forcedGvnKind; bool forceRegisterAllocator; IonRegisterAllocator forcedRegisterAllocator; bool limitScriptSize; diff --git a/js/src/jit/LiveRangeAllocator.cpp b/js/src/jit/LiveRangeAllocator.cpp index e4299430ea9f..f99f1e7c8052 100644 --- a/js/src/jit/LiveRangeAllocator.cpp +++ b/js/src/jit/LiveRangeAllocator.cpp @@ -819,7 +819,9 @@ LiveRangeAllocator::buildLivenessInfo() to = use->usedAtStart() ? inputOf(*ins) : outputOf(*ins); } } else { - to = (use->usedAtStart() || ins->isCall()) + // Fixed uses on calls are specially overridden to + // happen at the input position. + to = (use->usedAtStart() || (ins->isCall() && use->isFixedRegister())) ? inputOf(*ins) : outputOf(*ins); if (use->isFixedRegister()) { LAllocation reg(AnyRegister::FromCode(use->registerCode())); diff --git a/js/src/jit/LiveRangeAllocator.h b/js/src/jit/LiveRangeAllocator.h index 0b74d71dbffb..2cec3e192783 100644 --- a/js/src/jit/LiveRangeAllocator.h +++ b/js/src/jit/LiveRangeAllocator.h @@ -132,7 +132,15 @@ struct UsePosition : public TempObject, UsePosition(LUse *use, CodePosition pos) : use(use), pos(pos) - { } + { + // Verify that the usedAtStart() flag is consistent with the + // subposition. For now ignore fixed registers, because they + // are handled specially around calls. + JS_ASSERT_IF(!use->isFixedRegister(), + pos.subpos() == (use->usedAtStart() + ? CodePosition::INPUT + : CodePosition::OUTPUT)); + } }; typedef InlineForwardListIterator UsePositionIterator; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 70cc9224dbdb..1f31353525e8 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -69,15 +69,6 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op) fprintf(fp, "%c", tolower(name[i])); } -static inline bool -EqualValues(bool useGVN, MDefinition *left, MDefinition *right) -{ - if (useGVN) - return left->valueNumber() == right->valueNumber(); - - return left == right; -} - static MConstant * EvaluateConstantOperands(TempAllocator &alloc, MBinaryInstruction *ins, bool *ptypeChange = nullptr) { @@ -148,9 +139,6 @@ MDefinition::printName(FILE *fp) const { PrintOpcodeName(fp, op()); fprintf(fp, "%u", id()); - - if (valueNumber() != 0) - fprintf(fp, "-vn%u", valueNumber()); } HashNumber @@ -158,7 +146,7 @@ MDefinition::valueHash() const { HashNumber out = op(); for (size_t i = 0, e = numOperands(); i < e; i++) { - uint32_t valueNumber = getOperand(i)->valueNumber(); + uint32_t valueNumber = getOperand(i)->id(); out = valueNumber + (out << 6) + (out << 16) - out; } return out; @@ -180,7 +168,7 @@ MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const return false; for (size_t i = 0, e = numOperands(); i < e; i++) { - if (getOperand(i)->valueNumber() != ins->getOperand(i)->valueNumber()) + if (getOperand(i) != ins->getOperand(i)) return false; } @@ -188,7 +176,7 @@ MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const } MDefinition * -MDefinition::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MDefinition::foldsTo(TempAllocator &alloc) { // In the default case, there are no constants to fold. return this; @@ -246,7 +234,7 @@ MTest::cacheOperandMightEmulateUndefined() } MDefinition * -MTest::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MTest::foldsTo(TempAllocator &alloc) { MDefinition *op = getOperand(0); @@ -808,7 +796,7 @@ MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDef } MDefinition* -MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MStringLength::foldsTo(TempAllocator &alloc) { if ((type() == MIRType_Int32) && (string()->isConstant())) { Value value = string()->toConstant()->value(); @@ -949,22 +937,31 @@ MPhi::removeAllOperands() } MDefinition * -MPhi::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MPhi::operandIfRedundant() { - JS_ASSERT(!inputs_.empty()); + JS_ASSERT(inputs_.length() != 0); + // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)), + // returns the operand that it will always be equal to (a, in + // those two cases). MDefinition *first = getOperand(0); - - for (size_t i = 1; i < inputs_.length(); i++) { - // Phis need dominator information to fold based on value numbers. For - // simplicity, we only compare SSA names right now (bug 714727). - if (!EqualValues(false, getOperand(i), first)) - return this; + for (size_t i = 1, e = numOperands(); i < e; i++) { + MDefinition *op = getOperand(i); + if (op != first && op != this) + return nullptr; } - return first; } +MDefinition * +MPhi::foldsTo(TempAllocator &alloc) +{ + if (MDefinition *def = operandIfRedundant()) + return def; + + return this; +} + bool MPhi::congruentTo(const MDefinition *ins) const { @@ -1224,7 +1221,7 @@ IsConstant(MDefinition *def, double v) } MDefinition * -MBinaryBitwiseInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MBinaryBitwiseInstruction::foldsTo(TempAllocator &alloc) { if (specialization_ != MIRType_Int32) return this; @@ -1259,7 +1256,7 @@ MBinaryBitwiseInstruction::foldUnnecessaryBitop() if (IsConstant(rhs, -1)) return foldIfNegOne(1); - if (EqualValues(false, lhs, rhs)) + if (lhs == rhs) return foldIfEqual(); return this; @@ -1416,7 +1413,7 @@ NeedNegativeZeroCheck(MDefinition *def) } MDefinition * -MBinaryArithInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MBinaryArithInstruction::foldsTo(TempAllocator &alloc) { if (specialization_ == MIRType_None) return this; @@ -1483,7 +1480,7 @@ MAbs::trySpecializeFloat32(TempAllocator &alloc) } MDefinition * -MDiv::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MDiv::foldsTo(TempAllocator &alloc) { if (specialization_ == MIRType_None) return this; @@ -1540,7 +1537,7 @@ MDiv::fallible() const } MDefinition * -MMod::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MMod::foldsTo(TempAllocator &alloc) { if (specialization_ == MIRType_None) return this; @@ -1612,16 +1609,16 @@ MSub::fallible() const } MDefinition * -MMul::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MMul::foldsTo(TempAllocator &alloc) { - MDefinition *out = MBinaryArithInstruction::foldsTo(alloc, useValueNumbers); + MDefinition *out = MBinaryArithInstruction::foldsTo(alloc); if (out != this) return out; if (specialization() != MIRType_Int32) return this; - if (EqualValues(useValueNumbers, lhs(), rhs())) + if (lhs() == rhs()) setCanBeNegativeZero(false); return this; @@ -2086,7 +2083,7 @@ MBitNot::NewAsmJS(TempAllocator &alloc, MDefinition *input) } MDefinition * -MBitNot::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MBitNot::foldsTo(TempAllocator &alloc) { if (specialization_ != MIRType_Int32) return this; @@ -2107,7 +2104,7 @@ MBitNot::foldsTo(TempAllocator &alloc, bool useValueNumbers) } MDefinition * -MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MTypeOf::foldsTo(TempAllocator &alloc) { // Note: we can't use input->type() here, type analysis has // boxed the input. @@ -2335,7 +2332,7 @@ MResumePoint::isObservableOperand(size_t index) const } MDefinition * -MToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MToInt32::foldsTo(TempAllocator &alloc) { MDefinition *input = getOperand(0); if (input->type() == MIRType_Int32) @@ -2351,7 +2348,7 @@ MToInt32::analyzeEdgeCasesBackward() } MDefinition * -MTruncateToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MTruncateToInt32::foldsTo(TempAllocator &alloc) { MDefinition *input = getOperand(0); if (input->type() == MIRType_Int32) @@ -2367,7 +2364,7 @@ MTruncateToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers) } MDefinition * -MToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MToDouble::foldsTo(TempAllocator &alloc) { MDefinition *in = input(); if (in->type() == MIRType_Double) @@ -2385,7 +2382,7 @@ MToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers) } MDefinition * -MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MToFloat32::foldsTo(TempAllocator &alloc) { if (input()->type() == MIRType_Float32) return input(); @@ -2407,7 +2404,7 @@ MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers) } MDefinition * -MToString::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MToString::foldsTo(TempAllocator &alloc) { MDefinition *in = input(); if (in->type() == MIRType_String) @@ -2416,7 +2413,7 @@ MToString::foldsTo(TempAllocator &alloc, bool useValueNumbers) } MDefinition * -MClampToUint8::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MClampToUint8::foldsTo(TempAllocator &alloc) { if (input()->isConstant()) { const Value &v = input()->toConstant()->value(); @@ -2637,7 +2634,7 @@ MCompare::evaluateConstantOperands(bool *result) } MDefinition * -MCompare::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MCompare::foldsTo(TempAllocator &alloc) { bool result; @@ -2709,7 +2706,7 @@ MNot::cacheOperandMightEmulateUndefined() } MDefinition * -MNot::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MNot::foldsTo(TempAllocator &alloc) { // Fold if the input is constant if (operand()->isConstant()) { @@ -3007,7 +3004,7 @@ MGetPropertyCache::updateForReplacement(MDefinition *ins) { } MDefinition * -MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) { if (input()->isConstant()) { const Value &v = input()->toConstant()->value(); @@ -3019,7 +3016,7 @@ MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers) } MDefinition * -MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers) +MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc) { if (input()->isConstant()) { const Value &v = input()->toConstant()->value(); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index b630ba5f8294..239fd331dddf 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -32,7 +32,6 @@ class StringObject; namespace jit { class BaselineInspector; -class ValueNumberData; class Range; static inline @@ -323,7 +322,6 @@ class MDefinition : public MNode InlineList uses_; // Use chain. uint32_t id_; // Instruction ID, which after block re-ordering // is sorted within a basic block. - ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use) Range *range_; // Any computed range for this def. MIRType resultType_; // Representation of result type. types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type. @@ -365,7 +363,6 @@ class MDefinition : public MNode public: MDefinition() : id_(0), - valueNumber_(nullptr), range_(nullptr), resultType_(MIRType_None), resultTypeSet_(nullptr), @@ -448,7 +445,7 @@ class MDefinition : public MNode return false; } bool congruentIfOperandsEqual(const MDefinition *ins) const; - virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + virtual MDefinition *foldsTo(TempAllocator &alloc); virtual void analyzeEdgeCasesForward(); virtual void analyzeEdgeCasesBackward(); @@ -511,18 +508,6 @@ class MDefinition : public MNode id_ = id; } - uint32_t valueNumber() const; - void setValueNumber(uint32_t vn); - ValueNumberData *valueNumberData() { - return valueNumber_; - } - void clearValueNumberData() { - valueNumber_ = nullptr; - } - void setValueNumberData(ValueNumberData *vn) { - JS_ASSERT(valueNumber_ == nullptr); - valueNumber_ = vn; - } #define FLAG_ACCESSOR(flag) \ bool is##flag() const {\ return hasFlags(1 << flag);\ @@ -537,6 +522,9 @@ class MDefinition : public MNode }\ void set##flag##Unchecked() {\ setFlags(1 << flag);\ + } \ + void setNot##flag##Unchecked() {\ + removeFlags(1 << flag);\ } MIR_FLAG_LIST(FLAG_ACCESSOR) @@ -869,7 +857,7 @@ class MBinaryInstruction : public MAryInstruction<2> MDefinition *lhs = getOperand(0); MDefinition *rhs = getOperand(1); - return op() + lhs->valueNumber() + rhs->valueNumber(); + return op() + lhs->id() + rhs->id(); } void swapOperands() { MDefinition *temp = getOperand(0); @@ -892,7 +880,7 @@ class MBinaryInstruction : public MAryInstruction<2> const MDefinition *right = getOperand(1); const MDefinition *tmp; - if (isCommutative() && left->valueNumber() > right->valueNumber()) { + if (isCommutative() && left->id() > right->id()) { tmp = right; right = left; left = tmp; @@ -901,14 +889,14 @@ class MBinaryInstruction : public MAryInstruction<2> const MBinaryInstruction *bi = static_cast(ins); const MDefinition *insLeft = bi->getOperand(0); const MDefinition *insRight = bi->getOperand(1); - if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) { + if (isCommutative() && insLeft->id() > insRight->id()) { tmp = insRight; insRight = insLeft; insLeft = tmp; } - return (left->valueNumber() == insLeft->valueNumber()) && - (right->valueNumber() == insRight->valueNumber()); + return left == insLeft && + right == insRight; } // Return true if the operands to this instruction are both unsigned, @@ -934,7 +922,7 @@ class MTernaryInstruction : public MAryInstruction<3> MDefinition *second = getOperand(1); MDefinition *third = getOperand(2); - return op() + first->valueNumber() + second->valueNumber() + third->valueNumber(); + return op() + first->id() + second->id() + third->id(); } }; @@ -958,8 +946,8 @@ class MQuaternaryInstruction : public MAryInstruction<4> MDefinition *third = getOperand(2); MDefinition *fourth = getOperand(3); - return op() + first->valueNumber() + second->valueNumber() + - third->valueNumber() + fourth->valueNumber(); + return op() + first->id() + second->id() + + third->id() + fourth->id(); } }; @@ -1479,7 +1467,7 @@ class MTest // to check whether the operand might do this. If this method is never // called, we'll assume our operand can emulate undefined. void cacheOperandMightEmulateUndefined(); - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined, bool *filtersNull); @@ -2557,7 +2545,7 @@ class MCompare bool tryFold(bool *result); bool evaluateConstantOperands(bool *result); - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined, bool *filtersNull); @@ -3203,7 +3191,7 @@ class MToDouble return this; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); bool congruentTo(const MDefinition *ins) const { if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion()) return false; @@ -3276,7 +3264,7 @@ class MToFloat32 return this; } - virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + virtual MDefinition *foldsTo(TempAllocator &alloc); bool congruentTo(const MDefinition *ins) const { if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion()) return false; @@ -3309,7 +3297,7 @@ class MAsmJSUnsignedToDouble return new(alloc) MAsmJSUnsignedToDouble(def); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); bool congruentTo(const MDefinition *ins) const { return congruentIfOperandsEqual(ins); } @@ -3335,7 +3323,7 @@ class MAsmJSUnsignedToFloat32 return new(alloc) MAsmJSUnsignedToFloat32(def); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); bool congruentTo(const MDefinition *ins) const { return congruentIfOperandsEqual(ins); } @@ -3378,7 +3366,7 @@ class MToInt32 return new(alloc) MToInt32(def, conversion); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); // this only has backwards information flow. void analyzeEdgeCasesBackward(); @@ -3437,7 +3425,7 @@ class MTruncateToInt32 : public MUnaryInstruction return new(alloc) MTruncateToInt32(def); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); bool congruentTo(const MDefinition *ins) const { return congruentIfOperandsEqual(ins); @@ -3474,7 +3462,7 @@ class MToString : return new(alloc) MToString(def); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); TypePolicy *typePolicy() { return this; @@ -3514,7 +3502,7 @@ class MBitNot return this; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void infer(); bool congruentTo(const MDefinition *ins) const { @@ -3562,7 +3550,7 @@ class MTypeOf return inputType_; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void cacheInputMaybeCallableOrEmulatesUndefined(); bool inputMaybeCallableOrEmulatesUndefined() const { @@ -3631,7 +3619,7 @@ class MBinaryBitwiseInstruction return this; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); MDefinition *foldUnnecessaryBitop(); virtual MDefinition *foldIfZero(size_t operand) = 0; virtual MDefinition *foldIfNegOne(size_t operand) = 0; @@ -3869,7 +3857,7 @@ class MBinaryArithInstruction return specialization_; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); virtual double getIdentity() = 0; @@ -4467,7 +4455,7 @@ class MMul : public MBinaryArithInstruction return new(alloc) MMul(left, right, type, mode); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void analyzeEdgeCasesForward(); void analyzeEdgeCasesBackward(); void collectRangeInfoPreTrunc(); @@ -4562,7 +4550,7 @@ class MDiv : public MBinaryArithInstruction return div; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void analyzeEdgeCasesForward(); void analyzeEdgeCasesBackward(); @@ -4658,7 +4646,7 @@ class MMod : public MBinaryArithInstruction return mod; } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); double getIdentity() { MOZ_ASSUME_UNREACHABLE("not used"); @@ -4959,7 +4947,7 @@ class MLoadArrowThis } }; -class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode +class MPhi MOZ_FINAL : public MDefinition, public InlineListNode { js::Vector inputs_; @@ -5056,7 +5044,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode // Prefer reserveLength() and addInput() instead, where possible. bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr); - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); bool congruentTo(const MDefinition *ins) const; @@ -5072,17 +5060,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode } void computeRange(TempAllocator &alloc); - MDefinition *operandIfRedundant() { - // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)), - // returns the operand that it will always be equal to (a, in - // those two cases). - MDefinition *first = getOperand(0); - for (size_t i = 1, e = numOperands(); i < e; i++) { - if (getOperand(i) != first && getOperand(i) != this) - return nullptr; - } - return first; - } + MDefinition *operandIfRedundant(); bool canProduceFloat32() const { return canProduceFloat32_; @@ -6210,7 +6188,7 @@ class MNot INSTRUCTION_HEADER(Not); void cacheOperandMightEmulateUndefined(); - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); void markOperandCantEmulateUndefined() { operandMightEmulateUndefined_ = false; @@ -7153,7 +7131,7 @@ class MClampToUint8 return new(alloc) MClampToUint8(input); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); TypePolicy *typePolicy() { return this; @@ -8900,7 +8878,7 @@ class MStringLength return new(alloc) MStringLength(string); } - MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); + MDefinition *foldsTo(TempAllocator &alloc); TypePolicy *typePolicy() { return this; diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index c2dc49cf8a4d..aebc9daa4664 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -118,6 +118,15 @@ MIRGraph::removeBlock(MBasicBlock *block) numBlocks_--; } +void +MIRGraph::removeBlockIncludingPhis(MBasicBlock *block) +{ + // removeBlock doesn't clear phis because of IonBuilder constraints. Here, + // we want to totally clear everything. + removeBlock(block); + block->discardAllPhis(); +} + void MIRGraph::unmarkBlocks() { @@ -930,6 +939,20 @@ MBasicBlock::addImmediatelyDominatedBlock(MBasicBlock *child) return immediatelyDominated_.append(child); } +void +MBasicBlock::removeImmediatelyDominatedBlock(MBasicBlock *child) +{ + for (size_t i = 0; ; ++i) { + MOZ_ASSERT(i < immediatelyDominated_.length(), + "Dominated block to remove not present"); + if (immediatelyDominated_[i] == child) { + immediatelyDominated_[i] = immediatelyDominated_.back(); + immediatelyDominated_.popBack(); + return; + } + } +} + void MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end) { diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index 934a0984aacb..d436ceab3589 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -26,7 +26,7 @@ class MDefinitionIterator; typedef InlineListIterator MInstructionIterator; typedef InlineListReverseIterator MInstructionReverseIterator; -typedef InlineForwardListIterator MPhiIterator; +typedef InlineListIterator MPhiIterator; typedef InlineForwardListIterator MResumePointIterator; class LBlock; @@ -189,9 +189,8 @@ class MBasicBlock : public TempObject, public InlineListNode void replacePredecessor(MBasicBlock *old, MBasicBlock *split); void replaceSuccessor(size_t pos, MBasicBlock *split); - // Removes `pred` from the predecessor list. `pred` should not be - // the final predecessor. If this block defines phis, removes the - // entry for `pred` and updates the indices of later entries. + // Removes `pred` from the predecessor list. If this block defines phis, + // removes the entry for `pred` and updates the indices of later entries. // This may introduce redundant phis if the new block has fewer // than two predecessors. void removePredecessor(MBasicBlock *pred); @@ -292,6 +291,9 @@ class MBasicBlock : public TempObject, public InlineListNode MPhiIterator phisBegin() const { return phis_.begin(); } + MPhiIterator phisBegin(MPhi *at) const { + return phis_.begin(at); + } MPhiIterator phisEnd() const { return phis_.end(); } @@ -420,8 +422,12 @@ class MBasicBlock : public TempObject, public InlineListNode numDominated_ += n; } + // Add |child| to this block's immediately-dominated set. bool addImmediatelyDominatedBlock(MBasicBlock *child); + // Remove |child| from this block's immediately-dominated set. + void removeImmediatelyDominatedBlock(MBasicBlock *child); + // This function retrieves the internal instruction associated with a // slot, and should not be used for normal stack operations. It is an // internal helper that is also used to enhance spew. @@ -506,7 +512,7 @@ class MBasicBlock : public TempObject, public InlineListNode CompileInfo &info_; // Each block originates from a particular script. InlineList instructions_; Vector predecessors_; - InlineForwardList phis_; + InlineList phis_; InlineForwardList resumePoints_; FixedList slots_; uint32_t stackPosition_; @@ -565,7 +571,7 @@ class MIRGraph : alloc_(alloc), returnAccumulator_(nullptr), blockIdGen_(0), - idGen_(1), + idGen_(0), osrBlock_(nullptr), osrStart_(nullptr), numBlocks_(0), @@ -627,6 +633,7 @@ class MIRGraph } void removeBlocksAfter(MBasicBlock *block); void removeBlock(MBasicBlock *block); + void removeBlockIncludingPhis(MBasicBlock *block); void moveBlockToEnd(MBasicBlock *block) { JS_ASSERT(block->id()); blocks_.remove(block); diff --git a/js/src/jit/UnreachableCodeElimination.cpp b/js/src/jit/UnreachableCodeElimination.cpp index 634c9195f488..d60cb443f083 100644 --- a/js/src/jit/UnreachableCodeElimination.cpp +++ b/js/src/jit/UnreachableCodeElimination.cpp @@ -83,8 +83,10 @@ UnreachableCodeElimination::removeUnmarkedBlocksAndCleanup() // Pass 5: It's important for optimizations to re-run GVN (and in // turn alias analysis) after UCE if we eliminated branches. if (rerunAliasAnalysis_ && mir_->optimizationInfo().gvnEnabled()) { - ValueNumberer gvn(mir_, graph_, mir_->optimizationInfo().gvnKind() == GVN_Optimistic); - if (!gvn.clear() || !gvn.analyze()) + ValueNumberer gvn(mir_, graph_); + if (!gvn.run(rerunAliasAnalysis_ + ? ValueNumberer::UpdateAliasAnalysis + : ValueNumberer::DontUpdateAliasAnalysis)) return false; IonSpewPass("GVN-after-UCE"); AssertExtendedGraphCoherency(graph_); diff --git a/js/src/jit/ValueNumbering.cpp b/js/src/jit/ValueNumbering.cpp index 274052d83c85..6667758ebd8a 100644 --- a/js/src/jit/ValueNumbering.cpp +++ b/js/src/jit/ValueNumbering.cpp @@ -6,571 +6,724 @@ #include "jit/ValueNumbering.h" +#include "jit/AliasAnalysis.h" +#include "jit/IonAnalysis.h" #include "jit/IonSpewer.h" #include "jit/MIRGenerator.h" -#include "jit/MIRGraph.h" using namespace js; using namespace js::jit; -ValueNumberer::ValueNumberer(MIRGenerator *mir, MIRGraph &graph, bool optimistic) - : mir(mir), - graph_(graph), - values(graph.alloc()), - pessimisticPass_(!optimistic), - count_(0) -{ } +/** + * Some notes on the main algorithm here: + * - The SSA identifier id() is the value number. We do replaceAllUsesWith as + * we go, so there's always at most one visible value with a given number. + * + * - Consequently, the GVN algorithm is effectively pessimistic. This means it + * is not as powerful as an optimistic GVN would be, but it is simpler and + * faster. + * + * - We iterate in RPO, so that when visiting a block, we've already optimized + * and hashed all values in dominating blocks. With occasional exceptions, + * this allows us to do everything in a single pass. + * + * - When we do use multiple passes, we just re-run the algorithm on the whole + * graph instead of doing sparse propagation. This is a tradeoff to keep the + * algorithm simpler and lighter on inputs that don't have a lot of + * interesting unreachable blocks or degenerate loop induction variables, at + * the expense of being slower on inputs that do. The loop for this + * always terminates, because it only iterates when code is or will be + * removed, so eventually it must stop iterating. + * + * - Values are not immediately removed from the hash set when they go out of + * scope. Instead, we check for dominance after a lookup. If the dominance + * check fails, the value is removed. + */ -TempAllocator & -ValueNumberer::alloc() const +HashNumber +ValueNumberer::VisibleValues::ValueHasher::hash(Lookup ins) { - return graph_.alloc(); -} - -uint32_t -ValueNumberer::lookupValue(MDefinition *ins) -{ - ValueMap::AddPtr p = values.lookupForAdd(ins); - if (p) { - // make sure this is in the correct group - setClass(ins, p->key()); - return p->value(); - } - - if (!values.add(p, ins, ins->id())) - return 0; - breakClass(ins); - - return ins->id(); -} - -MDefinition * -ValueNumberer::simplify(MDefinition *def, bool useValueNumbers) -{ - if (def->isEffectful()) - return def; - - MDefinition *ins = def->foldsTo(alloc(), useValueNumbers); - if (ins == def) - return def; - - // Ensure this instruction has a value number. - if (!ins->valueNumberData()) - ins->setValueNumberData(new(alloc()) ValueNumberData); - - if (!ins->block()) { - // In this case, we made a new def by constant folding, for - // example, we replaced add(#3,#4) with a new const(#7) node. - - // We will only fold a phi into one of its operands. - JS_ASSERT(!def->isPhi()); - - def->block()->insertAfter(def->toInstruction(), ins->toInstruction()); - ins->setValueNumber(lookupValue(ins)); - } - - JS_ASSERT(ins->id() != 0); - - def->replaceAllUsesWith(ins); - - IonSpew(IonSpew_GVN, "Folding %d to be %d", def->id(), ins->id()); - return ins; -} - -MControlInstruction * -ValueNumberer::simplifyControlInstruction(MControlInstruction *def) -{ - if (def->isEffectful()) - return def; - - MDefinition *repl = def->foldsTo(alloc(), false); - if (repl == def) - return def; - - // Ensure this instruction has a value number. - if (!repl->valueNumberData()) - repl->setValueNumberData(new(alloc()) ValueNumberData); - - MBasicBlock *block = def->block(); - - // MControlInstructions should not have consumers. - JS_ASSERT(repl->isControlInstruction()); - JS_ASSERT(!def->hasUses()); - - if (def->isInWorklist()) - repl->setInWorklist(); - - block->discardLastIns(); - block->end(repl->toControlInstruction()); - return repl->toControlInstruction(); -} - -void -ValueNumberer::markDefinition(MDefinition *def) -{ - if (isMarked(def)) - return; - - IonSpew(IonSpew_GVN, "marked %d", def->id()); - def->setInWorklist(); - count_++; -} - -void -ValueNumberer::unmarkDefinition(MDefinition *def) -{ - if (pessimisticPass_) - return; - - JS_ASSERT(count_ > 0); - IonSpew(IonSpew_GVN, "unmarked %d", def->id()); - def->setNotInWorklist(); - count_--; -} - -void -ValueNumberer::markBlock(MBasicBlock *block) -{ - for (MDefinitionIterator iter(block); iter; iter++) - markDefinition(*iter); - markDefinition(block->lastIns()); -} - -void -ValueNumberer::markConsumers(MDefinition *def) -{ - if (pessimisticPass_) - return; - - JS_ASSERT(!def->isInWorklist()); - JS_ASSERT(!def->isControlInstruction()); - for (MUseDefIterator use(def); use; use++) - markDefinition(use.def()); + return ins->valueHash(); } +// Test whether two MDefinitions are congruent. bool -ValueNumberer::computeValueNumbers() +ValueNumberer::VisibleValues::ValueHasher::match(Key k, Lookup l) { - // At the end of this function, we will have the value numbering stored in - // each instruction. - // - // We also need an "optimistic" value number, for temporary use, which is - // stored in a hashtable. - // - // For the instruction x := y op z, we map (op, VN[y], VN[z]) to a value - // number, say v. If it is not in the map, we use the instruction id. - // - // If the instruction in question's value number is not already - // v, we break the congruence and set it to v. We repeat until saturation. - // This will take at worst O(d) time, where d is the loop connectedness - // of the SSA def/use graph. - // - // The algorithm is the simple RPO-based algorithm from - // "SCC-Based Value Numbering" by Cooper and Simpson. - // - // If we are performing a pessimistic pass, then we assume that every - // definition is in its own congruence class, since we know nothing about - // values that enter Phi nodes through back edges. We then make one pass - // through the graph, ignoring back edges. This yields less congruences on - // any graph with back-edges, but is much faster to perform. - - IonSpew(IonSpew_GVN, "Numbering instructions"); - - if (!values.init()) + // If one of the instructions depends on a store, and the other instruction + // does not depend on the same store, the instructions are not congruent. + if (k->dependency() != l->dependency()) return false; - // Stick a VN object onto every mdefinition - for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - if (mir->shouldCancel("Value Numbering (preparation loop")) - return false; - for (MDefinitionIterator iter(*block); iter; iter++) - iter->setValueNumberData(new(alloc()) ValueNumberData); - MControlInstruction *jump = block->lastIns(); - jump->setValueNumberData(new(alloc()) ValueNumberData); - } - // Assign unique value numbers if pessimistic. - // It might be productive to do this in the MDefinition constructor or - // possibly in a previous pass, if it seems reasonable. - if (pessimisticPass_) { - for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - for (MDefinitionIterator iter(*block); iter; iter++) - iter->setValueNumber(iter->id()); - } - } else { - // For each root block, add all of its instructions to the worklist. - markBlock(*(graph_.begin())); - if (graph_.osrBlock()) - markBlock(graph_.osrBlock()); - } + return k->congruentTo(l); // Ask the values themselves what they think. +} - while (count_ > 0) { -#ifdef DEBUG - if (!pessimisticPass_) { - size_t debugCount = 0; - IonSpew(IonSpew_GVN, "The following instructions require processing:"); - for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - for (MDefinitionIterator iter(*block); iter; iter++) { - if (iter->isInWorklist()) { - IonSpew(IonSpew_GVN, "\t%d", iter->id()); - debugCount++; - } - } - if (block->lastIns()->isInWorklist()) { - IonSpew(IonSpew_GVN, "\t%d", block->lastIns()->id()); - debugCount++; - } +void +ValueNumberer::VisibleValues::ValueHasher::rekey(Key &k, Key newKey) +{ + k = newKey; +} + +ValueNumberer::VisibleValues::VisibleValues(TempAllocator &alloc) + : set_(alloc) +{} + +// Initialize the set in preparation for holding num elements. +bool +ValueNumberer::VisibleValues::init() +{ + return set_.init(); +} + +// Look up the first entry for the given def. +ValueNumberer::VisibleValues::Ptr +ValueNumberer::VisibleValues::findLeader(const MDefinition *def) const +{ + return set_.lookup(def); +} + +// Look up the first entry for the given def. +ValueNumberer::VisibleValues::AddPtr +ValueNumberer::VisibleValues::findLeaderForAdd(MDefinition *def) +{ + return set_.lookupForAdd(def); +} + +// Insert a value into the set. +bool +ValueNumberer::VisibleValues::insert(AddPtr p, MDefinition *def) +{ + return set_.add(p, def); +} + +// Insert a value onto the set overwriting any existing entry. +void +ValueNumberer::VisibleValues::overwrite(AddPtr p, MDefinition *def) +{ + set_.rekeyInPlace(p, def); +} + +// The given def will be deleted, so remove it from any sets. +void +ValueNumberer::VisibleValues::forget(const MDefinition *def) +{ + Ptr p = set_.lookup(def); + if (p && *p == def) + set_.remove(p); +} + +// Clear all state. +void +ValueNumberer::VisibleValues::clear() +{ + set_.clear(); +} + +// Test whether the value would be needed if it had no uses. +static bool +DeadIfUnused(const MDefinition *def) +{ + return !def->isEffectful() && !def->isGuard() && !def->isControlInstruction() && + (!def->isInstruction() || !def->toInstruction()->resumePoint()); +} + +// Test whether the given definition is no longer needed. +static bool +IsDead(const MDefinition *def) +{ + return !def->hasUses() && DeadIfUnused(def); +} + +// Test whether the given definition will no longer be needed after its user +// is deleted. TODO: This misses cases where the definition is used multiple +// times by the same user (bug 1031396). +static bool +WillBecomeDead(const MDefinition *def) +{ + return def->hasOneUse() && DeadIfUnused(def); +} + +// Call MDefinition::replaceAllUsesWith, and add some GVN-specific asserts. +static void +ReplaceAllUsesWith(MDefinition *from, MDefinition *to) +{ + MOZ_ASSERT(from != to, "GVN shouldn't try to replace a value with itself"); + MOZ_ASSERT(from->type() == to->type(), "Def replacement has different type"); + + from->replaceAllUsesWith(to); +} + +// Test whether succ is a successor of newControl. +static bool +HasSuccessor(const MControlInstruction *newControl, const MBasicBlock *succ) +{ + for (size_t i = 0, e = newControl->numSuccessors(); i != e; ++i) { + if (newControl->getSuccessor(i) == succ) + return true; + } + return false; +} + +// Given a block which has had predecessors removed but is still reachable, +// test whether the block's new dominator will be closer than its old one +// and whether it will expose potential optimization opportunities. +static MBasicBlock * +ComputeNewDominator(MBasicBlock *block, MBasicBlock *old) +{ + MBasicBlock *now = block->getPredecessor(0); + for (size_t i = 1, e = block->numPredecessors(); i != e; ++i) { + MBasicBlock *pred = block->getPredecessor(i); + // Note that dominators haven't been recomputed yet, so we have to check + // whether now dominates pred, not block. + while (!now->dominates(pred)) { + MBasicBlock *next = now->immediateDominator(); + if (next == old) + return old; + if (next == now) { + MOZ_ASSERT(block == old, "Non-self-dominating block became self-dominating"); + return block; } - if (!debugCount) - IonSpew(IonSpew_GVN, "\tNone"); - JS_ASSERT(debugCount == count_); + now = next; } -#endif - for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - if (mir->shouldCancel("Value Numbering (main loop)")) + } + MOZ_ASSERT(old != block || old != now, "Missed self-dominating block staying self-dominating"); + return now; +} + +// Given a block which has had predecessors removed but is still reachable, +// test whether the block's new dominator will be closer than its old one +// and whether it will expose potential optimization opportunities. +static bool +IsDominatorRefined(MBasicBlock *block) +{ + MBasicBlock *old = block->immediateDominator(); + MBasicBlock *now = ComputeNewDominator(block, old); + + // We've computed block's new dominator. Test whether there are any + // newly-dominating definitions which look interesting. + MOZ_ASSERT(old->dominates(now), "Refined dominator not dominated by old dominator"); + for (MBasicBlock *i = now; i != old; i = i->immediateDominator()) { + if (!i->phisEmpty() || *i->begin() != i->lastIns()) + return true; + } + + return false; +} + +// Delete the given instruction and anything in its use-def subtree which is no +// longer needed. +bool +ValueNumberer::deleteDefsRecursively(MDefinition *def) +{ + def->setInWorklist(); + return deadDefs_.append(def) && processDeadDefs(); +} + +// Assuming phi is dead, push each dead operand of phi not dominated by the phi +// to the delete worklist. +bool +ValueNumberer::pushDeadPhiOperands(MPhi *phi, const MBasicBlock *phiBlock) +{ + for (size_t o = 0, e = phi->numOperands(); o != e; ++o) { + MDefinition *op = phi->getOperand(o); + if (WillBecomeDead(op) && !op->isInWorklist() && + !phiBlock->dominates(phiBlock->getPredecessor(o))) + { + op->setInWorklist(); + if (!deadDefs_.append(op)) return false; - for (MDefinitionIterator iter(*block); iter; ) { + } else { + op->setUseRemovedUnchecked(); + } + } + return true; +} - if (!isMarked(*iter)) { - iter++; - continue; +// Assuming ins is dead, push each dead operand of ins to the delete worklist. +bool +ValueNumberer::pushDeadInsOperands(MInstruction *ins) +{ + for (size_t o = 0, e = ins->numOperands(); o != e; ++o) { + MDefinition *op = ins->getOperand(o); + if (WillBecomeDead(op) && !op->isInWorklist()) { + op->setInWorklist(); + if (!deadDefs_.append(op)) + return false; + } else { + op->setUseRemovedUnchecked(); + } + } + return true; +} + +// Recursively delete all the defs on the deadDefs_ worklist. +bool +ValueNumberer::processDeadDefs() +{ + while (!deadDefs_.empty()) { + MDefinition *def = deadDefs_.popCopy(); + IonSpew(IonSpew_GVN, " Deleting %s%u", def->opName(), def->id()); + MOZ_ASSERT(def->isInWorklist(), "Deleting value not on the worklist"); + MOZ_ASSERT(IsDead(def), "Deleting non-dead definition"); + + values_.forget(def); + + if (def->isPhi()) { + MPhi *phi = def->toPhi(); + MBasicBlock *phiBlock = phi->block(); + if (!pushDeadPhiOperands(phi, phiBlock)) + return false; + MPhiIterator at(phiBlock->phisBegin(phi)); + phiBlock->discardPhiAt(at); + } else { + MInstruction *ins = def->toInstruction(); + if (!pushDeadInsOperands(ins)) + return false; + ins->block()->discard(ins); + } + } + return true; +} + +// Delete an edge from the CFG. Return true if the block becomes unreachable. +bool +ValueNumberer::removePredecessor(MBasicBlock *block, MBasicBlock *pred) +{ + bool isUnreachableLoop = false; + if (block->isLoopHeader()) { + if (block->loopPredecessor() == pred) { + // Deleting the entry into the loop makes the loop unreachable. + isUnreachableLoop = true; + IonSpew(IonSpew_GVN, " Loop with header block%u is no longer reachable", block->id()); +#ifdef DEBUG + } else if (block->hasUniqueBackedge() && block->backedge() == pred) { + IonSpew(IonSpew_GVN, " Loop with header block%u is no longer a loop", block->id()); +#endif + } + } + + // TODO: Removing a predecessor removes operands from phis, and these + // operands may become dead. We should detect this and delete them. + // In practice though, when this happens, we often end up re-running GVN + // for other reasons anyway. + block->removePredecessor(pred); + return block->numPredecessors() == 0 || isUnreachableLoop; +} + +// Delete the given block and any block in its dominator subtree. +bool +ValueNumberer::removeBlocksRecursively(MBasicBlock *start, const MBasicBlock *dominatorRoot) +{ + MOZ_ASSERT(start != graph_.entryBlock(), "Removing normal entry block"); + MOZ_ASSERT(start != graph_.osrBlock(), "Removing OSR entry block"); + + // Remove this block from its dominator parent's subtree. This is the only + // immediately-dominated-block information we need to manually update, + // because everything dominated by this block is about to be swept away. + MBasicBlock *parent = start->immediateDominator(); + if (parent != start) + parent->removeImmediatelyDominatedBlock(start); + + if (!unreachableBlocks_.append(start)) + return false; + do { + MBasicBlock *block = unreachableBlocks_.popCopy(); + if (block->isDead()) + continue; + + // If a block is removed while it is on the worklist, skip it. + for (size_t i = 0, e = block->numSuccessors(); i != e; ++i) { + MBasicBlock *succ = block->getSuccessor(i); + if (!succ->isDead()) { + if (removePredecessor(succ, block)) { + if (!unreachableBlocks_.append(succ)) + return false; + } else if (!rerun_) { + if (!remainingBlocks_.append(succ)) + return false; } - - JS_ASSERT_IF(!pessimisticPass_, count_ > 0); - unmarkDefinition(*iter); - - MDefinition *ins = simplify(*iter, false); - - if (ins != *iter) { - iter = block->discardDefAt(iter); - continue; - } - - // Don't bother storing this instruction in the HashMap if - // (a) eliminateRedundancies will never eliminate it (because - // it's non-movable or effectful) and (b) no other instruction's - // value number depends on it. - if (!ins->hasDefUses() && (!ins->isMovable() || ins->isEffectful())) { - iter++; - continue; - } - - uint32_t value = lookupValue(ins); - - if (!value) - return false; // Hashtable insertion failed - - if (ins->valueNumber() != value) { - IonSpew(IonSpew_GVN, - "Broke congruence for instruction %d (%p) with VN %d (now using %d)", - ins->id(), (void *) ins, ins->valueNumber(), value); - ins->setValueNumber(value); - markConsumers(ins); - } - - iter++; } - // Process control flow instruction: - MControlInstruction *jump = block->lastIns(); - jump = simplifyControlInstruction(jump); - - // If we are pessimistic, then this will never get set. - if (!jump->isInWorklist()) - continue; - unmarkDefinition(jump); - if (jump->valueNumber() == 0) { - jump->setValueNumber(jump->id()); - for (size_t i = 0; i < jump->numSuccessors(); i++) - markBlock(jump->getSuccessor(i)); - } - } - // If we are doing a pessimistic pass, we only go once through the - // instruction list. - if (pessimisticPass_) +#ifdef DEBUG + IonSpew(IonSpew_GVN, " Deleting block%u%s%s%s", block->id(), + block->isLoopHeader() ? " (loop header)" : "", + block->isSplitEdge() ? " (split edge)" : "", + block->immediateDominator() == block ? " (dominator root)" : ""); + for (MDefinitionIterator iter(block); iter; iter++) { + MDefinition *def = *iter; + IonSpew(IonSpew_GVN, " Deleting %s%u", def->opName(), def->id()); + } + MControlInstruction *control = block->lastIns(); + IonSpew(IonSpew_GVN, " Deleting %s%u", control->opName(), control->id()); +#endif + + // Keep track of how many blocks within dominatorRoot's tree have been deleted. + if (dominatorRoot->dominates(block)) + ++numBlocksDeleted_; + + // TODO: Removing a block deletes the phis, instructions, and resume + // points in the block, and their operands may become dead. We should + // detect this and delete them. In practice though, when this happens, + // we often end up re-running GVN for other reasons anyway (bug 1031412). + graph_.removeBlockIncludingPhis(block); + blocksRemoved_ = true; + } while (!unreachableBlocks_.empty()); + + return true; +} + +// Return a simplified form of the given definition, if we can. +MDefinition * +ValueNumberer::simplified(MDefinition *def) const +{ + return def->foldsTo(graph_.alloc()); +} + +// If an equivalent and dominating value already exists in the set, return it. +// Otherwise insert the given definition into the set and return it. +MDefinition * +ValueNumberer::leader(MDefinition *def) +{ + // If the value isn't suitable for eliminating, don't bother hashing it. The + // convention is that congruentTo returns false for node kinds that wish to + // opt out of redundance elimination. + // TODO: It'd be nice to clean up that convention (bug 1031406). + if (!def->isEffectful() && def->congruentTo(def)) { + // Look for a match. + VisibleValues::AddPtr p = values_.findLeaderForAdd(def); + if (p) { + MDefinition *rep = *p; + if (rep->block()->dominates(def->block())) { + // We found a dominating congruent value. + MOZ_ASSERT(!rep->isInWorklist(), "Dead value in set"); + return rep; + } + + // The congruent value doesn't dominate. It never will again in this + // dominator tree, so overwrite it. + values_.overwrite(p, def); + } else { + // No match. Add a new entry. + if (!values_.insert(p, def)) + return nullptr; + } + } + + return def; +} + +// Test whether the given phi is dominated by a congruent phi. +bool +ValueNumberer::hasLeader(const MPhi *phi, const MBasicBlock *phiBlock) const +{ + if (VisibleValues::Ptr p = values_.findLeader(phi)) { + const MDefinition *rep = *p; + return rep != phi && rep->block()->dominates(phiBlock); + } + return false; +} + +// Test whether there are any phis in the backedge's loop header which are +// newly optimizable, as a result of optimizations done inside the loop. This +// is not a sparse approach, but restarting is rare enough in practice. +// Termination is ensured by deleting the phi triggering the iteration. +bool +ValueNumberer::loopHasOptimizablePhi(MBasicBlock *backedge) const +{ + // Rescan the phis for any that can be simplified, since they may be reading + // values from backedges. + MBasicBlock *header = backedge->loopHeaderOfBackedge(); + for (MPhiIterator iter(header->phisBegin()), end(header->phisEnd()); iter != end; ++iter) { + MPhi *phi = *iter; + MOZ_ASSERT(phi->hasUses(), "Missed an unused phi"); + + if (phi->operandIfRedundant() || hasLeader(phi, header)) + return true; // Phi can be simplified. + } + return false; +} + +// Visit the given definition. +bool +ValueNumberer::visitDefinition(MDefinition *def) +{ + // Look for a simplified form of this def. + MDefinition *sim = simplified(def); + if (sim != def) { + if (sim == nullptr) + return false; + + // If sim doesn't belong to a block, insert it next to def. + if (sim->block() == nullptr) + def->block()->insertAfter(def->toInstruction(), sim->toInstruction()); + + IonSpew(IonSpew_GVN, " Folded %s%u to %s%u", + def->opName(), def->id(), sim->opName(), sim->id()); + ReplaceAllUsesWith(def, sim); + if (IsDead(def) && !deleteDefsRecursively(def)) + return false; + def = sim; + } + + // Look for a dominating def which makes this def redundant. + MDefinition *rep = leader(def); + if (rep != def) { + if (rep == nullptr) + return false; + if (rep->updateForReplacement(def)) { + IonSpew(IonSpew_GVN, + " Replacing %s%u with %s%u", + def->opName(), def->id(), rep->opName(), rep->id()); + ReplaceAllUsesWith(def, rep); + + // This is effectively what the old GVN did. It allows isGuard() + // instructions to be deleted if they are redundant, and the + // replacement is not even guaranteed to have isGuard() set. + // TODO: Clean this up (bug 1031410). + def->setNotGuardUnchecked(); + + if (IsDead(def) && !deleteDefsRecursively(def)) + return false; + def = rep; + } + } + + // If this instruction has a dependency() into an unreachable block, we'll + // need to update AliasAnalysis. + if (updateAliasAnalysis_ && !dependenciesBroken_) { + const MDefinition *dep = def->dependency(); + if (dep != nullptr && dep->block()->isDead()) { + IonSpew(IonSpew_GVN, " AliasAnalysis invalidated; will recompute!"); + dependenciesBroken_ = true; + } + } + + return true; +} + +// Visit the control instruction at the end of the given block. +bool +ValueNumberer::visitControlInstruction(MBasicBlock *block, const MBasicBlock *dominatorRoot) +{ + // Look for a simplified form of the control instruction. + MControlInstruction *control = block->lastIns(); + MDefinition *rep = simplified(control); + if (rep == control) + return true; + + if (rep == nullptr) + return false; + + MControlInstruction *newControl = rep->toControlInstruction(); + MOZ_ASSERT(!newControl->block(), + "Control instruction replacement shouldn't already be in a block"); + IonSpew(IonSpew_GVN, " Folded control instruction %s%u to %s%u", + control->opName(), control->id(), newControl->opName(), graph_.getNumInstructionIds()); + + // If the simplification removes any CFG edges, update the CFG and remove + // any blocks that become dead. + size_t oldNumSuccs = control->numSuccessors(); + size_t newNumSuccs = newControl->numSuccessors(); + if (newNumSuccs != oldNumSuccs) { + MOZ_ASSERT(newNumSuccs < oldNumSuccs, "New control instruction has too many successors"); + for (size_t i = 0; i != oldNumSuccs; ++i) { + MBasicBlock *succ = control->getSuccessor(i); + if (!HasSuccessor(newControl, succ)) { + if (removePredecessor(succ, block)) { + if (!removeBlocksRecursively(succ, dominatorRoot)) + return false; + } else if (!rerun_) { + if (!remainingBlocks_.append(succ)) + return false; + } + } + } + } + + if (!pushDeadInsOperands(control)) + return false; + block->discardLastIns(); + block->end(newControl); + return processDeadDefs(); +} + +// Visit all the phis and instructions in the given block. +bool +ValueNumberer::visitBlock(MBasicBlock *block, const MBasicBlock *dominatorRoot) +{ + MOZ_ASSERT(!block->unreachable(), "Blocks marked unreachable during GVN"); + MOZ_ASSERT(!block->isDead(), "Block to visit is already dead"); + + // Visit the definitions in the block top-down. + for (MDefinitionIterator iter(block); iter; ) { + MDefinition *def = *iter++; + + // If the definition is dead, delete it. + if (IsDead(def)) { + if (!deleteDefsRecursively(def)) + return false; + continue; + } + + if (!visitDefinition(def)) + return false; + } + + return visitControlInstruction(block, dominatorRoot); +} + +// Visit all the blocks dominated by dominatorRoot. +bool +ValueNumberer::visitDominatorTree(MBasicBlock *dominatorRoot, size_t *totalNumVisited) +{ + IonSpew(IonSpew_GVN, " Visiting dominator tree (with %llu blocks) rooted at block%u%s", + uint64_t(dominatorRoot->numDominated()), dominatorRoot->id(), + dominatorRoot == graph_.entryBlock() ? " (normal entry block)" : + dominatorRoot == graph_.osrBlock() ? " (OSR entry block)" : + " (normal entry and OSR entry merge point)"); + MOZ_ASSERT(numBlocksDeleted_ == 0, "numBlocksDeleted_ wasn't reset"); + MOZ_ASSERT(dominatorRoot->immediateDominator() == dominatorRoot, + "root is not a dominator tree root"); + + // Visit all blocks dominated by dominatorRoot, in RPO. This has the nice property + // that we'll always visit a block before any block it dominates, so we can + // make a single pass through the list and see every full redundance. + size_t numVisited = 0; + for (ReversePostorderIterator iter(graph_.rpoBegin(dominatorRoot)); ; ++iter) { + MOZ_ASSERT(iter != graph_.rpoEnd(), "Inconsistent dominator information"); + MBasicBlock *block = *iter; + // We're only visiting blocks in dominatorRoot's tree right now. + if (!dominatorRoot->dominates(block)) + continue; + // Visit the block! + if (!visitBlock(block, dominatorRoot)) + return false; + // If this was the end of a loop, check for optimization in the header. + if (!rerun_ && block->isLoopBackedge() && loopHasOptimizablePhi(block)) { + IonSpew(IonSpew_GVN, " Loop phi in block%u can now be optimized; will re-run GVN!", + block->id()); + rerun_ = true; + remainingBlocks_.clear(); + } + ++numVisited; + MOZ_ASSERT(numVisited <= dominatorRoot->numDominated() - numBlocksDeleted_, + "Visited blocks too many times"); + if (numVisited >= dominatorRoot->numDominated() - numBlocksDeleted_) break; } -#ifdef DEBUG - for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - for (MDefinitionIterator iter(*block); iter; iter++) { - JS_ASSERT(!iter->isInWorklist()); - JS_ASSERT_IF(iter->valueNumber() == 0, - !iter->hasDefUses() && (!iter->isMovable() || iter->isEffectful())); - } - } -#endif + + *totalNumVisited += numVisited; + values_.clear(); + numBlocksDeleted_ = 0; return true; } -MDefinition * -ValueNumberer::findDominatingDef(InstructionMap &defs, MDefinition *ins, size_t index) +// Visit all the blocks in the graph. +bool +ValueNumberer::visitGraph() { - JS_ASSERT(ins->valueNumber() != 0); - InstructionMap::Ptr p = defs.lookup(ins->valueNumber()); - MDefinition *dom; - if (!p || index >= p->value().validEnd) { - DominatingValue value; - value.def = ins; - // Since we are traversing the dominator tree in pre-order, when we - // are looking at the |index|-th block, the next numDominated() blocks - // we traverse are precisely the set of blocks that are dominated. - // - // So, this value is visible in all blocks if: - // index < index + ins->block->numDominated() - // and becomes invalid after that. - value.validEnd = index + ins->block()->numDominated(); - - if(!defs.put(ins->valueNumber(), value)) - return nullptr; - - dom = ins; - } else { - dom = p->value().def; + // Due to OSR blocks, the set of blocks dominated by a blocks may not be + // contiguous in the RPO. Do a separate traversal for each dominator tree + // root. There's always the main entry, and sometimes there's an OSR entry, + // and then there are the roots formed where the OSR paths merge with the + // main entry paths. + size_t totalNumVisited = 0; + for (ReversePostorderIterator iter(graph_.rpoBegin()); ; ++iter) { + MBasicBlock *block = *iter; + if (block->immediateDominator() == block) { + if (!visitDominatorTree(block, &totalNumVisited)) + return false; + MOZ_ASSERT(totalNumVisited <= graph_.numBlocks(), "Visited blocks too many times"); + if (totalNumVisited >= graph_.numBlocks()) + break; + } + MOZ_ASSERT(iter != graph_.rpoEnd(), "Inconsistent dominator information"); } - - return dom; + return true; } +ValueNumberer::ValueNumberer(MIRGenerator *mir, MIRGraph &graph) + : mir_(mir), graph_(graph), + values_(graph.alloc()), + deadDefs_(graph.alloc()), + unreachableBlocks_(graph.alloc()), + remainingBlocks_(graph.alloc()), + numBlocksDeleted_(0), + rerun_(false), + blocksRemoved_(false), + updateAliasAnalysis_(false), + dependenciesBroken_(false) +{} + bool -ValueNumberer::eliminateRedundancies() +ValueNumberer::run(UpdateAliasAnalysisFlag updateAliasAnalysis) { - // A definition is 'redundant' iff it is dominated by another definition - // with the same value number. - // - // So, we traverse the dominator tree in pre-order, maintaining a hashmap - // from value numbers to instructions. - // - // For each definition d with value number v, we look up v in the hashmap. - // - // If there is a definition d' in the hashmap, and the current traversal - // index is within that instruction's dominated range, then we eliminate d, - // replacing all uses of d with uses of d'. - // - // If there is no valid definition in the hashtable (the current definition - // is not in dominated scope), then we insert the current instruction, - // since it is the most dominant instruction with the given value number. + updateAliasAnalysis_ = updateAliasAnalysis == UpdateAliasAnalysis; - InstructionMap defs(alloc()); - - if (!defs.init()) + // Initialize the value set. It's tempting to pass in a size here of some + // function of graph_.getNumInstructionIds(), however if we start out with + // a large capacity, it will be far larger than the actual element count + // for most of the pass, so when we remove elements, it would often think + // it needs to compact itself. Empirically, just letting the HashTable grow + // as needed on its own seems to work pretty well. + if (!values_.init()) return false; - IonSpew(IonSpew_GVN, "Eliminating redundant instructions"); + IonSpew(IonSpew_GVN, "Running GVN on graph (with %llu blocks)", + uint64_t(graph_.numBlocks())); - // Stack for pre-order CFG traversal. - Vector worklist(alloc()); + // Top level non-sparse iteration loop. If an iteration performs a + // significant change, such as deleting a block which changes the dominator + // tree and may enable more optimization, this loop takes another iteration. + int runs = 0; + for (;;) { + if (!visitGraph()) + return false; - // The index of the current block in the CFG traversal. - size_t index = 0; + // Test whether any block which was not removed but which had at least + // one predecessor removed will have a new dominator parent. + while (!remainingBlocks_.empty()) { + MBasicBlock *block = remainingBlocks_.popCopy(); + if (!block->isDead() && IsDominatorRefined(block)) { + IonSpew(IonSpew_GVN, " Dominator for block%u can now be refined; will re-run GVN!", + block->id()); + rerun_ = true; + remainingBlocks_.clear(); + break; + } + } - // Add all self-dominating blocks to the worklist. - // This includes all roots. Order does not matter. - for (MBasicBlockIterator i(graph_.begin()); i != graph_.end(); i++) { - MBasicBlock *block = *i; - if (block->immediateDominator() == block) { - if (!worklist.append(block)) + if (blocksRemoved_) { + if (!AccountForCFGChanges(mir_, graph_, dependenciesBroken_)) return false; - } - } - // Starting from each self-dominating block, traverse the CFG in pre-order. - while (!worklist.empty()) { - if (mir->shouldCancel("Value Numbering (eliminate loop)")) - return false; - MBasicBlock *block = worklist.popCopy(); - - IonSpew(IonSpew_GVN, "Looking at block %d", block->id()); - - // Add all immediate dominators to the front of the worklist. - if (!worklist.append(block->immediatelyDominatedBlocksBegin(), - block->immediatelyDominatedBlocksEnd())) { - return false; + blocksRemoved_ = false; + dependenciesBroken_ = false; } - // For each instruction, attempt to look up a dominating definition. - for (MDefinitionIterator iter(block); iter; ) { - MDefinition *ins = simplify(*iter, true); - - // Instruction was replaced, and all uses have already been fixed. - if (ins != *iter) { - iter = block->discardDefAt(iter); - continue; - } - - // Instruction has side-effects and cannot be folded. - if (!ins->isMovable() || ins->isEffectful()) { - iter++; - continue; - } - - MDefinition *dom = findDominatingDef(defs, ins, index); - if (!dom) - return false; // Insertion failed. - - if (dom == ins || !dom->updateForReplacement(ins)) { - iter++; - continue; - } - - IonSpew(IonSpew_GVN, "instruction %d is dominated by instruction %d (from block %d)", - ins->id(), dom->id(), dom->block()->id()); - - ins->replaceAllUsesWith(dom); - - JS_ASSERT(!ins->hasUses()); - JS_ASSERT(ins->block() == block); - JS_ASSERT(!ins->isEffectful()); - JS_ASSERT(ins->isMovable()); - - iter = ins->block()->discardDefAt(iter); - } - index++; - } - - JS_ASSERT(index == graph_.numBlocks()); - return true; -} - -// Exported method, called by the compiler. -bool -ValueNumberer::analyze() -{ - return computeValueNumbers() && eliminateRedundancies(); -} - -// Called by the compiler if we need to re-run GVN. -bool -ValueNumberer::clear() -{ - IonSpew(IonSpew_GVN, "Clearing value numbers"); - - // Clear the VN of every MDefinition - for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { - if (mir->shouldCancel("Value Numbering (clearing)")) + if (mir_->shouldCancel("GVN (outer loop)")) return false; - for (MDefinitionIterator iter(*block); iter; iter++) - iter->clearValueNumberData(); - block->lastIns()->clearValueNumberData(); + + // If no further opportunities have been discovered, we're done. + if (!rerun_) + break; + + IonSpew(IonSpew_GVN, "Re-running GVN on graph (run %d, now with %llu blocks)", + runs, uint64_t(graph_.numBlocks())); + rerun_ = false; + + // Enforce an arbitrary iteration limit. This is rarely reached, and + // isn't even strictly necessary, as the algorithm is guaranteed to + // terminate on its own in a finite amount of time (since every time we + // re-run we delete the construct which triggered the re-run), but it + // does help avoid slow compile times on pathlogical code. + ++runs; + if (runs == 6) { + IonSpew(IonSpew_GVN, "Re-run cutoff reached. Terminating GVN!"); + break; + } } return true; } - -uint32_t -MDefinition::valueNumber() const -{ - JS_ASSERT(block_); - if (valueNumber_ == nullptr) - return 0; - return valueNumber_->valueNumber(); -} -void -MDefinition::setValueNumber(uint32_t vn) -{ - valueNumber_->setValueNumber(vn); -} -// Set the class of this to the given representative value. -void -ValueNumberer::setClass(MDefinition *def, MDefinition *rep) -{ - def->valueNumberData()->setClass(def, rep); -} - -MDefinition * -ValueNumberer::findSplit(MDefinition *def) -{ - for (MDefinition *vncheck = def->valueNumberData()->classNext; - vncheck != nullptr; - vncheck = vncheck->valueNumberData()->classNext) { - if (!def->congruentTo(vncheck)) { - IonSpew(IonSpew_GVN, "Proceeding with split because %d is not congruent to %d", - def->id(), vncheck->id()); - return vncheck; - } - } - return nullptr; -} - -void -ValueNumberer::breakClass(MDefinition *def) -{ - if (def->valueNumber() == def->id()) { - IonSpew(IonSpew_GVN, "Breaking congruence with itself: %d", def->id()); - ValueNumberData *defdata = def->valueNumberData(); - JS_ASSERT(defdata->classPrev == nullptr); - // If the def was the only member of the class, then there is nothing to do. - if (defdata->classNext == nullptr) - return; - // If upon closer inspection, we are still equivalent to this class - // then there isn't anything for us to do. - MDefinition *newRep = findSplit(def); - if (!newRep) - return; - markConsumers(def); - ValueNumberData *newdata = newRep->valueNumberData(); - - // Right now, |defdata| is at the front of the list, and |newdata| is - // somewhere in the middle. - // - // We want to move |defdata| and everything up to but excluding - // |newdata| to a new list, with |defdata| still as the canonical - // element. - // - // We then want to take |newdata| and everything after, and - // mark them for processing (since |newdata| is now a new canonical - // element). - // - MDefinition *lastOld = newdata->classPrev; - - JS_ASSERT(lastOld); // newRep is NOT the first element of the list. - JS_ASSERT(lastOld->valueNumberData()->classNext == newRep); - - //lastOld is now the last element of the old list (congruent to - //|def|) - lastOld->valueNumberData()->classNext = nullptr; - -#ifdef DEBUG - for (MDefinition *tmp = def; tmp != nullptr; tmp = tmp->valueNumberData()->classNext) { - JS_ASSERT(tmp->valueNumber() == def->valueNumber()); - JS_ASSERT(tmp->congruentTo(def)); - JS_ASSERT(tmp != newRep); - } -#endif - //|newRep| is now the first element of a new list, therefore it is the - //new canonical element. Mark the remaining elements in the list - //(including |newRep|) - newdata->classPrev = nullptr; - IonSpew(IonSpew_GVN, "Choosing a new representative: %d", newRep->id()); - - // make the VN of every member in the class the VN of the new representative number. - for (MDefinition *tmp = newRep; tmp != nullptr; tmp = tmp->valueNumberData()->classNext) { - // if this instruction is already scheduled to be processed, don't do anything. - if (tmp->isInWorklist()) { - IonSpew(IonSpew_GVN, "Defer to a new congruence class: %d", tmp->id()); - continue; - } - IonSpew(IonSpew_GVN, "Moving to a new congruence class: %d", tmp->id()); - tmp->setValueNumber(newRep->id()); - markConsumers(tmp); - markDefinition(tmp); - } - - // Insert the new representative => number mapping into the table - // Logically, there should not be anything in the table currently, but - // old values are never removed, so there's a good chance something will - // already be there. - values.put(newRep, newRep->id()); - } else { - // The element that is breaking from the list isn't the representative element - // just strip it from the list - ValueNumberData *defdata = def->valueNumberData(); - if (defdata->classPrev) - defdata->classPrev->valueNumberData()->classNext = defdata->classNext; - if (defdata->classNext) - defdata->classNext->valueNumberData()->classPrev = defdata->classPrev; - - // Make sure there is no nastinees accidentally linking elements into the old list later. - defdata->classPrev = nullptr; - defdata->classNext = nullptr; - } -} diff --git a/js/src/jit/ValueNumbering.h b/js/src/jit/ValueNumbering.h index b8736dde630a..674724c2a6ea 100644 --- a/js/src/jit/ValueNumbering.h +++ b/js/src/jit/ValueNumbering.h @@ -7,131 +7,101 @@ #ifndef jit_ValueNumbering_h #define jit_ValueNumbering_h -#include "jit/MIR.h" +#include "jit/IonAllocPolicy.h" +#include "js/HashTable.h" namespace js { namespace jit { +class MDefinition; +class MBasicBlock; +class MIRGraph; +class MPhi; +class MInstruction; +class MIRGenerator; + class ValueNumberer { - protected: - struct ValueHasher + // Value numbering data. + class VisibleValues { - typedef MDefinition * Lookup; - typedef MDefinition * Key; - static HashNumber hash(const Lookup &ins) { - return ins->valueHash(); - } + // Hash policy for ValueSet. + struct ValueHasher + { + typedef const MDefinition *Lookup; + typedef MDefinition *Key; + static HashNumber hash(Lookup ins); + static bool match(Key k, Lookup l); + static void rekey(Key &k, Key newKey); + }; - static bool match(const Key &k, const Lookup &l) { - // If one of the instructions depends on a store, and the - // other instruction does not depend on the same store, - // the instructions are not congruent. - if (k->dependency() != l->dependency()) - return false; - return k->congruentTo(l); - } + typedef HashSet ValueSet; + + ValueSet set_; // Set of visible values + + public: + explicit VisibleValues(TempAllocator &alloc); + bool init(); + + typedef ValueSet::Ptr Ptr; + typedef ValueSet::AddPtr AddPtr; + + Ptr findLeader(const MDefinition *def) const; + AddPtr findLeaderForAdd(MDefinition *def); + bool insert(AddPtr p, MDefinition *def); + void overwrite(AddPtr p, MDefinition *def); + void forget(const MDefinition *def); + void clear(); }; - typedef HashMap ValueMap; + typedef Vector BlockWorklist; + typedef Vector DefWorklist; - struct DominatingValue - { - MDefinition *def; - uint32_t validEnd; - }; - - typedef HashMap, - IonAllocPolicy> InstructionMap; - - protected: - TempAllocator &alloc() const; - uint32_t lookupValue(MDefinition *ins); - MDefinition *findDominatingDef(InstructionMap &defs, MDefinition *ins, size_t index); - - MDefinition *simplify(MDefinition *def, bool useValueNumbers); - MControlInstruction *simplifyControlInstruction(MControlInstruction *def); - bool eliminateRedundancies(); - - bool computeValueNumbers(); - - inline bool isMarked(MDefinition *def) { - return pessimisticPass_ || def->isInWorklist(); - } - - void markDefinition(MDefinition *def); - void unmarkDefinition(MDefinition *def); - - void markConsumers(MDefinition *def); - void markBlock(MBasicBlock *block); - void setClass(MDefinition *toSet, MDefinition *representative); - - public: - static MDefinition *findSplit(MDefinition *); - void breakClass(MDefinition*); - - protected: - MIRGenerator *mir; + MIRGenerator *const mir_; MIRGraph &graph_; - ValueMap values; - bool pessimisticPass_; - size_t count_; + VisibleValues values_; // Numbered values + DefWorklist deadDefs_; // Worklist for deleting values + BlockWorklist unreachableBlocks_; // Worklist for unreachable blocks + BlockWorklist remainingBlocks_; // Blocks remaining with fewer preds + size_t numBlocksDeleted_; // Num deleted blocks in current tree + bool rerun_; // Should we run another GVN iteration? + bool blocksRemoved_; // Have any blocks been removed? + bool updateAliasAnalysis_; // Do we care about AliasAnalysis? + bool dependenciesBroken_; // Have we broken AliasAnalysis? + + bool deleteDefsRecursively(MDefinition *def); + bool pushDeadPhiOperands(MPhi *phi, const MBasicBlock *phiBlock); + bool pushDeadInsOperands(MInstruction *ins); + bool processDeadDefs(); + + bool removePredecessor(MBasicBlock *block, MBasicBlock *pred); + bool removeBlocksRecursively(MBasicBlock *block, const MBasicBlock *root); + + MDefinition *simplified(MDefinition *def) const; + MDefinition *leader(MDefinition *def); + bool hasLeader(const MPhi *phi, const MBasicBlock *phiBlock) const; + bool loopHasOptimizablePhi(MBasicBlock *backedge) const; + + bool visitDefinition(MDefinition *def); + bool visitControlInstruction(MBasicBlock *block, const MBasicBlock *root); + bool visitBlock(MBasicBlock *block, const MBasicBlock *root); + bool visitDominatorTree(MBasicBlock *root, size_t *totalNumVisited); + bool visitGraph(); public: - ValueNumberer(MIRGenerator *mir, MIRGraph &graph, bool optimistic); - bool analyze(); - bool clear(); + ValueNumberer(MIRGenerator *mir, MIRGraph &graph); + + enum UpdateAliasAnalysisFlag { + DontUpdateAliasAnalysis, + UpdateAliasAnalysis, + }; + + // Optimize the graph, performing expression simplification and + // canonicalization, eliminating statically fully-redundant expressions, + // deleting dead instructions, and removing unreachable blocks. + bool run(UpdateAliasAnalysisFlag updateAliasAnalysis); }; -class ValueNumberData : public TempObject { - - friend void ValueNumberer::breakClass(MDefinition*); - friend MDefinition *ValueNumberer::findSplit(MDefinition*); - uint32_t number; - MDefinition *classNext; - MDefinition *classPrev; - - public: - ValueNumberData() : number(0), classNext(nullptr), classPrev(nullptr) {} - - void setValueNumber(uint32_t number_) { - number = number_; - } - - uint32_t valueNumber() { - return number; - } - // Set the class of this to the given representative value. - void setClass(MDefinition *thisDef, MDefinition *rep) { - JS_ASSERT(thisDef->valueNumberData() == this); - // If we are attempting to insert ourself, then nothing needs to be done. - // However, if the definition to be inserted already has the correct value number, - // it still needs to be inserted, since the value number needs to be updated lazily. - // this updating tactic can leave the world in a state where thisDef is not in the - // equivalence class of rep, but it has the same value number. Defs in this state - // need to be re-processed. - if (this == rep->valueNumberData()) - return; - - if (classNext) - classNext->valueNumberData()->classPrev = classPrev; - if (classPrev) - classPrev->valueNumberData()->classNext = classNext; - - - classPrev = rep; - classNext = rep->valueNumberData()->classNext; - - if (rep->valueNumberData()->classNext) - rep->valueNumberData()->classNext->valueNumberData()->classPrev = thisDef; - rep->valueNumberData()->classNext = thisDef; - } -}; } // namespace jit } // namespace js diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index d1e3da2edf2a..3c0c3c3a7cf2 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -524,12 +524,6 @@ JSCompartment::wrap(JSContext *cx, MutableHandle desc) return false; desc.setSetter(set); } - if (desc.descriptorValue().isObject()) { - RootedObject descObj(cx, &desc.descriptorValue().toObject()); - if (!comp->wrap(cx, &descObj)) - return false; - desc.setDescriptorObject(descObj); - } return true; } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index adcff82e4642..947bced0a188 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -962,6 +962,9 @@ JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind) if (!ptr) return; + if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast(ptr))) + return; + gc::Cell *cell = static_cast(ptr); Zone *zone = kind == JSTRACE_OBJECT ? static_cast(cell)->zone() diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 184f39ede302..8d3b46f95ac7 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -269,9 +269,10 @@ js::NewPropertyDescriptorObject(JSContext *cx, Handle desc, Rooted d(cx); d.initFromPropertyDescriptor(desc); - if (!d.makeObject(cx)) + RootedObject descObj(cx); + if (!d.makeObject(cx, &descObj)) return false; - vp.set(d.descriptorValue()); + vp.setObject(*descObj); return true; } @@ -284,7 +285,6 @@ PropDesc::initFromPropertyDescriptor(Handle desc) return; isUndefined_ = false; - descObj_ = nullptr; attrs = uint8_t(desc.attributes()); JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER))); if (desc.hasGetterOrSetterObject()) { @@ -328,11 +328,11 @@ PropDesc::populatePropertyDescriptor(HandleObject obj, MutableHandle desc(cx); if (!desc.initialize(cx, args[1], false)) return false; - desc.clearDescriptorObject(); if (!dbg->unwrapPropDescInto(cx, obj, desc, &desc)) return false; @@ -5340,8 +5339,6 @@ DebuggerObject_defineProperty(JSContext *cx, unsigned argc, Value *vp) ac.construct(cx, obj); if (!cx->compartment()->wrap(cx, &desc)) return false; - if (!desc.makeObject(cx)) - return false; ErrorCopier ec(ac, dbg->toJSObject()); bool dummy; @@ -5383,8 +5380,6 @@ DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp) for (size_t i = 0; i < n; i++) { if (!cx->compartment()->wrap(cx, descs[i])) return false; - if (descs[i].descriptorValue().isUndefined() && !descs[i].makeObject(cx)) - return false; } ErrorCopier ec(ac, dbg->toJSObject()); diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index e05a1cbf8ac3..35b11865f1d5 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -25,7 +25,6 @@ PropDesc::PropDesc() void PropDesc::setUndefined() { - descObj_ = nullptr; value_ = UndefinedValue(); get_ = UndefinedValue(); set_ = UndefinedValue(); @@ -302,8 +301,6 @@ js::ObjectImpl::markChildren(JSTracer *trc) void PropDesc::trace(JSTracer *trc) { - if (descObj_) - gc::MarkObjectRoot(trc, &descObj_, "PropDesc descriptor object"); gc::MarkValueRoot(trc, &value_, "PropDesc value"); gc::MarkValueRoot(trc, &get_, "PropDesc get"); gc::MarkValueRoot(trc, &set_, "PropDesc set"); diff --git a/js/src/vm/PropDesc.h b/js/src/vm/PropDesc.h index f0f467587521..6066e226c209 100644 --- a/js/src/vm/PropDesc.h +++ b/js/src/vm/PropDesc.h @@ -30,12 +30,6 @@ CastAsStrictPropertyOp(JSObject *object) */ struct PropDesc { private: - /* - * Original object from which this descriptor derives, passed through for - * the benefit of proxies. - */ - JSObject *descObj_; - Value value_, get_, set_; /* Property descriptor boolean fields. */ @@ -53,8 +47,7 @@ struct PropDesc { bool isUndefined_ : 1; explicit PropDesc(const Value &v) - : descObj_(nullptr), - value_(v), + : value_(v), get_(UndefinedValue()), set_(UndefinedValue()), attrs(0), hasGet_(false), hasSet_(false), @@ -80,8 +73,7 @@ struct PropDesc { PropDesc(const Value &v, Writability writable, Enumerability enumerable, Configurability configurable) - : descObj_(nullptr), - value_(v), + : value_(v), get_(UndefinedValue()), set_(UndefinedValue()), attrs((writable ? 0 : JSPROP_READONLY) | (enumerable ? JSPROP_ENUMERATE : 0) | @@ -126,7 +118,7 @@ struct PropDesc { */ void initFromPropertyDescriptor(Handle desc); void populatePropertyDescriptor(HandleObject obj, MutableHandle desc) const; - bool makeObject(JSContext *cx); + bool makeObject(JSContext *cx, MutableHandleObject objp); /* Reset the descriptor entirely. */ void setUndefined(); @@ -139,13 +131,6 @@ struct PropDesc { bool hasEnumerable() const { MOZ_ASSERT(!isUndefined()); return hasEnumerable_; } bool hasConfigurable() const { MOZ_ASSERT(!isUndefined()); return hasConfigurable_; } - Value descriptorValue() const { - MOZ_ASSERT(!isUndefined()); - return descObj_ ? ObjectValue(*descObj_) : UndefinedValue(); - } - void setDescriptorObject(JSObject *obj) { descObj_ = obj; } - void clearDescriptorObject() { setDescriptorObject(nullptr); } - uint8_t attributes() const { MOZ_ASSERT(!isUndefined()); return attrs; } /* 8.10.1 IsAccessorDescriptor(desc) */ @@ -263,8 +248,6 @@ class PropDescOperations bool hasEnumerable() const { return desc()->hasEnumerable(); } bool hasConfigurable() const { return desc()->hasConfigurable(); } - Value descriptorValue() const { return desc()->descriptorValue(); } - uint8_t attributes() const { return desc()->attributes(); } bool isAccessorDescriptor() const { return desc()->isAccessorDescriptor(); } @@ -309,8 +292,8 @@ class MutablePropDescOperations : public PropDescOperations void initFromPropertyDescriptor(Handle descriptor) { desc()->initFromPropertyDescriptor(descriptor); } - bool makeObject(JSContext *cx) { - return desc()->makeObject(cx); + bool makeObject(JSContext *cx, MutableHandleObject objp) { + return desc()->makeObject(cx, objp); } void setValue(const Value &value) { @@ -324,9 +307,6 @@ class MutablePropDescOperations : public PropDescOperations } void setUndefined() { desc()->setUndefined(); } - - void setDescriptorObject(JSObject *obj) { desc()->setDescriptorObject(obj); } - void clearDescriptorObject() { desc()->clearDescriptorObject(); } }; } /* namespace JS */ @@ -337,8 +317,7 @@ template <> struct GCMethods { static PropDesc initial() { return PropDesc(); } static bool poisoned(const PropDesc &desc) { - return JS::IsPoisonedPtr(desc.descObj_) || - (desc.value_.isGCThing() && + return (desc.value_.isGCThing() && JS::IsPoisonedPtr(desc.value_.toGCThing())) || (desc.get_.isGCThing() && JS::IsPoisonedPtr(desc.get_.toGCThing())) || diff --git a/js/xpconnect/idl/nsIXPConnect.idl b/js/xpconnect/idl/nsIXPConnect.idl index 31bddeea75ce..dde377b1f1bf 100644 --- a/js/xpconnect/idl/nsIXPConnect.idl +++ b/js/xpconnect/idl/nsIXPConnect.idl @@ -274,7 +274,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[noscript, uuid(47fbe8ff-0507-4647-9ea7-e0e1fc76c995)] +[noscript, uuid(523da588-95a4-469f-ba1b-c637c3ad4142)] interface nsIXPConnect : nsISupports { %{ C++ @@ -573,16 +573,6 @@ interface nsIXPConnect : nsISupports nsIXPConnectJSObjectHolder holdObject(in JSContextPtr aJSContext, in JSObjectPtr aObject); - /** - * When we place the browser in JS debug mode, there can't be any - * JS on the stack. This is because we currently activate debugMode - * on all scripts in the JSRuntime when the debugger is activated. - * This method will turn debug mode on or off when the context - * stack reaches zero length. - */ - [noscript] void setDebugModeWhenPossible(in boolean mode, - in boolean allowSyncDisable); - [noscript] void writeScript(in nsIObjectOutputStream aStream, in JSContextPtr aJSContext, in JSScriptPtr aJSScript); diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index f4b13d104db8..a928da65f777 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2945,7 +2945,7 @@ nsXPCComponents_Utils::NondeterministicGetWeakMapKeys(HandleValue aMap, return NS_OK; } -/* void getDebugObject(); */ +/* [implicit_jscontext] jsval getJSTestingFunctions(); */ NS_IMETHODIMP nsXPCComponents_Utils::GetJSTestingFunctions(JSContext *cx, MutableHandleValue retval) diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index b78dfdb074ea..e86855bafeac 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1123,7 +1123,7 @@ ProcessArgs(JSContext *cx, JS::Handle obj, char **argv, int argc, XPC case 'x': break; case 'd': - xpc_ActivateDebugMode(); + /* This used to try to turn on the debugger. */ break; case 'f': if (++i == argc) { diff --git a/js/xpconnect/src/moz.build b/js/xpconnect/src/moz.build index 61865c7fc850..72570f95daa6 100644 --- a/js/xpconnect/src/moz.build +++ b/js/xpconnect/src/moz.build @@ -76,9 +76,6 @@ GENERATED_FILES = [ DEFINES['JS_THREADSAFE'] = True -if CONFIG['MOZ_JSDEBUGGER']: - DEFINES['MOZ_JSDEBUGGER'] = True - LOCAL_INCLUDES += [ '../loader', '../wrappers', diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index d1fc40540866..69deae5bc34d 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -21,10 +21,6 @@ #include "WrapperFactory.h" #include "AccessCheck.h" -#ifdef MOZ_JSDEBUGGER -#include "jsdIDebuggerService.h" -#endif - #include "XPCQuickStubs.h" #include "mozilla/dom/BindingUtils.h" @@ -57,9 +53,6 @@ nsXPConnect* nsXPConnect::gSelf = nullptr; bool nsXPConnect::gOnceAliveNowDead = false; uint32_t nsXPConnect::gReportAllJSExceptions = 0; -bool xpc::gDebugMode = false; -bool xpc::gDesiredDebugMode = false; - // Global cache of the default script security manager (QI'd to // nsIScriptSecurityManager) nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nullptr; @@ -1047,12 +1040,6 @@ nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread, PopJSContextNoScriptContext(); - // If the cx stack is empty, that means we're at the an un-nested event - // loop. This is a good time to make changes to debug mode. - if (XPCJSRuntime::Get()->GetJSContextStack()->Count() == 0) { - MOZ_ASSERT(mEventDepth == 0); - CheckForDebugMode(XPCJSRuntime::Get()->Runtime()); - } return NS_OK; } @@ -1114,69 +1101,6 @@ nsXPConnect::UnregisterContextCallback(xpcContextCallback func) mRuntime->RemoveContextCallback(func); } -#ifdef MOZ_JSDEBUGGER -void -nsXPConnect::CheckForDebugMode(JSRuntime *rt) -{ - if (gDebugMode == gDesiredDebugMode) { - return; - } - - // This can happen if a Worker is running, but we don't have the ability to - // debug workers right now, so just return. - if (!NS_IsMainThread()) - MOZ_CRASH(); - - AutoSafeJSContext cx; - JS_SetRuntimeDebugMode(rt, gDesiredDebugMode); - - nsresult rv; - const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1"; - nsCOMPtr jsds = do_GetService(jsdServiceCtrID, &rv); - if (NS_FAILED(rv)) { - goto fail; - } - - if (!JS_SetDebugModeForAllCompartments(cx, gDesiredDebugMode)) - goto fail; - - if (gDesiredDebugMode) { - rv = jsds->ActivateDebugger(rt); - } - - gDebugMode = gDesiredDebugMode; - return; - -fail: - if (jsds) - jsds->DeactivateDebugger(); - - /* - * If an attempt to turn debug mode on fails, cancel the request. It's - * always safe to turn debug mode off, since DeactivateDebugger prevents - * debugger callbacks from having any effect. - */ - if (gDesiredDebugMode) - JS_SetRuntimeDebugMode(rt, false); - gDesiredDebugMode = gDebugMode = false; -} -#else //MOZ_JSDEBUGGER not defined -void -nsXPConnect::CheckForDebugMode(JSRuntime *rt) -{ - gDesiredDebugMode = gDebugMode = false; -} -#endif //#ifdef MOZ_JSDEBUGGER - - -void -xpc_ActivateDebugMode() -{ - XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); - nsXPConnect::XPConnect()->SetDebugModeWhenPossible(true, true); - nsXPConnect::CheckForDebugMode(rt->Runtime()); -} - /* virtual */ JSContext* nsXPConnect::GetCurrentJSContext() @@ -1319,15 +1243,6 @@ SetLocationForGlobal(JSObject *global, nsIURI *locationURI) } // namespace xpc -NS_IMETHODIMP -nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable) -{ - gDesiredDebugMode = mode; - if (!mode && allowSyncDisable) - CheckForDebugMode(mRuntime->Runtime()); - return NS_OK; -} - NS_IMETHODIMP nsXPConnect::NotifyDidPaint() { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 6632127f211c..e7be6a895b6b 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -313,8 +313,6 @@ public: return gReportAllJSExceptions > 0; } - static void CheckForDebugMode(JSRuntime *rt); - protected: virtual ~nsXPConnect(); @@ -3650,9 +3648,6 @@ GetObjectScope(JSObject *obj) // This returns null if a scope doesn't already exist. XPCWrappedNativeScope* MaybeGetObjectScope(JSObject *obj); -extern bool gDebugMode; -extern bool gDesiredDebugMode; - extern const JSClass SafeJSContextGlobalClass; JSObject* NewOutObject(JSContext* cx, JSObject* scope); diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 79600875135f..835721096481 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -207,11 +207,6 @@ xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS); extern void xpc_UnmarkSkippableJSHolders(); -// No JS can be on the stack when this is called. Probably only useful from -// xpcshell. -void -xpc_ActivateDebugMode(); - // readable string conversions, static methods and members only class XPCStringConvert { diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index e6b93dbb750e..f9f0a3f466d9 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -7,6 +7,7 @@ #include "FrameLayerBuilder.h" +#include "mozilla/gfx/Matrix.h" #include "nsDisplayList.h" #include "nsPresContext.h" #include "nsLayoutUtils.h" @@ -2309,13 +2310,13 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, #ifdef MOZ_DUMP_PAINTING static void -DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf) +DumpPaintedImage(nsDisplayItem* aItem, SourceSurface* aSurface) { nsCString string(aItem->Name()); string.Append('-'); string.AppendInt((uint64_t)aItem); fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading()); - aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile); + gfxUtils::DumpAsDataURI(aSurface, gfxUtils::sDumpPaintFile); fprintf_stderr(gfxUtils::sDumpPaintFile, "\";"); } #endif @@ -2336,12 +2337,14 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder, nsIntRect itemVisibleRect = aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel); - nsRefPtr surf; + RefPtr tempDT; if (gfxUtils::sDumpPainting) { - surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size().ToIntSize(), - gfxContentType::COLOR_ALPHA); - surf->SetDeviceOffset(-itemVisibleRect.TopLeft()); - context = new gfxContext(surf); + tempDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( + itemVisibleRect.Size().ToIntSize(), + SurfaceFormat::B8G8R8A8); + context = new gfxContext(tempDT); + context->SetMatrix(gfxMatrix().Translate(-gfxPoint(itemVisibleRect.x, + itemVisibleRect.y))); } #endif basic->BeginTransaction(); @@ -2364,12 +2367,14 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder, #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { - DumpPaintedImage(aItem, surf); + RefPtr surface = tempDT->Snapshot(); + DumpPaintedImage(aItem, surface); + + DrawTarget* drawTarget = aContext->GetDrawTarget(); + Rect rect(itemVisibleRect.x, itemVisibleRect.y, + itemVisibleRect.width, itemVisibleRect.height); + drawTarget->DrawSurface(surface, rect, Rect(Point(0,0), rect.Size())); - surf->SetDeviceOffset(gfxPoint(0, 0)); - aContext->SetSource(surf, itemVisibleRect.TopLeft()); - aContext->Rectangle(itemVisibleRect); - aContext->Fill(); aItem->SetPainted(); } #endif @@ -3570,22 +3575,24 @@ static void DebugPaintItem(nsRenderingContext* aDest, gfxRect bounds(appUnitBounds.x, appUnitBounds.y, appUnitBounds.width, appUnitBounds.height); bounds.ScaleInverse(aPresContext->AppUnitsPerDevPixel()); - nsRefPtr surf = - gfxPlatform::GetPlatform()->CreateOffscreenSurface(IntSize(bounds.width, bounds.height), - gfxContentType::COLOR_ALPHA); - surf->SetDeviceOffset(-bounds.TopLeft()); - nsRefPtr context = new gfxContext(surf); + RefPtr tempDT = + gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( + IntSize(bounds.width, bounds.height), + SurfaceFormat::B8G8R8A8); + nsRefPtr context = new gfxContext(tempDT); + context->SetMatrix(gfxMatrix().Translate(-gfxPoint(bounds.x, bounds.y))); nsRefPtr ctx = new nsRenderingContext(); ctx->Init(aDest->DeviceContext(), context); aItem->Paint(aBuilder, ctx); - DumpPaintedImage(aItem, surf); - aItem->SetPainted(); + RefPtr surface = tempDT->Snapshot(); + DumpPaintedImage(aItem, surface); - surf->SetDeviceOffset(gfxPoint(0, 0)); - aDest->ThebesContext()->SetSource(surf, bounds.TopLeft()); - aDest->ThebesContext()->Rectangle(bounds); - aDest->ThebesContext()->Fill(); + DrawTarget* drawTarget = aDest->ThebesContext()->GetDrawTarget(); + Rect rect = ToRect(bounds); + drawTarget->DrawSurface(surface, rect, Rect(Point(0,0), rect.Size())); + + aItem->SetPainted(); } #endif diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 21c310c9a8be..ffe56d0f7917 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3883,7 +3883,7 @@ nsLayoutUtils::IntrinsicForContainer(nsRenderingContext *aRenderingContext, bool canOverride = true; nsPresContext *presContext = aFrame->PresContext(); presContext->GetTheme()-> - GetMinimumWidgetSize(aRenderingContext, aFrame, disp->mAppearance, + GetMinimumWidgetSize(presContext, aFrame, disp->mAppearance, &size, &canOverride); nscoord themeWidth = presContext->DevPixelsToAppUnits(size.width); diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index ad71ab1f327b..d1b4b868959e 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -114,6 +114,7 @@ #include "nsStyleSheetService.h" #include "gfxImageSurface.h" #include "gfxContext.h" +#include "gfxUtils.h" #include "nsSMILAnimationController.h" #include "SVGContentUtils.h" #include "nsSVGEffects.h" @@ -9522,68 +9523,6 @@ PresShell::CloneStyleSet(nsStyleSet* aSet) return clone; } -#ifdef DEBUG_Eli -static nsresult -DumpToPNG(nsIPresShell* shell, nsAString& name) { - int32_t width=1000, height=1000; - nsRect r(0, 0, shell->GetPresContext()->DevPixelsToAppUnits(width), - shell->GetPresContext()->DevPixelsToAppUnits(height)); - - nsRefPtr imgSurface = - new gfxImageSurface(gfxIntSize(width, height), - gfxImageFormat::ARGB32); - - nsRefPtr imgContext = new gfxContext(imgSurface); - - nsRefPtr surface = - gfxPlatform::GetPlatform()-> - CreateOffscreenSurface(IntSize(width, height), - gfxASurface::ContentFromFormat(gfxImageFormat::ARGB32)); - NS_ENSURE_TRUE(surface, NS_ERROR_OUT_OF_MEMORY); - - nsRefPtr context = new gfxContext(surface); - - shell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context); - - imgContext->DrawSurface(surface, gfxSize(width, height)); - - nsCOMPtr encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png"); - NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE); - encoder->InitFromData(imgSurface->Data(), imgSurface->Stride() * height, - width, height, imgSurface->Stride(), - imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString()); - - // XXX not sure if this is the right way to write to a file - nsCOMPtr file = do_CreateInstance("@mozilla.org/file/local;1"); - NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); - rv = file->InitWithPath(name); - NS_ENSURE_SUCCESS(rv, rv); - - uint64_t length64; - rv = encoder->Available(&length64); - NS_ENSURE_SUCCESS(rv, rv); - if (length64 > UINT32_MAX) - return NS_ERROR_FILE_TOO_BIG; - - uint32_t length = (uint32_t)length64; - - nsCOMPtr outputStream; - rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr bufferedOutputStream; - rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), - outputStream, length); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t numWritten; - rv = bufferedOutputStream->WriteFrom(encoder, length, &numWritten); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} -#endif - // After an incremental reflow, we verify the correctness by doing a // full reflow into a fresh frame tree. bool @@ -9668,7 +9607,7 @@ PresShell::VerifyIncrementalReflow() root2->List(stdout, 0); } -#ifdef DEBUG_Eli +#if 0 // Sample code for dumping page to png // XXX Needs to be made more flexible if (!ok) { @@ -9677,12 +9616,12 @@ PresShell::VerifyIncrementalReflow() stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea"); stra.AppendInt(num); stra.AppendLiteral(".png"); - DumpToPNG(sh, stra); + gfxUtils::WriteAsPNG(sh, stra); nsString strb; strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb"); strb.AppendInt(num); strb.AppendLiteral(".png"); - DumpToPNG(this, strb); + gfxUtils::WriteAsPNG(sh, strb); ++num; } #endif diff --git a/layout/forms/nsRangeFrame.cpp b/layout/forms/nsRangeFrame.cpp index f303caae65e1..2d58bcbbaac5 100644 --- a/layout/forms/nsRangeFrame.cpp +++ b/layout/forms/nsRangeFrame.cpp @@ -499,12 +499,10 @@ nsRangeFrame::GetValueAtEventPoint(WidgetGUIEvent* aEvent) if (IsThemed()) { // We need to get the size of the thumb from the theme. nsPresContext *presContext = PresContext(); - nsRefPtr tmpCtx = - presContext->PresShell()->CreateReferenceRenderingContext(); bool notUsedCanOverride; nsIntSize size; presContext->GetTheme()-> - GetMinimumWidgetSize(tmpCtx.get(), this, NS_THEME_RANGE_THUMB, &size, + GetMinimumWidgetSize(presContext, this, NS_THEME_RANGE_THUMB, &size, ¬UsedCanOverride); thumbSize.width = presContext->DevPixelsToAppUnits(size.width); thumbSize.height = presContext->DevPixelsToAppUnits(size.height); diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 967f6f95f965..2b95d089e0f7 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -1000,7 +1000,7 @@ nsFlexContainerFrame::GenerateFlexItemForChild( nsIntSize widgetMinSize(0, 0); bool canOverride = true; aPresContext->GetTheme()-> - GetMinimumWidgetSize(childRS.rendContext, aChildFrame, + GetMinimumWidgetSize(aPresContext, aChildFrame, disp->mAppearance, &widgetMinSize, &canOverride); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 2c503f58f427..a81a122745e3 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4132,7 +4132,7 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext, bool canOverride = true; nsPresContext *presContext = PresContext(); presContext->GetTheme()-> - GetMinimumWidgetSize(aRenderingContext, this, disp->mAppearance, + GetMinimumWidgetSize(presContext, this, disp->mAppearance, &widget, &canOverride); nsSize size; diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index d75bded7ae6f..6b0c80f1dd01 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -974,17 +974,14 @@ ScrollFrameHelper::GetNondisappearingScrollbarWidth(nsBoxLayoutState* aState) mVScrollbarBox, NS_THEME_SCROLLBAR_NON_DISAPPEARING)) { nsIntSize size; - nsRenderingContext* rendContext = aState->GetRenderingContext(); - if (rendContext) { - bool canOverride = true; - theme->GetMinimumWidgetSize(rendContext, - mVScrollbarBox, - NS_THEME_SCROLLBAR_NON_DISAPPEARING, - &size, - &canOverride); - if (size.width) { - return aState->PresContext()->DevPixelsToAppUnits(size.width); - } + bool canOverride = true; + theme->GetMinimumWidgetSize(aState->PresContext(), + mVScrollbarBox, + NS_THEME_SCROLLBAR_NON_DISAPPEARING, + &size, + &canOverride); + if (size.width) { + return aState->PresContext()->DevPixelsToAppUnits(size.width); } } } diff --git a/layout/reftests/svg/filters/svg-filter-chains/clip-input-ref.svg b/layout/reftests/svg/filters/svg-filter-chains/clip-input-ref.svg new file mode 100644 index 000000000000..8b14a53c0158 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/clip-input-ref.svg @@ -0,0 +1,22 @@ + + + + SVG Filter Chains: Clip Input Filter + + + + + namespace svg + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/clip-input.svg b/layout/reftests/svg/filters/svg-filter-chains/clip-input.svg new file mode 100644 index 000000000000..4ec53b9b3914 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/clip-input.svg @@ -0,0 +1,48 @@ + + + + SVG Filter Chains: Clip Input Filter + + + + + + namespace svg + + In an SVG filter chain, this test verifies that a filter region clips a + SourceGraphic input filter. If the test passes, you should see a green + square. + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/clip-output-ref.svg b/layout/reftests/svg/filters/svg-filter-chains/clip-output-ref.svg new file mode 100644 index 000000000000..53cf12a35990 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/clip-output-ref.svg @@ -0,0 +1,26 @@ + + + + SVG Filter Chains: Clip Filter Output + + + + + namespace svg + + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/clip-output.svg b/layout/reftests/svg/filters/svg-filter-chains/clip-output.svg new file mode 100644 index 000000000000..911589473594 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/clip-output.svg @@ -0,0 +1,48 @@ + + + + SVG Filter Chains: Clip Filter Output + + + + + + namespace svg + + In an SVG filter chain, this test verifies a filter region clips its + filter's output into the next filter. If the test passes, you should see a + green square. + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/default-subregion-ref.svg b/layout/reftests/svg/filters/svg-filter-chains/default-subregion-ref.svg new file mode 100644 index 000000000000..ae43488ea2d7 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/default-subregion-ref.svg @@ -0,0 +1,25 @@ + + + + SVG Filter Chains: Default Filter Primitive Subregion + + + + + namespace svg + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/default-subregion.svg b/layout/reftests/svg/filters/svg-filter-chains/default-subregion.svg new file mode 100644 index 000000000000..0a04629f361d --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/default-subregion.svg @@ -0,0 +1,44 @@ + + + + SVG Filter Chains: Default Filter Primitive Subregion + + + + + + namespace svg + + In an SVG filter chain, this test verifies that the default filter + primitive subregion is equal to the filter region. If the test passes, + you should see a blurred green square. + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/intersecting-filter-regions-ref.svg b/layout/reftests/svg/filters/svg-filter-chains/intersecting-filter-regions-ref.svg new file mode 100644 index 000000000000..c65db2e99b61 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/intersecting-filter-regions-ref.svg @@ -0,0 +1,25 @@ + + + + SVG Filter Chains: Intersecting Filter Regions + + + + + namespace svg + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/intersecting-filter-regions.svg b/layout/reftests/svg/filters/svg-filter-chains/intersecting-filter-regions.svg new file mode 100644 index 000000000000..f9ff60aa2f17 --- /dev/null +++ b/layout/reftests/svg/filters/svg-filter-chains/intersecting-filter-regions.svg @@ -0,0 +1,45 @@ + + + + SVG Filter Chains: Intersecting Filter Regions + + + + + + namespace svg + + In an SVG filter chain, this test verifies that filters with intersecting + filter regions render properly. If the test passes, you should see a green + square. + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/filters/svg-filter-chains/reftest.list b/layout/reftests/svg/filters/svg-filter-chains/reftest.list index d95c17e020f4..163bcc0b5887 100644 --- a/layout/reftests/svg/filters/svg-filter-chains/reftest.list +++ b/layout/reftests/svg/filters/svg-filter-chains/reftest.list @@ -3,6 +3,10 @@ default-preferences pref(layout.css.filters.enabled,true) +== clip-input.svg clip-input-ref.svg +== clip-output.svg clip-output.svg +== default-subregion.svg default-subregion-ref.svg +== intersecting-filter-regions.svg intersecting-filter-regions-ref.svg == long-chain.svg simple-chain-ref.svg == multiple-primitives-per-filter.svg simple-chain-ref.svg == second-filter-uses-SourceGraphic.svg simple-chain-ref.svg diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp index 5935c544459d..14d10c8446b0 100644 --- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -1150,7 +1150,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSStyleSheet) tmp->DropRuleCollection(); tmp->UnlinkInner(); tmp->mScopeElement = nullptr; - tmp->ClearRuleCascades(); NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CSSStyleSheet) diff --git a/layout/svg/nsSVGFilterInstance.cpp b/layout/svg/nsSVGFilterInstance.cpp index b6c6be4d6239..ed5eb59488df 100644 --- a/layout/svg/nsSVGFilterInstance.cpp +++ b/layout/svg/nsSVGFilterInstance.cpp @@ -229,9 +229,10 @@ nsSVGFilterInstance::ComputeFilterPrimitiveSubregion(nsSVGFE* aFilterElement, if (fE->SubregionIsUnionOfRegions()) { for (uint32_t i = 0; i < aInputIndices.Length(); ++i) { int32_t inputIndex = aInputIndices[i]; - IntRect inputSubregion = inputIndex >= 0 ? - aPrimitiveDescrs[inputIndex].PrimitiveSubregion() : - ToIntRect(mFilterSpaceBounds); + bool isStandardInput = inputIndex < 0 || inputIndex == mSourceGraphicIndex; + IntRect inputSubregion = isStandardInput ? + ToIntRect(mFilterSpaceBounds) : + aPrimitiveDescrs[inputIndex].PrimitiveSubregion(); defaultFilterSubregion = defaultFilterSubregion.Union(inputSubregion); } @@ -256,8 +257,10 @@ nsSVGFilterInstance::ComputeFilterPrimitiveSubregion(nsSVGFE* aFilterElement, // Following the spec, any pixel partially in the region is included // in the region. region.RoundOut(); + IntRect regionInt = RoundedToInt(region); - return RoundedToInt(region); + // Clip the primitive subregion to this filter's filter region. + return regionInt.Intersect(ToIntRect(mFilterSpaceBounds)); } void diff --git a/layout/xul/nsBox.cpp b/layout/xul/nsBox.cpp index beb4a53af83b..38c8b9706c36 100644 --- a/layout/xul/nsBox.cpp +++ b/layout/xul/nsBox.cpp @@ -682,18 +682,15 @@ nsIFrame::AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize, nsITheme *theme = aState.PresContext()->GetTheme(); if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) { nsIntSize size; - nsRenderingContext* rendContext = aState.GetRenderingContext(); - if (rendContext) { - theme->GetMinimumWidgetSize(rendContext, aBox, - display->mAppearance, &size, &canOverride); - if (size.width) { - aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width); - aWidthSet = true; - } - if (size.height) { - aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height); - aHeightSet = true; - } + theme->GetMinimumWidgetSize(aState.PresContext(), aBox, + display->mAppearance, &size, &canOverride); + if (size.width) { + aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width); + aWidthSet = true; + } + if (size.height) { + aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height); + aHeightSet = true; } } } diff --git a/layout/xul/nsScrollbarFrame.cpp b/layout/xul/nsScrollbarFrame.cpp index 77603290b668..5e21d175f6b2 100644 --- a/layout/xul/nsScrollbarFrame.cpp +++ b/layout/xul/nsScrollbarFrame.cpp @@ -167,9 +167,7 @@ nsScrollbarFrame::GetMargin(nsMargin& aMargin) if (theme) { nsIntSize size; bool isOverridable; - nsRefPtr rc = - presContext->PresShell()->CreateReferenceRenderingContext(); - theme->GetMinimumWidgetSize(rc, this, NS_THEME_SCROLLBAR, &size, + theme->GetMinimumWidgetSize(presContext, this, NS_THEME_SCROLLBAR, &size, &isOverridable); if (IsHorizontal()) { aMargin.top = -presContext->DevPixelsToAppUnits(size.height); diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index 1f0ca0df2613..582dc88b2fae 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -2087,7 +2087,7 @@ nsTreeBodyFrame::GetTwistyRect(int32_t aRowIndex, if (useTheme) { nsIntSize minTwistySizePx(0,0); bool canOverride = true; - theme->GetMinimumWidgetSize(&aRenderingContext, this, twistyDisplayData->mAppearance, + theme->GetMinimumWidgetSize(aPresContext, this, twistyDisplayData->mAppearance, &minTwistySizePx, &canOverride); // GMWS() returns size in pixels, we need to convert it back to app units diff --git a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp index bbc55b7b81f0..65deed1fe7eb 100644 --- a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp +++ b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp @@ -406,7 +406,7 @@ static void StoreLongTermICEStatisticsImpl_m( Accumulate(WEBRTC_VIDEO_ENCODER_FRAMERATE_10X_STD_DEV_PER_CALL, uint32_t(s.mFramerateStdDev.Value() * 10)); } - if (s.mDroppedFrames.WasPassed()) { + if (s.mDroppedFrames.WasPassed() && !query->iceStartTime.IsNull()) { double mins = (TimeStamp::Now() - query->iceStartTime).ToSeconds() / 60; if (mins > 0) { Accumulate(WEBRTC_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM, @@ -440,7 +440,7 @@ static void StoreLongTermICEStatisticsImpl_m( Accumulate(WEBRTC_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL, uint32_t(s.mFramerateStdDev.Value() * 10)); } - if (s.mDiscardedPackets.WasPassed()) { + if (s.mDiscardedPackets.WasPassed() && !query->iceStartTime.IsNull()) { double mins = (TimeStamp::Now() - query->iceStartTime).ToSeconds() / 60; if (mins > 0) { Accumulate(WEBRTC_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM, @@ -469,10 +469,12 @@ static void GetStatsForLongTermStorage_s( // this call. (These calls must be made on STS) unsigned char rate_limit_bit_pattern = 0; if (!mozilla::nr_socket_short_term_violation_time().IsNull() && + !query->iceStartTime.IsNull() && mozilla::nr_socket_short_term_violation_time() >= query->iceStartTime) { rate_limit_bit_pattern |= 1; } if (!mozilla::nr_socket_long_term_violation_time().IsNull() && + !query->iceStartTime.IsNull() && mozilla::nr_socket_long_term_violation_time() >= query->iceStartTime) { rate_limit_bit_pattern |= 2; } diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java b/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java index e08bef3b2633..33f0e3237c35 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java +++ b/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java @@ -184,8 +184,11 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback { } } List focusModeList = parameters.getSupportedFocusModes(); - if (focusModeList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { - parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); + // Not supposed to fail, but observed on Android 4.0 emulator nevertheless + if (focusModeList != null) { + if (focusModeList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { + parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); + } } parameters.setPreviewSize(width, height); if (android.os.Build.VERSION.SDK_INT>8) { diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 45a96142daa9..2b76e332cb82 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -988,7 +988,7 @@ pref("network.http.default-socket-type", ""); // the packet is lost or delayed on the route. pref("network.http.keep-alive.timeout", 115); -// Timeout connections if an initial response is not received after 10 mins. +// Timeout connections if an initial response is not received after 5 mins. pref("network.http.response.timeout", 300); // Limit the absolute number of http connections. diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 23ae00df2703..559e4bbedd85 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -100,27 +100,18 @@ NeckoParent::GetValidatedAppInfo(const SerializedLoadContext& aSerialized, *aAppId = NECKO_UNKNOWN_APP_ID; *aInBrowserElement = false; - if (!UsingNeckoIPCSecurity()) { - // We are running xpcshell tests - if (aSerialized.IsNotNull()) { - *aAppId = aSerialized.mAppId; - *aInBrowserElement = aSerialized.mIsInBrowserElement; - } else { - *aAppId = NECKO_NO_APP_ID; + if (UsingNeckoIPCSecurity()) { + if (!aSerialized.IsNotNull()) { + return "SerializedLoadContext from child is null"; } - return nullptr; } - if (!aSerialized.IsNotNull()) { - return "SerializedLoadContext from child is null"; - } - - const InfallibleTArray& browsers = - aContent->ManagedPBrowserParent(); - + const InfallibleTArray& browsers = aContent->ManagedPBrowserParent(); for (uint32_t i = 0; i < browsers.Length(); i++) { nsRefPtr tabParent = static_cast(browsers[i]); uint32_t appId = tabParent->OwnOrContainingAppId(); + bool inBrowserElement = aSerialized.IsNotNull() ? aSerialized.mIsInBrowserElement + : tabParent->IsBrowserElement(); if (appId == NECKO_UNKNOWN_APP_ID) { continue; @@ -130,7 +121,7 @@ NeckoParent::GetValidatedAppInfo(const SerializedLoadContext& aSerialized, if (tabParent->HasOwnApp()) { continue; } - if (tabParent->IsBrowserElement()) { + if (UsingNeckoIPCSecurity() && tabParent->IsBrowserElement()) { //