зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c.
This commit is contained in:
Коммит
f7f6976e6e
|
@ -922,11 +922,47 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
|
|||
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-arrow");
|
||||
background: transparent;
|
||||
border: none;
|
||||
transition: opacity 300ms;
|
||||
transform: scale(.7);
|
||||
opacity: 0;
|
||||
transition-property: transform, opacity;
|
||||
transition-duration: 0.15s;
|
||||
transition-timing-function: ease;
|
||||
/* The popup inherits -moz-image-region from the button, must reset it */
|
||||
-moz-image-region: auto;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[animate="open"] {
|
||||
transform: none;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_start"] {
|
||||
transform-origin: 20px top;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_end"] {
|
||||
transform-origin: calc(100% - 20px) top;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="before_start"] {
|
||||
transform-origin: 20px bottom;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="before_end"] {
|
||||
transform-origin: calc(100% - 20px) bottom;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_start"][animate="cancel"],
|
||||
#BMB_bookmarksPopup[arrowposition="before_end"][animate="cancel"] {
|
||||
transform: scale(.7) skew(30deg, 20deg);
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_end"][animate="cancel"],
|
||||
#BMB_bookmarksPopup[arrowposition="before_start"][animate="cancel"] {
|
||||
transform: scale(.7) skew(-30deg, -20deg);
|
||||
}
|
||||
|
||||
|
||||
/* Customize mode */
|
||||
#navigator-toolbox,
|
||||
#browser-bottombox,
|
||||
|
|
|
@ -879,10 +879,13 @@ function test() {
|
|||
Services.obs.addObserver(XPInstallObserver, "addon-install-failed", false);
|
||||
Services.obs.addObserver(XPInstallObserver, "addon-install-complete", false);
|
||||
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Make sure no more test parts run in case we were timed out
|
||||
TESTS = [];
|
||||
PopupNotifications.panel.removeEventListener("popupshown", check_notification, false);
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
aInstalls.forEach(function(aInstall) {
|
||||
|
|
|
@ -12,14 +12,17 @@ function test() {
|
|||
|
||||
waitForFocus(function () {
|
||||
let PN = newWin.PopupNotifications;
|
||||
PN.transitionsEnabled = false;
|
||||
try {
|
||||
let notification = PN.show(newWin.gBrowser.selectedBrowser, "some-notification", "Some message");
|
||||
ok(notification, "showed the notification");
|
||||
ok(PN.isPanelOpen, "panel is open");
|
||||
is(PN.panel.anchorNode, newWin.gBrowser.selectedTab, "notification is correctly anchored to the tab");
|
||||
PN.panel.hidePopup();
|
||||
} catch (ex) {
|
||||
ok(false, "threw exception: " + ex);
|
||||
}
|
||||
PN.transitionsEnabled = true;
|
||||
newWin.close();
|
||||
finish();
|
||||
}, newWin);
|
||||
|
|
|
@ -8,6 +8,10 @@ function test() {
|
|||
ok(PopupNotifications, "PopupNotifications object exists");
|
||||
ok(PopupNotifications.panel, "PopupNotifications panel exists");
|
||||
|
||||
// Disable transitions as they slow the test down and we want to click the
|
||||
// mouse buttons in a predictable location.
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
registerCleanupFunction(cleanUp);
|
||||
|
||||
runNextTest();
|
||||
|
@ -19,6 +23,7 @@ function cleanUp() {
|
|||
for (var eventName in gActiveListeners)
|
||||
PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName], false);
|
||||
PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL;
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
}
|
||||
|
||||
const PREF_SECURITY_DELAY_INITIAL = Services.prefs.getIntPref("security.notification_enable_delay");
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
type="arrow"
|
||||
hidden="true"
|
||||
flip="slide"
|
||||
animate="false"
|
||||
position="bottomcenter topright"
|
||||
noautofocus="true">
|
||||
<panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">
|
||||
|
|
|
@ -6,12 +6,16 @@ const isOSX = (Services.appinfo.OS === "Darwin");
|
|||
|
||||
let originalWindowWidth;
|
||||
registerCleanupFunction(function() {
|
||||
overflowPanel.removeAttribute("animate");
|
||||
window.resizeTo(originalWindowWidth, window.outerHeight);
|
||||
});
|
||||
|
||||
// Right-click on an item within the overflow panel should
|
||||
// show a context menu with options to move it.
|
||||
add_task(function() {
|
||||
|
||||
overflowPanel.setAttribute("animate", "false");
|
||||
|
||||
originalWindowWidth = window.outerWidth;
|
||||
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
||||
|
|
|
@ -526,6 +526,9 @@
|
|||
|
||||
var position = this.alignmentPosition;
|
||||
var offset = this.alignmentOffset;
|
||||
|
||||
this.setAttribute("arrowposition", position);
|
||||
|
||||
// if this panel has a "sliding" arrow, we may have previously set margins...
|
||||
arrowbox.style.removeProperty("transform");
|
||||
if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
|
||||
|
@ -578,6 +581,7 @@
|
|||
<handlers>
|
||||
<handler event="popupshowing" phase="target"><![CDATA[
|
||||
this.adjustArrowPosition();
|
||||
this.setAttribute("animate", "open");
|
||||
]]></handler>
|
||||
<handler event="popupshown" phase="target"><![CDATA[
|
||||
this.setAttribute("panelopen", "true");
|
||||
|
@ -604,11 +608,15 @@
|
|||
this.style.removeProperty("pointer-events");
|
||||
}
|
||||
]]></handler>
|
||||
<handler event="popuphiding" phase="target"><![CDATA[
|
||||
this.setAttribute("animate", "cancel");
|
||||
]]></handler>
|
||||
<handler event="popuphidden" phase="target"><![CDATA[
|
||||
this.removeAttribute("panelopen");
|
||||
if (this.getAttribute("disablepointereventsfortransition") == "true") {
|
||||
this.style.pointerEvents = 'none';
|
||||
}
|
||||
this.removeAttribute("animate");
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
|
|
@ -17,6 +17,7 @@ add_task(function testPopup() {
|
|||
|
||||
function* checkPopupContextMenu() {
|
||||
let dropmarker = document.getAnonymousElementByAttribute(bookmarksMenuButton, "anonid", "dropmarker");
|
||||
BMB_menuPopup.setAttribute("style", "transition: none;");
|
||||
let popupShownPromise = onPopupEvent(BMB_menuPopup, "shown");
|
||||
EventUtils.synthesizeMouseAtCenter(dropmarker, {});
|
||||
info("Waiting for bookmarks menu to be shown.");
|
||||
|
@ -28,6 +29,7 @@ function* checkPopupContextMenu() {
|
|||
ok(!newBookmarkItem.hasAttribute("disabled"), "New bookmark item shouldn't be disabled");
|
||||
let contextMenuHiddenPromise = onPopupEvent(contextMenu, "hidden");
|
||||
contextMenu.hidePopup();
|
||||
BMB_menuPopup.removeAttribute("style");
|
||||
info("Waiting for context menu on bookmarks menu to be hidden.");
|
||||
yield contextMenuHiddenPromise;
|
||||
let popupHiddenPromise = onPopupEvent(BMB_menuPopup, "hidden");
|
||||
|
|
|
@ -103,6 +103,7 @@ let PanelFactory = {
|
|||
let panel = doc.createElement("panel");
|
||||
panel.setAttribute("hidden", true);
|
||||
panel.setAttribute("ignorekeys", true);
|
||||
panel.setAttribute("animate", false);
|
||||
|
||||
panel.setAttribute("consumeoutsideclicks", options.get("consumeOutsideClick"));
|
||||
panel.setAttribute("noautofocus", options.get("noAutoFocus"));
|
||||
|
|
|
@ -276,6 +276,8 @@ function test() {
|
|||
return;
|
||||
}
|
||||
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
registerCleanupFunction(cleanUp);
|
||||
|
||||
ok(sitw.SignInToWebsiteUX, "SignInToWebsiteUX object exists");
|
||||
|
@ -313,6 +315,8 @@ function cleanUp() {
|
|||
info("cleanup");
|
||||
resetState();
|
||||
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
|
||||
for (let topic in gActiveObservers)
|
||||
Services.obs.removeObserver(gActiveObservers[topic], topic);
|
||||
for (let eventName in gActiveListeners)
|
||||
|
|
|
@ -23,6 +23,10 @@ let tests = [
|
|||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
// Disable the animation to prevent the mouse clicks from hitting the main
|
||||
// window during the transition instead of the buttons in the popup.
|
||||
popup.setAttribute("animate", "false");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
|
||||
|
@ -150,6 +154,7 @@ let tests = [
|
|||
is(gContentWindow.callbackResult, "target", "target callback called");
|
||||
is(gContentWindow.callbackData.target, "appMenu", "target callback was from the appMenu");
|
||||
is(gContentWindow.callbackData.type, "popupshown", "target callback was from the mousedown");
|
||||
popup.removeAttribute("animate");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4895,7 +4895,7 @@ dnl ========================================================
|
|||
dnl = GNOME component (mozgnome)
|
||||
dnl ========================================================
|
||||
|
||||
if test "$MOZ_ENABLE_GTK2"
|
||||
if test "$MOZ_ENABLE_GTK"
|
||||
then
|
||||
MOZ_ENABLE_GNOME_COMPONENT=1
|
||||
fi
|
||||
|
|
|
@ -3664,17 +3664,7 @@ nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
|
|||
JS::Value
|
||||
nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aRv)
|
||||
{
|
||||
const nsID* iid = aIID->GetID();
|
||||
nsCOMPtr<nsISupports> result;
|
||||
JS::Rooted<JS::Value> v(aCx, JSVAL_NULL);
|
||||
aRv = GetInterface(*iid, getter_AddRefs(result));
|
||||
NS_ENSURE_FALSE(aRv.Failed(), JSVAL_NULL);
|
||||
|
||||
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
|
||||
JSAutoCompartment ac(aCx, wrapper);
|
||||
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, wrapper));
|
||||
aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
|
||||
return aRv.Failed() ? JSVAL_NULL : v;
|
||||
return dom::GetInterface(aCx, this, aIID, aRv);
|
||||
}
|
||||
|
||||
nsXMLHttpRequestUpload*
|
||||
|
|
|
@ -25,8 +25,8 @@ var frame = document.getElementById("i");
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var viewer =
|
||||
SpecialPowers.wrap(frame.contentWindow
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor))
|
||||
SpecialPowers.wrap(frame.contentWindow)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
|
||||
.contentViewer
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
SpecialPowers.setBoolPref("media.webspeech.synth.enabled", true);
|
||||
|
||||
var gSpeechRegistry = SpecialPowers.Cc["@mozilla.org/synth-voice-registry;1"]
|
||||
.getService(SpecialPowers.Ci.nsISynthVoiceRegistry);
|
||||
|
||||
|
@ -170,7 +168,6 @@ function synthCleanup() {
|
|||
.getService(SpecialPowers.Ci.nsISyncMessageSender);
|
||||
mm.sendSyncMessage('test:SpeechSynthesis:ipcSynthCleanup');
|
||||
}
|
||||
SpecialPowers.clearUserPref("media.webspeech.synth.enabled");
|
||||
}
|
||||
|
||||
function synthTestQueue(aTestArgs, aEndFunc) {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Bob Marley', 'en-JM', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Amy Winehouse', 'en-GB', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Leonard Cohen', 'en-CA', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Celine Dion', 'fr-CA', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Julieta Venegas', 'es-MX', true);
|
||||
|
||||
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
|
||||
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
|
||||
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
|
||||
|
||||
// SpeechSynthesisUtterance is the only type that has a constructor
|
||||
// and writable properties
|
||||
ok(SpeechSynthesisUtterance, "SpeechSynthesisUtterance exists in global scope");
|
||||
var ssu = new SpeechSynthesisUtterance("hello world");
|
||||
is(typeof ssu, "object", "SpeechSynthesisUtterance instance is an object");
|
||||
is(ssu.text, "hello world", "SpeechSynthesisUtterance.text is correct");
|
||||
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume default is correct");
|
||||
is(ssu.rate, 1, "SpeechSynthesisUtterance.rate default is correct");
|
||||
is(ssu.pitch, 1, "SpeechSynthesisUtterance.pitch default is correct");
|
||||
ssu.lang = "he-IL";
|
||||
ssu.volume = 0.5;
|
||||
ssu.rate = 2.0;
|
||||
ssu.pitch = 1.5;
|
||||
is(ssu.lang, "he-IL", "SpeechSynthesisUtterance.lang is correct");
|
||||
is(ssu.volume, 0.5, "SpeechSynthesisUtterance.volume is correct");
|
||||
is(ssu.rate, 2.0, "SpeechSynthesisUtterance.rate is correct");
|
||||
is(ssu.pitch, 1.5, "SpeechSynthesisUtterance.pitch is correct");
|
||||
|
||||
// Test for singleton instance hanging off of window.
|
||||
ok(speechSynthesis, "speechSynthesis exists in global scope");
|
||||
is(typeof speechSynthesis, "object", "speechSynthesis instance is an object");
|
||||
is(typeof speechSynthesis.speak, "function", "speechSynthesis.speak is a function");
|
||||
is(typeof speechSynthesis.cancel, "function", "speechSynthesis.cancel is a function");
|
||||
is(typeof speechSynthesis.pause, "function", "speechSynthesis.pause is a function");
|
||||
is(typeof speechSynthesis.resume, "function", "speechSynthesis.resume is a function");
|
||||
is(typeof speechSynthesis.getVoices, "function", "speechSynthesis.getVoices is a function");
|
||||
|
||||
is(typeof speechSynthesis.pending, "boolean", "speechSynthesis.pending is a boolean");
|
||||
is(typeof speechSynthesis.speaking, "boolean", "speechSynthesis.speaking is a boolean");
|
||||
is(typeof speechSynthesis.paused, "boolean", "speechSynthesis.paused is a boolean");
|
||||
|
||||
var voices1 = speechSynthesis.getVoices();
|
||||
var voices2 = speechSynthesis.getVoices();
|
||||
|
||||
ok(voices1.length == voices2.length, "Voice count matches");
|
||||
|
||||
for (var i in voices1) {
|
||||
ok(voices1[i] == voices2[i], "Voice instance matches");
|
||||
}
|
||||
|
||||
synthCleanup();
|
||||
|
||||
SimpleTest.finish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
var englishJamaican = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Bob Marley', 'en-JM', true);
|
||||
var englishBritish = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Amy Winehouse', 'en-GB', true);
|
||||
var englishCanadian = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Leonard Cohen', 'en-CA', true);
|
||||
var frenchCanadian = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Celine Dion', 'fr-CA', true);
|
||||
var spanishMexican = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Julieta Venegas', 'es-MX', true);
|
||||
|
||||
synthSetDefault(englishBritish, true);
|
||||
|
||||
synthTestQueue(
|
||||
[[{text: "Hello, world."},
|
||||
{ uri: englishBritish }],
|
||||
[{text: "Bonjour tout le monde .", lang: "fr", rate: 0.5, pitch: 0.75},
|
||||
{ uri: frenchCanadian, rate: 0.5, pitch: 0.75}],
|
||||
[{text: "How are you doing?", lang: "en-GB"},
|
||||
{ rate: 1, pitch: 1, uri: englishBritish}],
|
||||
[{text: "¡hasta mañana", lang: "es-ES"},
|
||||
{ uri: spanishMexican }]],
|
||||
function () {
|
||||
synthSetDefault(englishJamaican, true);
|
||||
var test_data = [[{text: "I shot the sheriff."},
|
||||
{ uri: englishJamaican }]];
|
||||
var voices = speechSynthesis.getVoices();
|
||||
for (var i in voices) {
|
||||
test_data.push([{text: "Hello world", voice: voices[i]},
|
||||
{uri: voices[i].voiceURI}]);
|
||||
}
|
||||
|
||||
synthTestQueue(test_data,
|
||||
function () {
|
||||
synthCleanup();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
synthAddVoice('TestSpeechServiceWithAudio', 'Male 1', 'en-GB', true);
|
||||
|
||||
var gotStartEvent = false;
|
||||
var gotBoundaryEvent = false;
|
||||
var utterance = new SpeechSynthesisUtterance("Hello, world!");
|
||||
utterance.addEventListener('start', function(e) {
|
||||
ok(speechSynthesis.speaking, "speechSynthesis is speaking.");
|
||||
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
|
||||
gotStartEvent = true;
|
||||
});
|
||||
|
||||
utterance.addEventListener('end', function(e) {
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
|
||||
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
|
||||
ok(gotStartEvent, "Got 'start' event.");
|
||||
info('end ' + e.elapsedTime);
|
||||
synthCleanup();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
|
||||
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,10 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s
|
||||
support-files = common.js
|
||||
support-files =
|
||||
common.js
|
||||
file_setup.html
|
||||
file_speech_queue.html
|
||||
file_speech_simple.html
|
||||
|
||||
[test_setup.html]
|
||||
[test_speech_queue.html]
|
||||
|
|
|
@ -7,12 +7,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
|||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
@ -21,57 +21,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
|||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Bob Marley', 'en-JM', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Amy Winehouse', 'en-GB', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Leonard Cohen', 'en-CA', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Celine Dion', 'fr-CA', true);
|
||||
synthAddVoice('TestSpeechServiceNoAudio', 'Julieta Venegas', 'es-MX', true);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
|
||||
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
|
||||
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
|
||||
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
|
||||
function() { document.getElementById("testFrame").src = "file_setup.html"; });
|
||||
|
||||
// SpeechSynthesisUtterance is the only type that has a constructor
|
||||
// and writable properties
|
||||
ok(SpeechSynthesisUtterance, "SpeechSynthesisUtterance exists in global scope");
|
||||
var ssu = new SpeechSynthesisUtterance("hello world");
|
||||
is(typeof ssu, "object", "SpeechSynthesisUtterance instance is an object");
|
||||
is(ssu.text, "hello world", "SpeechSynthesisUtterance.text is correct");
|
||||
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume default is correct");
|
||||
is(ssu.rate, 1, "SpeechSynthesisUtterance.rate default is correct");
|
||||
is(ssu.pitch, 1, "SpeechSynthesisUtterance.pitch default is correct");
|
||||
ssu.lang = "he-IL";
|
||||
ssu.volume = 0.5;
|
||||
ssu.rate = 2.0;
|
||||
ssu.pitch = 1.5;
|
||||
is(ssu.lang, "he-IL", "SpeechSynthesisUtterance.lang is correct");
|
||||
is(ssu.volume, 0.5, "SpeechSynthesisUtterance.volume is correct");
|
||||
is(ssu.rate, 2.0, "SpeechSynthesisUtterance.rate is correct");
|
||||
is(ssu.pitch, 1.5, "SpeechSynthesisUtterance.pitch is correct");
|
||||
|
||||
// Test for singleton instance hanging off of window.
|
||||
ok(speechSynthesis, "speechSynthesis exists in global scope");
|
||||
is(typeof speechSynthesis, "object", "speechSynthesis instance is an object");
|
||||
is(typeof speechSynthesis.speak, "function", "speechSynthesis.speak is a function");
|
||||
is(typeof speechSynthesis.cancel, "function", "speechSynthesis.cancel is a function");
|
||||
is(typeof speechSynthesis.pause, "function", "speechSynthesis.pause is a function");
|
||||
is(typeof speechSynthesis.resume, "function", "speechSynthesis.resume is a function");
|
||||
is(typeof speechSynthesis.getVoices, "function", "speechSynthesis.getVoices is a function");
|
||||
|
||||
is(typeof speechSynthesis.pending, "boolean", "speechSynthesis.pending is a boolean");
|
||||
is(typeof speechSynthesis.speaking, "boolean", "speechSynthesis.speaking is a boolean");
|
||||
is(typeof speechSynthesis.paused, "boolean", "speechSynthesis.paused is a boolean");
|
||||
|
||||
var voices1 = speechSynthesis.getVoices();
|
||||
var voices2 = speechSynthesis.getVoices();
|
||||
|
||||
ok(voices1.length == voices2.length, "Voice count matches");
|
||||
|
||||
for (var i in voices1) {
|
||||
ok(voices1[i] == voices2[i], "Voice instance matches");
|
||||
}
|
||||
|
||||
synthCleanup();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -13,6 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
|||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
@ -23,46 +24,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var englishJamaican = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Bob Marley', 'en-JM', true);
|
||||
var englishBritish = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Amy Winehouse', 'en-GB', true);
|
||||
var englishCanadian = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Leonard Cohen', 'en-CA', true);
|
||||
var frenchCanadian = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Celine Dion', 'fr-CA', true);
|
||||
var spanishMexican = synthAddVoice('TestSpeechServiceNoAudio',
|
||||
'Julieta Venegas', 'es-MX', true);
|
||||
|
||||
synthSetDefault(englishBritish, true);
|
||||
|
||||
synthTestQueue(
|
||||
[[{text: "Hello, world."},
|
||||
{ uri: englishBritish }],
|
||||
[{text: "Bonjour tout le monde .", lang: "fr", rate: 0.5, pitch: 0.75},
|
||||
{ uri: frenchCanadian, rate: 0.5, pitch: 0.75}],
|
||||
[{text: "How are you doing?", lang: "en-GB"},
|
||||
{ rate: 1, pitch: 1, uri: englishBritish}],
|
||||
[{text: "¡hasta mañana", lang: "es-ES"},
|
||||
{ uri: spanishMexican }]],
|
||||
function () {
|
||||
synthSetDefault(englishJamaican, true);
|
||||
var test_data = [[{text: "I shot the sheriff."},
|
||||
{ uri: englishJamaican }]];
|
||||
var voices = speechSynthesis.getVoices();
|
||||
for (var i in voices) {
|
||||
test_data.push([{text: "Hello world", voice: voices[i]},
|
||||
{uri: voices[i].voiceURI}]);
|
||||
}
|
||||
|
||||
synthTestQueue(test_data,
|
||||
function () {
|
||||
synthCleanup();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
|
||||
function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -13,6 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
|||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
@ -23,29 +24,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
synthAddVoice('TestSpeechServiceWithAudio', 'Male 1', 'en-GB', true);
|
||||
|
||||
var gotStartEvent = false;
|
||||
var gotBoundaryEvent = false;
|
||||
var utterance = new SpeechSynthesisUtterance("Hello, world!");
|
||||
utterance.addEventListener('start', function(e) {
|
||||
ok(speechSynthesis.speaking, "speechSynthesis is speaking.");
|
||||
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
|
||||
gotStartEvent = true;
|
||||
});
|
||||
|
||||
utterance.addEventListener('end', function(e) {
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
|
||||
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
|
||||
ok(gotStartEvent, "Got 'start' event.");
|
||||
info('end ' + e.elapsedTime);
|
||||
synthCleanup();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
|
||||
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
|
||||
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
|
||||
function() { document.getElementById("testFrame").src = "file_speech_simple.html"; });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -297,7 +297,7 @@ nsXULPopupListener::ClosePopup()
|
|||
// fire events during destruction.
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm)
|
||||
pm->HidePopup(mPopupContent, false, true, true);
|
||||
pm->HidePopup(mPopupContent, false, true, true, false);
|
||||
mPopupContent = nullptr; // release the popup
|
||||
}
|
||||
} // ClosePopup
|
||||
|
|
|
@ -142,7 +142,8 @@ this.OperatorAppsRegistry = {
|
|||
let orgDir = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsIFile);
|
||||
orgDir.initWithPath(aOrg);
|
||||
if (!orgDir.isDirectory()) {
|
||||
if (!orgDir.exists() || !orgDir.isDirectory()) {
|
||||
debug(aOrg + " does not exist or is not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -168,7 +169,7 @@ this.OperatorAppsRegistry = {
|
|||
entry.copyTo(dstDir, entry.leafName);
|
||||
} else {
|
||||
yield this._copyDirectory(entry.path,
|
||||
Path.join(aDst, entry.name));
|
||||
Path.join(aDst, entry.leafName));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -182,7 +182,6 @@ static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
|||
#define WINDOW_SCRIPTABLE_FLAGS \
|
||||
(nsIXPCScriptable::WANT_PRECREATE | \
|
||||
nsIXPCScriptable::WANT_POSTCREATE | \
|
||||
nsIXPCScriptable::WANT_FINALIZE | \
|
||||
nsIXPCScriptable::WANT_ENUMERATE | \
|
||||
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
|
||||
nsIXPCScriptable::IS_GLOBAL_OBJECT | \
|
||||
|
@ -1855,7 +1854,7 @@ nsWindowSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
|
|||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
|
||||
|
||||
NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == nullptr,
|
||||
NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == obj,
|
||||
"Multiple wrappers created for global object!");
|
||||
#endif
|
||||
|
||||
|
@ -3399,26 +3398,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
|
||||
JSObject *obj)
|
||||
{
|
||||
// Since this call is virtual, the exact rooting hazard static analysis is
|
||||
// not able to determine that it happens during finalization and should be
|
||||
// ignored. Moreover, the analysis cannot discover and validate the
|
||||
// potential targets of the virtual call to OnFinalize below because of the
|
||||
// indirection through nsCOMMPtr. Thus, we annotate the analysis here so
|
||||
// that it does not report OnFinalize as GCing with |obj| on stack.
|
||||
JS::AutoAssertNoGC nogc;
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
|
||||
|
||||
sgo->OnFinalize(obj);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
|
||||
JSObject * obj, JSObject * *_retval)
|
||||
|
|
|
@ -270,8 +270,6 @@ public:
|
|||
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, uint32_t flags,
|
||||
JSObject **objp, bool *_retval) MOZ_OVERRIDE;
|
||||
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
|
||||
JSObject *obj) MOZ_OVERRIDE;
|
||||
NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
|
||||
JSObject * obj, JSObject * *_retval) MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -1371,7 +1371,6 @@ nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
|
|||
if (aWindow->mCachedXBLPrototypeHandlers &&
|
||||
aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
|
||||
aWindow->mCachedXBLPrototypeHandlers->Clear();
|
||||
mozilla::DropJSObjects(aWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1617,17 +1616,11 @@ nsGlobalWindow::FreeInnerObjects()
|
|||
// nsGlobalWindow::nsISupports
|
||||
//*****************************************************************************
|
||||
|
||||
#define OUTER_WINDOW_ONLY \
|
||||
if (IsOuterWindow()) {
|
||||
|
||||
#define END_OUTER_WINDOW_ONLY \
|
||||
foundInterface = 0; \
|
||||
} else
|
||||
|
||||
DOMCI_DATA(Window, nsGlobalWindow)
|
||||
|
||||
// QueryInterface implementation for nsGlobalWindow
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
// Make sure this matches the cast in nsGlobalWindow::FromWrapper()
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
|
||||
|
@ -1660,9 +1653,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
|
|||
NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
|
||||
OUTER_WINDOW_ONLY
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
END_OUTER_WINDOW_ONLY
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
|
@ -1722,6 +1712,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
|
||||
|
@ -1769,6 +1760,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
|
||||
|
@ -1779,6 +1771,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
|
||||
|
@ -1828,6 +1821,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -1857,6 +1851,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
|
|||
TraceData data = { aCallbacks, aClosure };
|
||||
tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
bool
|
||||
|
@ -1902,12 +1897,12 @@ nsGlobalWindow::EnsureScriptEnvironment()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (outer->mJSObject) {
|
||||
if (outer->GetWrapperPreserveColor()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
|
||||
"mJSObject is null, but we have an inner window?");
|
||||
"No cached wrapper, but we have an inner window?");
|
||||
|
||||
// If this window is a [i]frame, don't bother GC'ing when the frame's context
|
||||
// is destroyed since a GC will happen when the frameset or host document is
|
||||
|
@ -1942,9 +1937,40 @@ nsGlobalWindow::GetGlobalJSObject()
|
|||
void
|
||||
nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
|
||||
{
|
||||
if (mJSObject) {
|
||||
JS_CallTenuredObjectTracer(aTrc, &mJSObject, "active window global");
|
||||
TraceWrapper(aTrc, "active window global");
|
||||
}
|
||||
|
||||
/* static */
|
||||
JSObject*
|
||||
nsGlobalWindow::OuterObject(JSContext* aCx, JS::HandleObject aObj)
|
||||
{
|
||||
nsGlobalWindow *origWin;
|
||||
UNWRAP_OBJECT(Window, aObj, origWin);
|
||||
nsGlobalWindow *win = origWin->GetOuterWindowInternal();
|
||||
|
||||
if (!win) {
|
||||
// If we no longer have an outer window. No code should ever be
|
||||
// running on a window w/o an outer, which means this hook should
|
||||
// never be called when we have no outer. But just in case, return
|
||||
// null to prevent leaking an inner window to code in a different
|
||||
// window.
|
||||
NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> winObj(aCx, win->FastGetGlobalJSObject());
|
||||
MOZ_ASSERT(winObj);
|
||||
|
||||
// Note that while |wrapper| is same-compartment with cx, the outer window
|
||||
// might not be. If we're running script in an inactive scope and evalute
|
||||
// |this|, the outer window is actually a cross-compartment wrapper. So we
|
||||
// need to wrap here.
|
||||
if (!JS_WrapObject(aCx, &winObj)) {
|
||||
NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return winObj;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2127,7 +2153,7 @@ WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
|
|||
aWindow->SuspendTimeouts();
|
||||
|
||||
// When a global goes into the bfcache, we disable script.
|
||||
xpc::Scriptability::Get(aWindow->mJSObject).SetDocShellAllowsScript(false);
|
||||
xpc::Scriptability::Get(aWindow->GetWrapperPreserveColor()).SetDocShellAllowsScript(false);
|
||||
}
|
||||
|
||||
WindowStateHolder::~WindowStateHolder()
|
||||
|
@ -2165,7 +2191,6 @@ CreateNativeGlobalForInner(JSContext* aCx,
|
|||
nsGlobalWindow* aNewInner,
|
||||
nsIURI* aURI,
|
||||
nsIPrincipal* aPrincipal,
|
||||
JS::TenuredHeap<JSObject*>& aNativeGlobal,
|
||||
nsIXPConnectJSObjectHolder** aHolder)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
|
@ -2193,20 +2218,15 @@ CreateNativeGlobalForInner(JSContext* aCx,
|
|||
uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
|
||||
flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
|
||||
|
||||
nsRefPtr<nsIXPConnectJSObjectHolder> jsholder;
|
||||
nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
|
||||
aCx, ToSupports(aNewInner),
|
||||
aPrincipal, flags, options, getter_AddRefs(jsholder));
|
||||
aPrincipal, flags, options, aHolder);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_ASSERT(jsholder);
|
||||
aNativeGlobal = jsholder->GetJSObject();
|
||||
jsholder.forget(aHolder);
|
||||
|
||||
// Set the location information for the new global, so that tools like
|
||||
// about:memory may use that information
|
||||
MOZ_ASSERT(aNativeGlobal.getPtr());
|
||||
xpc::SetLocationForGlobal(aNativeGlobal, aURI);
|
||||
MOZ_ASSERT(aNewInner->GetWrapperPreserveColor());
|
||||
xpc::SetLocationForGlobal(aNewInner->GetWrapperPreserveColor(), aURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2336,22 +2356,23 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
JS::Rooted<JSObject*> newInnerGlobal(cx);
|
||||
if (reUseInnerWindow) {
|
||||
// We're reusing the current inner window.
|
||||
NS_ASSERTION(!currentInner->IsFrozen(),
|
||||
"We should never be reusing a shared inner window");
|
||||
newInnerWindow = currentInner;
|
||||
newInnerGlobal = currentInner->GetWrapperPreserveColor();
|
||||
|
||||
if (aDocument != oldDoc) {
|
||||
JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
|
||||
JS::ExposeObjectToActiveJS(obj);
|
||||
JS::ExposeObjectToActiveJS(newInnerGlobal);
|
||||
}
|
||||
|
||||
// We're reusing the inner window, but this still counts as a navigation,
|
||||
// so all expandos and such defined on the outer window should go away. Force
|
||||
// all Xray wrappers to be recomputed.
|
||||
JS::ExposeObjectToActiveJS(mJSObject);
|
||||
JS::Rooted<JSObject*> rootedObject(cx, mJSObject);
|
||||
JS::Rooted<JSObject*> rootedObject(cx, GetWrapperPreserveColor());
|
||||
JS::ExposeObjectToActiveJS(rootedObject);
|
||||
if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2361,7 +2382,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
// match the new document.
|
||||
// NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
|
||||
// because we haven't yet set its mDoc to aDocument.
|
||||
JSCompartment *compartment = js::GetObjectCompartment(currentInner->mJSObject);
|
||||
JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
|
||||
#ifdef DEBUG
|
||||
bool sameOrigin = false;
|
||||
nsIPrincipal *existing =
|
||||
|
@ -2374,18 +2395,17 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
} else {
|
||||
if (aState) {
|
||||
newInnerWindow = wsh->GetInnerWindow();
|
||||
newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
|
||||
mInnerWindowHolder = wsh->GetInnerWindowHolder();
|
||||
|
||||
NS_ASSERTION(newInnerWindow, "Got a state without inner window");
|
||||
} else if (thisChrome) {
|
||||
newInnerWindow = new nsGlobalChromeWindow(this);
|
||||
} else if (mIsModalContentWindow) {
|
||||
newInnerWindow = new nsGlobalModalWindow(this);
|
||||
} else {
|
||||
newInnerWindow = new nsGlobalWindow(this);
|
||||
}
|
||||
if (thisChrome) {
|
||||
newInnerWindow = new nsGlobalChromeWindow(this);
|
||||
} else if (mIsModalContentWindow) {
|
||||
newInnerWindow = new nsGlobalModalWindow(this);
|
||||
} else {
|
||||
newInnerWindow = new nsGlobalWindow(this);
|
||||
}
|
||||
|
||||
if (!aState) {
|
||||
// Freeze the outer window and null out the inner window so
|
||||
// that initializing classes on the new inner doesn't end up
|
||||
// reaching into the old inner window for classes etc.
|
||||
|
@ -2405,10 +2425,11 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
rv = CreateNativeGlobalForInner(cx, newInnerWindow,
|
||||
aDocument->GetDocumentURI(),
|
||||
aDocument->NodePrincipal(),
|
||||
newInnerWindow->mJSObject,
|
||||
getter_AddRefs(mInnerWindowHolder));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerWindow->mJSObject && mInnerWindowHolder,
|
||||
"Failed to get script global and holder");
|
||||
newInnerGlobal = mInnerWindowHolder->GetJSObject();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
|
||||
newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
|
||||
"Failed to get script global");
|
||||
|
||||
mCreatingInnerWindow = false;
|
||||
createdInnerWindow = true;
|
||||
|
@ -2417,7 +2438,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (currentInner && currentInner->mJSObject) {
|
||||
if (currentInner && currentInner->GetWrapperPreserveColor()) {
|
||||
if (oldDoc == aDocument) {
|
||||
// Move the navigator from the old inner window to the new one since
|
||||
// this is a document.write. This is safe from a same-origin point of
|
||||
|
@ -2449,32 +2470,32 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
|
||||
mInnerWindow = newInnerWindow;
|
||||
|
||||
if (!mJSObject) {
|
||||
JS::Rooted<JSObject*> global(cx, newInnerWindow->FastGetGlobalJSObject());
|
||||
JS::Rooted<JSObject*> outer(cx, NewOuterWindowProxy(cx, global, thisChrome));
|
||||
if (!GetWrapperPreserveColor()) {
|
||||
JS::Rooted<JSObject*> outer(cx,
|
||||
NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
|
||||
NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
|
||||
|
||||
js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
|
||||
js::SetProxyExtra(outer, 1, JS::ObjectValue(*newInnerGlobal));
|
||||
|
||||
// Inform the nsJSContext, which is the canonical holder of the outer.
|
||||
mContext->SetWindowProxy(outer);
|
||||
mContext->DidInitializeContext();
|
||||
|
||||
mJSObject = mContext->GetWindowProxy();
|
||||
SetWrapper(mJSObject);
|
||||
SetWrapper(mContext->GetWindowProxy());
|
||||
} else {
|
||||
JS::ExposeObjectToActiveJS(newInnerWindow->mJSObject);
|
||||
JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject);
|
||||
JS::ExposeObjectToActiveJS(newInnerGlobal);
|
||||
JS::Rooted<JSObject*> outerObject(cx,
|
||||
NewOuterWindowProxy(cx, global, thisChrome));
|
||||
NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
|
||||
if (!outerObject) {
|
||||
NS_ERROR("out of memory");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
js::SetProxyExtra(mJSObject, 0, js::PrivateValue(nullptr));
|
||||
JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
|
||||
|
||||
js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, mJSObject);
|
||||
outerObject = xpc::TransplantObject(cx, obj, outerObject);
|
||||
if (!outerObject) {
|
||||
NS_ERROR("unable to transplant wrappers, probably OOM");
|
||||
|
@ -2483,41 +2504,38 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
|
||||
js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this)));
|
||||
|
||||
mJSObject = outerObject;
|
||||
SetWrapper(mJSObject);
|
||||
SetWrapper(outerObject);
|
||||
|
||||
{
|
||||
JSAutoCompartment ac(cx, mJSObject);
|
||||
JSAutoCompartment ac(cx, outerObject);
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, mJSObject);
|
||||
JS::Rooted<JSObject*> newParent(cx, newInnerWindow->mJSObject);
|
||||
JS_SetParent(cx, obj, newParent);
|
||||
JS_SetParent(cx, outerObject, newInnerGlobal);
|
||||
|
||||
// Inform the nsJSContext, which is the canonical holder of the outer.
|
||||
mContext->SetWindowProxy(obj);
|
||||
mContext->SetWindowProxy(outerObject);
|
||||
|
||||
NS_ASSERTION(!JS_IsExceptionPending(cx),
|
||||
"We might overwrite a pending exception!");
|
||||
XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj);
|
||||
XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject);
|
||||
if (scope->mWaiverWrapperMap) {
|
||||
scope->mWaiverWrapperMap->Reparent(cx, newParent);
|
||||
scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enter the new global's compartment.
|
||||
JSAutoCompartment ac(cx, mJSObject);
|
||||
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
|
||||
|
||||
// Set scriptability based on the state of the docshell.
|
||||
bool allow = GetDocShell()->GetCanExecuteScripts();
|
||||
xpc::Scriptability::Get(mJSObject).SetDocShellAllowsScript(allow);
|
||||
xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
|
||||
|
||||
// If we created a new inner window above, we need to do the last little bit
|
||||
// of initialization now that the dust has settled.
|
||||
if (createdInnerWindow) {
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject,
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
|
||||
|
@ -2526,8 +2544,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
}
|
||||
|
||||
if (!aState) {
|
||||
if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window",
|
||||
OBJECT_TO_JSVAL(mJSObject),
|
||||
if (!JS_DefineProperty(cx, newInnerGlobal, "window",
|
||||
OBJECT_TO_JSVAL(GetWrapperPreserveColor()),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
|
||||
NS_ERROR("can't create the 'window' property");
|
||||
|
@ -2536,7 +2554,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
}
|
||||
}
|
||||
|
||||
JSAutoCompartment ac(cx, mJSObject);
|
||||
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
|
||||
|
||||
if (!aState && !reUseInnerWindow) {
|
||||
// Loading a new page and creating a new inner window, *not*
|
||||
|
@ -2544,17 +2562,12 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
|
||||
// Now that both the the inner and outer windows are initialized
|
||||
// let the script context do its magic to hook them together.
|
||||
MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
|
||||
#ifdef DEBUG
|
||||
JS::Rooted<JSObject*> newInnerJSObject(cx,
|
||||
newInnerWindow->FastGetGlobalJSObject());
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(mContext->GetWindowProxy() == mJSObject);
|
||||
#ifdef DEBUG
|
||||
JS::Rooted<JSObject*> rootedJSObject(cx, mJSObject);
|
||||
JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
|
||||
JS::Rooted<JSObject*> proto1(cx), proto2(cx);
|
||||
JS_GetPrototype(cx, rootedJSObject, &proto1);
|
||||
JS_GetPrototype(cx, newInnerJSObject, &proto2);
|
||||
JS_GetPrototype(cx, newInnerGlobal, &proto2);
|
||||
NS_ASSERTION(proto1 == proto2,
|
||||
"outer and inner globals should have the same prototype");
|
||||
#endif
|
||||
|
@ -2583,14 +2596,14 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
// make sure the cached document property gets updated.
|
||||
|
||||
// XXXmarkh - tell other languages about this?
|
||||
JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
|
||||
JS::Rooted<JSObject*> obj(cx, currentInner->GetWrapperPreserveColor());
|
||||
::JS_DeleteProperty(cx, obj, "document");
|
||||
}
|
||||
} else {
|
||||
newInnerWindow->InnerSetNewDocument(aDocument);
|
||||
|
||||
// Initialize DOM classes etc on the inner window.
|
||||
JS::Rooted<JSObject*> obj(cx, newInnerWindow->mJSObject);
|
||||
JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
|
||||
rv = mContext->InitClasses(obj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
@ -2600,7 +2613,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
// calling Block() and throwing away the key.
|
||||
nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
|
||||
if (jarChannel && jarChannel->GetIsUnsafe()) {
|
||||
xpc::Scriptability::Get(newInnerWindow->mJSObject).Block();
|
||||
xpc::Scriptability::Get(newInnerGlobal).Block();
|
||||
}
|
||||
|
||||
if (mArguments) {
|
||||
|
@ -2619,7 +2632,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
// We wait to fire the debugger hook until the window is all set up and hooked
|
||||
// up with the outer. See bug 969156.
|
||||
if (createdInnerWindow) {
|
||||
JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject);
|
||||
JS::Rooted<JSObject*> global(cx, newInnerWindow->GetWrapper());
|
||||
JS_FireOnNewGlobalObject(cx, global);
|
||||
}
|
||||
|
||||
|
@ -2788,8 +2801,7 @@ nsGlobalWindow::DetachFromDocShell()
|
|||
// DetachFromDocShell means the window is being torn down. Drop our
|
||||
// reference to the script context, allowing it to be deleted
|
||||
// later. Meanwhile, keep our weak reference to the script object
|
||||
// (mJSObject) so that it can be retrieved later (until it is
|
||||
// finalized by the JS GC).
|
||||
// so that it can be retrieved later (until it is finalized by the JS GC).
|
||||
|
||||
NS_ASSERTION(mTimeouts.isEmpty(), "Uh, outer window holds timeouts!");
|
||||
|
||||
|
@ -3212,20 +3224,12 @@ nsGlobalWindow::DispatchDOMEvent(WidgetEvent* aEvent,
|
|||
aEventStatus);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::OnFinalize(JSObject* aObject)
|
||||
{
|
||||
if (aObject == mJSObject) {
|
||||
mJSObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
|
||||
{
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
if (aObject == mJSObject) {
|
||||
mJSObject.setToCrashOnTouch();
|
||||
if (aObject == GetWrapperPreserveColor()) {
|
||||
PoisonWrapper();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3273,7 +3277,7 @@ nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
|
|||
AutoPushJSContext cx(ctx->GetNativeContext());
|
||||
NS_ENSURE_TRUE(cx, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, mJSObject);
|
||||
JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
|
||||
return GetContextInternal()->SetProperty(obj, "arguments", aArguments);
|
||||
}
|
||||
|
||||
|
@ -4389,10 +4393,10 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
|
|||
{
|
||||
// Check if we were called from a privileged chrome script. If not, and if
|
||||
// aOpener is not null, just define aOpener on our inner window's JS object,
|
||||
// wapped into the current compartment so that for Xrays we define on the Xray
|
||||
// expando object, but don't set it on the outer window, so that it'll get
|
||||
// reset on navigation. This is just like replaceable properties, but we're
|
||||
// not quite readonly.
|
||||
// wrapped into the current compartment so that for Xrays we define on the
|
||||
// Xray expando object, but don't set it on the outer window, so that it'll
|
||||
// get reset on navigation. This is just like replaceable properties, but
|
||||
// we're not quite readonly.
|
||||
if (aOpener && !nsContentUtils::IsCallerChrome()) {
|
||||
// JS_WrapObject will outerize, so we don't care if aOpener is an inner.
|
||||
nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOpener);
|
||||
|
@ -4413,8 +4417,8 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
|
|||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> thisObj(cx, mJSObject);
|
||||
if (!mJSObject) {
|
||||
JS::Rooted<JSObject*> thisObj(cx, GetWrapperPreserveColor());
|
||||
if (!thisObj) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
@ -5098,8 +5102,8 @@ nsGlobalWindow::RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHol
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (mJSObject) {
|
||||
js::NotifyAnimationActivity(mJSObject);
|
||||
if (GetWrapperPreserveColor()) {
|
||||
js::NotifyAnimationActivity(GetWrapperPreserveColor());
|
||||
}
|
||||
|
||||
int32_t handle;
|
||||
|
@ -5660,7 +5664,7 @@ nsGlobalWindow::DispatchResizeEvent(const nsIntSize& aSize)
|
|||
}
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoCompartment ac(cx, mJSObject);
|
||||
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
|
||||
DOMWindowResizeEventDetail detail;
|
||||
detail.mWidth = aSize.width;
|
||||
detail.mHeight = aSize.height;
|
||||
|
@ -5697,7 +5701,7 @@ nsGlobalWindow::RefreshCompartmentPrincipal()
|
|||
{
|
||||
FORWARD_TO_INNER(RefreshCompartmentPrincipal, (), /* void */ );
|
||||
|
||||
JS_SetCompartmentPrincipals(js::GetObjectCompartment(mJSObject),
|
||||
JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
|
||||
nsJSPrincipals::get(mDoc->NodePrincipal()));
|
||||
}
|
||||
|
||||
|
@ -8655,10 +8659,7 @@ nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
|
|||
{
|
||||
if (!mCachedXBLPrototypeHandlers) {
|
||||
mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>();
|
||||
}
|
||||
|
||||
if (!mCachedXBLPrototypeHandlers->Count()) {
|
||||
mozilla::HoldJSObjects(this);
|
||||
PreserveWrapper(ToSupports(this));
|
||||
}
|
||||
|
||||
mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
|
||||
|
@ -10407,6 +10408,12 @@ nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
|
|||
return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
nsGlobalWindow::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aError)
|
||||
{
|
||||
return dom::GetInterface(aCx, this, aIID, aError);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::FireOfflineStatusEvent()
|
||||
{
|
||||
|
@ -12540,7 +12547,7 @@ nsGlobalWindow::SaveWindowState()
|
|||
{
|
||||
NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
|
||||
|
||||
if (!mContext || !mJSObject) {
|
||||
if (!mContext || !GetWrapperPreserveColor()) {
|
||||
// The window may be getting torn down; don't bother saving state.
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -12570,7 +12577,7 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState)
|
|||
{
|
||||
NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
|
||||
|
||||
if (!mContext || !mJSObject) {
|
||||
if (!mContext || !GetWrapperPreserveColor()) {
|
||||
// The window may be getting torn down; don't bother restoring state.
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -13421,13 +13428,9 @@ nsGlobalWindow::GetMessageManager(ErrorResult& aError)
|
|||
// nsGlobalModalWindow implementation
|
||||
|
||||
// QueryInterface implementation for nsGlobalModalWindow
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(nsGlobalModalWindow,
|
||||
nsGlobalWindow,
|
||||
mReturnValue)
|
||||
|
||||
DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
|
||||
NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
|
||||
|
@ -13436,6 +13439,25 @@ NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
|
|||
NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
|
||||
|
||||
|
||||
JS::Value
|
||||
nsGlobalWindow::GetDialogArguments(JSContext* aCx, ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(GetDialogArguments, (aCx, aError), aError,
|
||||
JS::UndefinedValue());
|
||||
|
||||
MOZ_ASSERT(IsModalContentWindow(),
|
||||
"This should only be called on modal windows!");
|
||||
|
||||
// This does an internal origin check, and returns undefined if the subject
|
||||
// does not subsumes the origin of the arguments.
|
||||
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
|
||||
JSAutoCompartment ac(aCx, wrapper);
|
||||
JS::Rooted<JS::Value> args(aCx);
|
||||
mDialogArguments->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
|
||||
&args, aError);
|
||||
return args;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
|
||||
{
|
||||
|
@ -13447,6 +13469,25 @@ nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
|
|||
return mDialogArguments->Get(nsContentUtils::GetSubjectPrincipal(), aArguments);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
nsGlobalWindow::GetReturnValue(JSContext* aCx, ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aCx, aError), aError,
|
||||
JS::UndefinedValue());
|
||||
|
||||
MOZ_ASSERT(IsModalContentWindow(),
|
||||
"This should only be called on modal windows!");
|
||||
|
||||
JS::Rooted<JS::Value> returnValue(aCx);
|
||||
if (mReturnValue) {
|
||||
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
|
||||
JSAutoCompartment ac(aCx, wrapper);
|
||||
mReturnValue->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
|
||||
&returnValue, aError);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
|
||||
{
|
||||
|
@ -13461,6 +13502,27 @@ nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
|
|||
return mReturnValue->Get(nsContentUtils::GetSubjectPrincipal(), aRetVal);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SetReturnValue(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aReturnValue,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(SetReturnValue, (aCx, aReturnValue, aError),
|
||||
aError, );
|
||||
|
||||
MOZ_ASSERT(IsModalContentWindow(),
|
||||
"This should only be called on modal windows!");
|
||||
|
||||
nsCOMPtr<nsIVariant> returnValue;
|
||||
aError =
|
||||
nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
|
||||
getter_AddRefs(returnValue));
|
||||
if (!aError.Failed()) {
|
||||
mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
|
||||
returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
|
||||
{
|
||||
|
@ -13471,6 +13533,20 @@ nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
// For now, have to deal with XPConnect objects here.
|
||||
nsGlobalWindow* win;
|
||||
nsresult rv = UNWRAP_OBJECT(Window, aGlobal, win);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrapper(aCx, aGlobal);
|
||||
win = static_cast<nsGlobalWindow*>(piWin.get());
|
||||
}
|
||||
return win->IsModalContentWindow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetConsole(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aConsole)
|
||||
|
@ -13481,8 +13557,8 @@ nsGlobalWindow::GetConsole(JSContext* aCx,
|
|||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> thisObj(aCx, mJSObject);
|
||||
if (!mJSObject) {
|
||||
JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
|
||||
if (!thisObj) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
@ -13497,8 +13573,8 @@ nsGlobalWindow::GetConsole(JSContext* aCx,
|
|||
NS_IMETHODIMP
|
||||
nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
JS::Rooted<JSObject*> thisObj(aCx, mJSObject);
|
||||
if (!mJSObject) {
|
||||
JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
|
||||
if (!thisObj) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ class nsIDOMCrypto;
|
|||
class nsIDOMOfflineResourceList;
|
||||
class nsIScrollableFrame;
|
||||
class nsIControllers;
|
||||
class nsIJSID;
|
||||
class nsIScriptContext;
|
||||
class nsIScriptTimeoutHandler;
|
||||
class nsIWebBrowserChrome;
|
||||
|
@ -277,6 +278,16 @@ public:
|
|||
result.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
void Get(JSContext* aCx, JS::Handle<JSObject*> aScope, nsIPrincipal* aSubject,
|
||||
JS::MutableHandle<JS::Value> aResult, mozilla::ErrorResult& aError)
|
||||
{
|
||||
if (aSubject->Subsumes(mOrigin)) {
|
||||
aError = nsContentUtils::XPConnect()->VariantToJS(aCx, aScope,
|
||||
mValue, aResult);
|
||||
} else {
|
||||
aResult.setUndefined();
|
||||
}
|
||||
}
|
||||
virtual ~DialogValueHolder() {}
|
||||
private:
|
||||
nsCOMPtr<nsIPrincipal> mOrigin;
|
||||
|
@ -348,8 +359,9 @@ public:
|
|||
// nsIScriptGlobalObject
|
||||
JSObject *FastGetGlobalJSObject() const
|
||||
{
|
||||
return mJSObject;
|
||||
return GetWrapperPreserveColor();
|
||||
}
|
||||
|
||||
void TraceGlobalJSObject(JSTracer* aTrc);
|
||||
|
||||
virtual nsresult EnsureScriptEnvironment();
|
||||
|
@ -357,10 +369,11 @@ public:
|
|||
virtual nsIScriptContext *GetScriptContext();
|
||||
|
||||
void PoisonOuterWindowProxy(JSObject *aObject);
|
||||
virtual void OnFinalize(JSObject* aObject);
|
||||
|
||||
virtual bool IsBlackForCC(bool aTracingNeeded = true);
|
||||
|
||||
static JSObject* OuterObject(JSContext* aCx, JS::HandleObject aObj);
|
||||
|
||||
// nsIScriptObjectPrincipal
|
||||
virtual nsIPrincipal* GetPrincipal();
|
||||
|
||||
|
@ -581,6 +594,9 @@ public:
|
|||
return mIsChrome;
|
||||
}
|
||||
|
||||
using nsPIDOMWindow::IsModalContentWindow;
|
||||
static bool IsModalContentWindow(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
// GetScrollFrame does not flush. Callers should do it themselves as needed,
|
||||
// depending on which info they actually want off the scrollable frame.
|
||||
nsIScrollableFrame *GetScrollFrame();
|
||||
|
@ -982,6 +998,14 @@ public:
|
|||
mozilla::dom::Element* aPanel,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
||||
JS::Value GetDialogArguments(JSContext* aCx, mozilla::ErrorResult& aError);
|
||||
JS::Value GetReturnValue(JSContext* aCx, mozilla::ErrorResult& aError);
|
||||
void SetReturnValue(JSContext* aCx, JS::Handle<JS::Value> aReturnValue,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
||||
JS::Value GetInterface(JSContext* aCx, nsIJSID* aIID,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
||||
protected:
|
||||
// Array of idle observers that are notified of idle events.
|
||||
nsTObserverArray<IdleObserverHolder> mIdleObservers;
|
||||
|
@ -1440,6 +1464,9 @@ protected:
|
|||
// For |window.dialogArguments|, via |showModalDialog|.
|
||||
nsRefPtr<DialogValueHolder> mDialogArguments;
|
||||
|
||||
// Only used in the outer.
|
||||
nsRefPtr<DialogValueHolder> mReturnValue;
|
||||
|
||||
nsRefPtr<mozilla::dom::Navigator> mNavigator;
|
||||
nsRefPtr<nsScreen> mScreen;
|
||||
nsRefPtr<nsDOMWindowList> mFrames;
|
||||
|
@ -1485,9 +1512,6 @@ protected:
|
|||
// These member variables are used on both inner and the outer windows.
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
|
||||
// The JS global object. Global objects are always allocated tenured.
|
||||
JS::TenuredHeap<JSObject*> mJSObject;
|
||||
|
||||
typedef nsCOMArray<nsIDOMStorageEvent> nsDOMStorageEventArray;
|
||||
nsDOMStorageEventArray mPendingStorageEvents;
|
||||
|
||||
|
@ -1639,12 +1663,6 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMMODALCONTENTWINDOW
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
|
||||
|
||||
protected:
|
||||
// For use by outer windows only.
|
||||
nsRefPtr<DialogValueHolder> mReturnValue;
|
||||
};
|
||||
|
||||
/* factory function */
|
||||
|
|
|
@ -33,8 +33,8 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
|
|||
|
||||
|
||||
#define NS_ISCRIPTGLOBALOBJECT_IID \
|
||||
{ 0x6995e1ff, 0x9fc5, 0x44a7, \
|
||||
{ 0xbd, 0x7c, 0xe7, 0xcd, 0x44, 0x47, 0x22, 0x87 } }
|
||||
{ 0x876f83bd, 0x6314, 0x460a, \
|
||||
{ 0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1 } }
|
||||
|
||||
/**
|
||||
* The global object which keeps a script context for each supported script
|
||||
|
@ -67,15 +67,6 @@ public:
|
|||
return GetScriptContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the global script for a language is finalized, typically as
|
||||
* part of its GC process. By the time this call is made, the
|
||||
* nsIScriptContext for the language has probably already been removed.
|
||||
* After this call, the passed object is dead - which should generally be the
|
||||
* same object the global is using for a global for that language.
|
||||
*/
|
||||
virtual void OnFinalize(JSObject* aObject) = 0;
|
||||
|
||||
/**
|
||||
* Handle a script error. Generally called by a script context.
|
||||
*/
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include "js/Id.h" // must come before js/RootingAPI.h
|
||||
#include "js/Value.h" // must come before js/RootingAPI.h
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Tracer.h"
|
||||
|
||||
struct JSTracer;
|
||||
class XPCWrappedNativeScope;
|
||||
|
||||
#define NS_WRAPPERCACHE_IID \
|
||||
|
@ -222,6 +222,21 @@ public:
|
|||
|
||||
void ReleaseWrapper(void* aScriptObjectHolder);
|
||||
|
||||
protected:
|
||||
void TraceWrapper(JSTracer* aTrc, const char* name)
|
||||
{
|
||||
if (mWrapper) {
|
||||
JS_CallHeapObjectTracer(aTrc, &mWrapper, name);
|
||||
}
|
||||
}
|
||||
|
||||
void PoisonWrapper()
|
||||
{
|
||||
if (mWrapper) {
|
||||
mWrapper.setToCrashOnTouch();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
JSObject *GetWrapperJSObject() const
|
||||
{
|
||||
|
|
|
@ -25,10 +25,6 @@
|
|||
|
||||
class nsWrapperCache;
|
||||
|
||||
// nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't
|
||||
// try to use it without fixing that first.
|
||||
class nsGlobalWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -442,12 +438,6 @@ GetWrapperCache(nsWrapperCache* cache)
|
|||
return cache;
|
||||
}
|
||||
|
||||
inline nsWrapperCache*
|
||||
GetWrapperCache(nsGlobalWindow*)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline nsWrapperCache*
|
||||
GetWrapperCache(void* p)
|
||||
{
|
||||
|
|
|
@ -815,13 +815,20 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
|
|||
// Get the object. It might be a security wrapper, in which case we do a checked
|
||||
// unwrap.
|
||||
JS::Rooted<JSObject*> origObj(cx, &thisv.toObject());
|
||||
JSObject* obj = js::CheckedUnwrap(origObj);
|
||||
JSObject* obj = js::CheckedUnwrap(origObj, /* stopAtOuter = */ false);
|
||||
if (!obj) {
|
||||
JS_ReportError(cx, "Permission denied to access object");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsISupports* native = UnwrapDOMObjectToISupports(obj);
|
||||
// Switch this to UnwrapDOMObjectToISupports once our global objects are
|
||||
// using new bindings.
|
||||
JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*obj));
|
||||
nsISupports* native = nullptr;
|
||||
nsCOMPtr<nsISupports> nativeRef;
|
||||
xpc_qsUnwrapArg<nsISupports>(cx, val, &native,
|
||||
static_cast<nsISupports**>(getter_AddRefs(nativeRef)),
|
||||
&val);
|
||||
if (!native) {
|
||||
return Throw(cx, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
@ -862,6 +869,29 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
|
||||
nsWrapperCache* aCache, nsIJSID* aIID, ErrorResult& aError)
|
||||
{
|
||||
const nsID* iid = aIID->GetID();
|
||||
|
||||
nsRefPtr<nsISupports> result;
|
||||
aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
|
||||
if (aError.Failed()) {
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> wrapper(aCx, aCache->GetWrapper());
|
||||
JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(wrapper));
|
||||
JS::Rooted<JS::Value> v(aCx, JSVAL_NULL);
|
||||
if (!WrapObject(aCx, global, result, iid, &v)) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
class nsIJSID;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
extern nsresult
|
||||
|
@ -1606,6 +1607,17 @@ WantsQueryInterface
|
|||
}
|
||||
};
|
||||
|
||||
JS::Value
|
||||
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
|
||||
nsWrapperCache* aCache, nsIJSID* aIID, ErrorResult& aError);
|
||||
|
||||
template<class T>
|
||||
JS::Value
|
||||
GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID, ErrorResult& aError)
|
||||
{
|
||||
return GetInterfaceImpl(aCx, aThis, aThis, aIID, aError);
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ def isTypeCopyConstructible(type):
|
|||
def wantsAddProperty(desc):
|
||||
return (desc.concrete and
|
||||
desc.wrapperCache and
|
||||
not desc.interface.getExtendedAttribute("Global"))
|
||||
not (desc.workers and
|
||||
desc.interface.getExtendedAttribute("Global")))
|
||||
|
||||
|
||||
# We'll want to insert the indent at the beginnings of lines, but we
|
||||
|
@ -330,9 +331,46 @@ class CGDOMJSClass(CGThing):
|
|||
callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
|
||||
slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
|
||||
classFlags = "JSCLASS_IS_DOMJSCLASS | "
|
||||
classExtensionAndObjectOps = """\
|
||||
JS_NULL_CLASS_EXT,
|
||||
JS_NULL_OBJECT_OPS
|
||||
"""
|
||||
if self.descriptor.interface.getExtendedAttribute("Global"):
|
||||
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
|
||||
traceHook = "JS_GlobalObjectTraceHook"
|
||||
if not self.descriptor.workers:
|
||||
classExtensionAndObjectOps = """\
|
||||
{
|
||||
nsGlobalWindow::OuterObject, /* outerObject */
|
||||
nullptr, /* innerObject */
|
||||
nullptr, /* iteratorObject */
|
||||
false, /* isWrappedNative */
|
||||
nullptr /* weakmapKeyDelegateOp */
|
||||
},
|
||||
{
|
||||
nullptr, /* lookupGeneric */
|
||||
nullptr, /* lookupProperty */
|
||||
nullptr, /* lookupElement */
|
||||
nullptr, /* defineGeneric */
|
||||
nullptr, /* defineProperty */
|
||||
nullptr, /* defineElement */
|
||||
nullptr, /* getGeneric */
|
||||
nullptr, /* getProperty */
|
||||
nullptr, /* getElement */
|
||||
nullptr, /* setGeneric */
|
||||
nullptr, /* setProperty */
|
||||
nullptr, /* setElement */
|
||||
nullptr, /* getGenericAttributes */
|
||||
nullptr, /* setGenericAttributes */
|
||||
nullptr, /* deleteProperty */
|
||||
nullptr, /* deleteElement */
|
||||
nullptr, /* watch */
|
||||
nullptr, /* unwatch */
|
||||
nullptr, /* slice */
|
||||
nullptr, /* enumerate */
|
||||
JS_ObjectToOuterObject /* thisObject */
|
||||
}
|
||||
"""
|
||||
else:
|
||||
classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
|
||||
if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
|
||||
|
@ -366,8 +404,7 @@ class CGDOMJSClass(CGThing):
|
|||
nullptr, /* construct */
|
||||
${trace}, /* trace */
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
JS_NULL_OBJECT_OPS
|
||||
$*{classExtensionAndObjectOps}
|
||||
},
|
||||
$*{descriptor}
|
||||
};
|
||||
|
@ -380,6 +417,7 @@ class CGDOMJSClass(CGThing):
|
|||
finalize=FINALIZE_HOOK_NAME,
|
||||
call=callHook,
|
||||
trace=traceHook,
|
||||
classExtensionAndObjectOps=classExtensionAndObjectOps,
|
||||
descriptor=DOMClass(self.descriptor))
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ const CONTACTS_SENDMORE_MINIMUM = 5;
|
|||
// Keep in sync with the interfaces.
|
||||
const PROPERTIES = [
|
||||
"name", "honorificPrefix", "givenName", "additionalName", "familyName",
|
||||
"phoneticGivenName", "phoneticFamilyName",
|
||||
"honorificSuffix", "nickname", "photo", "category", "org", "jobTitle",
|
||||
"bday", "note", "anniversary", "sex", "genderIdentity", "key", "adr", "email",
|
||||
"url", "impp", "tel"
|
||||
|
|
|
@ -22,7 +22,7 @@ Cu.importGlobalProperties(["indexedDB"]);
|
|||
|
||||
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
|
||||
this.DB_NAME = "contacts";
|
||||
this.DB_VERSION = 19;
|
||||
this.DB_VERSION = 20;
|
||||
this.STORE_NAME = "contacts";
|
||||
this.SAVED_GETALL_STORE_NAME = "getallcache";
|
||||
const CHUNK_SIZE = 20;
|
||||
|
@ -169,6 +169,10 @@ ContactDB.prototype = {
|
|||
objectStore.createIndex("category", "properties.category", { multiEntry: true });
|
||||
objectStore.createIndex("email", "search.email", { multiEntry: true });
|
||||
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
|
||||
objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
|
||||
objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
|
||||
objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
|
||||
objectStore.createIndex("phoneticGivenNameLowerCase", "search.phoneticGivenName", { multiEntry: true });
|
||||
aDb.createObjectStore(SAVED_GETALL_STORE_NAME);
|
||||
aDb.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
|
||||
}
|
||||
|
@ -705,6 +709,17 @@ ContactDB.prototype = {
|
|||
|
||||
next();
|
||||
},
|
||||
function upgrade19to20() {
|
||||
if (DEBUG) debug("upgrade19to20 create schema(phonetic)");
|
||||
if (!objectStore) {
|
||||
objectStore = aTransaction.objectStore(STORE_NAME);
|
||||
}
|
||||
objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
|
||||
objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
|
||||
objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
|
||||
objectStore.createIndex("phoneticGivenNameLowerCase", "search.phoneticGivenName", { multiEntry: true });
|
||||
next();
|
||||
},
|
||||
];
|
||||
|
||||
let index = aOldVersion;
|
||||
|
@ -824,6 +839,8 @@ ContactDB.prototype = {
|
|||
tel: [],
|
||||
exactTel: [],
|
||||
parsedTel: [],
|
||||
phoneticFamilyName: [],
|
||||
phoneticGivenName: [],
|
||||
};
|
||||
|
||||
for (let field in aContact.properties) {
|
||||
|
@ -1115,6 +1132,21 @@ ContactDB.prototype = {
|
|||
}, null, aErrorCb);
|
||||
},
|
||||
|
||||
getSortByParam: function CDB_getSortByParam(aFindOptions) {
|
||||
switch (aFindOptions.sortBy) {
|
||||
case "familyName":
|
||||
return [ "familyName", "givenName" ];
|
||||
case "givenName":
|
||||
return [ "givenName" , "familyName" ];
|
||||
case "phoneticFamilyName":
|
||||
return [ "phoneticFamilyName" , "phoneticGivenName" ];
|
||||
case "phoneticGivenName":
|
||||
return [ "phoneticGivenName" , "phoneticFamilyName" ];
|
||||
default:
|
||||
return [ "givenName" , "familyName" ];
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sorting the contacts by sortBy field. aSortBy can either be familyName or givenName.
|
||||
* If 2 entries have the same sortyBy field or no sortBy field is present, we continue
|
||||
|
@ -1125,7 +1157,7 @@ ContactDB.prototype = {
|
|||
return;
|
||||
if (aFindOptions.sortBy != "undefined") {
|
||||
const sortOrder = aFindOptions.sortOrder;
|
||||
const sortBy = aFindOptions.sortBy == "familyName" ? [ "familyName", "givenName" ] : [ "givenName" , "familyName" ];
|
||||
const sortBy = this.getSortByParam(aFindOptions);
|
||||
|
||||
aResults.sort(function (a, b) {
|
||||
let x, y;
|
||||
|
|
|
@ -90,6 +90,8 @@ var properties1 = {
|
|||
name: ["Test1 TestFamilyName", "Test2 Wagner"],
|
||||
familyName: ["TestFamilyName","Wagner"],
|
||||
givenName: ["Test1","Test2"],
|
||||
phoneticFamilyName: ["TestphoneticFamilyName1","TestphoneticFamilyName2"],
|
||||
phoneticGivenName: ["TestphoneticGivenName1","TestphoneticGivenName2"],
|
||||
nickname: ["nicktest"],
|
||||
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
|
||||
adr: [adr1],
|
||||
|
@ -100,6 +102,8 @@ var properties2 = {
|
|||
name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
|
||||
familyName: ["dummyFamilyName"],
|
||||
givenName: ["dummyGivenName"],
|
||||
phoneticFamilyName: ["dummyphoneticFamilyName"],
|
||||
phoneticGivenName: ["dummyphoneticGivenName"],
|
||||
honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
|
||||
honorificSuffix: ["dummyHonorificSuffix"],
|
||||
additionalName: ["dummyadditionalName"],
|
||||
|
@ -120,6 +124,86 @@ var properties2 = {
|
|||
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
|
||||
};
|
||||
|
||||
// To test sorting(CJK)
|
||||
var c9 = {
|
||||
phoneticFamilyName: ["a"],
|
||||
phoneticGivenName: ["a"],
|
||||
};
|
||||
|
||||
var c10 = {
|
||||
phoneticFamilyName: ["b"],
|
||||
phoneticGivenName: ["b"],
|
||||
};
|
||||
|
||||
var c11 = {
|
||||
phoneticFamilyName: ["c","a","b"],
|
||||
phoneticGivenName: ["c","a","b"],
|
||||
};
|
||||
|
||||
var c12 = {
|
||||
phoneticFamilyName: ["c","a","c"],
|
||||
phoneticGivenName: ["c","a","c"],
|
||||
};
|
||||
|
||||
var c13 = {
|
||||
phoneticFamilyName: [],
|
||||
phoneticGivenName: [],
|
||||
};
|
||||
|
||||
var c14 = {
|
||||
phoneticFamilyName: ["e","e","e"],
|
||||
phoneticGivenName: ["e","e","e"],
|
||||
};
|
||||
|
||||
var c15 = {
|
||||
phoneticFamilyName: ["e","e","e"],
|
||||
phoneticGivenName: ["e","e","e"],
|
||||
};
|
||||
|
||||
var c16 = {
|
||||
phoneticFamilyName: ["e","e","e"],
|
||||
phoneticGivenName: ["e","e","e"],
|
||||
};
|
||||
|
||||
var properties3 = {
|
||||
// please keep capital letters at the start of these names
|
||||
name: ["Taro Yamada", "Ichiro Suzuki"],
|
||||
familyName: ["Yamada","Suzuki"],
|
||||
givenName: ["Taro","Ichiro"],
|
||||
phoneticFamilyName: ["TestPhoneticFamilyYamada","TestPhoneticFamilySuzuki"],
|
||||
phoneticGivenName: ["TestPhoneticGivenTaro","TestPhoneticGivenIchiro"],
|
||||
nickname: ["phoneticNicktest"],
|
||||
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
|
||||
adr: [adr1],
|
||||
email: [{type: ["work"], value: "x@y.com"}],
|
||||
};
|
||||
|
||||
var properties4 = {
|
||||
name: ["dummyHonorificPrefix dummyTaro dummyYamada dummyHonorificSuffix", "dummyHonorificPrefix2"],
|
||||
familyName: ["dummyYamada"],
|
||||
givenName: ["dummyTaro"],
|
||||
phoneticFamilyName: ["dummyTestPhoneticFamilyYamada"],
|
||||
phoneticGivenName: ["dummyTestPhoneticGivenTaro"],
|
||||
honorificPrefix: ["dummyPhoneticHonorificPrefix","dummyPhoneticHonorificPrefix2"],
|
||||
honorificSuffix: ["dummyPhoneticHonorificSuffix"],
|
||||
additionalName: ["dummyPhoneticAdditionalName"],
|
||||
nickname: ["dummyPhoneticNickname"],
|
||||
tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
|
||||
email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
|
||||
adr: [adr1, adr2],
|
||||
impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
|
||||
org: ["org1", "org2"],
|
||||
jobTitle: ["boss", "superboss"],
|
||||
note: ["test note"],
|
||||
category: ["cat1", "cat2"],
|
||||
url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
|
||||
bday: new Date("1980, 12, 01"),
|
||||
anniversary: new Date("2000, 12, 01"),
|
||||
sex: "male",
|
||||
genderIdentity: "test",
|
||||
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
|
||||
};
|
||||
|
||||
var sample_id1;
|
||||
var sample_id2;
|
||||
|
||||
|
@ -265,6 +349,8 @@ function checkContacts(contact1, contact2) {
|
|||
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
|
||||
checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
|
||||
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
|
||||
checkStrArray(contact1.phoneticFamilyName, contact2.phoneticFamilyName, "Same phoneticFamilyName");
|
||||
checkStrArray(contact1.phoneticGivenName, contact2.phoneticGivenName, "Same phoneticGivenName");
|
||||
checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
|
||||
checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
|
||||
checkCategory(contact1.category, contact2.category);
|
||||
|
|
|
@ -745,6 +745,8 @@ var steps = [
|
|||
name: [],
|
||||
familyName: [],
|
||||
givenName: [],
|
||||
phoneticFamilyName: [],
|
||||
phoneticGivenName: [],
|
||||
nickname: [],
|
||||
tel: [],
|
||||
adr: [],
|
||||
|
@ -825,6 +827,301 @@ var steps = [
|
|||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding a new contact");
|
||||
createResult1 = new mozContact(properties3);
|
||||
req = mozContacts.save(createResult1)
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding a new contact2");
|
||||
createResult2 = new mozContact(properties4);
|
||||
req = mozContacts.save(createResult2);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult2.id, "The contact now has an ID.");
|
||||
sample_id2 = createResult2.id;
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving all contacts");
|
||||
req = mozContacts.find({sortBy: "phoneticFamilyName"});
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 2, "Found exactly 2 contact.");
|
||||
checkContacts(req.result[1], properties3);
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Searching contacts by query1");
|
||||
var options = {filterBy: ["phoneticGivenName", "email"],
|
||||
filterOp: "startsWith",
|
||||
filterValue: properties3.phoneticGivenName[0].substring(0, 3)}
|
||||
req = mozContacts.find(options)
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
ok(findResult1.id == sample_id1, "Same ID");
|
||||
checkContacts(findResult1, createResult1);
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Searching contacts by query2");
|
||||
var options = {filterBy: ["phoneticGivenName", "email"],
|
||||
filterOp: "startsWith",
|
||||
filterValue: properties4.phoneticGivenName[0].substring(0, 3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
is(findResult1.adr.length, 2, "Adr length 2");
|
||||
checkContacts(findResult1, createResult2);
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
clearDatabase,
|
||||
function () {
|
||||
ok(true, "Adding 20 contacts");
|
||||
for (var i=0; i<19; i++) {
|
||||
createResult1 = new mozContact(properties3);
|
||||
req = mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
};
|
||||
createResult1 = new mozContact(properties3);
|
||||
req = mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkStrArray(createResult1.name, properties3.name, "Same Name");
|
||||
checkCount(20, "20 contacts in DB", next);
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving all contacts");
|
||||
req = mozContacts.find(defaultOptions);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 20, "20 Entries.");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving all contacts2");
|
||||
var options = {filterBy: ["phoneticGivenName"],
|
||||
filterOp: "startsWith",
|
||||
filterValue: properties3.phoneticGivenName[0].substring(0, 3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 20, "20 Entries.");
|
||||
checkContacts(createResult1, req.result[19]);
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving all contacts3");
|
||||
var options = {filterBy: ["phoneticGivenName", "tel", "email"],
|
||||
filterOp: "startsWith",
|
||||
filterValue: properties3.phoneticGivenName[0].substring(0, 3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 20, "20 Entries.");
|
||||
checkContacts(createResult1, req.result[10]);
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
clearDatabase,
|
||||
function () {
|
||||
ok(true, "Testing clone contact");
|
||||
createResult1 = new mozContact(properties3);
|
||||
req = mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkStrArray(createResult1.phoneticFamilyName, properties3.phoneticFamilyName, "Same phoneticFamilyName");
|
||||
checkStrArray(createResult1.phoneticGivenName, properties3.phoneticGivenName, "Same phoneticGivenName");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving all contacts");
|
||||
req = mozContacts.find({sortBy: "phoneticGivenName"});
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "1 Entries.");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
clearDatabase,
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c11);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c11, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c10);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c10, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c12);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c12, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c9);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c9, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
var options = {sortBy: "phoneticFamilyName",
|
||||
sortOrder: "ascending"};
|
||||
req = navigator.mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 4, "4 results");
|
||||
checkContacts(req.result[0], c9);
|
||||
checkContacts(req.result[1], c10);
|
||||
checkContacts(req.result[2], c11);
|
||||
checkContacts(req.result[3], c12);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
var options = {sortBy: "phoneticFamilyName",
|
||||
sortOrder: "descending"};
|
||||
req = navigator.mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 4, "4 results");
|
||||
checkContacts(req.result[0], c12);
|
||||
checkContacts(req.result[1], c11);
|
||||
checkContacts(req.result[2], c10);
|
||||
checkContacts(req.result[3], c9);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c13);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c13, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting with empty string");
|
||||
var options = {sortBy: "phoneticFamilyName",
|
||||
sortOrder: "ascending"};
|
||||
req = navigator.mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 5, "5 results");
|
||||
checkContacts(req.result[0], c13);
|
||||
checkContacts(req.result[1], c9);
|
||||
checkContacts(req.result[2], c10);
|
||||
checkContacts(req.result[3], c11);
|
||||
checkContacts(req.result[4], c12);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
clearDatabase,
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c15);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c15, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c14);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c14, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Test sorting");
|
||||
createResult1 = new mozContact(c16);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
checkContacts(c16, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
// Android does not support published/updated fields. Skip this.
|
||||
if (isAndroid) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "Test sorting with published");
|
||||
var options = {sortBy: "phoneticFamilyName",
|
||||
sortOrder: "descending"};
|
||||
req = navigator.mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 3, "3 results");
|
||||
ok(req.result[0].published < req.result[1].published, "Right sorting order");
|
||||
ok(req.result[1].published < req.result[2].published, "Right sorting order");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
clearDatabase,
|
||||
function () {
|
||||
ok(true, "all done!\n");
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -13,10 +13,7 @@ var gGotNotHandlingDrop = false;
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function fireEvent(target, event) {
|
||||
var utils =
|
||||
window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
|
||||
getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
|
||||
SpecialPowers.wrap(utils).dispatchDOMEventViaPresShell(target, event, true);
|
||||
SpecialPowers.DOMWindowUtils.dispatchDOMEventViaPresShell(target, event, true);
|
||||
}
|
||||
|
||||
function fireDrop(element, shouldAllowDrop, shouldAllowOnlyChromeDrop) {
|
||||
|
|
|
@ -10,6 +10,9 @@ const notificationID = "indexedDB-permissions-prompt";
|
|||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
// We want a prompt.
|
||||
setPermission(testPageURL, "indexedDB", "allow");
|
||||
executeSoon(test1);
|
||||
|
@ -69,6 +72,7 @@ function test2()
|
|||
gBrowser.removeCurrentTab();
|
||||
unregisterAllPopupEventHandlers();
|
||||
removePermission(testPageURL, "indexedDB");
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
executeSoon(finish);
|
||||
});
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ function test()
|
|||
{
|
||||
waitForExplicitFinish();
|
||||
// We want the prompt.
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
setPermission(testPageURL, "indexedDB", "allow");
|
||||
executeSoon(test1);
|
||||
}
|
||||
|
@ -68,6 +69,7 @@ function test2()
|
|||
gBrowser.selectedBrowser.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing = false;
|
||||
unregisterAllPopupEventHandlers();
|
||||
gBrowser.removeCurrentTab();
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
executeSoon(test3);
|
||||
});
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ function test()
|
|||
{
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(10);
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
removePermission(testPageURL, "indexedDB-unlimited");
|
||||
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
|
||||
executeSoon(test1);
|
||||
|
@ -108,6 +109,7 @@ function test2()
|
|||
unregisterAllPopupEventHandlers();
|
||||
removePermission(testPageURL, "indexedDB");
|
||||
Services.prefs.clearUserPref("dom.indexedDB.warningQuota");
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
executeSoon(finish);
|
||||
});
|
||||
executeSoon(function() { dispatchEvent("indexedDB-done"); });
|
||||
|
|
|
@ -12,6 +12,7 @@ function test()
|
|||
{
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(10);
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
removePermission(testPageURL, "indexedDB-unlimited");
|
||||
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
|
||||
executeSoon(test1);
|
||||
|
@ -43,6 +44,7 @@ function test1()
|
|||
gBrowser.removeCurrentTab();
|
||||
unregisterAllPopupEventHandlers();
|
||||
addMoreTest1Count = seenPopupCount;
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
executeSoon(finish);
|
||||
});
|
||||
executeSoon(function() { dispatchEvent("indexedDB-done"); });
|
||||
|
|
|
@ -12,6 +12,7 @@ function test()
|
|||
{
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(10);
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
removePermission(testPageURL, "indexedDB-unlimited");
|
||||
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
|
||||
executeSoon(test1);
|
||||
|
@ -54,6 +55,7 @@ function test1()
|
|||
"Correct permission set");
|
||||
gBrowser.removeCurrentTab();
|
||||
unregisterAllPopupEventHandlers();
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
executeSoon(finish);
|
||||
});
|
||||
executeSoon(function() { dispatchEvent("indexedDB-done"); });
|
||||
|
|
|
@ -12,6 +12,7 @@ function test()
|
|||
{
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(10);
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
removePermission(testPageURL, "indexedDB-unlimited");
|
||||
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
|
||||
executeSoon(test1);
|
||||
|
@ -48,6 +49,7 @@ function test1()
|
|||
gBrowser.removeCurrentTab();
|
||||
unregisterAllPopupEventHandlers();
|
||||
addMoreTest1Count = seenPopupCount;
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
executeSoon(test2);
|
||||
});
|
||||
executeSoon(function() { dispatchEvent("indexedDB-done"); });
|
||||
|
|
|
@ -43,8 +43,7 @@ var ConsoleObserver = {
|
|||
// Close the window.
|
||||
gBrowser.removeTab(tab, {animate: false});
|
||||
// Ensure actual window destruction is not delayed (too long).
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
// Ensure "inner-window-destroyed" event is processed,
|
||||
// so the storage cache is cleared.
|
||||
executeSoon(function () {
|
||||
|
|
|
@ -135,10 +135,7 @@ function messageReceiver(evt) {
|
|||
|
||||
function handleTestEnd() {
|
||||
function gc() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.garbageCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
}
|
||||
if (numTestsSet1) {
|
||||
if (!--numTestsSet1) {
|
||||
|
|
|
@ -22,8 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=397571
|
|||
/** Test for Bug 397571 **/
|
||||
|
||||
// Get the interface
|
||||
var utils = window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
|
||||
getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
|
||||
var utils = SpecialPowers.DOMWindowUtils.SpecialPowers_wrappedObject;
|
||||
|
||||
// Try to call functions without privileges
|
||||
var success = false;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<script>
|
||||
function go() {
|
||||
is(SpecialPowers.wrap(window).location.toString(), location.toString(), "sanity");
|
||||
is(SpecialPowers.Cu.getClassName(window, /* aUnwrap = */ true), "ModalContentWindow", "We are modal");
|
||||
ok("returnValue" in window && "dialogArguments" in window, "We are modal");
|
||||
var iwin = document.getElementById('ifr').contentWindow;
|
||||
is(SpecialPowers.Cu.getClassName(iwin, /* aUnwrap = */ true), "Window", "Descendant frames should not be modal");
|
||||
|
||||
|
|
|
@ -1224,11 +1224,11 @@ function createInterfaceMap(isXBLScope) {
|
|||
|
||||
var interfaceMap = {};
|
||||
|
||||
function addInterfaces(interfaces, shouldExpect)
|
||||
function addInterfaces(interfaces)
|
||||
{
|
||||
for (var entry of interfaces) {
|
||||
if (typeof(entry) === "string") {
|
||||
interfaceMap[entry] = shouldExpect;
|
||||
interfaceMap[entry] = true;
|
||||
} else if ((entry.nightly === !isNightly) ||
|
||||
(entry.xbl === !isXBLScope) ||
|
||||
(entry.desktop === !isDesktop) ||
|
||||
|
@ -1238,13 +1238,19 @@ function createInterfaceMap(isXBLScope) {
|
|||
(entry.permission && !hasPermission(entry.permission))) {
|
||||
interfaceMap[entry.name] = false;
|
||||
} else {
|
||||
interfaceMap[entry.name] = shouldExpect;
|
||||
interfaceMap[entry.name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addInterfaces(ecmaGlobals, true);
|
||||
addInterfaces(interfaceNamesInGlobalScope, true);
|
||||
addInterfaces(ecmaGlobals);
|
||||
addInterfaces(interfaceNamesInGlobalScope);
|
||||
if (isXBLScope) {
|
||||
// We expose QueryInterface to XBL scopes. It's not an interface but we
|
||||
// need to handle it because it's an own property of the global and the
|
||||
// property name starts with an uppercase letter.
|
||||
interfaceMap["QueryInterface"] = true;
|
||||
}
|
||||
|
||||
return interfaceMap;
|
||||
}
|
||||
|
|
|
@ -44,8 +44,10 @@ dictionary ContactProperties {
|
|||
sequence<DOMString>? name;
|
||||
sequence<DOMString>? honorificPrefix;
|
||||
sequence<DOMString>? givenName;
|
||||
sequence<DOMString>? phoneticGivenName;
|
||||
sequence<DOMString>? additionalName;
|
||||
sequence<DOMString>? familyName;
|
||||
sequence<DOMString>? phoneticFamilyName;
|
||||
sequence<DOMString>? honorificSuffix;
|
||||
sequence<DOMString>? nickname;
|
||||
sequence<DOMString>? category;
|
||||
|
@ -81,8 +83,10 @@ interface mozContact {
|
|||
[Cached, Pure] attribute sequence<DOMString>? name;
|
||||
[Cached, Pure] attribute sequence<DOMString>? honorificPrefix;
|
||||
[Cached, Pure] attribute sequence<DOMString>? givenName;
|
||||
[Cached, Pure] attribute sequence<DOMString>? phoneticGivenName;
|
||||
[Cached, Pure] attribute sequence<DOMString>? additionalName;
|
||||
[Cached, Pure] attribute sequence<DOMString>? familyName;
|
||||
[Cached, Pure] attribute sequence<DOMString>? phoneticFamilyName;
|
||||
[Cached, Pure] attribute sequence<DOMString>? honorificSuffix;
|
||||
[Cached, Pure] attribute sequence<DOMString>? nickname;
|
||||
[Cached, Pure] attribute sequence<DOMString>? category;
|
||||
|
|
|
@ -86,6 +86,7 @@ TreeWalker implements LegacyQueryInterface;
|
|||
UndoManager implements LegacyQueryInterface;
|
||||
ValidityState implements LegacyQueryInterface;
|
||||
WebSocket implements LegacyQueryInterface;
|
||||
Window implements LegacyQueryInterface;
|
||||
XMLHttpRequest implements LegacyQueryInterface;
|
||||
XMLHttpRequestUpload implements LegacyQueryInterface;
|
||||
XMLSerializer implements LegacyQueryInterface;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
interface ApplicationCache;
|
||||
interface IID;
|
||||
interface MozFrameRequestCallback;
|
||||
interface nsIBrowserDOMWindow;
|
||||
interface nsIMessageBroadcaster;
|
||||
|
@ -225,6 +226,14 @@ interface SpeechSynthesisGetter {
|
|||
Window implements SpeechSynthesisGetter;
|
||||
#endif
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/
|
||||
[NoInterfaceObject]
|
||||
interface WindowModal {
|
||||
[Throws, Func="nsGlobalWindow::IsModalContentWindow"] readonly attribute any dialogArguments;
|
||||
[Throws, Func="nsGlobalWindow::IsModalContentWindow"] attribute any returnValue;
|
||||
};
|
||||
Window implements WindowModal;
|
||||
|
||||
// Mozilla-specific stuff
|
||||
partial interface Window {
|
||||
//[NewObject, Throws] CSSStyleDeclaration getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = "");
|
||||
|
@ -341,6 +350,8 @@ partial interface Window {
|
|||
[Replaceable, Throws] readonly attribute object? content;
|
||||
|
||||
[ChromeOnly, Throws] readonly attribute object? __content;
|
||||
|
||||
[Throws, ChromeOnly] any getInterface(IID iid);
|
||||
};
|
||||
|
||||
Window implements TouchEventHandlers;
|
||||
|
|
|
@ -22,7 +22,8 @@ var iframe = document.getElementById("load-frame");
|
|||
function enableJS() allowJS(true, iframe);
|
||||
function disableJS() allowJS(false, iframe);
|
||||
function allowJS(allow, frame) {
|
||||
SpecialPowers.wrap(frame.contentWindow.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor))
|
||||
SpecialPowers.wrap(frame.contentWindow)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
|
||||
.allowJavascript = allow;
|
||||
|
|
|
@ -36,7 +36,8 @@ function editDoc() {
|
|||
function getSpellCheckSelection() {
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var win = editDoc().defaultView;
|
||||
var editingSession = SpecialPowers.wrap(win.QueryInterface(Ci.nsIInterfaceRequestor))
|
||||
var editingSession = SpecialPowers.wrap(win)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession);
|
||||
|
|
|
@ -53,7 +53,8 @@ function runTest() {
|
|||
editdoc.designMode='on';
|
||||
|
||||
// Hold the reference to the editor
|
||||
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
|
||||
editor = SpecialPowers.wrap(editframe)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession)
|
||||
|
@ -72,7 +73,8 @@ function runTest() {
|
|||
editdoc.body.contentEditable = true;
|
||||
|
||||
// Hold the reference to the editor
|
||||
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
|
||||
editor = SpecialPowers.wrap(editframe)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession)
|
||||
|
@ -89,7 +91,8 @@ function runTest() {
|
|||
editdoc.designMode = "off";
|
||||
|
||||
// Hold the reference to the editor
|
||||
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
|
||||
editor = SpecialPowers.wrap(editframe)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession)
|
||||
|
|
|
@ -48,6 +48,29 @@ CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CopyBGRXSurfaceDataToPackedBGRArray(uint8_t* aSrc, uint8_t* aDst,
|
||||
IntSize aSrcSize, int32_t aSrcStride)
|
||||
{
|
||||
int packedStride = aSrcSize.width * 3;
|
||||
|
||||
uint8_t* srcPx = aSrc;
|
||||
uint8_t* dstPx = aDst;
|
||||
|
||||
for (int row = 0; row < aSrcSize.height; ++row) {
|
||||
for (int col = 0; col < aSrcSize.height; ++col) {
|
||||
dstPx[0] = srcPx[0];
|
||||
dstPx[1] = srcPx[1];
|
||||
dstPx[2] = srcPx[2];
|
||||
// srcPx[3] (unused or alpha component) dropped on floor
|
||||
srcPx += 4;
|
||||
dstPx += 3;
|
||||
}
|
||||
srcPx = aSrc += aSrcStride;
|
||||
dstPx = aDst += packedStride;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
SurfaceToPackedBGRA(DataSourceSurface *aSurface)
|
||||
{
|
||||
|
@ -82,5 +105,37 @@ SurfaceToPackedBGRA(DataSourceSurface *aSurface)
|
|||
return imageBuffer;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
SurfaceToPackedBGR(DataSourceSurface *aSurface)
|
||||
{
|
||||
SurfaceFormat format = aSurface->GetFormat();
|
||||
MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported");
|
||||
|
||||
if (format != SurfaceFormat::B8G8R8X8) {
|
||||
// To support B8G8R8A8 we'd need to un-pre-multiply alpha
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IntSize size = aSurface->GetSize();
|
||||
|
||||
uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * 3 * sizeof(uint8_t)];
|
||||
if (!imageBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
|
||||
delete [] imageBuffer;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CopyBGRXSurfaceDataToPackedBGRArray(map.mData, imageBuffer, size,
|
||||
map.mStride);
|
||||
|
||||
aSurface->Unmap();
|
||||
|
||||
return imageBuffer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,5 +30,17 @@ CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
|
|||
uint8_t*
|
||||
SurfaceToPackedBGRA(DataSourceSurface *aSurface);
|
||||
|
||||
/**
|
||||
* Convert aSurface to a packed buffer in BGR format. The pixel data is
|
||||
* returned in a buffer allocated with new uint8_t[].
|
||||
*
|
||||
* This function is currently only intended for use with surfaces of format
|
||||
* SurfaceFormat::B8G8R8X8 since the X components of the pixel data are simply
|
||||
* dropped (no attempt is made to un-pre-multiply alpha from the color
|
||||
* components).
|
||||
*/
|
||||
uint8_t*
|
||||
SurfaceToPackedBGR(DataSourceSurface *aSurface);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <X11/Xutil.h>
|
||||
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/X11Util.h"
|
||||
|
||||
#include "prenv.h"
|
||||
|
@ -1188,15 +1189,21 @@ GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
|
|||
return glContext.forget();
|
||||
}
|
||||
|
||||
static nsRefPtr<GLContext> gGlobalContext;
|
||||
// TODO move that out of static initializaion
|
||||
static bool gUseContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
|
||||
static StaticRefPtr<GLContext> gGlobalContext;
|
||||
|
||||
GLContext*
|
||||
GLContextProviderGLX::GetGlobalContext()
|
||||
{
|
||||
static bool checkedContextSharing = false;
|
||||
static bool useContextSharing = false;
|
||||
|
||||
if (!checkedContextSharing) {
|
||||
useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
|
||||
checkedContextSharing = true;
|
||||
}
|
||||
|
||||
// TODO: get GLX context sharing to work well with multiple threads
|
||||
if (!gUseContextSharing) {
|
||||
if (!useContextSharing) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1205,7 +1212,11 @@ GLContextProviderGLX::GetGlobalContext()
|
|||
triedToCreateContext = true;
|
||||
|
||||
gfxIntSize dummySize = gfxIntSize(16, 16);
|
||||
gGlobalContext = CreateOffscreenPixmapContext(dummySize);
|
||||
// StaticPtr doesn't support assignments from already_AddRefed,
|
||||
// so use a temporary nsRefPtr to make the reference counting
|
||||
// fall out correctly.
|
||||
nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize);
|
||||
gGlobalContext = holder;
|
||||
}
|
||||
|
||||
return gGlobalContext;
|
||||
|
|
|
@ -284,19 +284,26 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
|||
|
||||
RefPtr<TextureClient> result;
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) || defined(XP_WIN)
|
||||
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
|
||||
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
|
||||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
|
||||
gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
|
||||
|
||||
aSizeHint.width <= maxTextureSize &&
|
||||
aSizeHint.height <= maxTextureSize &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
result = new TextureClientD3D11(aFormat, aTextureFlags);
|
||||
}
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
||||
aMoz2DBackend == gfx::BackendType::CAIRO &&
|
||||
aAllocator->IsSameProcess() &&
|
||||
aSizeHint.width <= maxTextureSize &&
|
||||
aSizeHint.height <= maxTextureSize &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
||||
result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
|
||||
|
@ -337,7 +344,6 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
|||
if (!DisableGralloc(aFormat, aSizeHint)) {
|
||||
// Don't allow Gralloc texture clients to exceed the maximum texture size.
|
||||
// BufferTextureClients have code to handle tiling the surface client-side.
|
||||
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
|
||||
if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
|
||||
result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
|
||||
aTextureFlags);
|
||||
|
|
|
@ -173,6 +173,9 @@ TextureClientD3D11::~TextureClientD3D11()
|
|||
bool
|
||||
TextureClientD3D11::Lock(OpenMode aMode)
|
||||
{
|
||||
if (!mTexture) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
|
||||
LockD3DTexture(mTexture.get());
|
||||
mIsLocked = true;
|
||||
|
@ -190,6 +193,7 @@ void
|
|||
TextureClientD3D11::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
|
||||
|
||||
if (mDrawTarget) {
|
||||
// see the comment on TextureClientDrawTarget::GetAsDrawTarget.
|
||||
// This DrawTarget is internal to the TextureClient and is only exposed to the
|
||||
|
@ -210,6 +214,10 @@ TextureClientD3D11::GetAsDrawTarget()
|
|||
{
|
||||
MOZ_ASSERT(mIsLocked, "Calling TextureClient::GetAsDrawTarget without locking :(");
|
||||
|
||||
if (!mTexture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mDrawTarget) {
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
@ -224,7 +232,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
|
|||
mSize = aSize;
|
||||
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
|
||||
CD3D10_TEXTURE2D_DESC newDesc(SurfaceFormatToDXGIFormat(mFormat),
|
||||
CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
aSize.width, aSize.height, 1, 1,
|
||||
D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
|
||||
|
||||
|
@ -332,10 +340,10 @@ DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
|
|||
nsIntRegion* aDestRegion,
|
||||
IntPoint* aSrcOffset)
|
||||
{
|
||||
// Right now we only support null aDestRegion and aSrcOffset (which means)
|
||||
// full surface update. Incremental update is only used on Mac so it is
|
||||
// not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
|
||||
// Right now we only support full surface update. If aDestRegion is provided,
|
||||
// It will be ignored. Incremental update with a source offset is only used
|
||||
// on Mac so it is not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aSrcOffset);
|
||||
MOZ_ASSERT(aSurface);
|
||||
|
||||
if (!mCompositor || !mCompositor->GetDevice()) {
|
||||
|
|
|
@ -376,10 +376,10 @@ DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface,
|
|||
nsIntRegion* aDestRegion,
|
||||
gfx::IntPoint* aSrcOffset)
|
||||
{
|
||||
// Right now we only support null aDestRegion and aSrcOffset (which means
|
||||
// full surface update). Incremental update is only used on Mac so it is
|
||||
// not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
|
||||
// Right now we only support full surface update. If aDestRegion is provided,
|
||||
// It will be ignored. Incremental update with a source offset is only used
|
||||
// on Mac so it is not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aSrcOffset);
|
||||
|
||||
if (!mCompositor || !mCompositor->device()) {
|
||||
NS_WARNING("No D3D device to update the texture.");
|
||||
|
|
|
@ -394,7 +394,6 @@ GrallocTextureHostOGL::GetAsSurface() {
|
|||
|
||||
TemporaryRef<gfx::DataSourceSurface>
|
||||
GrallocTextureSourceOGL::GetAsSurface() {
|
||||
MOZ_ASSERT(gl());
|
||||
if (!IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@ var layoutCSSBranch = prefService.getBranch("layout.css.");
|
|||
var oldVal = layoutCSSBranch.getCharPref("devPixelsPerPx");
|
||||
|
||||
try {
|
||||
var domWindowUtils = window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
|
||||
var domWindowUtils = SpecialPowers.DOMWindowUtils;
|
||||
var devPxPerCSSPx = domWindowUtils.screenPixelsPerCSSPixel;
|
||||
|
||||
layoutCSSBranch.setCharPref("devPixelsPerPx", "2");
|
||||
|
|
|
@ -351,6 +351,14 @@ gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
|
|||
aLength);
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxAndroidPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
|
||||
const nsAString& aFontName)
|
||||
{
|
||||
return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
|
||||
aFontName);
|
||||
}
|
||||
|
||||
TemporaryRef<ScaledFont>
|
||||
gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
virtual gfxPlatformFontList* CreatePlatformFontList();
|
||||
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
|
||||
const uint8_t *aFontData, uint32_t aLength);
|
||||
virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
|
||||
const nsAString& aFontName);
|
||||
|
||||
virtual void GetCommonFallbackFonts(const uint32_t aCh,
|
||||
int32_t aRunScript,
|
||||
|
|
|
@ -1386,7 +1386,7 @@ struct FullFontNameSearch {
|
|||
{ }
|
||||
|
||||
nsString mFullName;
|
||||
gfxFontEntry *mFontEntry;
|
||||
FT2FontEntry *mFontEntry;
|
||||
};
|
||||
|
||||
// callback called for each family name, based on the assumption that the
|
||||
|
@ -1400,17 +1400,22 @@ FindFullName(nsStringHashKey::KeyType aKey,
|
|||
|
||||
// does the family name match up to the length of the family name?
|
||||
const nsString& family = aFontFamily->Name();
|
||||
|
||||
|
||||
nsString fullNameFamily;
|
||||
data->mFullName.Left(fullNameFamily, family.Length());
|
||||
|
||||
// if so, iterate over faces in this family to see if there is a match
|
||||
if (family.Equals(fullNameFamily)) {
|
||||
if (family.Equals(fullNameFamily, nsCaseInsensitiveStringComparator())) {
|
||||
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = aFontFamily->GetFontList();
|
||||
int index, len = fontList.Length();
|
||||
for (index = 0; index < len; index++) {
|
||||
if (fontList[index]->Name().Equals(data->mFullName)) {
|
||||
data->mFontEntry = fontList[index];
|
||||
gfxFontEntry* fe = fontList[index];
|
||||
if (!fe) {
|
||||
continue;
|
||||
}
|
||||
if (fe->Name().Equals(data->mFullName,
|
||||
nsCaseInsensitiveStringComparator())) {
|
||||
data->mFontEntry = static_cast<FT2FontEntry*>(fe);
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
}
|
||||
|
@ -1428,7 +1433,32 @@ gfxFT2FontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
|
|||
|
||||
mFontFamilies.Enumerate(FindFullName, &data);
|
||||
|
||||
return data.mFontEntry;
|
||||
if (!data.mFontEntry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Clone the font entry so that we can then set its style descriptors
|
||||
// from the proxy rather than the actual font.
|
||||
|
||||
// Ensure existence of mFTFace in the original entry
|
||||
data.mFontEntry->CairoFontFace();
|
||||
if (!data.mFontEntry->mFTFace) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FT2FontEntry* fe =
|
||||
FT2FontEntry::CreateFontEntry(data.mFontEntry->mFTFace,
|
||||
data.mFontEntry->mFilename.get(),
|
||||
data.mFontEntry->mFTFontIndex,
|
||||
data.mFontEntry->Name(), nullptr);
|
||||
if (fe) {
|
||||
fe->mItalic = aProxyEntry->mItalic;
|
||||
fe->mWeight = aProxyEntry->mWeight;
|
||||
fe->mStretch = aProxyEntry->mStretch;
|
||||
fe->mIsUserFont = fe->mIsLocalUserFont = true;
|
||||
}
|
||||
|
||||
return fe;
|
||||
}
|
||||
|
||||
gfxFontFamily*
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxDrawable.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsRegion.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "ycbcr_to_rgb565.h"
|
||||
|
@ -848,6 +850,76 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ TemporaryRef<DataSourceSurface>
|
||||
gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(aFormat != aSurface->GetFormat(),
|
||||
"Unnecessary - and very expersive - surface format conversion");
|
||||
|
||||
Rect bounds(0, 0, aSurface->GetSize().width, aSurface->GetSize().height);
|
||||
|
||||
if (aSurface->GetType() != SurfaceType::DATA) {
|
||||
// If the surface is NOT of type DATA then its data is not mapped into main
|
||||
// memory. Format conversion is probably faster on the GPU, and by doing it
|
||||
// there we can avoid any expensive uploads/readbacks except for (possibly)
|
||||
// a single readback due to the unavoidable GetDataSurface() call. Using
|
||||
// CreateOffscreenContentDrawTarget ensures the conversion happens on the
|
||||
// GPU.
|
||||
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenContentDrawTarget(aSurface->GetSize(), aFormat);
|
||||
// Using DrawSurface() here rather than CopySurface() because CopySurface
|
||||
// is optimized for memcpy and therefore isn't good for format conversion.
|
||||
// Using OP_OVER since in our case it's equivalent to OP_SOURCE and
|
||||
// generally more optimized.
|
||||
dt->DrawSurface(aSurface, bounds, bounds, DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
RefPtr<SourceSurface> surface = dt->Snapshot();
|
||||
return surface->GetDataSurface();
|
||||
}
|
||||
|
||||
// If the surface IS of type DATA then it may or may not be in main memory
|
||||
// depending on whether or not it has been mapped yet. We have no way of
|
||||
// knowing, so we can't be sure if it's best to create a data wrapping
|
||||
// DrawTarget for the conversion or an offscreen content DrawTarget. We could
|
||||
// guess it's not mapped and create an offscreen content DrawTarget, but if
|
||||
// it is then we'll end up uploading the surface data, and most likely the
|
||||
// caller is going to be accessing the resulting surface data, resulting in a
|
||||
// readback (both very expensive operations). Alternatively we could guess
|
||||
// the data is mapped and create a data wrapping DrawTarget and, if the
|
||||
// surface is not in main memory, then we will incure a readback. The latter
|
||||
// of these two "wrong choices" is the least costly (a readback, vs an
|
||||
// upload and a readback), and more than likely the DATA surface that we've
|
||||
// been passed actually IS in main memory anyway. For these reasons it's most
|
||||
// likely best to create a data wrapping DrawTarget here to do the format
|
||||
// conversion.
|
||||
RefPtr<DataSourceSurface> dataSurface =
|
||||
Factory::CreateDataSourceSurface(aSurface->GetSize(), aFormat);
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dataSurface ||
|
||||
!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
map.mData,
|
||||
dataSurface->GetSize(),
|
||||
map.mStride,
|
||||
aFormat);
|
||||
if (!dt) {
|
||||
dataSurface->Unmap();
|
||||
return nullptr;
|
||||
}
|
||||
// Using DrawSurface() here rather than CopySurface() because CopySurface
|
||||
// is optimized for memcpy and therefore isn't good for format conversion.
|
||||
// Using OP_OVER since in our case it's equivalent to OP_SOURCE and
|
||||
// generally more optimized.
|
||||
dt->DrawSurface(aSurface, bounds, bounds, DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
dataSurface->Unmap();
|
||||
return dataSurface.forget();
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
/* static */ void
|
||||
gfxUtils::WriteAsPNG(DrawTarget* aDT, const char* aFile)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "gfxTypes.h"
|
||||
#include "GraphicsFilter.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class gfxDrawable;
|
||||
class nsIntRegion;
|
||||
|
@ -22,8 +24,12 @@ class PlanarYCbCrData;
|
|||
|
||||
class gfxUtils {
|
||||
public:
|
||||
typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
|
||||
typedef mozilla::gfx::IntPoint IntPoint;
|
||||
typedef mozilla::gfx::Matrix Matrix;
|
||||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
|
||||
|
||||
/*
|
||||
* Premultiply or Unpremultiply aSourceSurface, writing the result
|
||||
* to aDestSurface or back into aSourceSurface if aDestSurface is null.
|
||||
|
@ -155,6 +161,51 @@ public:
|
|||
unsigned char* aDestBuffer,
|
||||
int32_t aStride);
|
||||
|
||||
/**
|
||||
* Creates a copy of aSurface, but having the SurfaceFormat aFormat.
|
||||
*
|
||||
* This function always creates a new surface. Do not call it if aSurface's
|
||||
* format is the same as aFormat. Such a non-conversion would just be an
|
||||
* unnecessary and wasteful copy (this function asserts to prevent that).
|
||||
*
|
||||
* This function is intended to be called by code that needs to access the
|
||||
* pixel data of the surface, but doesn't want to have lots of branches
|
||||
* to handle different pixel data formats (code which would become out of
|
||||
* date if and when new formats are added). Callers can use this function
|
||||
* to copy the surface to a specified format so that they only have to
|
||||
* handle pixel data in that one format.
|
||||
*
|
||||
* WARNING: There are format conversions that will not be supported by this
|
||||
* function. It very much depends on what the Moz2D backends support. If
|
||||
* the temporary B8G8R8A8 DrawTarget that this function creates has a
|
||||
* backend that supports DrawSurface() calls passing a surface with
|
||||
* aSurface's format it will work. Otherwise it will not.
|
||||
*
|
||||
* *** IMPORTANT PERF NOTE ***
|
||||
*
|
||||
* This function exists partly because format conversion is fraught with
|
||||
* non-obvious performance hazards, so we don't want Moz2D consumers to be
|
||||
* doing their own format conversion. Do not try to do so, or at least read
|
||||
* the comments in this functions implemtation. That said, the copy that
|
||||
* this function carries out has a cost and, although this function tries
|
||||
* to avoid perf hazards such as expensive uploads to/readbacks from the
|
||||
* GPU, it can't guarantee that it always successfully does so. Perf
|
||||
* critical code that can directly handle the common formats that it
|
||||
* encounters in a way that is cheaper than a copy-with-format-conversion
|
||||
* should consider doing so, and only use this function as a fallback to
|
||||
* handle other formats.
|
||||
*
|
||||
* XXXjwatt it would be nice if SourceSurface::GetDataSurface took a
|
||||
* SurfaceFormat argument (with a default argument meaning "use the
|
||||
* existing surface's format") and returned a DataSourceSurface in that
|
||||
* format. (There would then be an issue of callers maybe failing to
|
||||
* realize format conversion may involve expensive copying/uploading/
|
||||
* readback.)
|
||||
*/
|
||||
static mozilla::TemporaryRef<DataSourceSurface>
|
||||
CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
static const uint8_t sUnpremultiplyTable[256*256];
|
||||
static const uint8_t sPremultiplyTable[256*256];
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
|
|
|
@ -67,7 +67,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
|||
'gfxFT2Fonts.cpp',
|
||||
'gfxFT2Utils.cpp',
|
||||
'gfxPDFSurface.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
EXPORTS += [
|
||||
|
@ -83,7 +82,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
|||
'gfxFT2Fonts.cpp',
|
||||
'gfxFT2Utils.cpp',
|
||||
'gfxPDFSurface.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
EXPORTS += [
|
||||
|
@ -99,7 +97,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|||
'gfxQuartzImageSurface.cpp',
|
||||
'gfxQuartzNativeDrawing.cpp',
|
||||
'gfxQuartzSurface.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_GTK']:
|
||||
EXPORTS += [
|
||||
|
@ -120,7 +117,6 @@ elif CONFIG['MOZ_WIDGET_GTK']:
|
|||
'gfxPDFSurface.cpp',
|
||||
'gfxPlatformGtk.cpp',
|
||||
'gfxPSSurface.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_X11']:
|
||||
|
@ -150,7 +146,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
|
|||
'gfxPDFSurface.cpp',
|
||||
'gfxQPainterSurface.cpp',
|
||||
'gfxQtPlatform.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_X11']:
|
||||
|
@ -184,7 +179,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'gfxWindowsNativeDrawing.cpp',
|
||||
'gfxWindowsPlatform.cpp',
|
||||
'gfxWindowsSurface.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_ENABLE_DWRITE_FONT']:
|
||||
# gfxDWriteFontList.cpp forces NSPR logging, so it cannot be built in unified mode.
|
||||
|
@ -253,6 +247,7 @@ UNIFIED_SOURCES += [
|
|||
'gfxTeeSurface.cpp',
|
||||
'gfxUtils.cpp',
|
||||
'nsSurfaceTexture.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "nsUTF16ToUnicode.h"
|
||||
#include "nsCharTraits.h"
|
||||
#include "mozilla/Endian.h"
|
||||
|
||||
enum {
|
||||
STATE_NORMAL = 0,
|
||||
|
@ -75,7 +76,7 @@ nsUTF16ToUnicodeBase::UTF16ConvertToUnicode(const char * aSrc,
|
|||
// the 1st byte of a 16-bit code unit was stored in |mOddByte| in the
|
||||
// previous run while the 2nd byte has to come from |*src|.
|
||||
mState = STATE_NORMAL;
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#if MOZ_BIG_ENDIAN
|
||||
u = (mOddByte << 8) | uint8_t(*src++); // safe, we know we have at least one byte.
|
||||
#else
|
||||
u = (*src++ << 8) | mOddByte; // safe, we know we have at least one byte.
|
||||
|
@ -209,7 +210,7 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
|
|||
mState = STATE_SECOND_BYTE;
|
||||
return NS_OK_UDEC_MOREINPUT;
|
||||
}
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#if MOZ_LITTLE_ENDIAN
|
||||
// on LE machines, BE BOM is 0xFFFE
|
||||
if (0xFFFE != *((char16_t*)aSrc)) {
|
||||
mState = STATE_NORMAL;
|
||||
|
@ -233,14 +234,8 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
|
|||
break;
|
||||
}
|
||||
|
||||
nsresult rv = UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
return rv;
|
||||
return UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
|
||||
bool(MOZ_LITTLE_ENDIAN));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -262,7 +257,7 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
|
|||
mState = STATE_SECOND_BYTE;
|
||||
return NS_OK_UDEC_MOREINPUT;
|
||||
}
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#if MOZ_BIG_ENDIAN
|
||||
// on BE machines, LE BOM is 0xFFFE
|
||||
if (0xFFFE != *((char16_t*)aSrc)) {
|
||||
mState = STATE_NORMAL;
|
||||
|
@ -286,14 +281,8 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
|
|||
break;
|
||||
}
|
||||
|
||||
nsresult rv = UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
return rv;
|
||||
return UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
|
||||
bool(MOZ_BIG_ENDIAN));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -348,12 +337,10 @@ nsUTF16ToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
|
|||
}
|
||||
|
||||
nsresult rv = UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#if MOZ_BIG_ENDIAN
|
||||
(mEndian == kLittleEndian)
|
||||
#elif defined(IS_LITTLE_ENDIAN)
|
||||
(mEndian == kBigEndian)
|
||||
#else
|
||||
#error "Unknown endianness"
|
||||
(mEndian == kBigEndian)
|
||||
#endif
|
||||
);
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include "nsUnicodeToUTF16.h"
|
||||
#include <string.h>
|
||||
|
||||
inline static void SwapBytes(char *aDest, const char16_t* aSrc, int32_t aLen);
|
||||
|
||||
NS_IMETHODIMP nsUnicodeToUTF16BE::Convert(const char16_t * aSrc, int32_t * aSrcLength,
|
||||
char * aDest, int32_t * aDestLength)
|
||||
{
|
||||
|
@ -97,40 +95,12 @@ NS_IMETHODIMP nsUnicodeToUTF16BE::SetOutputErrorBehavior(int32_t aBehavior,
|
|||
|
||||
NS_IMETHODIMP nsUnicodeToUTF16BE::CopyData(char* aDest, const char16_t* aSrc, int32_t aLen )
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
//UnicodeToUTF16SameEndian
|
||||
::memcpy(aDest, (void*) aSrc, aLen * 2);
|
||||
#elif defined(IS_LITTLE_ENDIAN)
|
||||
//UnicodeToUTF16DiffEndian
|
||||
SwapBytes(aDest, aSrc, aLen);
|
||||
#else
|
||||
#error "Unknown endianness"
|
||||
#endif
|
||||
mozilla::NativeEndian::copyAndSwapToBigEndian(aDest, aSrc, aLen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsUnicodeToUTF16LE::CopyData(char* aDest, const char16_t* aSrc, int32_t aLen )
|
||||
{
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
//UnicodeToUTF16SameEndian
|
||||
::memcpy(aDest, (void*) aSrc, aLen * 2);
|
||||
#elif defined(IS_BIG_ENDIAN)
|
||||
//UnicodeToUTF16DiffEndian
|
||||
SwapBytes(aDest, aSrc, aLen);
|
||||
#else
|
||||
#error "Unknown endianness"
|
||||
#endif
|
||||
mozilla::NativeEndian::copyAndSwapToLittleEndian(aDest, aSrc, aLen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline void SwapBytes(char *aDest, const char16_t* aSrc, int32_t aLen)
|
||||
{
|
||||
char16_t *p = (char16_t*) aDest;
|
||||
// copy the data by swaping
|
||||
for(int32_t i = 0; i < aLen; i++)
|
||||
{
|
||||
char16_t aChar = *aSrc++;
|
||||
*p++ = (0x00FF & (aChar >> 8)) | (0xFF00 & (aChar << 8));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define nsUnicodeToUTF16_h_
|
||||
|
||||
#include "nsUCSupport.h"
|
||||
#include "mozilla/Endian.h"
|
||||
|
||||
class nsUnicodeToUTF16BE: public nsBasicEncoder
|
||||
{
|
||||
|
@ -39,14 +40,10 @@ protected:
|
|||
NS_IMETHOD CopyData(char* aDest, const char16_t* aSrc, int32_t aLen );
|
||||
};
|
||||
|
||||
// XXX In theory, we have to check the endianness at run-time because some
|
||||
// modern RISC processors can be run at both LE and BE.
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#if MOZ_LITTLE_ENDIAN
|
||||
class nsUnicodeToUTF16: public nsUnicodeToUTF16LE
|
||||
#elif defined(IS_BIG_ENDIAN)
|
||||
class nsUnicodeToUTF16: public nsUnicodeToUTF16BE
|
||||
#else
|
||||
#error "Unknown endianness"
|
||||
class nsUnicodeToUTF16: public nsUnicodeToUTF16BE
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -35,9 +35,9 @@ class ProfileEntry
|
|||
// if a sample were taken it would be examining bogus information.
|
||||
//
|
||||
// A ProfileEntry represents both a C++ profile entry and a JS one. Both use
|
||||
// the string as a description, but JS uses the sp as nullptr to indicate
|
||||
// that it is a JS entry. The script_ is then only ever examined for a JS
|
||||
// entry, and the idx is used by both, but with different meanings.
|
||||
// the string as a description, but JS uses the sp as nullptr or (void*)1 to
|
||||
// indicate that it is a JS entry. The script_ is then only ever examined for
|
||||
// a JS entry, and the idx is used by both, but with different meanings.
|
||||
//
|
||||
const char * volatile string; // Descriptive string of this entry
|
||||
void * volatile sp; // Relevant stack pointer for the entry
|
||||
|
|
|
@ -245,6 +245,18 @@ class Heap : public js::HeapBase<T>
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the pointer to a value which will cause a crash if it is
|
||||
* dereferenced.
|
||||
*/
|
||||
void setToCrashOnTouch() {
|
||||
ptr = reinterpret_cast<T>(crashOnTouchPointer);
|
||||
}
|
||||
|
||||
bool isSetToCrashOnTouch() {
|
||||
return ptr == crashOnTouchPointer;
|
||||
}
|
||||
|
||||
private:
|
||||
void init(T newPtr) {
|
||||
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
|
||||
|
@ -266,6 +278,10 @@ class Heap : public js::HeapBase<T>
|
|||
#endif
|
||||
}
|
||||
|
||||
enum {
|
||||
crashOnTouchPointer = 1
|
||||
};
|
||||
|
||||
T ptr;
|
||||
};
|
||||
|
||||
|
@ -363,23 +379,10 @@ class TenuredHeap : public js::HeapBase<T>
|
|||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the pointer to a value which will cause a crash if it is
|
||||
* dereferenced.
|
||||
*/
|
||||
void setToCrashOnTouch() {
|
||||
bits = (bits & flagsMask) | crashOnTouchPointer;
|
||||
}
|
||||
|
||||
bool isSetToCrashOnTouch() {
|
||||
return (bits & ~flagsMask) == crashOnTouchPointer;
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
maskBits = 3,
|
||||
flagsMask = (1 << maskBits) - 1,
|
||||
crashOnTouchPointer = 1 << maskBits
|
||||
};
|
||||
|
||||
uintptr_t bits;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/CompileInfo.h"
|
||||
#include "jit/IonSpewer.h"
|
||||
#include "jit/Recover.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
@ -476,7 +477,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
if (excInfo)
|
||||
exprStackSlots = excInfo->numExprSlots;
|
||||
else
|
||||
exprStackSlots = iter.allocations() - (script->nfixed() + CountArgSlots(script, fun));
|
||||
exprStackSlots = iter.numAllocations() - (script->nfixed() + CountArgSlots(script, fun));
|
||||
|
||||
builder.resetFramePushed();
|
||||
|
||||
|
@ -629,9 +630,9 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
|
||||
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
|
||||
|
||||
JS_ASSERT(iter.allocations() >= CountArgSlots(script, fun));
|
||||
JS_ASSERT(iter.numAllocations() >= CountArgSlots(script, fun));
|
||||
IonSpew(IonSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
|
||||
iter.allocations(), fun->nargs(), script->nfixed());
|
||||
iter.numAllocations(), fun->nargs(), script->nfixed());
|
||||
|
||||
if (!callerPC) {
|
||||
// This is the first frame. Store the formals in a Vector until we
|
||||
|
@ -1348,6 +1349,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
|
|||
jsbytecode *topCallerPC = nullptr;
|
||||
|
||||
while (true) {
|
||||
MOZ_ASSERT(snapIter.instruction()->isResumePoint());
|
||||
|
||||
#if JS_TRACE_LOGGING
|
||||
if (frameNo > 0) {
|
||||
TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, scr);
|
||||
|
@ -1383,7 +1386,6 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
|
|||
callerPC = callPC;
|
||||
fun = nextCallee;
|
||||
scr = fun->existingScript();
|
||||
snapIter.nextFrame();
|
||||
|
||||
// Save top caller info for adjusting SPS frames later.
|
||||
if (!topCaller) {
|
||||
|
@ -1393,6 +1395,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
|
|||
}
|
||||
|
||||
frameNo++;
|
||||
|
||||
snapIter.nextInstruction();
|
||||
}
|
||||
IonSpew(IonSpew_BaselineBailouts, " Done restoring frames");
|
||||
|
||||
|
|
|
@ -7938,15 +7938,15 @@ static const VMFunction SPSEnterInfo = FunctionInfo<SPSFn>(SPSEnter);
|
|||
static const VMFunction SPSExitInfo = FunctionInfo<SPSFn>(SPSExit);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
|
||||
CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
|
||||
{
|
||||
Register temp = ToRegister(lir->temp()->output());
|
||||
bool inlinedFunction = lir->inlineLevel() > 0;
|
||||
|
||||
switch (lir->type()) {
|
||||
case MFunctionBoundary::Inline_Enter:
|
||||
case MProfilerStackOp::InlineEnter:
|
||||
// Multiple scripts can be inlined at one depth, but there is only
|
||||
// one Inline_Exit node to signify this. To deal with this, if we
|
||||
// one InlineExit node to signify this. To deal with this, if we
|
||||
// reach the entry of another inline script on the same level, then
|
||||
// just reset the sps metadata about the frame. We must balance
|
||||
// calls to leave()/reenter(), so perform the balance without
|
||||
|
@ -7965,7 +7965,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
|
|||
return false;
|
||||
// fallthrough
|
||||
|
||||
case MFunctionBoundary::Enter:
|
||||
case MProfilerStackOp::Enter:
|
||||
if (gen->options.spsSlowAssertionsEnabled()) {
|
||||
if (!inlinedFunction || js_JitOptions.profileInlineFrames) {
|
||||
saveLive(lir);
|
||||
|
@ -7980,7 +7980,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
|
|||
|
||||
return sps_.push(lir->script(), masm, temp, /* inlinedFunction = */ inlinedFunction);
|
||||
|
||||
case MFunctionBoundary::Inline_Exit:
|
||||
case MProfilerStackOp::InlineExit:
|
||||
// all inline returns were covered with ::Exit, so we just need to
|
||||
// maintain the state of inline frames currently active and then
|
||||
// reenter the caller
|
||||
|
@ -7988,7 +7988,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
|
|||
sps_.reenter(masm, temp, /* inlinedFunction = */ true);
|
||||
return true;
|
||||
|
||||
case MFunctionBoundary::Exit:
|
||||
case MProfilerStackOp::Exit:
|
||||
if (gen->options.spsSlowAssertionsEnabled()) {
|
||||
if (!inlinedFunction || js_JitOptions.profileInlineFrames) {
|
||||
saveLive(lir);
|
||||
|
@ -8008,7 +8008,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
|
|||
return true;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("invalid LFunctionBoundary type");
|
||||
MOZ_ASSUME_UNREACHABLE("invalid LProfilerStackOp type");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool visitInstanceOfO(LInstanceOfO *ins);
|
||||
bool visitInstanceOfV(LInstanceOfV *ins);
|
||||
bool visitCallInstanceOf(LCallInstanceOf *ins);
|
||||
bool visitFunctionBoundary(LFunctionBoundary *lir);
|
||||
bool visitProfilerStackOp(LProfilerStackOp *lir);
|
||||
bool visitGetDOMProperty(LGetDOMProperty *lir);
|
||||
bool visitGetDOMMember(LGetDOMMember *lir);
|
||||
bool visitSetDOMProperty(LSetDOMProperty *lir);
|
||||
|
|
|
@ -654,7 +654,7 @@ IonBuilder::build()
|
|||
// Emit the start instruction, so we can begin real instructions.
|
||||
current->makeStart(MStart::New(alloc(), MStart::StartType_Default));
|
||||
if (instrumentedProfiling())
|
||||
current->add(MFunctionBoundary::New(alloc(), script(), MFunctionBoundary::Enter));
|
||||
current->add(MProfilerStackOp::New(alloc(), script(), MProfilerStackOp::Enter));
|
||||
|
||||
// Guard against over-recursion. Do this before we start unboxing, since
|
||||
// this will create an OSI point that will read the incoming argument
|
||||
|
@ -791,11 +791,11 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
|
|||
// All further instructions generated in from this scope should be
|
||||
// considered as part of the function that we're inlining. We also need to
|
||||
// keep track of the inlining depth because all scripts inlined on the same
|
||||
// level contiguously have only one Inline_Exit node.
|
||||
// level contiguously have only one InlineExit node.
|
||||
if (instrumentedProfiling()) {
|
||||
predecessor->add(MFunctionBoundary::New(alloc(), script(),
|
||||
MFunctionBoundary::Inline_Enter,
|
||||
inliningDepth_));
|
||||
predecessor->add(MProfilerStackOp::New(alloc(), script(),
|
||||
MProfilerStackOp::InlineEnter,
|
||||
inliningDepth_));
|
||||
}
|
||||
|
||||
predecessor->end(MGoto::New(alloc(), current));
|
||||
|
@ -3628,8 +3628,8 @@ IonBuilder::processReturn(JSOp op)
|
|||
}
|
||||
|
||||
if (instrumentedProfiling()) {
|
||||
current->add(MFunctionBoundary::New(alloc(), script(), MFunctionBoundary::Exit,
|
||||
inliningDepth_));
|
||||
current->add(MProfilerStackOp::New(alloc(), script(), MProfilerStackOp::Exit,
|
||||
inliningDepth_));
|
||||
}
|
||||
MReturn *ret = MReturn::New(alloc(), def);
|
||||
current->end(ret);
|
||||
|
@ -3961,9 +3961,9 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
|
|||
return false;
|
||||
returnBlock->setCallerResumePoint(callerResumePoint_);
|
||||
|
||||
// When profiling add Inline_Exit instruction to indicate end of inlined function.
|
||||
// When profiling add InlineExit instruction to indicate end of inlined function.
|
||||
if (instrumentedProfiling())
|
||||
returnBlock->add(MFunctionBoundary::New(alloc(), nullptr, MFunctionBoundary::Inline_Exit));
|
||||
returnBlock->add(MProfilerStackOp::New(alloc(), nullptr, MProfilerStackOp::InlineExit));
|
||||
|
||||
// Inherit the slots from current and pop |fun|.
|
||||
returnBlock->inheritSlots(current);
|
||||
|
|
|
@ -23,6 +23,7 @@ InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(
|
|||
JSContext *cx, const IonBailoutIterator *iter)
|
||||
: frame_(iter),
|
||||
framesRead_(0),
|
||||
frameCount_(UINT32_MAX),
|
||||
callee_(cx),
|
||||
script_(cx)
|
||||
{
|
||||
|
|
|
@ -244,6 +244,8 @@ class IonFrameIterator
|
|||
class IonJSFrameLayout;
|
||||
class IonBailoutIterator;
|
||||
|
||||
class RResumePoint;
|
||||
|
||||
// Reads frame information in snapshot-encoding order (that is, outermost frame
|
||||
// to innermost frame).
|
||||
class SnapshotIterator
|
||||
|
@ -287,22 +289,23 @@ class SnapshotIterator
|
|||
return snapshot_.readAllocation();
|
||||
}
|
||||
Value skip() {
|
||||
readAllocation();
|
||||
snapshot_.skipAllocation();
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
inline uint32_t allocations() const {
|
||||
return recover_.allocations();
|
||||
const RResumePoint *resumePoint() const;
|
||||
const RInstruction *instruction() const {
|
||||
return recover_.instruction();
|
||||
}
|
||||
|
||||
uint32_t numAllocations() const;
|
||||
inline bool moreAllocations() const {
|
||||
return recover_.moreAllocations(snapshot_);
|
||||
return snapshot_.numAllocationsRead() < numAllocations();
|
||||
}
|
||||
|
||||
public:
|
||||
// Exhibits frame properties contained in the snapshot.
|
||||
inline uint32_t pcOffset() const {
|
||||
return recover_.pcOffset();
|
||||
}
|
||||
uint32_t pcOffset() const;
|
||||
inline bool resumeAfter() const {
|
||||
// Inline frames are inlined on calls, which are considered as being
|
||||
// resumed on the Call as baseline will push the pc once we return from
|
||||
|
@ -315,17 +318,31 @@ class SnapshotIterator
|
|||
return snapshot_.bailoutKind();
|
||||
}
|
||||
|
||||
public:
|
||||
// Read the next instruction available and get ready to either skip it or
|
||||
// evaluate it.
|
||||
inline void nextInstruction() {
|
||||
MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations());
|
||||
recover_.nextInstruction();
|
||||
snapshot_.resetNumAllocationsRead();
|
||||
}
|
||||
|
||||
// Skip an Instruction by walking to the next instruction and by skipping
|
||||
// all the allocations corresponding to this instruction.
|
||||
void skipInstruction();
|
||||
|
||||
inline bool moreInstructions() const {
|
||||
return recover_.moreInstructions();
|
||||
}
|
||||
|
||||
public:
|
||||
// Handle iterating over frames of the snapshots.
|
||||
inline void nextFrame() {
|
||||
// Reuse the Snapshot buffer.
|
||||
recover_.nextFrame(snapshot_);
|
||||
}
|
||||
void nextFrame();
|
||||
|
||||
inline bool moreFrames() const {
|
||||
return recover_.moreFrames();
|
||||
}
|
||||
inline uint32_t frameCount() const {
|
||||
return recover_.frameCount();
|
||||
// The last instruction is recovering the innermost frame, so as long as
|
||||
// there is more instruction there is necesseray more frames.
|
||||
return moreInstructions();
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -409,7 +426,14 @@ class InlineFrameIteratorMaybeGC
|
|||
const IonFrameIterator *frame_;
|
||||
SnapshotIterator start_;
|
||||
SnapshotIterator si_;
|
||||
unsigned framesRead_;
|
||||
uint32_t framesRead_;
|
||||
|
||||
// When the inline-frame-iterator is created, this variable is defined to
|
||||
// UINT32_MAX. Then the first iteration of findNextFrame, which settle on
|
||||
// the innermost frame, is used to update this counter to the number of
|
||||
// frames contained in the recover buffer.
|
||||
uint32_t frameCount_;
|
||||
|
||||
typename MaybeRooted<JSFunction*, allowGC>::RootType callee_;
|
||||
typename MaybeRooted<JSScript*, allowGC>::RootType script_;
|
||||
jsbytecode *pc_;
|
||||
|
@ -442,6 +466,7 @@ class InlineFrameIteratorMaybeGC
|
|||
InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter)
|
||||
: frame_(iter ? iter->frame_ : nullptr),
|
||||
framesRead_(0),
|
||||
frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
|
||||
callee_(cx),
|
||||
script_(cx)
|
||||
{
|
||||
|
@ -455,7 +480,7 @@ class InlineFrameIteratorMaybeGC
|
|||
}
|
||||
|
||||
bool more() const {
|
||||
return frame_ && framesRead_ < start_.frameCount();
|
||||
return frame_ && framesRead_ < frameCount_;
|
||||
}
|
||||
JSFunction *callee() const {
|
||||
JS_ASSERT(callee_);
|
||||
|
@ -510,8 +535,8 @@ class InlineFrameIteratorMaybeGC
|
|||
// Skip over all slots until we get to the last slots
|
||||
// (= arguments slots of callee) the +3 is for [this], [returnvalue],
|
||||
// [scopechain], and maybe +1 for [argsObj]
|
||||
JS_ASSERT(parent_s.allocations() >= nactual + 3 + argsObjAdj);
|
||||
unsigned skip = parent_s.allocations() - nactual - 3 - argsObjAdj;
|
||||
JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj);
|
||||
unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj;
|
||||
for (unsigned j = 0; j < skip; j++)
|
||||
parent_s.skip();
|
||||
|
||||
|
@ -597,7 +622,8 @@ class InlineFrameIteratorMaybeGC
|
|||
|
||||
// Inline frame number, 0 for the outermost (non-inlined) frame.
|
||||
size_t frameNo() const {
|
||||
return start_.frameCount() - framesRead_;
|
||||
MOZ_ASSERT(frameCount_ != UINT32_MAX);
|
||||
return frameCount_ - framesRead_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "jit/JitCompartment.h"
|
||||
#include "jit/ParallelFunctions.h"
|
||||
#include "jit/PcScriptCache.h"
|
||||
#include "jit/Recover.h"
|
||||
#include "jit/Safepoints.h"
|
||||
#include "jit/Snapshots.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
|
@ -1498,6 +1499,42 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
|||
}
|
||||
}
|
||||
|
||||
const RResumePoint *
|
||||
SnapshotIterator::resumePoint() const
|
||||
{
|
||||
return instruction()->toResumePoint();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SnapshotIterator::numAllocations() const
|
||||
{
|
||||
return resumePoint()->numOperands();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SnapshotIterator::pcOffset() const
|
||||
{
|
||||
return resumePoint()->pcOffset();
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::skipInstruction()
|
||||
{
|
||||
MOZ_ASSERT(snapshot_.numAllocationsRead() == 0);
|
||||
size_t numOperands = instruction()->numOperands();
|
||||
for (size_t i = 0; i < numOperands; i++)
|
||||
skip();
|
||||
nextInstruction();
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::nextFrame()
|
||||
{
|
||||
nextInstruction();
|
||||
while (!instruction()->isResumePoint())
|
||||
skipInstruction();
|
||||
}
|
||||
|
||||
IonScript *
|
||||
IonFrameIterator::ionScript() const
|
||||
{
|
||||
|
@ -1536,6 +1573,7 @@ InlineFrameIteratorMaybeGC<allowGC>::resetOn(const IonFrameIterator *iter)
|
|||
{
|
||||
frame_ = iter;
|
||||
framesRead_ = 0;
|
||||
frameCount_ = UINT32_MAX;
|
||||
|
||||
if (iter) {
|
||||
start_ = SnapshotIterator(*iter);
|
||||
|
@ -1553,9 +1591,15 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
|
|||
|
||||
si_ = start_;
|
||||
|
||||
// Read the initial frame.
|
||||
// Read the initial frame out of the C stack.
|
||||
callee_ = frame_->maybeCallee();
|
||||
script_ = frame_->script();
|
||||
|
||||
// Settle on the outermost frame without evaluating any instructions before
|
||||
// looking for a pc.
|
||||
if (!si_.instruction()->isResumePoint())
|
||||
si_.nextFrame();
|
||||
|
||||
pc_ = script_->offsetToPC(si_.pcOffset());
|
||||
#ifdef DEBUG
|
||||
numActualArgs_ = 0xbadbad;
|
||||
|
@ -1563,8 +1607,15 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
|
|||
|
||||
// This unfortunately is O(n*m), because we must skip over outer frames
|
||||
// before reading inner ones.
|
||||
unsigned remaining = start_.frameCount() - framesRead_ - 1;
|
||||
for (unsigned i = 0; i < remaining; i++) {
|
||||
|
||||
// The first time (frameCount_ == UINT32_MAX) we do not know the number of
|
||||
// frames that we are going to inspect. So we are iterating until there is
|
||||
// no more frames, to settle on the inner most frame and to count the number
|
||||
// of frames.
|
||||
size_t remaining = (frameCount_ != UINT32_MAX) ? frameNo() - 1 : SIZE_MAX;
|
||||
|
||||
size_t i = 1;
|
||||
for (; i <= remaining && si_.moreFrames(); i++) {
|
||||
JS_ASSERT(IsIonInlinablePC(pc_));
|
||||
|
||||
// Recover the number of actual arguments from the script.
|
||||
|
@ -1582,10 +1633,11 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
|
|||
JS_ASSERT(numActualArgs_ != 0xbadbad);
|
||||
|
||||
// Skip over non-argument slots, as well as |this|.
|
||||
unsigned skipCount = (si_.allocations() - 1) - numActualArgs_ - 1;
|
||||
unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1;
|
||||
for (unsigned j = 0; j < skipCount; j++)
|
||||
si_.skip();
|
||||
|
||||
// The JSFunction is a constant, otherwise we would not have inlined it.
|
||||
Value funval = si_.read();
|
||||
|
||||
// Skip extra value allocations.
|
||||
|
@ -1604,6 +1656,14 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
|
|||
pc_ = script_->offsetToPC(si_.pcOffset());
|
||||
}
|
||||
|
||||
// The first time we do not know the number of frames, we only settle on the
|
||||
// last frame, and update the number of frames based on the number of
|
||||
// iteration that we have done.
|
||||
if (frameCount_ == UINT32_MAX) {
|
||||
MOZ_ASSERT(!si_.moreFrames());
|
||||
frameCount_ = i;
|
||||
}
|
||||
|
||||
framesRead_++;
|
||||
}
|
||||
template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
|
||||
|
@ -1804,8 +1864,8 @@ InlineFrameIteratorMaybeGC<allowGC>::dump() const
|
|||
}
|
||||
|
||||
SnapshotIterator si = snapshotIterator();
|
||||
fprintf(stderr, " slots: %u\n", si.allocations() - 1);
|
||||
for (unsigned i = 0; i < si.allocations() - 1; i++) {
|
||||
fprintf(stderr, " slots: %u\n", si.numAllocations() - 1);
|
||||
for (unsigned i = 0; i < si.numAllocations() - 1; i++) {
|
||||
if (isFunction) {
|
||||
if (i == 0)
|
||||
fprintf(stderr, " scope chain: ");
|
||||
|
|
|
@ -5695,12 +5695,12 @@ class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
|
|||
static const size_t RHS = BOX_PIECES;
|
||||
};
|
||||
|
||||
class LFunctionBoundary : public LInstructionHelper<0, 0, 1>
|
||||
class LProfilerStackOp : public LInstructionHelper<0, 0, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(FunctionBoundary)
|
||||
LIR_HEADER(ProfilerStackOp)
|
||||
|
||||
LFunctionBoundary(const LDefinition &temp) {
|
||||
LProfilerStackOp(const LDefinition &temp) {
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
|
@ -5709,15 +5709,15 @@ class LFunctionBoundary : public LInstructionHelper<0, 0, 1>
|
|||
}
|
||||
|
||||
JSScript *script() {
|
||||
return mir_->toFunctionBoundary()->script();
|
||||
return mir_->toProfilerStackOp()->script();
|
||||
}
|
||||
|
||||
MFunctionBoundary::Type type() {
|
||||
return mir_->toFunctionBoundary()->type();
|
||||
MProfilerStackOp::Type type() {
|
||||
return mir_->toProfilerStackOp()->type();
|
||||
}
|
||||
|
||||
unsigned inlineLevel() {
|
||||
return mir_->toFunctionBoundary()->inlineLevel();
|
||||
return mir_->toProfilerStackOp()->inlineLevel();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -119,28 +119,48 @@ TotalOperandCount(MResumePoint *mir)
|
|||
return accum;
|
||||
}
|
||||
|
||||
LRecoverInfo::LRecoverInfo(MResumePoint *mir)
|
||||
: mir_(mir),
|
||||
LRecoverInfo::LRecoverInfo(TempAllocator &alloc)
|
||||
: instructions_(alloc),
|
||||
recoverOffset_(INVALID_RECOVER_OFFSET)
|
||||
{ }
|
||||
|
||||
LRecoverInfo *
|
||||
LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
|
||||
{
|
||||
LRecoverInfo *recover = new(gen->alloc()) LRecoverInfo(mir);
|
||||
if (!recover)
|
||||
LRecoverInfo *recoverInfo = new(gen->alloc()) LRecoverInfo(gen->alloc());
|
||||
if (!recoverInfo || !recoverInfo->init(mir))
|
||||
return nullptr;
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Generating LIR recover %p from MIR (%p)",
|
||||
(void *)recover, (void *)mir);
|
||||
IonSpew(IonSpew_Snapshots, "Generating LIR recover info %p from MIR (%p)",
|
||||
(void *)recoverInfo, (void *)mir);
|
||||
|
||||
return recover;
|
||||
return recoverInfo;
|
||||
}
|
||||
|
||||
LSnapshot::LSnapshot(LRecoverInfo *recover, BailoutKind kind)
|
||||
: numSlots_(TotalOperandCount(recover->mir()) * BOX_PIECES),
|
||||
bool
|
||||
LRecoverInfo::init(MResumePoint *rp)
|
||||
{
|
||||
MResumePoint *it = rp;
|
||||
|
||||
// Sort operations in the order in which we need to restore the stack. This
|
||||
// implies that outer frames, as well as operations needed to recover the
|
||||
// current frame, are located before the current frame. The inner-most
|
||||
// resume point should be the last element in the list.
|
||||
do {
|
||||
if (!instructions_.append(it))
|
||||
return false;
|
||||
it = it->caller();
|
||||
} while (it);
|
||||
|
||||
Reverse(instructions_.begin(), instructions_.end());
|
||||
MOZ_ASSERT(mir() == rp);
|
||||
return true;
|
||||
}
|
||||
|
||||
LSnapshot::LSnapshot(LRecoverInfo *recoverInfo, BailoutKind kind)
|
||||
: numSlots_(TotalOperandCount(recoverInfo->mir()) * BOX_PIECES),
|
||||
slots_(nullptr),
|
||||
recoverInfo_(recover),
|
||||
recoverInfo_(recoverInfo),
|
||||
snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
|
||||
bailoutId_(INVALID_BAILOUT_ID),
|
||||
bailoutKind_(kind)
|
||||
|
|
|
@ -878,18 +878,26 @@ class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
|
|||
|
||||
class LRecoverInfo : public TempObject
|
||||
{
|
||||
MResumePoint *mir_;
|
||||
public:
|
||||
typedef Vector<MResumePoint *, 2, IonAllocPolicy> Instructions;
|
||||
|
||||
private:
|
||||
// List of instructions needed to recover the stack frames.
|
||||
// Outer frames are stored before inner frames.
|
||||
Instructions instructions_;
|
||||
|
||||
// Cached offset where this resume point is encoded.
|
||||
RecoverOffset recoverOffset_;
|
||||
|
||||
LRecoverInfo(MResumePoint *mir);
|
||||
LRecoverInfo(TempAllocator &alloc);
|
||||
bool init(MResumePoint *mir);
|
||||
|
||||
public:
|
||||
static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
|
||||
|
||||
// Resume point of the inner most function.
|
||||
MResumePoint *mir() const {
|
||||
return mir_;
|
||||
return instructions_.back();
|
||||
}
|
||||
RecoverOffset recoverOffset() const {
|
||||
return recoverOffset_;
|
||||
|
@ -898,6 +906,13 @@ class LRecoverInfo : public TempObject
|
|||
JS_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
|
||||
recoverOffset_ = offset;
|
||||
}
|
||||
|
||||
MResumePoint **begin() {
|
||||
return instructions_.begin();
|
||||
}
|
||||
MResumePoint **end() {
|
||||
return instructions_.end();
|
||||
}
|
||||
};
|
||||
|
||||
// An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
|
||||
|
|
|
@ -272,7 +272,7 @@
|
|||
_(CallInstanceOf) \
|
||||
_(InterruptCheck) \
|
||||
_(InterruptCheckImplicit) \
|
||||
_(FunctionBoundary) \
|
||||
_(ProfilerStackOp) \
|
||||
_(GetDOMProperty) \
|
||||
_(GetDOMMember) \
|
||||
_(SetDOMProperty) \
|
||||
|
|
|
@ -3358,9 +3358,9 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
|
|||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitFunctionBoundary(MFunctionBoundary *ins)
|
||||
LIRGenerator::visitProfilerStackOp(MProfilerStackOp *ins)
|
||||
{
|
||||
LFunctionBoundary *lir = new(alloc()) LFunctionBoundary(temp());
|
||||
LProfilerStackOp *lir = new(alloc()) LProfilerStackOp(temp());
|
||||
if (!add(lir, ins))
|
||||
return false;
|
||||
// If slow assertions are enabled, then this node will result in a callVM
|
||||
|
@ -3532,8 +3532,11 @@ bool
|
|||
LIRGenerator::visitGetDOMMember(MGetDOMMember *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
|
||||
MOZ_ASSERT(ins->domAliasSet() == JSJitInfo::AliasNone,
|
||||
"Members had better not alias anything");
|
||||
// We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
|
||||
// but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
|
||||
// value can in fact change as a result of DOM setters and method calls.
|
||||
MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
|
||||
"Member gets had better not alias the world");
|
||||
LGetDOMMember *lir =
|
||||
new(alloc()) LGetDOMMember(useRegister(ins->object()));
|
||||
return defineBox(lir, ins);
|
||||
|
|
|
@ -238,7 +238,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
bool visitInArray(MInArray *ins);
|
||||
bool visitInstanceOf(MInstanceOf *ins);
|
||||
bool visitCallInstanceOf(MCallInstanceOf *ins);
|
||||
bool visitFunctionBoundary(MFunctionBoundary *ins);
|
||||
bool visitProfilerStackOp(MProfilerStackOp *ins);
|
||||
bool visitIsCallable(MIsCallable *ins);
|
||||
bool visitHaveSameClass(MHaveSameClass *ins);
|
||||
bool visitHasClass(MHasClass *ins);
|
||||
|
|
|
@ -9217,15 +9217,15 @@ class MNewStringObject :
|
|||
// Node that represents that a script has begun executing. This comes at the
|
||||
// start of the function and is called once per function (including inline
|
||||
// ones)
|
||||
class MFunctionBoundary : public MNullaryInstruction
|
||||
class MProfilerStackOp : public MNullaryInstruction
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
Enter, // a function has begun executing and it is not inline
|
||||
Exit, // any function has exited (inlined or normal)
|
||||
Inline_Enter, // an inline function has begun executing
|
||||
InlineEnter, // an inline function has begun executing
|
||||
|
||||
Inline_Exit // all instructions of an inline function are done, a
|
||||
InlineExit // all instructions of an inline function are done, a
|
||||
// return from the inline function could have occurred
|
||||
// before this boundary
|
||||
};
|
||||
|
@ -9235,20 +9235,20 @@ class MFunctionBoundary : public MNullaryInstruction
|
|||
Type type_;
|
||||
unsigned inlineLevel_;
|
||||
|
||||
MFunctionBoundary(JSScript *script, Type type, unsigned inlineLevel)
|
||||
MProfilerStackOp(JSScript *script, Type type, unsigned inlineLevel)
|
||||
: script_(script), type_(type), inlineLevel_(inlineLevel)
|
||||
{
|
||||
JS_ASSERT_IF(type != Inline_Exit, script != nullptr);
|
||||
JS_ASSERT_IF(type == Inline_Enter, inlineLevel != 0);
|
||||
JS_ASSERT_IF(type != InlineExit, script != nullptr);
|
||||
JS_ASSERT_IF(type == InlineEnter, inlineLevel != 0);
|
||||
setGuard();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(FunctionBoundary)
|
||||
INSTRUCTION_HEADER(ProfilerStackOp)
|
||||
|
||||
static MFunctionBoundary *New(TempAllocator &alloc, JSScript *script, Type type,
|
||||
static MProfilerStackOp *New(TempAllocator &alloc, JSScript *script, Type type,
|
||||
unsigned inlineLevel = 0) {
|
||||
return new(alloc) MFunctionBoundary(script, type, inlineLevel);
|
||||
return new(alloc) MProfilerStackOp(script, type, inlineLevel);
|
||||
}
|
||||
|
||||
JSScript *script() {
|
||||
|
@ -9425,44 +9425,8 @@ class MResumePoint MOZ_FINAL : public MNode, public InlineForwardListNode<MResum
|
|||
operands_[i].producer()->removeUse(&operands_[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Facade for a chain of MResumePoints that cross frame boundaries (due to
|
||||
* function inlining). Operands are ordered from oldest frame to newest.
|
||||
*/
|
||||
class FlattenedMResumePointIter
|
||||
{
|
||||
Vector<MResumePoint *, 8, SystemAllocPolicy> resumePoints;
|
||||
MResumePoint *newest;
|
||||
size_t numOperands_;
|
||||
|
||||
public:
|
||||
explicit FlattenedMResumePointIter(MResumePoint *newest)
|
||||
: newest(newest), numOperands_(0)
|
||||
{}
|
||||
|
||||
bool init() {
|
||||
MResumePoint *it = newest;
|
||||
do {
|
||||
if (!resumePoints.append(it))
|
||||
return false;
|
||||
it = it->caller();
|
||||
} while (it);
|
||||
Reverse(resumePoints.begin(), resumePoints.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
MResumePoint **begin() {
|
||||
return resumePoints.begin();
|
||||
}
|
||||
MResumePoint **end() {
|
||||
return resumePoints.end();
|
||||
}
|
||||
|
||||
size_t numOperands() const {
|
||||
return numOperands_;
|
||||
}
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
};
|
||||
|
||||
class MIsCallable
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace jit {
|
|||
_(InstanceOf) \
|
||||
_(CallInstanceOf) \
|
||||
_(InterruptCheck) \
|
||||
_(FunctionBoundary) \
|
||||
_(ProfilerStackOp) \
|
||||
_(GetDOMProperty) \
|
||||
_(GetDOMMember) \
|
||||
_(SetDOMProperty) \
|
||||
|
|
|
@ -291,7 +291,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
|||
UNSAFE_OP(RegExpReplace)
|
||||
UNSAFE_OP(StringReplace)
|
||||
UNSAFE_OP(CallInstanceOf)
|
||||
UNSAFE_OP(FunctionBoundary)
|
||||
UNSAFE_OP(ProfilerStackOp)
|
||||
UNSAFE_OP(GuardString)
|
||||
UNSAFE_OP(NewDeclEnvObject)
|
||||
UNSAFE_OP(In)
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/Recover.h"
|
||||
|
||||
#include "jit/IonSpewer.h"
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
void
|
||||
RInstruction::readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw)
|
||||
{
|
||||
uint32_t op = reader.readUnsigned();
|
||||
switch (Opcode(op)) {
|
||||
case Recover_ResumePoint:
|
||||
new (raw->addr()) RResumePoint(reader);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Bad decoding of the previous instruction?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MResumePoint::writeRecoverData(CompactBufferWriter &writer) const
|
||||
{
|
||||
writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
|
||||
|
||||
MBasicBlock *bb = block();
|
||||
JSFunction *fun = bb->info().funMaybeLazy();
|
||||
JSScript *script = bb->info().script();
|
||||
uint32_t exprStack = stackDepth() - bb->info().ninvoke();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Ensure that all snapshot which are encoded can safely be used for
|
||||
// bailouts.
|
||||
if (GetIonContext()->cx) {
|
||||
uint32_t stackDepth;
|
||||
bool reachablePC;
|
||||
jsbytecode *bailPC = pc();
|
||||
|
||||
if (mode() == MResumePoint::ResumeAfter)
|
||||
bailPC = GetNextPc(pc());
|
||||
|
||||
if (!ReconstructStackDepth(GetIonContext()->cx, script,
|
||||
bailPC, &stackDepth, &reachablePC))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reachablePC) {
|
||||
if (JSOp(*bailPC) == JSOP_FUNCALL) {
|
||||
// For fun.call(this, ...); the reconstructStackDepth will
|
||||
// include the this. When inlining that is not included. So the
|
||||
// exprStackSlots will be one less.
|
||||
MOZ_ASSERT(stackDepth - exprStack <= 1);
|
||||
} else if (JSOp(*bailPC) != JSOP_FUNAPPLY &&
|
||||
!IsGetPropPC(bailPC) && !IsSetPropPC(bailPC))
|
||||
{
|
||||
// For fun.apply({}, arguments) the reconstructStackDepth will
|
||||
// have stackdepth 4, but it could be that we inlined the
|
||||
// funapply. In that case exprStackSlots, will have the real
|
||||
// arguments in the slots and not be 4.
|
||||
|
||||
// With accessors, we have different stack depths depending on
|
||||
// whether or not we inlined the accessor, as the inlined stack
|
||||
// contains a callee function that should never have been there
|
||||
// and we might just be capturing an uneventful property site,
|
||||
// in which case there won't have been any violence.
|
||||
MOZ_ASSERT(exprStack == stackDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test if we honor the maximum of arguments at all times. This is a sanity
|
||||
// check and not an algorithm limit. So check might be a bit too loose. +4
|
||||
// to account for scope chain, return value, this value and maybe
|
||||
// arguments_object.
|
||||
MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4);
|
||||
|
||||
uint32_t implicit = StartArgSlot(script);
|
||||
uint32_t formalArgs = CountArgSlots(script, fun);
|
||||
uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
|
||||
implicit, formalArgs - implicit, script->nfixed(), exprStack);
|
||||
|
||||
uint32_t pcoff = script->pcToOffset(pc());
|
||||
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
|
||||
writer.writeUnsigned(pcoff);
|
||||
writer.writeUnsigned(nallocs);
|
||||
return true;
|
||||
}
|
||||
|
||||
RResumePoint::RResumePoint(CompactBufferReader &reader)
|
||||
{
|
||||
static_assert(sizeof(*this) <= sizeof(RInstructionStorage),
|
||||
"Storage space is too small to decode this recover instruction.");
|
||||
pcOffset_ = reader.readUnsigned();
|
||||
numOperands_ = reader.readUnsigned();
|
||||
IonSpew(IonSpew_Snapshots, "Read RResumePoint (pc offset %u, nslots %u)",
|
||||
pcOffset_, numOperands_);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* -*- 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 jit_Recover_h
|
||||
#define jit_Recover_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class RResumePoint;
|
||||
|
||||
class RInstruction
|
||||
{
|
||||
public:
|
||||
enum Opcode
|
||||
{
|
||||
Recover_ResumePoint = 0
|
||||
};
|
||||
|
||||
virtual Opcode opcode() const = 0;
|
||||
|
||||
bool isResumePoint() const {
|
||||
return opcode() == Recover_ResumePoint;
|
||||
}
|
||||
inline const RResumePoint *toResumePoint() const;
|
||||
|
||||
virtual uint32_t numOperands() const = 0;
|
||||
|
||||
static void readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw);
|
||||
};
|
||||
|
||||
class RResumePoint MOZ_FINAL : public RInstruction
|
||||
{
|
||||
private:
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t numOperands_; // Number of slots.
|
||||
|
||||
friend class RInstruction;
|
||||
RResumePoint(CompactBufferReader &reader);
|
||||
|
||||
public:
|
||||
virtual Opcode opcode() const {
|
||||
return Recover_ResumePoint;
|
||||
}
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
}
|
||||
virtual uint32_t numOperands() const {
|
||||
return numOperands_;
|
||||
}
|
||||
};
|
||||
|
||||
const RResumePoint *
|
||||
RInstruction::toResumePoint() const
|
||||
{
|
||||
MOZ_ASSERT(isResumePoint());
|
||||
return static_cast<const RResumePoint *>(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jit_Recover_h */
|
|
@ -12,8 +12,9 @@
|
|||
#include "jit/IonSpewer.h"
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
# include "jit/LIR.h"
|
||||
# include "jit/MIR.h"
|
||||
#endif
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/Recover.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
@ -481,9 +482,9 @@ static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
|
|||
static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
|
||||
static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
|
||||
|
||||
static const uint32_t RECOVER_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
|
||||
static const uint32_t RECOVER_FRAMECOUNT_BITS = 32 - RECOVER_FRAMECOUNT_SHIFT;
|
||||
static const uint32_t RECOVER_FRAMECOUNT_MASK = COMPUTE_MASK_(RECOVER_FRAMECOUNT);
|
||||
static const uint32_t RECOVER_RINSCOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
|
||||
static const uint32_t RECOVER_RINSCOUNT_BITS = 32 - RECOVER_RINSCOUNT_SHIFT;
|
||||
static const uint32_t RECOVER_RINSCOUNT_MASK = COMPUTE_MASK_(RECOVER_RINSCOUNT);
|
||||
|
||||
#undef COMPUTE_MASK_
|
||||
#undef COMPUTE_SHIFT_AFTER_
|
||||
|
@ -530,13 +531,18 @@ SnapshotReader::spewBailingFrom() const
|
|||
}
|
||||
#endif
|
||||
|
||||
uint32_t
|
||||
SnapshotReader::readAllocationIndex()
|
||||
{
|
||||
allocRead_++;
|
||||
return reader_.readUnsigned();
|
||||
}
|
||||
|
||||
RValueAllocation
|
||||
SnapshotReader::readAllocation()
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
|
||||
allocRead_++;
|
||||
|
||||
uint32_t offset = reader_.readUnsigned() * ALLOCATION_TABLE_ALIGNMENT;
|
||||
uint32_t offset = readAllocationIndex() * ALLOCATION_TABLE_ALIGNMENT;
|
||||
allocReader_.seek(allocTable_, offset);
|
||||
return RValueAllocation::read(allocReader_);
|
||||
}
|
||||
|
@ -552,15 +558,14 @@ SnapshotWriter::init()
|
|||
|
||||
RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
|
||||
: reader_(nullptr, nullptr),
|
||||
frameCount_(0),
|
||||
framesRead_(0),
|
||||
allocCount_(0)
|
||||
numInstructions_(0),
|
||||
numInstructionsRead_(0)
|
||||
{
|
||||
if (!recovers)
|
||||
return;
|
||||
reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
|
||||
readRecoverHeader();
|
||||
readFrame(snapshot);
|
||||
readInstruction();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -568,26 +573,20 @@ RecoverReader::readRecoverHeader()
|
|||
{
|
||||
uint32_t bits = reader_.readUnsigned();
|
||||
|
||||
frameCount_ = (bits & RECOVER_FRAMECOUNT_MASK) >> RECOVER_FRAMECOUNT_SHIFT;
|
||||
numInstructions_ = (bits & RECOVER_RINSCOUNT_MASK) >> RECOVER_RINSCOUNT_SHIFT;
|
||||
resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
|
||||
JS_ASSERT(frameCount_);
|
||||
MOZ_ASSERT(numInstructions_);
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Read recover header with frameCount %u (ra: %d)",
|
||||
frameCount_, resumeAfter_);
|
||||
IonSpew(IonSpew_Snapshots, "Read recover header with instructionCount %u (ra: %d)",
|
||||
numInstructions_, resumeAfter_);
|
||||
}
|
||||
|
||||
void
|
||||
RecoverReader::readFrame(SnapshotReader &snapshot)
|
||||
RecoverReader::readInstruction()
|
||||
{
|
||||
JS_ASSERT(moreFrames());
|
||||
JS_ASSERT(snapshot.allocRead_ == allocCount_);
|
||||
|
||||
pcOffset_ = reader_.readUnsigned();
|
||||
allocCount_ = reader_.readUnsigned();
|
||||
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
|
||||
|
||||
framesRead_++;
|
||||
snapshot.allocRead_ = 0;
|
||||
MOZ_ASSERT(moreInstructions());
|
||||
RInstruction::readRecoverData(reader_, &rawData_);
|
||||
numInstructionsRead_++;
|
||||
}
|
||||
|
||||
SnapshotOffset
|
||||
|
@ -673,37 +672,23 @@ RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
|
|||
frameCount);
|
||||
|
||||
MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
|
||||
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_FRAMECOUNT_BITS));
|
||||
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS));
|
||||
uint32_t bits =
|
||||
(uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
|
||||
(frameCount << RECOVER_FRAMECOUNT_SHIFT);
|
||||
(frameCount << RECOVER_RINSCOUNT_SHIFT);
|
||||
|
||||
RecoverOffset recoverOffset = writer_.length();
|
||||
writer_.writeUnsigned(bits);
|
||||
return recoverOffset;
|
||||
}
|
||||
|
||||
void
|
||||
RecoverWriter::writeFrame(JSFunction *fun, JSScript *script,
|
||||
jsbytecode *pc, uint32_t exprStack)
|
||||
bool
|
||||
RecoverWriter::writeFrame(const MResumePoint *rp)
|
||||
{
|
||||
// Test if we honor the maximum of arguments at all times.
|
||||
// This is a sanity check and not an algorithm limit. So check might be a bit too loose.
|
||||
// +4 to account for scope chain, return value, this value and maybe arguments_object.
|
||||
JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4);
|
||||
|
||||
uint32_t implicit = StartArgSlot(script);
|
||||
uint32_t formalArgs = CountArgSlots(script, fun);
|
||||
uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
|
||||
implicit, formalArgs - implicit, script->nfixed(), exprStack);
|
||||
|
||||
uint32_t pcoff = script->pcToOffset(pc);
|
||||
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
|
||||
writer_.writeUnsigned(pcoff);
|
||||
writer_.writeUnsigned(nallocs);
|
||||
if (!rp->writeRecoverData(writer_))
|
||||
return false;
|
||||
framesWritten_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef jit_Snapshot_h
|
||||
#define jit_Snapshot_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jsbytecode.h"
|
||||
|
||||
|
@ -308,7 +310,6 @@ class RecoverWriter;
|
|||
// memory after code generation.
|
||||
class SnapshotWriter
|
||||
{
|
||||
friend class RecoverWriter;
|
||||
CompactBufferWriter writer_;
|
||||
CompactBufferWriter allocWriter_;
|
||||
|
||||
|
@ -359,6 +360,8 @@ class SnapshotWriter
|
|||
}
|
||||
};
|
||||
|
||||
class MResumePoint;
|
||||
|
||||
class RecoverWriter
|
||||
{
|
||||
CompactBufferWriter writer_;
|
||||
|
@ -369,7 +372,7 @@ class RecoverWriter
|
|||
public:
|
||||
SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter);
|
||||
|
||||
void writeFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
|
||||
bool writeFrame(const MResumePoint *rp);
|
||||
|
||||
void endRecover();
|
||||
|
||||
|
@ -393,8 +396,6 @@ class RecoverReader;
|
|||
// recover the corresponding Value from an Ion frame.
|
||||
class SnapshotReader
|
||||
{
|
||||
friend class RecoverReader;
|
||||
|
||||
CompactBufferReader reader_;
|
||||
CompactBufferReader allocReader_;
|
||||
const uint8_t* allocTable_;
|
||||
|
@ -418,13 +419,16 @@ class SnapshotReader
|
|||
|
||||
private:
|
||||
void readSnapshotHeader();
|
||||
void readFrameHeader();
|
||||
uint32_t readAllocationIndex();
|
||||
|
||||
public:
|
||||
SnapshotReader(const uint8_t *snapshots, uint32_t offset,
|
||||
uint32_t RVATableSize, uint32_t listSize);
|
||||
|
||||
RValueAllocation readAllocation();
|
||||
void skipAllocation() {
|
||||
readAllocationIndex();
|
||||
}
|
||||
|
||||
BailoutKind bailoutKind() const {
|
||||
return bailoutKind_;
|
||||
|
@ -432,48 +436,57 @@ class SnapshotReader
|
|||
RecoverOffset recoverOffset() const {
|
||||
return recoverOffset_;
|
||||
}
|
||||
|
||||
uint32_t numAllocationsRead() const {
|
||||
return allocRead_;
|
||||
}
|
||||
void resetNumAllocationsRead() {
|
||||
allocRead_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef mozilla::AlignedStorage<4 * sizeof(uint32_t)> RInstructionStorage;
|
||||
class RInstruction;
|
||||
|
||||
class RecoverReader
|
||||
{
|
||||
CompactBufferReader reader_;
|
||||
|
||||
uint32_t frameCount_;
|
||||
uint32_t framesRead_; // Number of frame headers that have been read.
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t allocCount_; // Number of slots.
|
||||
// Number of encoded instructions.
|
||||
uint32_t numInstructions_;
|
||||
|
||||
// Number of instruction read.
|
||||
uint32_t numInstructionsRead_;
|
||||
|
||||
// True if we need to resume after the Resume Point instruction of the
|
||||
// innermost frame.
|
||||
bool resumeAfter_;
|
||||
|
||||
// Space is reserved as part of the RecoverReader to avoid allocations of
|
||||
// data which is needed to decode the current instruction.
|
||||
RInstructionStorage rawData_;
|
||||
|
||||
private:
|
||||
void readRecoverHeader();
|
||||
void readFrame(SnapshotReader &snapshot);
|
||||
void readInstruction();
|
||||
|
||||
public:
|
||||
RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
|
||||
|
||||
bool moreFrames() const {
|
||||
return framesRead_ < frameCount_;
|
||||
bool moreInstructions() const {
|
||||
return numInstructionsRead_ < numInstructions_;
|
||||
}
|
||||
void nextFrame(SnapshotReader &snapshot) {
|
||||
readFrame(snapshot);
|
||||
}
|
||||
uint32_t frameCount() const {
|
||||
return frameCount_;
|
||||
void nextInstruction() {
|
||||
readInstruction();
|
||||
}
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
const RInstruction *instruction() const {
|
||||
return reinterpret_cast<const RInstruction *>(rawData_.addr());
|
||||
}
|
||||
|
||||
bool resumeAfter() const {
|
||||
return resumeAfter_;
|
||||
}
|
||||
|
||||
uint32_t allocations() const {
|
||||
return allocCount_;
|
||||
}
|
||||
bool moreAllocations(const SnapshotReader &snapshot) const {
|
||||
return snapshot.allocRead_ < allocCount_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,25 @@
|
|||
#include "jit/AsmJS.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int64_t
|
||||
__aeabi_idivmod(int x, int y)
|
||||
{
|
||||
uint32_t lo = uint32_t(x / y);
|
||||
uint32_t hi = uint32_t(x % y);
|
||||
return (int64_t(hi) << 32) | lo;
|
||||
}
|
||||
|
||||
int64_t
|
||||
__aeabi_uidivmod(int x, int y)
|
||||
{
|
||||
uint32_t lo = uint32_t(x) / uint32_t(y);
|
||||
uint32_t hi = uint32_t(x) % uint32_t(y);
|
||||
return (int64_t(hi) << 32) | lo;
|
||||
}
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
|
@ -4271,22 +4290,3 @@ JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
|
|||
MOZ_ASSERT(!simulatorRuntime_);
|
||||
simulatorRuntime_ = srt;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int64_t
|
||||
__aeabi_idivmod(int x, int y)
|
||||
{
|
||||
uint32_t lo = uint32_t(x / y);
|
||||
uint32_t hi = uint32_t(x % y);
|
||||
return (int64_t(hi) << 32) | lo;
|
||||
}
|
||||
|
||||
int64_t
|
||||
__aeabi_uidivmod(int x, int y)
|
||||
{
|
||||
uint32_t lo = uint32_t(x) / uint32_t(y);
|
||||
uint32_t hi = uint32_t(x) % uint32_t(y);
|
||||
return (int64_t(hi) << 32) | lo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,63 +250,12 @@ CodeGeneratorShared::encode(LRecoverInfo *recover)
|
|||
|
||||
RecoverOffset offset = recovers_.startRecover(frameCount, resumeAfter);
|
||||
|
||||
FlattenedMResumePointIter mirOperandIter(recover->mir());
|
||||
if (!mirOperandIter.init())
|
||||
return false;
|
||||
|
||||
for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
|
||||
for (MResumePoint **it = recover->begin(), **end = recover->end();
|
||||
it != end;
|
||||
++it)
|
||||
{
|
||||
MResumePoint *mir = *it;
|
||||
MBasicBlock *block = mir->block();
|
||||
JSFunction *fun = block->info().funMaybeLazy();
|
||||
JSScript *script = block->info().script();
|
||||
jsbytecode *pc = mir->pc();
|
||||
uint32_t exprStack = mir->stackDepth() - block->info().ninvoke();
|
||||
recovers_.writeFrame(fun, script, pc, exprStack);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Ensure that all snapshot which are encoded can safely be used for
|
||||
// bailouts.
|
||||
if (GetIonContext()->cx) {
|
||||
uint32_t stackDepth;
|
||||
bool reachablePC;
|
||||
jsbytecode *bailPC = pc;
|
||||
|
||||
if (mir->mode() == MResumePoint::ResumeAfter)
|
||||
bailPC = GetNextPc(pc);
|
||||
|
||||
if (!ReconstructStackDepth(GetIonContext()->cx, script,
|
||||
bailPC, &stackDepth, &reachablePC))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reachablePC) {
|
||||
if (JSOp(*bailPC) == JSOP_FUNCALL) {
|
||||
// For fun.call(this, ...); the reconstructStackDepth will
|
||||
// include the this. When inlining that is not included.
|
||||
// So the exprStackSlots will be one less.
|
||||
JS_ASSERT(stackDepth - exprStack <= 1);
|
||||
} else if (JSOp(*bailPC) != JSOP_FUNAPPLY &&
|
||||
!IsGetPropPC(bailPC) && !IsSetPropPC(bailPC))
|
||||
{
|
||||
// For fun.apply({}, arguments) the reconstructStackDepth will
|
||||
// have stackdepth 4, but it could be that we inlined the
|
||||
// funapply. In that case exprStackSlots, will have the real
|
||||
// arguments in the slots and not be 4.
|
||||
|
||||
// With accessors, we have different stack depths depending on
|
||||
// whether or not we inlined the accessor, as the inlined stack
|
||||
// contains a callee function that should never have been there
|
||||
// and we might just be capturing an uneventful property site, in
|
||||
// which case there won't have been any violence.
|
||||
JS_ASSERT(exprStack == stackDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!recovers_.writeFrame(*it))
|
||||
return false;
|
||||
}
|
||||
|
||||
recovers_.endRecover();
|
||||
|
@ -320,14 +269,15 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
|
|||
if (snapshot->snapshotOffset() != INVALID_SNAPSHOT_OFFSET)
|
||||
return true;
|
||||
|
||||
if (!encode(snapshot->recoverInfo()))
|
||||
LRecoverInfo *recoverInfo = snapshot->recoverInfo();
|
||||
if (!encode(recoverInfo))
|
||||
return false;
|
||||
|
||||
RecoverOffset recoverOffset = snapshot->recoverInfo()->recoverOffset();
|
||||
RecoverOffset recoverOffset = recoverInfo->recoverOffset();
|
||||
MOZ_ASSERT(recoverOffset != INVALID_RECOVER_OFFSET);
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (LRecoverInfo %p)",
|
||||
(void *)snapshot, (void*) snapshot->recoverInfo());
|
||||
IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (LRecover %p)",
|
||||
(void *)snapshot, (void*) recoverInfo);
|
||||
|
||||
SnapshotOffset offset = snapshots_.startSnapshot(recoverOffset, snapshot->bailoutKind());
|
||||
|
||||
|
@ -351,12 +301,8 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
|
|||
snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
|
||||
#endif
|
||||
|
||||
FlattenedMResumePointIter mirOperandIter(snapshot->recoverInfo()->mir());
|
||||
if (!mirOperandIter.init())
|
||||
return false;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
|
||||
for (MResumePoint **it = recoverInfo->begin(), **end = recoverInfo->end();
|
||||
it != end;
|
||||
++it)
|
||||
{
|
||||
|
|
|
@ -63,6 +63,9 @@ LIRGeneratorShared::getRecoverInfo(MResumePoint *rp)
|
|||
return cachedRecoverInfo_;
|
||||
|
||||
LRecoverInfo *recoverInfo = LRecoverInfo::New(gen, rp);
|
||||
if (!recoverInfo)
|
||||
return nullptr;
|
||||
|
||||
cachedRecoverInfo_ = recoverInfo;
|
||||
return recoverInfo;
|
||||
}
|
||||
|
@ -79,12 +82,8 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
|
|||
if (!snapshot)
|
||||
return nullptr;
|
||||
|
||||
FlattenedMResumePointIter iter(rp);
|
||||
if (!iter.init())
|
||||
return nullptr;
|
||||
|
||||
size_t i = 0;
|
||||
for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) {
|
||||
for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) {
|
||||
MResumePoint *mir = *it;
|
||||
for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) {
|
||||
MDefinition *ins = mir->getOperand(j);
|
||||
|
@ -137,12 +136,8 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
|
|||
if (!snapshot)
|
||||
return nullptr;
|
||||
|
||||
FlattenedMResumePointIter iter(rp);
|
||||
if (!iter.init())
|
||||
return nullptr;
|
||||
|
||||
size_t i = 0;
|
||||
for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) {
|
||||
for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) {
|
||||
MResumePoint *mir = *it;
|
||||
for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) {
|
||||
MDefinition *def = mir->getOperand(j);
|
||||
|
|
|
@ -281,6 +281,7 @@ if CONFIG['ENABLE_ION']:
|
|||
'jit/ParallelSafetyAnalysis.cpp',
|
||||
'jit/PerfSpewer.cpp',
|
||||
'jit/RangeAnalysis.cpp',
|
||||
'jit/Recover.cpp',
|
||||
'jit/RegisterAllocator.cpp',
|
||||
'jit/Safepoints.cpp',
|
||||
'jit/shared/BaselineCompiler-shared.cpp',
|
||||
|
|
|
@ -1376,7 +1376,7 @@ FrameIter::numFrameSlots() const
|
|||
case JIT: {
|
||||
#ifdef JS_ION
|
||||
if (data_.ionFrames_.isIonJS()) {
|
||||
return ionInlineFrames_.snapshotIterator().allocations() -
|
||||
return ionInlineFrames_.snapshotIterator().numAllocations() -
|
||||
ionInlineFrames_.script()->nfixed();
|
||||
}
|
||||
jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame();
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче