This commit is contained in:
Wes Kocher 2014-06-27 17:40:49 -07:00
Родитель c04f11ecf4 9f2f121898
Коммит be05307be5
218 изменённых файлов: 5087 добавлений и 19101 удалений

Просмотреть файл

@ -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).

Просмотреть файл

@ -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);
}
},
/**

Просмотреть файл

@ -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.
*/

Просмотреть файл

@ -13,6 +13,7 @@ use_latest_firefox.innerHTML=To use Loop, please use the latest version of <a hr
incompatible_device=Incompatible device
sorry_device_unsupported=Sorry, Loop does not currently support your device.
use_firefox_windows_mac_linux=Please open this page using the latest Firefox on Windows, Android, Mac or Linux.
connection_error_see_console_notification=Call failed; see console for details.
[fr]
call_has_ended=L'appel est terminé.

Просмотреть файл

@ -26,7 +26,9 @@ describe("loop.shared.models", function() {
apiKey: "apiKey"
};
fakeSession = _.extend({
connect: sandbox.spy(),
connect: function () {},
endSession: sandbox.stub(),
set: sandbox.stub(),
disconnect: sandbox.spy(),
unpublish: sandbox.spy()
}, Backbone.Events);
@ -163,12 +165,72 @@ describe("loop.shared.models", function() {
sinon.assert.calledOnce(fakeSDK.initSession);
});
describe("Session events", function() {
it("should trigger a session:connected event on sessionConnected",
function(done) {
model.once("session:connected", function(){ done(); });
it("should call connect", function() {
fakeSession.connect = sandbox.stub();
fakeSession.trigger("sessionConnected");
model.startSession();
sinon.assert.calledOnce(fakeSession.connect);
sinon.assert.calledWithExactly(fakeSession.connect,
sinon.match.string, sinon.match.string,
sinon.match.func);
});
it("should set ongoing to true when no error is called back",
function() {
fakeSession.connect = function(key, token, cb) {
cb(null);
};
sinon.stub(model, "set");
model.startSession();
sinon.assert.calledWith(model.set, "ongoing", true);
});
it("should trigger session:connected when no error is called back",
function() {
fakeSession.connect = function(key, token, cb) {
cb(null);
};
sandbox.stub(model, "trigger");
model.startSession();
sinon.assert.calledWithExactly(model.trigger, "session:connected");
});
describe("Session events", function() {
it("should trigger a fail event when an error is called back",
function() {
fakeSession.connect = function(key, token, cb) {
cb({
error: true
});
};
sinon.stub(model, "endSession");
model.startSession();
sinon.assert.calledOnce(model.endSession);
sinon.assert.calledWithExactly(model.endSession);
});
it("should trigger session:connection-error event when an error is" +
" called back", function() {
fakeSession.connect = function(key, token, cb) {
cb({
error: true
});
};
sandbox.stub(model, "trigger");
model.startSession();
sinon.assert.calledOnce(model.trigger);
sinon.assert.calledWithExactly(model.trigger,
"session:connection-error", sinon.match.object);
});
it("should trigger a session:ended event on sessionDisconnected",

Просмотреть файл

@ -125,6 +125,24 @@ describe("loop.shared.router", function() {
});
});
describe("session:connection-error", function() {
it("should warn the user when .connect() call fails", function() {
conversation.trigger("session:connection-error");
sinon.assert.calledOnce(notifier.errorL10n);
sinon.assert.calledWithExactly(notifier.errorL10n, sinon.match.string);
});
it("should invoke endCall()", function() {
conversation.trigger("session:connection-error");
sinon.assert.calledOnce(router.endCall);
sinon.assert.calledWithExactly(router.endCall);
});
});
it("should call startCall() once the call session is ready", function() {
conversation.trigger("session:ready");

Просмотреть файл

@ -11,7 +11,7 @@ for platform in all_platforms:
whitelist['nightly'][platform] = [
'ac_add_options --enable-update-channel=nightly',
'ac_add_options --enable-profiling',
'mk_add_options CLIENT_PY_ARGS="--hg-options=\'--verbose --time\' --hgtool=../tools/buildfarm/utils/hgtool.py --skip-chatzilla --skip-comm --skip-inspector --skip-venkman --tinderbox-print"'
'mk_add_options CLIENT_PY_ARGS="--hg-options=\'--verbose --time\' --hgtool=../tools/buildfarm/utils/hgtool.py --skip-chatzilla --skip-comm --skip-inspector --tinderbox-print"'
]
for platform in ['linux32', 'linux64', 'macosx-universal']:

Просмотреть файл

@ -84,10 +84,6 @@ ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
DEFINES += -DMOZ_SHARED_MOZGLUE=1
endif
ifdef MOZ_JSDEBUGGER
DEFINES += -DMOZ_JSDEBUGGER
endif
ifdef NECKO_WIFI
DEFINES += -DNECKO_WIFI
endif

Просмотреть файл

@ -247,9 +247,6 @@
@BINPATH@/components/inspector.xpt
@BINPATH@/components/intl.xpt
@BINPATH@/components/jar.xpt
#ifdef MOZ_JSDEBUGGER
@BINPATH@/components/jsdservice.xpt
#endif
@BINPATH@/components/jsdebugger.xpt
@BINPATH@/components/jsdownloads.xpt
@BINPATH@/components/jsinspector.xpt

Просмотреть файл

@ -28,3 +28,5 @@ close_window=Close this window
cannot_start_call_session_not_ready=Can't start call, session is not ready.
network_disconnected=The network connection terminated abruptly.
connection_error_see_console_notification=Call failed; see console for details.

Просмотреть файл

@ -31,11 +31,6 @@ leak:GI___strdup
### Many leaks only affect some test suites. The suite annotations are not checked.
###
# Bug 800200 - JSD1 is leaking, but it is about to be removed, so ignore it. m4
leak:jsd_CreateLock
leak:jsdScript::GetExecutableLines
leak:jsdService::ActivateDebugger
# Bug 979928 - WebRTC is leaky. m2, m3
leak:/media/mtransport/
leak:/media/webrtc/signaling/

Просмотреть файл

@ -3849,7 +3849,6 @@ MOZ_BRANDING_DIRECTORY=
MOZ_OFFICIAL_BRANDING=
MOZ_FEEDS=1
MOZ_WEBAPP_RUNTIME=
MOZ_JSDEBUGGER=1
MOZ_AUTH_EXTENSION=1
MOZ_RAW=
MOZ_VORBIS=
@ -4944,15 +4943,6 @@ if test -n "$MOZ_ANDROID_BEAM"; then
AC_DEFINE(MOZ_ANDROID_BEAM)
fi
dnl ========================================================
dnl = JS Debugger XPCOM component (js/jsd)
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(jsd,
[ --disable-jsd Disable JavaScript debug library],
MOZ_JSDEBUGGER=,
MOZ_JSDEBUGGER=1)
dnl ========================================================
dnl = Enable IPDL's "expensive" unit tests
dnl ========================================================
@ -6182,11 +6172,6 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then
fi
AC_SUBST(MOZ_GIO_COMPONENT)
if test -z "$MOZ_JSDEBUGGER" -a `echo "$MOZ_EXTENSIONS" | grep -c venkman` -ne 0; then
AC_MSG_WARN([Cannot build venkman without JavaScript debug library. Removing venkman from MOZ_EXTENSIONS.])
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|venkman||'`
fi
dnl Remove dupes
MOZ_EXTENSIONS=`${PERL} ${srcdir}/build/unix/uniq.pl ${MOZ_EXTENSIONS}`
@ -8195,7 +8180,7 @@ if test "$MOZ_XUL"; then
AC_DEFINE(MOZ_XUL)
else
dnl remove extensions that require XUL
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's/inspector//' -e 's/venkman//' -e 's/irc//' -e 's/tasks//'`
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's/inspector//' -e 's/irc//' -e 's/tasks//'`
fi
AC_SUBST(MOZ_XUL)
@ -8429,7 +8414,6 @@ AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
AC_SUBST(MOZ_DEBUG_LDFLAGS)
AC_SUBST(WARNINGS_AS_ERRORS)
AC_SUBST(MOZ_EXTENSIONS)
AC_SUBST(MOZ_JSDEBUGGER)
AC_SUBST(MOZ_ENABLE_PROFILER_SPS)
AC_SUBST(MOZ_JPROF)
AC_SUBST(MOZ_SHARK)

Просмотреть файл

@ -125,7 +125,7 @@ SVGEllipseElement::BuildPath()
RefPtr<PathBuilder> 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();
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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<nsISlowScriptDebugCallback> 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<jsdIExecutionHook> jsdHook;
nsCOMPtr<jsdIDebuggerService> 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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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<jsdIDebuggerService> 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<JSAutoCompartment> ac;
JS::Rooted<JS::Value> v(cx);
if (GetJSVal(cx, ac, &v)) {
nsCOMPtr<jsdIValue> 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,

Просмотреть файл

@ -144,6 +144,3 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
LOCAL_INCLUDES += [
'/dom/wifi',
]
if CONFIG['MOZ_JSDEBUGGER']:
DEFINES['MOZ_JSDEBUGGER'] = True

Просмотреть файл

@ -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)]

Просмотреть файл

@ -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, {});

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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);
});

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<nsTWeakRef<Promise>> array;
array.SwapElements(mPromises);
for (uint32_t i = 0; i < array.Length(); ++i) {
nsTWeakRef<Promise>& pendingPromise = array.ElementAt(i);
if (pendingPromise) {
nsCOMPtr<nsIGlobalObject> go =
do_QueryInterface(pendingPromise->GetParentObject());
MOZ_ASSERT(go);
AutoSafeJSContext cx;
JS::Rooted<JSObject*> global(cx, go->GetGlobalJSObject());
JSAutoCompartment ac(cx, global);
GlobalObject domGlobal(cx, global);
nsRefPtr<ServiceWorker> 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<nsTWeakRef<Promise>> array;
array.SwapElements(mPromises);
for (uint32_t i = 0; i < array.Length(); ++i) {
nsTWeakRef<Promise>& pendingPromise = array.ElementAt(i);
if (pendingPromise) {
// Since ServiceWorkerContainer is only exposed to windows we can be
// certain about this cast.
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(pendingPromise->GetParentObject());
MOZ_ASSERT(window);
nsRefPtr<DOMError> domError = new DOMError(window, aRv);
pendingPromise->MaybeRejectBrokenly(domError);
}
}
}
class FinishFetchOnMainThreadRunnable : public nsRunnable
{
nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> mUpdateInstance;
public:
FinishFetchOnMainThreadRunnable
(const nsMainThreadPtrHandle<ServiceWorkerUpdateInstance>& aUpdateInstance)
: mUpdateInstance(aUpdateInstance)
{ }
NS_IMETHOD
Run() MOZ_OVERRIDE;
};
class FinishSuccessfulFetchWorkerRunnable : public WorkerRunnable
{
nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> mUpdateInstance;
public:
FinishSuccessfulFetchWorkerRunnable(WorkerPrivate* aWorkerPrivate,
const nsMainThreadPtrHandle<ServiceWorkerUpdateInstance>& aUpdateInstance)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
mUpdateInstance(aUpdateInstance)
{
AssertIsOnMainThread();
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->AssertIsOnWorkerThread();
if (!aWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
return true;
}
nsRefPtr<FinishFetchOnMainThreadRunnable> 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<nsPIDOMWindow> 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<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsRefPtr<ServiceWorker> 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<ServiceWorkerUpdateInstance> handle =
new nsMainThreadPtrHolder<ServiceWorkerUpdateInstance>(this);
// FIXME(nsm): Deal with error case (worker failed to download, redirect,
// parse) in error handler patch.
nsRefPtr<FinishSuccessfulFetchWorkerRunnable> 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<ServiceWorkerManager> 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<ServiceWorkerManager> 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<ServiceWorkerRegistration> registration = domainInfo->GetRegistration(mScope);
nsRefPtr<ServiceWorkerRegistration> 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>
ServiceWorkerManager::GetInstance()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsCOMPtr<nsIServiceWorkerManager> swm =
do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
nsRefPtr<ServiceWorkerManager> 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<ServiceWorker> 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,

Просмотреть файл

@ -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<nsTWeakRef<Promise>> 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<UpdatePromise> mUpdatePromise;
nsRefPtr<ServiceWorkerUpdateInstance> 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<nsCStringHashKey, ServiceWorkerDomainInfo> 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<ServiceWorkerManager>
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,

Просмотреть файл

@ -40,6 +40,7 @@ SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
SharedWorker::~SharedWorker()
{
AssertIsOnMainThread();
Close();
MOZ_ASSERT(!mWorkerPrivate);
}

Просмотреть файл

@ -0,0 +1,6 @@
self.addEventListener("connect", function(e) {
var port = e.ports[0];
port.onmessage = function(e) {
port.postMessage(eval(e.data));
};
});

Просмотреть файл

@ -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]

Просмотреть файл

@ -1,2 +1,8 @@
[DEFAULT]
support-files =
worker.js
worker2.js
worker3.js
[test_installation_simple.html]
[test_navigator.html]

Просмотреть файл

@ -16,7 +16,7 @@
<script class="testbody" type="text/javascript">
function simpleRegister() {
var p = navigator.serviceWorker.register("/fake_worker.js");
var p = navigator.serviceWorker.register("worker.js");
ok(p instanceof Promise, "register() should return a Promise");
return Promise.resolve();
}
@ -50,14 +50,60 @@
ok(false, "non-HTTPS pages cannot register ServiceWorkers");
}, function(e) {
ok(e.name === "SecurityError", "Should fail with a SecurityError");
}).then(function() {
return new Promise((resolve) => SpecialPowers.popPrefEnv(resolve));
});
}
function realWorker() {
var p = navigator.serviceWorker.register("worker.js");
return p.then(function(w) {
ok(w instanceof ServiceWorker, "Register a ServiceWorker");
info(w.scope);
ok(w.scope == (new URL("/*", document.baseURI)).href, "Scope should match");
ok(w.url == (new URL("worker.js", document.baseURI)).href, "URL should be of the worker");
}, function(e) {
info(e.name);
ok(false, "Registration should have succeeded!");
});
}
function abortPrevious() {
var p = navigator.serviceWorker.register("worker2.js", { scope: "foo/*" });
var q = navigator.serviceWorker.register("worker3.js", { scope: "foo/*" });
return Promise.all([
p.then(function(w) {
ok(false, "First registration should fail with AbortError");
}, function(e) {
ok(e.name === "AbortError", "First registration should fail with AbortError");
}),
q.then(function(w) {
ok(w instanceof ServiceWorker, "Second registration should succeed");
}, function(e) {
ok(false, "Second registration should succeed");
})
]);
}
function networkError404() {
return navigator.serviceWorker.register("404.js").then(function(w) {
todo(false, "Should fail with NetworkError");
}, function(e) {
todo(e.name === "NetworkError", "Should fail with NetworkError");
});
}
function runTest() {
simpleRegister()
.then(sameOriginWorker)
.then(sameOriginScope)
.then(httpsOnly)
.then(realWorker)
.then(abortPrevious)
// FIXME(nsm): Uncomment once we have the error trapping patch from Bug 984048.
// .then(networkError404)
// put more tests here.
.then(function() {
SimpleTest.finish();

Просмотреть файл

@ -0,0 +1 @@
// empty worker, always succeed!

Просмотреть файл

@ -0,0 +1 @@
// worker2.js

Просмотреть файл

@ -0,0 +1 @@
// worker3.js

Просмотреть файл

@ -0,0 +1,27 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 1002702</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var port = new SharedWorker('data:application/javascript,1').port;
port.close();
SpecialPowers.forceGC();
ok(true, "No crash \\o/");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,39 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 998474</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="boom();">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
function boom()
{
var worker = new SharedWorker("bug998474_worker.js");
setTimeout(function() {
port = worker.port;
port.postMessage("");
setTimeout(function() {
port.start();
ok(true, "Still alive!");
SimpleTest.finish();
}, 150);
}, 150);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1027221
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1027221</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1027221 **/
// Set up a permanent atom
SimpleTest.waitForExplicitFinish();
var x = "x";
// Trigger some incremental gc
SpecialPowers.Cu.getJSTestingFunctions().gcslice(0);
// Kick off a worker that uses this same atom
var w = new Worker("data:text/plain,Promise.resolve('x').then(function() { postMessage(1); });");
// Maybe trigger some more incremental gc
SpecialPowers.Cu.getJSTestingFunctions().gcslice(0);
w.onmessage = function() {
ok(true, "Got here");
SimpleTest.finish();
};
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1027221">Mozilla Bug 1027221</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -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.

Просмотреть файл

@ -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
{

Просмотреть файл

@ -100,6 +100,7 @@ public:
DrawTargetCG();
virtual ~DrawTargetCG();
virtual DrawTargetType GetType() const MOZ_OVERRIDE;
virtual BackendType GetBackendType() const;
virtual TemporaryRef<SourceSurface> Snapshot();

Просмотреть файл

@ -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()
{

Просмотреть файл

@ -58,6 +58,7 @@ public:
DrawTargetCairo();
virtual ~DrawTargetCairo();
virtual DrawTargetType GetType() const MOZ_OVERRIDE;
virtual BackendType GetBackendType() const { return BackendType::CAIRO; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize();

Просмотреть файл

@ -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<SourceSurface> Snapshot();
virtual IntSize GetSize() { return mSize; }

Просмотреть файл

@ -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<SourceSurface> Snapshot();
virtual IntSize GetSize() { return mSize; }

Просмотреть файл

@ -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<SourceSurface> Snapshot() { return new SourceSurfaceDual(mA, mB); }
virtual IntSize GetSize() { return mA->GetSize(); }

Просмотреть файл

@ -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<SourceSurface> Snapshot();

Просмотреть файл

@ -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,

Просмотреть файл

@ -31,6 +31,7 @@ public:
DrawTargetSkia();
virtual ~DrawTargetSkia();
virtual DrawTargetType GetType() const MOZ_OVERRIDE;
virtual BackendType GetBackendType() const { return BackendType::SKIA; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual IntSize GetSize() { return mSize; }

Просмотреть файл

@ -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<SourceSurface> Snapshot();
virtual IntSize GetSize() { return IntSize(mRect.XMost(), mRect.YMost()); }

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <typename T>
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.

Просмотреть файл

@ -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,

Просмотреть файл

@ -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 <typename T>
void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
{
nsRefPtr<gfxImageSurface> 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, "\";");
}

Просмотреть файл

@ -55,6 +55,17 @@ public:
uint64_t mAsyncID;
};
void
RemoveTextureFromCompositableTracker::ReleaseTextureClient()
{
if (mTextureClient) {
TextureClientReleaseTask* task = new TextureClientReleaseTask(mTextureClient);
RefPtr<ISurfaceAllocator> allocator = mTextureClient->GetAllocator();
mTextureClient = nullptr;
allocator->GetMessageLoop()->PostTask(FROM_HERE, task);
}
}
/* static */ void
CompositableClient::TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId)
{

Просмотреть файл

@ -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<TextureClient> mTextureClient;
};

Просмотреть файл

@ -203,6 +203,7 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
MOZ_ASSERT(mActor);
mActor->mForwarder = aForwarder;
mActor->mTextureClient = this;
mAllocator = aForwarder;
mShared = true;
return mActor->IPCOpen();
}

Просмотреть файл

@ -364,7 +364,13 @@ protected:
mFlags |= aFlags;
}
ISurfaceAllocator* GetAllocator()
{
return mAllocator;
}
RefPtr<TextureChild> mActor;
RefPtr<ISurfaceAllocator> 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<TextureClient> 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.

Просмотреть файл

@ -8,6 +8,7 @@
#include <utility> // 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<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
if (!surf) {
return;
}
// TODO stream surface
surf->DumpAsDataURL(stderr);
gfxUtils::DumpAsDataURI(dt, stderr);
}
#endif

Просмотреть файл

@ -85,7 +85,9 @@ class ISurfaceAllocator : public AtomicRefCountedWithFinalize<ISurfaceAllocator>
{
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<mozilla::ipc::Shmem> mUsedShmems;
MessageLoop* mDefaultMessageLoop;
friend class AtomicRefCountedWithFinalize<ISurfaceAllocator>;
};

Просмотреть файл

@ -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;

Просмотреть файл

@ -261,7 +261,7 @@ ImageBridgeParent::RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessa
return true;
}
MessageLoop * ImageBridgeParent::GetMessageLoop() {
MessageLoop * ImageBridgeParent::GetMessageLoop() const {
return mMessageLoop;
}

Просмотреть файл

@ -88,7 +88,7 @@ public:
// Shutdown step 2
virtual bool RecvStop() MOZ_OVERRIDE;
MessageLoop * GetMessageLoop();
virtual MessageLoop* GetMessageLoop() const MOZ_OVERRIDE;
// ISurfaceAllocator

Просмотреть файл

@ -28,14 +28,14 @@ class nsIAtom;
class nsIWidget;
// IID for the nsITheme interface
// {b0f3efe9-0bd4-4f6b-8daa-0ec7f6006822}
// {7a3474d9-3bd6-407c-8657-c5c7633639f0}
#define NS_ITHEME_IID \
{ 0x4440b5c7, 0xd8bd, 0x4d9c, \
{ 0x9c, 0x3e, 0xa5, 0xe6, 0x26, 0x81, 0x10, 0xa0 } }
// {D930E29B-6909-44e5-AB4B-AF10D6923705}
{ 0x7a3474d9, 0x3bd6, 0x407c, \
{ 0x86, 0x57, 0xc5, 0xc7, 0x63, 0x36, 0x39, 0xf0 } }
// {0ae05515-cf7a-45a8-9e02-6556de7685b1}
#define NS_THEMERENDERER_CID \
{ 0x9020805b, 0x14a3, 0x4125, \
{ 0xa5, 0x63, 0x4a, 0x8c, 0x5d, 0xe0, 0xa9, 0xa3 } }
{ 0x0ae05515, 0xcf7a, 0x45a8, \
{ 0x9e, 0x02, 0x65, 0x56, 0xde, 0x76, 0x85, 0xb1 } }
/**
* nsITheme is a service that provides platform-specific native
@ -113,7 +113,7 @@ public:
* minimum size; if false, this size is the only valid size for the
* widget.
*/
NS_IMETHOD GetMinimumWidgetSize(nsRenderingContext* aContext,
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext,
nsIFrame* aFrame,
uint8_t aWidgetType,
nsIntSize* aResult,

Просмотреть файл

@ -20,8 +20,6 @@
#include "nsRect.h" // for nsRect, nsIntRect
#include "nsRegion.h" // for nsIntRegionRectIterator, etc
class gfxASurface;
// XXXTodo: rename FORM_TWIPS to FROM_APPUNITS
#define FROM_TWIPS(_x) ((gfxFloat)((_x)/(mP2A)))
#define FROM_TWIPS_INT(_x) (NSToIntRound((gfxFloat)((_x)/(mP2A))))
@ -65,13 +63,6 @@ static int32_t FindSafeLength(const char *aString, uint32_t aLength,
//////////////////////////////////////////////////////////////////////
//// nsRenderingContext
void
nsRenderingContext::Init(nsDeviceContext* aContext,
gfxASurface *aThebesSurface)
{
Init(aContext, new gfxContext(aThebesSurface));
}
void
nsRenderingContext::Init(nsDeviceContext* aContext,
gfxContext *aThebesContext)

Просмотреть файл

@ -22,7 +22,6 @@
#include "nsString.h" // for nsString
#include "nscore.h" // for char16_t
class gfxASurface;
class nsIntRegion;
struct nsPoint;
struct nsRect;
@ -45,7 +44,6 @@ public:
NS_INLINE_DECL_REFCOUNTING(nsRenderingContext)
void Init(nsDeviceContext* aContext, gfxASurface* aThebesSurface);
void Init(nsDeviceContext* aContext, gfxContext* aThebesContext);
void Init(nsDeviceContext* aContext, DrawTarget* aDrawTarget);

Просмотреть файл

@ -683,179 +683,6 @@ gfxASurface::BytesPerPixel(gfxImageFormat aImageFormat)
}
}
void
gfxASurface::WriteAsPNG(const char* aFile)
{
FILE *file = fopen(aFile, "wb");
if (file) {
WriteAsPNG_internal(file, true);
fclose(file);
} else {
NS_WARNING("Failed to create file!\n");
}
}
void
gfxASurface::DumpAsDataURL(FILE* aOutput)
{
WriteAsPNG_internal(aOutput, false);
}
void
gfxASurface::CopyAsDataURL()
{
WriteAsPNG_internal(nullptr, false);
}
/**
* Write to a PNG file. If aBinary is true, then it is written
* as binary, otherwise as a data URL. If no file is specified then
* data is copied to the clipboard (must not be binary!).
*/
void
gfxASurface::WriteAsPNG_internal(FILE* aFile, bool aBinary)
{
nsRefPtr<gfxImageSurface> 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<gfxContext> 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<imgIEncoder> 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<uint32_t*>(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<nsIInputStream> 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<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
if (clipboard) {
clipboard->CopyString(NS_ConvertASCIItoUTF16(string), nullptr);
}
}
return;
}
void
gfxASurface::SetOpaqueRect(const gfxRect& aRect)
{

Просмотреть файл

@ -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() {

Просмотреть файл

@ -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<gfxASurface> 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<gfxASurface> 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<gfxASurface> 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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<uint8_t> buf(static_cast<uint8_t*>(moz_malloc(bufSize)));
static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<uint8_t> buf(new (fallible) uint8_t[bufSize]);
if (!buf) {
return;
}

Просмотреть файл

@ -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<nsIURI> principalURI;
rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_SUCCEEDED(rv)) {
principalURI->GetSpec(principalURISpec);
}
nsAutoCString principalURISpec("(null)");
bool setDomain = false;
nsCOMPtr<nsIURI> domainURI;
aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI));
if (domainURI) {
setDomain = true;
if (aEntry->mPrincipal) {
nsCOMPtr<nsIURI> principalURI;
rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_SUCCEEDED(rv)) {
principalURI->GetSpec(principalURISpec);
}
nsCOMPtr<nsIURI> domainURI;
aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI));
if (domainURI) {
setDomain = true;
}
}
NS_ASSERTION(aEntry->mURI, "null URI in userfont cache entry");

Просмотреть файл

@ -294,7 +294,7 @@ public:
// entry and the corresponding "real" font entry.
struct Key {
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPrincipal> 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<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPrincipal> 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

Просмотреть файл

@ -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<DataSourceSurface> 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<imgIEncoder> 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<uint32_t*>(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<nsIInputStream> 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<char> 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<nsIClipboardHelper> 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<nsIFile> comFile = do_CreateInstance("@mozilla.org/file/local;1");
if (comFile) {
NS_ConvertUTF8toUTF16 utf16path((nsDependentCString(aFile)));
rv = comFile->InitWithPath(utf16path);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> 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<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aDT);
if (surf) {
surf->WriteAsPNG(aFile);
RefPtr<SourceSurface> 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<gfxASurface> 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<mozilla::gfx::DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(IntSize(width, height),
SurfaceFormat::B8G8R8A8);
NS_ENSURE_TRUE(dt, /*void*/);
nsRefPtr<gfxContext> 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<SourceSurface> 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<gfxASurface> 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<SourceSurface> 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<gfx::DataSourceSurface> dataSurface = aSourceSurface->GetDataSurface();
RefPtr<gfx::DrawTarget> 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<gfx::DataSourceSurface> dataSurface = aSourceSurface->GetDataSurface();
RefPtr<gfx::DrawTarget> dt
= gfxPlatform::GetPlatform()
->CreateDrawTargetForData(dataSurface->GetData(),
dataSurface->GetSize(),
dataSurface->Stride(),
aSourceSurface->GetFormat());
gfxUtils::DumpAsDataURL(dt.get());
}
/* static */ void
gfxUtils::CopyAsDataURL(gfx::SourceSurface* aSourceSurface)
{
RefPtr<gfx::DataSourceSurface> dataSurface = aSourceSurface->GetDataSurface();
RefPtr<gfx::DrawTarget> 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

Просмотреть файл

@ -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
};

Просмотреть файл

@ -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.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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'

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <windows.h>
#include <ver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4 // major, minor, release (alpha 1), build #
PRODUCTVERSION 4
FILEFLAGSMASK 0
FILEFLAGS 0 // final version
FILEOS VOS_DOS_WINDOWS16
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
BEGIN
VALUE "CompanyName", "Netscape Communications Corporation\0"
VALUE "FileDescription", "Netscape 16-bit JavaScript Debugger Module\0"
VALUE "FileVersion", "4.0\0"
VALUE "InternalName", "JSD1640\0"
VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
VALUE "LegalTrademarks", "Netscape, Mozilla\0"
VALUE "OriginalFilename","JSD1640.DLL\0"
VALUE "ProductName", "NETSCAPE\0"
VALUE "ProductVersion", "4.0\0"
END
END
END

Просмотреть файл

@ -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
/////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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<JSDStaticLock>()) ||
! (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 */

Просмотреть файл

@ -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___ */

Просмотреть файл

@ -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));
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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("<unavailable>");
}
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;
}

Просмотреть файл

@ -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 <ctype.h>
#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<char>(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);
}

Просмотреть файл

@ -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<JSPropertyDescriptor> 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);
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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<jsdIScript *>(data);
} else {
rv = new jsdScript (aCx, aScript);
NS_IF_ADDREF(rv); /* addref for the SetScriptPrivate, released in
* Invalidate() */
JSD_SetScriptPrivate (aScript, static_cast<void *>(rv));
}
NS_IF_ADDREF(rv); /* addref for return value */
return rv;
}
static void InvalidateAll();
private:
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<nsISupports> 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<jsdIErrorHook> mErrorHook;
nsCOMPtr<jsdIExecutionHook> mBreakpointHook;
nsCOMPtr<jsdIExecutionHook> mDebugHook;
nsCOMPtr<jsdIExecutionHook> mDebuggerHook;
nsCOMPtr<jsdIExecutionHook> mInterruptHook;
nsCOMPtr<jsdIScriptHook> mScriptHook;
nsCOMPtr<jsdIExecutionHook> mThrowHook;
nsCOMPtr<jsdICallHook> mTopLevelHook;
nsCOMPtr<jsdICallHook> mFunctionHook;
nsCOMPtr<jsdIActivationCallback> mActivationCallback;
// 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<jsdIContext *>(data);
} else {
rv = new jsdContext (aCx);
NS_IF_ADDREF(rv); // addref for the SetContextPrivate
JSD_SetContextPrivate (aCx, static_cast<void *>(rv));
}
NS_IF_ADDREF(rv); // addref for the return value
return rv;
}
virtual ~jsdContext() { printf ("------ ~jsdContext\n"); }
private:
jsdContext(); /* no implementation */
jsdContext(const jsdContext&); /* no implementation */
JSDContext *mCx;
};
class jsdThreadState : public jsdIThreadState
{
public:
NS_DECL_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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <stdlib.h>
#include <string.h>
#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 <stdio.h>
void
JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
{
double sqsum, mean, sigma;
uint32_t nchains, nbuckets;
uint32_t i, n, maxChain, maxChainLen;
JSHashEntry *he;
sqsum = 0;
nchains = 0;
maxChain = maxChainLen = 0;
nbuckets = NBUCKETS(ht);
for (i = 0; i < nbuckets; i++) {
he = ht->buckets[i];
if (!he)
continue;
nchains++;
for (n = 0; he; he = he->next)
n++;
sqsum += n * n;
if (n > maxChainLen) {
maxChainLen = n;
maxChain = i;
}
}
mean = JS_MeanAndStdDev(nchains, ht->nentries, sqsum, &sigma);
fprintf(fp, "\nHash table statistics:\n");
fprintf(fp, " number of lookups: %u\n", ht->nlookups);
fprintf(fp, " number of entries: %u\n", ht->nentries);
fprintf(fp, " number of grows: %u\n", ht->ngrows);
fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
/ ht->nlookups);
fprintf(fp, "mean hash chain length: %g\n", mean);
fprintf(fp, " standard deviation: %g\n", sigma);
fprintf(fp, " max hash chain length: %u\n", maxChainLen);
fprintf(fp, " max hash chain: [%u]\n", maxChain);
for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
if (dump(he, i, fp) != HT_ENUMERATE_NEXT)
break;
}
#endif /* JS_HASHMETER */
int
JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
{
int count;
count = JS_HashTableEnumerateEntries(ht, dump, fp);
#ifdef JS_HASHMETER
JS_HashTableDumpMeter(ht, dump, fp);
#endif
return count;
}
JSHashNumber
JS_HashString(const void *key)
{
JSHashNumber h;
const unsigned char *s;
h = 0;
for (s = (const unsigned char *)key; *s; s++)
h = RotateLeft(h, 4) ^ *s;
return h;
}
int
JS_CompareValues(const void *v1, const void *v2)
{
return v1 == v2;
}

Просмотреть файл

@ -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 <stddef.h>
#include <stdint.h>
#include <stdio.h>
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___ */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше