This commit is contained in:
Ryan VanderMeulen 2015-09-01 21:22:15 -04:00
Родитель b963a8d796 288dfa7ea3
Коммит 0040548882
153 изменённых файлов: 2501 добавлений и 1365 удалений

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "c2582f4be03cd12124b96a263c8d14c774f0ffe4",
"git_revision": "b75979ec8862bd5799a7c42e938d3f67be38d6ae",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "a330673cd99b4f50094fb7dd14000efdb9cf81b4",
"revision": "f919c5b5f0f0b6fd3ef3346850710edafa2a615b",
"repo_path": "integration/gaia-central"
}

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2582f4be03cd12124b96a263c8d14c774f0ffe4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b75979ec8862bd5799a7c42e938d3f67be38d6ae"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -5458,23 +5458,30 @@
// to get a full-resolution drag image for use on HiDPI displays.
let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils);
let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom;
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
let canvas = this._dndCanvas ? this._dndCanvas
: document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
canvas.mozOpaque = true;
canvas.width = 160 * scale;
canvas.height = 90 * scale;
let toDrag;
if (gMultiProcessBrowser) {
var context = canvas.getContext('2d');
context.fillStyle = "white";
context.fillRect(0, 0, canvas.width, canvas.height);
// Create a panel to use it in setDragImage
// which will tell xul to render a panel that follows
// the pointer while a dnd session is on.
var panel = document.createElement("panel");
panel.setAttribute("type", "drag");
panel.appendChild(canvas);
document.documentElement.appendChild(panel);
if (!this._dndPanel) {
this._dndCanvas = canvas;
this._dndPanel = document.createElement("panel");
this._dndPanel.setAttribute("type", "drag");
this._dndPanel.appendChild(canvas);
document.documentElement.appendChild(this._dndPanel);
}
// PageThumb is async with e10s but that's fine
// since we can update the panel during the dnd.
PageThumbs.captureToCanvas(browser, canvas);
toDrag = panel;
toDrag = this._dndPanel;
} else {
// For the non e10s case we can just use PageThumbs
// sync. No need for xul magic, the native dnd will

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

@ -50,7 +50,7 @@ nsEdgeReadingListExtractor::Extract(const nsAString& aDBPath, nsIArray** aItems)
// the right things
bool instanceCreated, sessionCreated, dbOpened, tableOpened;
char16_t* dbPath = ToNewUnicode(aDBPath);
char16ptr_t dbPath = ToNewUnicode(aDBPath);
// Check for the right page size and initialize with that
unsigned long pageSize;

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

@ -103,17 +103,23 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
return NS_ERROR_FAILURE;
}
if (aWindow) {
nsCOMPtr<nsPIDOMWindow> pInnerWindow = do_QueryInterface(aWindow);
MOZ_ASSERT(pInnerWindow->IsInnerWindow());
mInnerWindowID = pInnerWindow->WindowID();
if (NS_WARN_IF(!aWindow)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMWindow> topWindow;
aWindow->GetScriptableTop(getter_AddRefs(topWindow));
mWindow = do_QueryInterface(topWindow);
if (mWindow) {
mWindow = mWindow->GetOuterWindow();
}
nsCOMPtr<nsPIDOMWindow> pInnerWindow = do_QueryInterface(aWindow);
MOZ_ASSERT(pInnerWindow->IsInnerWindow());
mInnerWindowID = pInnerWindow->WindowID();
nsCOMPtr<nsIDOMWindow> topWindow;
aWindow->GetScriptableTop(getter_AddRefs(topWindow));
mWindow = do_QueryInterface(topWindow);
if (mWindow) {
mWindow = mWindow->GetOuterWindow();
}
if (!mWindow) {
return NS_ERROR_FAILURE;
}
mAudioChannelType = aChannelType;
@ -134,6 +140,13 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(uint32_t aNotifyPlayback,
MOZ_ASSERT(aVolume);
MOZ_ASSERT(aMuted);
// Window-less AudioChannelAgents are muted by default.
if (!mWindow) {
*aVolume = 0;
*aMuted = true;
return NS_OK;
}
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
service == nullptr || mIsRegToService) {

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

@ -11,6 +11,7 @@
#include "nsAttrAndChildArray.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
@ -23,6 +24,8 @@
#include "nsAutoPtr.h"
#include "nsContentUtils.h" // nsAutoScriptBlocker
using mozilla::CheckedUint32;
/*
CACHE_POINTER_SHIFT indicates how many steps to downshift the |this| pointer.
It should be small enough to not cause collisions between adjecent arrays, and

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

@ -1591,6 +1591,18 @@ nsIDocument::~nsIDocument()
UnlinkOriginalDocumentIfStatic();
}
bool
nsDocument::IsAboutPage()
{
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
bool isAboutScheme = true;
if (uri) {
uri->SchemeIs("about", &isAboutScheme);
}
return isAboutScheme;
}
nsDocument::~nsDocument()
{
@ -1608,15 +1620,7 @@ nsDocument::~nsDocument()
if (IsTopLevelContentDocument()) {
//don't report for about: pages
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
bool isAboutScheme = true;
if (uri) {
uri->SchemeIs("about", &isAboutScheme);
}
if (!isAboutScheme) {
if (!IsAboutPage()) {
// Record the page load
uint32_t pageLoaded = 1;
Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER, pageLoaded);
@ -7900,9 +7904,10 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
CSSToScreenScale defaultScale = layoutDeviceScale
* LayoutDeviceToScreenScale(1.0);
// Get requested Desktopmode
// Special behaviour for desktop mode, provided we are not on an about: page
nsPIDOMWindow* win = GetWindow();
if (win && win->IsDesktopModeViewport())
if (win && win->IsDesktopModeViewport() && !IsAboutPage())
{
float viewportWidth = gfxPrefs::DesktopViewportWidth() / fullZoom;
float scaleToFit = aDisplaySize.width / viewportWidth;

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

@ -1770,6 +1770,9 @@ private:
// requestAnimationFrame, if it's OK to do so.
void MaybeRescheduleAnimationFrameNotifications();
// Returns true if the scheme for the url for this document is "about"
bool IsAboutPage();
// These are not implemented and not supported.
nsDocument(const nsDocument& aOther);
nsDocument& operator=(const nsDocument& aOther);

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

@ -23,7 +23,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=416317
<script class="testbody" type="text/javascript">
/** Test for Bug 416317 **/
SimpleTest.requestLongerTimeout(2);
SimpleTest.requestLongerTimeout(3);
// Subframe handles the test
</script>
</pre>

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

@ -6,6 +6,7 @@
#include "pk11pub.h"
#include "cryptohi.h"
#include "nsNSSComponent.h"
#include "ScopedNSSTypes.h"
#include "mozilla/dom/CryptoKey.h"
#include "mozilla/dom/WebCryptoCommon.h"
@ -1249,6 +1250,11 @@ CryptoKey::ReadStructuredClone(JSStructuredCloneReader* aReader)
return false;
}
// Ensure that NSS is initialized.
if (!EnsureNSSInitializedChromeOrContent()) {
return false;
}
uint32_t version;
CryptoBuffer sym, priv, pub;

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

@ -25,6 +25,7 @@ FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/security/manager/ssl',
'/security/pkix/include',
]
MOCHITEST_MANIFESTS += ['test/mochitest.ini']

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

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bug 1188750 - WebCrypto must ensure NSS is initialized before deserializing</title>
</head>
<body>
<script type="application/javascript;version=1.8">
let db;
function err(resolve) {
return e => resolve(e.target.error.message);
}
function openDatabase() {
return new Promise((resolve, reject) => {
let request = indexedDB.open("keystore", 1);
request.onerror = err(reject);
request.onsuccess = function (event) {
db = event.target.result;
resolve();
};
request.onupgradeneeded = function(event) {
db = event.target.result;
let objectStore = db.createObjectStore("keys", {autoIncrement: true});
objectStore.transaction.oncomplete = resolve;
};
});
}
function storeKey(key) {
return new Promise((resolve, reject) => {
let transaction = db.transaction("keys", "readwrite");
transaction.objectStore("keys").put(key, key.type);
transaction.onabort = err(reject);
transaction.onerror = err(reject);
transaction.oncomplete = function () {
resolve(key);
};
});
};
function retrieveKey() {
return new Promise((resolve, reject) => {
let transaction = db.transaction("keys", "readonly");
let cursor = transaction.objectStore("keys").openCursor();
cursor.onerror = err(reject);
cursor.onabort = err(reject);
cursor.onsuccess = function (event) {
try {
let result = event.target.result;
resolve(result && result.value);
} catch (e) {
reject(e.message);
}
};
});
}
function generateKey() {
let algorithm = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
modulusLength: 1024,
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
};
return crypto.subtle.generateKey(algorithm, true, ["sign", "verify"]);
}
openDatabase()
.then(retrieveKey).then(generateKey).then(storeKey)
.then(() => alert("ok")).catch(alert);
</script>
</body>
</html>

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

@ -2,11 +2,14 @@
# Bug 1010743 - Re-enable WebCrypto tests on b2g
skip-if = (buildapp == 'b2g')
support-files =
file_indexedDB.html
test-array.js
test-vectors.js
test_WebCrypto.css
util.js
[test_indexedDB.html]
skip-if = toolkit == 'android' # bug 1200570
[test_WebCrypto.html]
[test_WebCrypto_DH.html]
[test_WebCrypto_ECDH.html]

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

@ -0,0 +1,60 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Bug 1188750 - WebCrypto must ensure NSS is initialized before deserializing</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"?>
</head>
<body>
<script type="application/javascript;version=1.8">
/*
* Bug 1188750 - The WebCrypto API must ensure that NSS was initialized
* for the current process before trying to deserialize objects like
* CryptoKeys from e.g. IndexedDB.
*/
"use strict";
const TEST_URI = "http://www.example.com/tests/" +
"dom/crypto/test/file_indexedDB.html";
SimpleTest.waitForExplicitFinish();
function createMozBrowserFrame(cb) {
let frame = document.createElement("iframe");
SpecialPowers.wrap(frame).mozbrowser = true;
frame.src = TEST_URI;
frame.addEventListener("mozbrowsershowmodalprompt", function onPrompt(e) {
frame.removeEventListener("mozbrowsershowmodalprompt", onPrompt);
cb(frame, e.detail.message);
});
document.body.appendChild(frame);
}
function runTest() {
// Load the test app once, to generate and store keys.
createMozBrowserFrame((frame, result) => {
is(result, "ok", "stored keys successfully");
frame.remove();
// Load the test app again to retrieve stored keys.
createMozBrowserFrame((frame, result) => {
is(result, "ok", "retrieved keys successfully");
frame.remove();
SimpleTest.finish();
});
});
}
addEventListener("load", function () {
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.pushPrefEnv({set: [
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true]
]}, runTest);
});
</script>
</body>
</html>

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

@ -206,8 +206,9 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
return context;
}
// static
bool
InternalRequest::IsNavigationRequest() const
InternalRequest::IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType)
{
// https://fetch.spec.whatwg.org/#navigation-request-context
//
@ -215,17 +216,22 @@ InternalRequest::IsNavigationRequest() const
// "iframe", "internal" (as long as context frame type is not "none"),
// "location", "metarefresh", and "prerender".
//
// TODO: include equivalent check for "form" context
// TODO: include equivalent check for "prerender" context
return mContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
mContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
mContentPolicyType == nsIContentPolicy::TYPE_REFRESH;
// Note, all of these request types are effectively initiated by nsDocShell.
//
// The TYPE_REFRESH is used in some code paths for metarefresh, but will not
// be seen during the actual load. Instead the new load gets a normal
// nsDocShell policy type. We include it here in case this utility method
// is called before the load starts.
return aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
aContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
aContentPolicyType == nsIContentPolicy::TYPE_REFRESH;
}
// static
bool
InternalRequest::IsWorkerRequest() const
InternalRequest::IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType)
{
// https://fetch.spec.whatwg.org/#worker-request-context
//
@ -235,8 +241,20 @@ InternalRequest::IsWorkerRequest() const
// Note, service workers are not included here because currently there is
// no way to generate a Request with a "serviceworker" RequestContext.
// ServiceWorker scripts cannot be intercepted.
return mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
mContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
return aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
}
bool
InternalRequest::IsNavigationRequest() const
{
return IsNavigationContentPolicy(mContentPolicyType);
}
bool
InternalRequest::IsWorkerRequest() const
{
return IsWorkerContentPolicy(mContentPolicyType);
}
bool
@ -245,5 +263,63 @@ InternalRequest::IsClientRequest() const
return IsNavigationRequest() || IsWorkerRequest();
}
// static
RequestMode
InternalRequest::MapChannelToRequestMode(nsIChannel* aChannel)
{
MOZ_ASSERT(aChannel);
nsCOMPtr<nsILoadInfo> loadInfo;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aChannel->GetLoadInfo(getter_AddRefs(loadInfo))));
// RequestMode deviates from our internal security mode for navigations.
// While navigations normally allow cross origin we must set a same-origin
// RequestMode to get the correct service worker interception restrictions
// in place.
// TODO: remove the worker override once securityMode is fully implemented (bug 1189945)
nsContentPolicyType contentPolicy = loadInfo->InternalContentPolicyType();
if (IsNavigationContentPolicy(contentPolicy) ||
IsWorkerContentPolicy(contentPolicy)) {
return RequestMode::Same_origin;
}
uint32_t securityMode;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(loadInfo->GetSecurityMode(&securityMode)));
switch(securityMode) {
case nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS:
case nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED:
return RequestMode::Same_origin;
case nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS:
case nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL:
return RequestMode::No_cors;
case nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS:
// TODO: Check additional flag force-preflight after bug 1199693 (bug 1189945)
return RequestMode::Cors;
default:
// TODO: assert never reached after CorsMode flag removed (bug 1189945)
MOZ_ASSERT(securityMode == nsILoadInfo::SEC_NORMAL);
break;
}
// TODO: remove following code once securityMode is fully implemented (bug 1189945)
// We only support app:// protocol interception in non-release builds.
#ifndef RELEASE_BUILD
nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aChannel);
if (jarChannel) {
return RequestMode::No_cors;
}
#endif
nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
uint32_t corsMode;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(httpChannel->GetCorsMode(&corsMode)));
// This cast is valid due to static asserts in ServiceWorkerManager.cpp.
return static_cast<RequestMode>(corsMode);
}
} // namespace dom
} // namespace mozilla

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

@ -377,6 +377,8 @@ public:
bool
IsClientRequest() const;
static RequestMode
MapChannelToRequestMode(nsIChannel* aChannel);
private:
// Does not copy mBodyStream. Use fallible Clone() for complete copy.
@ -387,6 +389,12 @@ private:
static RequestContext
MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType);
static bool
IsNavigationContentPolicy(nsContentPolicyType aContentPolicyType);
static bool
IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType);
nsCString mMethod;
// mURL always stores the url with the ref stripped
nsCString mURL;

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

@ -130,7 +130,10 @@ public:
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mShouldNotify) {
mElement->NotifyAudioChannelAgent(false);
// The audio channel agent may not exist now.
if (mElement->MaybeCreateAudioChannelAgent()) {
mElement->NotifyAudioChannelAgent(false);
}
}
}
~AutoNotifyAudioChannelAgent()

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

@ -18,6 +18,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549475
</div>
<script type="application/javascript">
SimpleTest.requestLongerTimeout(2);
/**
* This files tests the 'value sanitization algorithm' for the various input
* types. Note that an input's value is affected by more than just its type's

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

@ -15,79 +15,4 @@ GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2)
return std::max(aChannels1, aChannels2);
}
/**
* UpMixMatrix represents a conversion matrix by exploiting the fact that
* each output channel comes from at most one input channel.
*/
struct UpMixMatrix {
uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
};
static const UpMixMatrix
gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
{
// Upmixes from mono
{ { 0, 0 } },
{ { 0, IGNORE, IGNORE } },
{ { 0, 0, IGNORE, IGNORE } },
{ { 0, IGNORE, IGNORE, IGNORE, IGNORE } },
{ { IGNORE, IGNORE, 0, IGNORE, IGNORE, IGNORE } },
// Upmixes from stereo
{ { 0, 1, IGNORE } },
{ { 0, 1, IGNORE, IGNORE } },
{ { 0, 1, IGNORE, IGNORE, IGNORE } },
{ { 0, 1, IGNORE, IGNORE, IGNORE, IGNORE } },
// Upmixes from 3-channel
{ { 0, 1, 2, IGNORE } },
{ { 0, 1, 2, IGNORE, IGNORE } },
{ { 0, 1, 2, IGNORE, IGNORE, IGNORE } },
// Upmixes from quad
{ { 0, 1, 2, 3, IGNORE } },
{ { 0, 1, IGNORE, IGNORE, 2, 3 } },
// Upmixes from 5-channel
{ { 0, 1, 2, 3, 4, IGNORE } }
};
void
AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
uint32_t aOutputChannelCount,
const void* aZeroChannel)
{
uint32_t inputChannelCount = aChannelArray->Length();
uint32_t outputChannelCount =
GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount);
NS_ASSERTION(outputChannelCount > inputChannelCount,
"No up-mix needed");
MOZ_ASSERT(inputChannelCount > 0, "Bad number of channels");
MOZ_ASSERT(outputChannelCount > 0, "Bad number of channels");
aChannelArray->SetLength(outputChannelCount);
if (inputChannelCount < CUSTOM_CHANNEL_LAYOUTS &&
outputChannelCount <= CUSTOM_CHANNEL_LAYOUTS) {
const UpMixMatrix& m = gUpMixMatrices[
gMixingMatrixIndexByChannels[inputChannelCount - 1] +
outputChannelCount - inputChannelCount - 1];
const void* outputChannels[CUSTOM_CHANNEL_LAYOUTS];
for (uint32_t i = 0; i < outputChannelCount; ++i) {
uint8_t channelIndex = m.mInputDestination[i];
if (channelIndex == IGNORE) {
outputChannels[i] = aZeroChannel;
} else {
outputChannels[i] = aChannelArray->ElementAt(channelIndex);
}
}
for (uint32_t i = 0; i < outputChannelCount; ++i) {
aChannelArray->ElementAt(i) = outputChannels[i];
}
return;
}
for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) {
aChannelArray->ElementAt(i) = aZeroChannel;
}
}
} // namespace mozilla

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

@ -58,24 +58,6 @@ const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] =
uint32_t
GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2);
/**
* Given an array of input channel data, and an output channel count,
* replaces the array with an array of upmixed channels.
* This shuffles the array and may set some channel buffers to aZeroChannel.
* Don't call this with input count >= output count.
* This may return *more* channels than requested. In that case, downmixing
* is required to to get to aOutputChannelCount. (This is how we handle
* odd cases like 3 -> 4 upmixing.)
* If aChannelArray.Length() was the input to one of a series of
* GetAudioChannelsSuperset calls resulting in aOutputChannelCount,
* no downmixing will be required.
*/
void
AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
uint32_t aOutputChannelCount,
const void* aZeroChannel);
/**
* DownMixMatrix represents a conversion matrix efficiently by exploiting the
* fact that each input channel contributes to at most one output channel,
@ -124,19 +106,19 @@ gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
* input count <= output count.
*/
template<typename T>
void AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
T** aOutputChannels,
uint32_t aOutputChannelCount,
uint32_t aDuration)
void AudioChannelsDownMix(const nsTArray<const T*>& aChannelArray,
T** aOutputChannels,
uint32_t aOutputChannelCount,
uint32_t aDuration)
{
uint32_t inputChannelCount = aChannelArray.Length();
const void* const* inputChannels = aChannelArray.Elements();
const T* const* inputChannels = aChannelArray.Elements();
NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do");
if (inputChannelCount > 6) {
// Just drop the unknown channels.
for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(T));
PodCopy(aOutputChannels[o], inputChannels[o], aDuration);
}
return;
}
@ -153,8 +135,7 @@ void AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
for (uint32_t s = 0; s < aDuration; ++s) {
// Reserve an extra junk channel at the end for the cases where we
// want an input channel to contribute to nothing
T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1];
memset(outputChannels, 0, sizeof(T)*(CUSTOM_CHANNEL_LAYOUTS));
T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1] = {0};
for (uint32_t c = 0; c < inputChannelCount; ++c) {
outputChannels[m.mInputDestination[c]] +=
m.mInputCoefficient[c]*(static_cast<const T*>(inputChannels[c]))[s];
@ -171,6 +152,94 @@ void AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
}
}
/**
* UpMixMatrix represents a conversion matrix by exploiting the fact that
* each output channel comes from at most one input channel.
*/
struct UpMixMatrix {
uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
};
static const UpMixMatrix
gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
{
// Upmixes from mono
{ { 0, 0 } },
{ { 0, IGNORE, IGNORE } },
{ { 0, 0, IGNORE, IGNORE } },
{ { 0, IGNORE, IGNORE, IGNORE, IGNORE } },
{ { IGNORE, IGNORE, 0, IGNORE, IGNORE, IGNORE } },
// Upmixes from stereo
{ { 0, 1, IGNORE } },
{ { 0, 1, IGNORE, IGNORE } },
{ { 0, 1, IGNORE, IGNORE, IGNORE } },
{ { 0, 1, IGNORE, IGNORE, IGNORE, IGNORE } },
// Upmixes from 3-channel
{ { 0, 1, 2, IGNORE } },
{ { 0, 1, 2, IGNORE, IGNORE } },
{ { 0, 1, 2, IGNORE, IGNORE, IGNORE } },
// Upmixes from quad
{ { 0, 1, 2, 3, IGNORE } },
{ { 0, 1, IGNORE, IGNORE, 2, 3 } },
// Upmixes from 5-channel
{ { 0, 1, 2, 3, 4, IGNORE } }
};
/**
* Given an array of input channel data, and an output channel count,
* replaces the array with an array of upmixed channels.
* This shuffles the array and may set some channel buffers to aZeroChannel.
* Don't call this with input count >= output count.
* This may return *more* channels than requested. In that case, downmixing
* is required to to get to aOutputChannelCount. (This is how we handle
* odd cases like 3 -> 4 upmixing.)
* If aChannelArray.Length() was the input to one of a series of
* GetAudioChannelsSuperset calls resulting in aOutputChannelCount,
* no downmixing will be required.
*/
template<typename T>
void
AudioChannelsUpMix(nsTArray<const T*>* aChannelArray,
uint32_t aOutputChannelCount,
const T* aZeroChannel)
{
uint32_t inputChannelCount = aChannelArray->Length();
uint32_t outputChannelCount =
GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount);
NS_ASSERTION(outputChannelCount > inputChannelCount,
"No up-mix needed");
MOZ_ASSERT(inputChannelCount > 0, "Bad number of channels");
MOZ_ASSERT(outputChannelCount > 0, "Bad number of channels");
aChannelArray->SetLength(outputChannelCount);
if (inputChannelCount < CUSTOM_CHANNEL_LAYOUTS &&
outputChannelCount <= CUSTOM_CHANNEL_LAYOUTS) {
const UpMixMatrix& m = gUpMixMatrices[
gMixingMatrixIndexByChannels[inputChannelCount - 1] +
outputChannelCount - inputChannelCount - 1];
const T* outputChannels[CUSTOM_CHANNEL_LAYOUTS];
for (uint32_t i = 0; i < outputChannelCount; ++i) {
uint8_t channelIndex = m.mInputDestination[i];
if (channelIndex == IGNORE) {
outputChannels[i] = aZeroChannel;
} else {
outputChannels[i] = aChannelArray->ElementAt(channelIndex);
}
}
for (uint32_t i = 0; i < outputChannelCount; ++i) {
aChannelArray->ElementAt(i) = outputChannels[i];
}
return;
}
for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) {
aChannelArray->ElementAt(i) = aZeroChannel;
}
}
} // namespace mozilla

196
dom/media/AudioPacketizer.h Normal file
Просмотреть файл

@ -0,0 +1,196 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef AudioPacketizer_h_
#define AudioPacketizer_h_
#include <mozilla/PodOperations.h>
#include <mozilla/Assertions.h>
#include <nsAutoPtr.h>
#include <AudioSampleFormat.h>
// Enable this to warn when `Output` has been called but not enough data was
// buffered.
// #define LOG_PACKETIZER_UNDERRUN
namespace mozilla {
/**
* This class takes arbitrary input data, and returns packets of a specific
* size. In the process, it can convert audio samples from 16bit integers to
* float (or vice-versa).
*
* Input and output, as well as length units in the public interface are
* interleaved frames.
*
* Allocations of output buffer can be performed by this class. Buffers can
* simply be delete-d. This is because packets are intended to be sent off to
* non-gecko code using normal pointers/length pairs
*
* Alternatively, consumers can pass in a buffer in which the output is copied.
* The buffer needs to be large enough to store a packet worth of audio.
*
* The implementation uses a circular buffer using absolute virtual indices.
*/
template <typename InputType, typename OutputType>
class AudioPacketizer
{
public:
AudioPacketizer(uint32_t aPacketSize, uint32_t aChannels)
: mPacketSize(aPacketSize)
, mChannels(aChannels)
, mReadIndex(0)
, mWriteIndex(0)
// Start off with a single packet
, mStorage(new InputType[aPacketSize * aChannels])
, mLength(aPacketSize * aChannels)
{
MOZ_ASSERT(aPacketSize > 0 && aChannels > 0,
"The packet size and the number of channel should be strictly positive");
}
void Input(const InputType* aFrames, uint32_t aFrameCount)
{
uint32_t inputSamples = aFrameCount * mChannels;
// Need to grow the storage. This should rarely happen, if at all, once the
// array has the right size.
if (inputSamples > EmptySlots()) {
// Calls to Input and Output are roughtly interleaved
// (Input,Output,Input,Output, etc.), or balanced
// (Input,Input,Input,Output,Output,Output), so we update the buffer to
// the exact right size in order to not waste space.
uint32_t newLength = AvailableSamples() + inputSamples;
uint32_t toCopy = AvailableSamples();
nsAutoPtr<InputType> oldStorage = mStorage;
mStorage = new InputType[newLength];
// Copy the old data at the beginning of the new storage.
if (WriteIndex() >= ReadIndex()) {
PodCopy(mStorage.get(),
oldStorage.get() + ReadIndex(),
AvailableSamples());
} else {
uint32_t firstPartLength = mLength - ReadIndex();
uint32_t secondPartLength = AvailableSamples() - firstPartLength;
PodCopy(mStorage.get(),
oldStorage.get() + ReadIndex(),
firstPartLength);
PodCopy(mStorage.get() + firstPartLength,
oldStorage.get(),
secondPartLength);
}
mWriteIndex = toCopy;
mReadIndex = 0;
mLength = newLength;
}
if (WriteIndex() + inputSamples <= mLength) {
PodCopy(mStorage.get() + WriteIndex(), aFrames, aFrameCount * mChannels);
} else {
uint32_t firstPartLength = mLength - WriteIndex();
uint32_t secondPartLength = inputSamples - firstPartLength;
PodCopy(mStorage.get() + WriteIndex(), aFrames, firstPartLength);
PodCopy(mStorage.get(), aFrames + firstPartLength, secondPartLength);
}
mWriteIndex += inputSamples;
}
OutputType* Output()
{
uint32_t samplesNeeded = mPacketSize * mChannels;
OutputType* out = new OutputType[samplesNeeded];
Output(out);
return out;
}
void Output(OutputType* aOutputBuffer)
{
uint32_t samplesNeeded = mPacketSize * mChannels;
// Under-run. Pad the end of the buffer with silence.
if (AvailableSamples() < samplesNeeded) {
#ifdef LOG_PACKETIZER_UNDERRUN
char buf[256];
snprintf(buf, 256,
"AudioPacketizer %p underrun: available: %u, needed: %u\n",
this, AvailableSamples(), samplesNeeded);
NS_WARNING(buf);
#endif
uint32_t zeros = samplesNeeded - AvailableSamples();
PodZero(aOutputBuffer + AvailableSamples(), zeros);
samplesNeeded -= zeros;
}
if (ReadIndex() + samplesNeeded <= mLength) {
ConvertAudioSamples<InputType,OutputType>(mStorage.get() + ReadIndex(),
aOutputBuffer,
samplesNeeded);
} else {
uint32_t firstPartLength = mLength - ReadIndex();
uint32_t secondPartLength = samplesNeeded - firstPartLength;
ConvertAudioSamples<InputType, OutputType>(mStorage.get() + ReadIndex(),
aOutputBuffer,
firstPartLength);
ConvertAudioSamples<InputType, OutputType>(mStorage.get(),
aOutputBuffer + firstPartLength,
secondPartLength);
}
mReadIndex += samplesNeeded;
}
uint32_t PacketsAvailable() const {
return AvailableSamples() / mChannels / mPacketSize;
}
bool Empty() const {
return mWriteIndex == mReadIndex;
}
bool Full() const {
return mWriteIndex - mReadIndex == mLength;
}
uint32_t PacketSize() const {
return mPacketSize;
}
uint32_t Channels() const {
return mChannels;
}
private:
uint32_t ReadIndex() const {
return mReadIndex % mLength;
}
uint32_t WriteIndex() const {
return mWriteIndex % mLength;
}
uint32_t AvailableSamples() const {
return mWriteIndex - mReadIndex;
}
uint32_t EmptySlots() const {
return mLength - AvailableSamples();
}
// Size of one packet of audio, in frames
uint32_t mPacketSize;
// Number of channels of the stream flowing through this packetizer
uint32_t mChannels;
// Two virtual index into the buffer: the read position and the write
// position.
uint64_t mReadIndex;
uint64_t mWriteIndex;
// Storage for the samples
nsAutoPtr<InputType> mStorage;
// Length of the buffer, in samples
uint32_t mLength;
};
} // mozilla
#endif // AudioPacketizer_h_

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

@ -96,6 +96,51 @@ FloatToAudioSample<int16_t>(float aValue)
return int16_t(clamped);
}
template <typename T> T IntegerToAudioSample(int16_t aValue);
template <> inline float
IntegerToAudioSample<float>(int16_t aValue)
{
return aValue / 32768.0f;
}
template <> inline int16_t
IntegerToAudioSample<int16_t>(int16_t aValue)
{
return aValue;
}
template<typename SrcT, typename DstT>
inline void
ConvertAudioSample(SrcT aIn, DstT& aOut);
template<>
inline void
ConvertAudioSample(int16_t aIn, int16_t & aOut)
{
aOut = aIn;
}
template<>
inline void
ConvertAudioSample(int16_t aIn, float& aOut)
{
aOut = AudioSampleToFloat(aIn);
}
template<>
inline void
ConvertAudioSample(float aIn, float& aOut)
{
aOut = aIn;
}
template<>
inline void
ConvertAudioSample(float aIn, int16_t& aOut)
{
aOut = FloatToAudioSample<int16_t>(aIn);
}
// Sample buffer conversion
template <typename From, typename To> inline void

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

@ -5,7 +5,6 @@
#include "AudioSegment.h"
#include "AudioStream.h"
#include "AudioMixer.h"
#include "AudioChannelFormat.h"
#include "Latency.h"
@ -13,49 +12,18 @@
namespace mozilla {
template <class SrcT, class DestT>
static void
InterleaveAndConvertBuffer(const SrcT** aSourceChannels,
int32_t aLength, float aVolume,
int32_t aChannels,
DestT* aOutput)
const uint8_t SilentChannel::gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*SilentChannel::AUDIO_PROCESSING_FRAMES] = {0};
template<>
const float* SilentChannel::ZeroChannel<float>()
{
DestT* output = aOutput;
for (int32_t i = 0; i < aLength; ++i) {
for (int32_t channel = 0; channel < aChannels; ++channel) {
float v = AudioSampleToFloat(aSourceChannels[channel][i])*aVolume;
*output = FloatToAudioSample<DestT>(v);
++output;
}
}
return reinterpret_cast<const float*>(SilentChannel::gZeroChannel);
}
void
InterleaveAndConvertBuffer(const void** aSourceChannels,
AudioSampleFormat aSourceFormat,
int32_t aLength, float aVolume,
int32_t aChannels,
AudioDataValue* aOutput)
template<>
const int16_t* SilentChannel::ZeroChannel<int16_t>()
{
switch (aSourceFormat) {
case AUDIO_FORMAT_FLOAT32:
InterleaveAndConvertBuffer(reinterpret_cast<const float**>(aSourceChannels),
aLength,
aVolume,
aChannels,
aOutput);
break;
case AUDIO_FORMAT_S16:
InterleaveAndConvertBuffer(reinterpret_cast<const int16_t**>(aSourceChannels),
aLength,
aVolume,
aChannels,
aOutput);
break;
case AUDIO_FORMAT_SILENCE:
// nothing to do here.
break;
}
return reinterpret_cast<const int16_t*>(SilentChannel::gZeroChannel);
}
void
@ -66,54 +34,6 @@ AudioSegment::ApplyVolume(float aVolume)
}
}
static const int AUDIO_PROCESSING_FRAMES = 640; /* > 10ms of 48KHz audio */
static const uint8_t gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*AUDIO_PROCESSING_FRAMES] = {0};
void
DownmixAndInterleave(const nsTArray<const void*>& aChannelData,
AudioSampleFormat aSourceFormat, int32_t aDuration,
float aVolume, uint32_t aOutputChannels,
AudioDataValue* aOutput)
{
nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channelData;
nsAutoTArray<float,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> downmixConversionBuffer;
nsAutoTArray<float,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> downmixOutputBuffer;
channelData.SetLength(aChannelData.Length());
if (aSourceFormat != AUDIO_FORMAT_FLOAT32) {
NS_ASSERTION(aSourceFormat == AUDIO_FORMAT_S16, "unknown format");
downmixConversionBuffer.SetLength(aDuration*aChannelData.Length());
for (uint32_t i = 0; i < aChannelData.Length(); ++i) {
float* conversionBuf = downmixConversionBuffer.Elements() + (i*aDuration);
const int16_t* sourceBuf = static_cast<const int16_t*>(aChannelData[i]);
for (uint32_t j = 0; j < (uint32_t)aDuration; ++j) {
conversionBuf[j] = AudioSampleToFloat(sourceBuf[j]);
}
channelData[i] = conversionBuf;
}
} else {
for (uint32_t i = 0; i < aChannelData.Length(); ++i) {
channelData[i] = aChannelData[i];
}
}
downmixOutputBuffer.SetLength(aDuration*aOutputChannels);
nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannelBuffers;
nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> outputChannelData;
outputChannelBuffers.SetLength(aOutputChannels);
outputChannelData.SetLength(aOutputChannels);
for (uint32_t i = 0; i < (uint32_t)aOutputChannels; ++i) {
outputChannelData[i] = outputChannelBuffers[i] =
downmixOutputBuffer.Elements() + aDuration*i;
}
if (channelData.Length() > aOutputChannels) {
AudioChannelsDownMix(channelData, outputChannelBuffers.Elements(),
aOutputChannels, aDuration);
}
InterleaveAndConvertBuffer(outputChannelData.Elements(), AUDIO_FORMAT_FLOAT32,
aDuration, aVolume, aOutputChannels, aOutput);
}
void AudioSegment::ResampleChunks(SpeexResamplerState* aResampler, uint32_t aInRate, uint32_t aOutRate)
{
if (mChunks.IsEmpty()) {
@ -165,9 +85,9 @@ void
AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels,
uint32_t aSampleRate)
{
nsAutoTArray<AudioDataValue, AUDIO_PROCESSING_FRAMES* GUESS_AUDIO_CHANNELS>
nsAutoTArray<AudioDataValue, SilentChannel::AUDIO_PROCESSING_FRAMES* GUESS_AUDIO_CHANNELS>
buf;
nsAutoTArray<const void*, GUESS_AUDIO_CHANNELS> channelData;
nsAutoTArray<const AudioDataValue*, GUESS_AUDIO_CHANNELS> channelData;
uint32_t offsetSamples = 0;
uint32_t duration = GetDuration();
@ -197,11 +117,11 @@ AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels,
// desired input and output channels.
channelData.SetLength(c.mChannelData.Length());
for (uint32_t i = 0; i < channelData.Length(); ++i) {
channelData[i] = c.mChannelData[i];
channelData[i] = static_cast<const AudioDataValue*>(c.mChannelData[i]);
}
if (channelData.Length() < aOutputChannels) {
// Up-mix.
AudioChannelsUpMix(&channelData, aOutputChannels, gZeroChannel);
AudioChannelsUpMix(&channelData, aOutputChannels, SilentChannel::ZeroChannel<AudioDataValue>());
for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
AudioDataValue* ptr =
PointerForOffsetInChannel(buf.Elements(), outBufferLength,
@ -246,9 +166,8 @@ AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels,
void
AudioSegment::WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aOutputChannels, uint32_t aSampleRate)
{
nsAutoTArray<AudioDataValue,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> buf;
nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channelData;
// Offset in the buffer that will end up sent to the AudioStream, in samples.
nsAutoTArray<AudioDataValue,SilentChannel::AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> buf;
// Offset in the buffer that will be written to the mixer, in samples.
uint32_t offset = 0;
if (GetDuration() <= 0) {
@ -262,39 +181,23 @@ AudioSegment::WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aOutputChannels
for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
AudioChunk& c = *ci;
uint32_t frames = c.mDuration;
// If we have written data in the past, or we have real (non-silent) data
// to write, we can proceed. Otherwise, it means we just started the
// AudioStream, and we don't have real data to write to it (just silence).
// To avoid overbuffering in the AudioStream, we simply drop the silence,
// here. The stream will underrun and output silence anyways.
if (c.mBuffer && c.mBufferFormat != AUDIO_FORMAT_SILENCE) {
channelData.SetLength(c.mChannelData.Length());
for (uint32_t i = 0; i < channelData.Length(); ++i) {
channelData[i] = c.mChannelData[i];
}
if (channelData.Length() < aOutputChannels) {
// Up-mix. Note that this might actually make channelData have more
// than aOutputChannels temporarily.
AudioChannelsUpMix(&channelData, aOutputChannels, gZeroChannel);
}
if (channelData.Length() > aOutputChannels) {
// Down-mix.
DownmixAndInterleave(channelData, c.mBufferFormat, frames,
c.mVolume, aOutputChannels, buf.Elements() + offset);
} else {
InterleaveAndConvertBuffer(channelData.Elements(), c.mBufferFormat,
frames, c.mVolume,
aOutputChannels,
buf.Elements() + offset);
}
} else {
// Assumes that a bit pattern of zeroes == 0.0f
memset(buf.Elements() + offset, 0, aOutputChannels * frames * sizeof(AudioDataValue));
switch (c.mBufferFormat) {
case AUDIO_FORMAT_S16:
WriteChunk<int16_t>(c, aOutputChannels, buf.Elements() + offset);
break;
case AUDIO_FORMAT_FLOAT32:
WriteChunk<float>(c, aOutputChannels, buf.Elements() + offset);
break;
case AUDIO_FORMAT_SILENCE:
// The mixer is expecting interleaved data, so this is ok.
PodZero(buf.Elements() + offset, c.mDuration * aOutputChannels);
break;
default:
MOZ_ASSERT(false, "Not handled");
}
offset += frames * aOutputChannels;
offset += c.mDuration * aOutputChannels;
#if !defined(MOZILLA_XPCOMRT_API)
if (!c.mTimeStamp.IsNull()) {

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

@ -8,6 +8,7 @@
#include "MediaSegment.h"
#include "AudioSampleFormat.h"
#include "AudioChannelFormat.h"
#include "SharedBuffer.h"
#include "WebAudioUtils.h"
#ifdef MOZILLA_INTERNAL_API
@ -56,21 +57,82 @@ const int GUESS_AUDIO_CHANNELS = 2;
const uint32_t WEBAUDIO_BLOCK_SIZE_BITS = 7;
const uint32_t WEBAUDIO_BLOCK_SIZE = 1 << WEBAUDIO_BLOCK_SIZE_BITS;
void InterleaveAndConvertBuffer(const void** aSourceChannels,
AudioSampleFormat aSourceFormat,
int32_t aLength, float aVolume,
int32_t aChannels,
AudioDataValue* aOutput);
template <typename SrcT, typename DestT>
static void
InterleaveAndConvertBuffer(const SrcT* const* aSourceChannels,
uint32_t aLength, float aVolume,
uint32_t aChannels,
DestT* aOutput)
{
DestT* output = aOutput;
for (size_t i = 0; i < aLength; ++i) {
for (size_t channel = 0; channel < aChannels; ++channel) {
float v = AudioSampleToFloat(aSourceChannels[channel][i])*aVolume;
*output = FloatToAudioSample<DestT>(v);
++output;
}
}
}
template <typename SrcT, typename DestT>
static void
DeinterleaveAndConvertBuffer(const SrcT* aSourceBuffer,
uint32_t aFrames, uint32_t aChannels,
DestT** aOutput)
{
for (size_t i = 0; i < aChannels; i++) {
size_t interleavedIndex = i;
for (size_t j = 0; j < aFrames; j++) {
ConvertAudioSample(aSourceBuffer[interleavedIndex],
aOutput[i][j]);
interleavedIndex += aChannels;
}
}
}
class SilentChannel
{
public:
static const int AUDIO_PROCESSING_FRAMES = 640; /* > 10ms of 48KHz audio */
static const uint8_t gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*AUDIO_PROCESSING_FRAMES];
// We take advantage of the fact that zero in float and zero in int have the
// same all-zeros bit layout.
template<typename T>
static const T* ZeroChannel();
};
/**
* Given an array of input channels (aChannelData), downmix to aOutputChannels,
* interleave the channel data. A total of aOutputChannels*aDuration
* interleaved samples will be copied to a channel buffer in aOutput.
*/
void DownmixAndInterleave(const nsTArray<const void*>& aChannelData,
AudioSampleFormat aSourceFormat, int32_t aDuration,
float aVolume, uint32_t aOutputChannels,
AudioDataValue* aOutput);
template <typename SrcT, typename DestT>
void
DownmixAndInterleave(const nsTArray<const SrcT*>& aChannelData,
int32_t aDuration, float aVolume, uint32_t aOutputChannels,
DestT* aOutput)
{
if (aChannelData.Length() == aOutputChannels) {
InterleaveAndConvertBuffer(aChannelData.Elements(),
aDuration, aVolume, aOutputChannels, aOutput);
} else {
nsAutoTArray<SrcT*,GUESS_AUDIO_CHANNELS> outputChannelData;
nsAutoTArray<SrcT, SilentChannel::AUDIO_PROCESSING_FRAMES * GUESS_AUDIO_CHANNELS> outputBuffers;
outputChannelData.SetLength(aOutputChannels);
outputBuffers.SetLength(aDuration * aOutputChannels);
for (uint32_t i = 0; i < aOutputChannels; i++) {
outputChannelData[i] = outputBuffers.Elements() + aDuration * i;
}
AudioChannelsDownMix(aChannelData,
outputChannelData.Elements(),
aOutputChannels,
aDuration);
InterleaveAndConvertBuffer(outputChannelData.Elements(),
aDuration, aVolume, aOutputChannels, aOutput);
}
}
/**
* An AudioChunk represents a multi-channel buffer of audio samples.
@ -190,6 +252,13 @@ struct AudioChunk {
return amount;
}
template<typename T>
const nsTArray<const T*>& ChannelData()
{
MOZ_ASSERT(AudioSampleTypeToFormat<T>::Format == mBufferFormat);
return *reinterpret_cast<nsTArray<const T*>*>(&mChannelData);
}
StreamTime mDuration; // in frames within the buffer
nsRefPtr<ThreadSharedObject> mBuffer; // the buffer object whose lifetime is managed; null means data is all zeroes
nsTArray<const void*> mChannelData; // one pointer per channel; empty if and only if mBuffer is null
@ -356,6 +425,34 @@ public:
}
};
template<typename SrcT>
void WriteChunk(AudioChunk& aChunk,
uint32_t aOutputChannels,
AudioDataValue* aOutputBuffer)
{
nsAutoTArray<const SrcT*,GUESS_AUDIO_CHANNELS> channelData;
channelData = aChunk.ChannelData<SrcT>();
if (channelData.Length() < aOutputChannels) {
// Up-mix. Note that this might actually make channelData have more
// than aOutputChannels temporarily.
AudioChannelsUpMix(&channelData, aOutputChannels, SilentChannel::ZeroChannel<SrcT>());
}
if (channelData.Length() > aOutputChannels) {
// Down-mix.
DownmixAndInterleave(channelData, aChunk.mDuration,
aChunk.mVolume, aOutputChannels, aOutputBuffer);
} else {
InterleaveAndConvertBuffer(channelData.Elements(),
aChunk.mDuration, aChunk.mVolume,
aOutputChannels,
aOutputBuffer);
}
}
} // namespace mozilla
#endif /* MOZILLA_AUDIOSEGMENT_H_ */

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

@ -359,6 +359,7 @@ DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
, mShuttingDown(false)
, mPlaying(false)
, mVolume(1.0)
, mSameOrigin(false)
, mAudioQueue(aAudioQueue)
, mVideoQueue(aVideoQueue)
{

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

@ -2483,24 +2483,19 @@ SourceMediaStream::ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSe
AudioSegment* segment = static_cast<AudioSegment*>(aSegment);
int channels = segment->ChannelCount();
// If this segment is just silence, we delay instanciating the resampler.
if (channels) {
if (aTrackData->mResampler) {
MOZ_ASSERT(aTrackData->mResamplerChannelCount == segment->ChannelCount());
} else {
SpeexResamplerState* state = speex_resampler_init(channels,
aTrackData->mInputRate,
GraphImpl()->GraphRate(),
SPEEX_RESAMPLER_QUALITY_MIN,
nullptr);
if (!state) {
return;
}
aTrackData->mResampler.own(state);
#ifdef DEBUG
aTrackData->mResamplerChannelCount = channels;
#endif
// If this segment is just silence, we delay instanciating the resampler. We
// also need to recreate the resampler if the channel count changes.
if (channels && aTrackData->mResamplerChannelCount != channels) {
SpeexResamplerState* state = speex_resampler_init(channels,
aTrackData->mInputRate,
GraphImpl()->GraphRate(),
SPEEX_RESAMPLER_QUALITY_MIN,
nullptr);
if (!state) {
return;
}
aTrackData->mResampler.own(state);
aTrackData->mResamplerChannelCount = channels;
}
segment->ResampleChunks(aTrackData->mResampler, aTrackData->mInputRate, GraphImpl()->GraphRate());
}

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

@ -897,9 +897,7 @@ protected:
// Resampler if the rate of the input track does not match the
// MediaStreamGraph's.
nsAutoRef<SpeexResamplerState> mResampler;
#ifdef DEBUG
int mResamplerChannelCount;
#endif
StreamTime mStart;
// End-time of data already flushed to the track (excluding mData)
StreamTime mEndOfFlushedData;

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

@ -0,0 +1,174 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#include <assert.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "../AudioPacketizer.h"
using namespace mozilla;
template<typename T>
class AutoBuffer
{
public:
explicit AutoBuffer(size_t aLength)
{
mStorage = new T[aLength];
}
~AutoBuffer() {
delete [] mStorage;
}
T* Get() {
return mStorage;
}
private:
T* mStorage;
};
int16_t Sequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0)
{
uint32_t i;
for (i = 0; i < aSize; i++) {
aBuffer[i] = aStart + i;
}
return aStart + i;
}
void IsSequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0)
{
for (uint32_t i = 0; i < aSize; i++) {
if (aBuffer[i] != static_cast<int64_t>(aStart + i)) {
fprintf(stderr, "Buffer is not a sequence at offset %u\n", i);
assert(false);
}
}
assert("Buffer is a sequence.");
}
void Zero(int16_t* aBuffer, uint32_t aSize)
{
for (uint32_t i = 0; i < aSize; i++) {
if (aBuffer[i] != 0) {
fprintf(stderr, "Buffer is not null at offset %u\n", i);
assert(false);
}
}
}
double sine(uint32_t aPhase) {
return sin(aPhase * 2 * M_PI * 440 / 44100);
}
int main() {
for (int16_t channels = 1; channels < 2; channels++) {
// Test that the packetizer returns zero on underrun
{
AudioPacketizer<int16_t, int16_t> ap(441, channels);
for (int16_t i = 0; i < 10; i++) {
int16_t* out = ap.Output();
Zero(out, 441);
delete out;
}
}
// Simple test, with input/output buffer size aligned on the packet size,
// alternating Input and Output calls.
{
AudioPacketizer<int16_t, int16_t> ap(441, channels);
int16_t seqEnd = 0;
for (int16_t i = 0; i < 10; i++) {
AutoBuffer<int16_t> b(441 * channels);
int16_t prevEnd = seqEnd;
seqEnd = Sequence(b.Get(), channels * 441, prevEnd);
ap.Input(b.Get(), 441);
int16_t* out = ap.Output();
IsSequence(out, 441 * channels, prevEnd);
delete out;
}
}
// Simple test, with input/output buffer size aligned on the packet size,
// alternating two Input and Output calls.
{
AudioPacketizer<int16_t, int16_t> ap(441, channels);
int16_t seqEnd = 0;
for (int16_t i = 0; i < 10; i++) {
AutoBuffer<int16_t> b(441 * channels);
AutoBuffer<int16_t> b1(441 * channels);
int16_t prevEnd0 = seqEnd;
seqEnd = Sequence(b.Get(), 441 * channels, prevEnd0);
int16_t prevEnd1 = seqEnd;
seqEnd = Sequence(b1.Get(), 441 * channels, seqEnd);
ap.Input(b.Get(), 441);
ap.Input(b1.Get(), 441);
int16_t* out = ap.Output();
int16_t* out2 = ap.Output();
IsSequence(out, 441 * channels, prevEnd0);
IsSequence(out2, 441 * channels, prevEnd1);
delete out;
delete out2;
}
}
// Input/output buffer size not aligned on the packet size,
// alternating two Input and Output calls.
{
AudioPacketizer<int16_t, int16_t> ap(441, channels);
int16_t prevEnd = 0;
int16_t prevSeq = 0;
for (int16_t i = 0; i < 10; i++) {
AutoBuffer<int16_t> b(480 * channels);
AutoBuffer<int16_t> b1(480 * channels);
prevSeq = Sequence(b.Get(), 480 * channels, prevSeq);
prevSeq = Sequence(b1.Get(), 480 * channels, prevSeq);
ap.Input(b.Get(), 480);
ap.Input(b1.Get(), 480);
int16_t* out = ap.Output();
int16_t* out2 = ap.Output();
IsSequence(out, 441 * channels, prevEnd);
prevEnd += 441 * channels;
IsSequence(out2, 441 * channels, prevEnd);
prevEnd += 441 * channels;
delete out;
delete out2;
}
printf("Available: %d\n", ap.PacketsAvailable());
}
// "Real-life" test case: streaming a sine wave through a packetizer, and
// checking that we have the right output.
// 128 is, for example, the size of a Web Audio API block, and 441 is the
// size of a webrtc.org packet when the sample rate is 44100 (10ms)
{
AudioPacketizer<int16_t, int16_t> ap(441, channels);
AutoBuffer<int16_t> b(128 * channels);
uint32_t phase = 0;
uint32_t outPhase = 0;
for (int16_t i = 0; i < 1000; i++) {
for (int32_t j = 0; j < 128; j++) {
for (int32_t c = 0; c < channels; c++) {
// int16_t sinewave at 440Hz/44100Hz sample rate
b.Get()[j * channels + c] = (2 << 14) * sine(phase);
}
phase++;
}
ap.Input(b.Get(), 128);
while (ap.PacketsAvailable()) {
int16_t* packet = ap.Output();
for (uint32_t k = 0; k < ap.PacketSize(); k++) {
for (int32_t c = 0; c < channels; c++) {
assert(packet[k * channels + c] ==
static_cast<int16_t>(((2 << 14) * sine(outPhase))));
}
outPhase++;
}
delete [] packet;
}
}
}
}
printf("OK\n");
return 0;
}

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

@ -0,0 +1,268 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioSegment.h"
#include <assert.h>
#include <iostream>
using namespace mozilla;
namespace mozilla {
uint32_t
GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2)
{
return std::max(aChannels1, aChannels2);
}
}
/* Helper function to give us the maximum and minimum value that don't clip,
* for a given sample format (integer or floating-point). */
template<typename T>
T GetLowValue();
template<typename T>
T GetHighValue();
template<typename T>
T GetSilentValue();
template<>
float GetLowValue<float>() {
return -1.0;
}
template<>
int16_t GetLowValue<short>() {
return -INT16_MAX;
}
template<>
float GetHighValue<float>() {
return 1.0;
}
template<>
int16_t GetHighValue<short>() {
return INT16_MAX;
}
template<>
float GetSilentValue() {
return 0.0;
}
template<>
int16_t GetSilentValue() {
return 0;
}
// Get an array of planar audio buffers that has the inverse of the index of the
// channel (1-indexed) as samples.
template<typename T>
const T* const* GetPlanarChannelArray(size_t aChannels, size_t aSize)
{
T** channels = new T*[aChannels];
for (size_t c = 0; c < aChannels; c++) {
channels[c] = new T[aSize];
for (size_t i = 0; i < aSize; i++) {
channels[c][i] = FloatToAudioSample<T>(1. / (c + 1));
}
}
return channels;
}
template<typename T>
void DeletePlanarChannelsArray(const T* const* aArrays, size_t aChannels)
{
for (size_t channel = 0; channel < aChannels; channel++) {
delete [] aArrays[channel];
}
delete [] aArrays;
}
template<typename T>
T** GetPlanarArray(size_t aChannels, size_t aSize)
{
T** channels = new T*[aChannels];
for (size_t c = 0; c < aChannels; c++) {
channels[c] = new T[aSize];
for (size_t i = 0; i < aSize; i++) {
channels[c][i] = 0.0f;
}
}
return channels;
}
template<typename T>
void DeletePlanarArray(T** aArrays, size_t aChannels)
{
for (size_t channel = 0; channel < aChannels; channel++) {
delete [] aArrays[channel];
}
delete [] aArrays;
}
// Get an array of audio samples that have the inverse of the index of the
// channel (1-indexed) as samples.
template<typename T>
const T* GetInterleavedChannelArray(size_t aChannels, size_t aSize)
{
size_t sampleCount = aChannels * aSize;
T* samples = new T[sampleCount];
for (size_t i = 0; i < sampleCount; i++) {
uint32_t channel = (i % aChannels) + 1;
samples[i] = FloatToAudioSample<T>(1. / channel);
}
return samples;
}
template<typename T>
void DeleteInterleavedChannelArray(const T* aArray)
{
delete [] aArray;
}
bool FuzzyEqual(float aLhs, float aRhs) {
return std::abs(aLhs - aRhs) < 0.01;
}
template<typename SrcT, typename DstT>
void TestInterleaveAndConvert()
{
size_t arraySize = 1024;
size_t maxChannels = 8; // 7.1
for (uint32_t channels = 1; channels < maxChannels; channels++) {
const SrcT* const* src = GetPlanarChannelArray<SrcT>(channels, arraySize);
DstT* dst = new DstT[channels * arraySize];
InterleaveAndConvertBuffer(src, arraySize, 1.0, channels, dst);
uint32_t channelIndex = 0;
for (size_t i = 0; i < arraySize * channels; i++) {
assert(FuzzyEqual(dst[i],
FloatToAudioSample<DstT>(1. / (channelIndex + 1))));
channelIndex++;
channelIndex %= channels;
}
DeletePlanarChannelsArray(src, channels);
delete [] dst;
}
}
template<typename SrcT, typename DstT>
void TestDeinterleaveAndConvert()
{
size_t arraySize = 1024;
size_t maxChannels = 8; // 7.1
for (uint32_t channels = 1; channels < maxChannels; channels++) {
const SrcT* src = GetInterleavedChannelArray<SrcT>(channels, arraySize);
DstT** dst = GetPlanarArray<DstT>(channels, arraySize);
DeinterleaveAndConvertBuffer(src, arraySize, channels, dst);
for (size_t channel = 0; channel < channels; channel++) {
for (size_t i = 0; i < arraySize; i++) {
assert(FuzzyEqual(dst[channel][i],
FloatToAudioSample<DstT>(1. / (channel + 1))));
}
}
DeleteInterleavedChannelArray(src);
DeletePlanarArray(dst, channels);
}
}
uint8_t gSilence[4096] = {0};
template<typename T>
T* SilentChannel()
{
return reinterpret_cast<T*>(gSilence);
}
template<typename T>
void TestUpmixStereo()
{
size_t arraySize = 1024;
nsTArray<T*> channels;
nsTArray<const T*> channelsptr;
channels.SetLength(1);
channelsptr.SetLength(1);
channels[0] = new T[arraySize];
for (size_t i = 0; i < arraySize; i++) {
channels[0][i] = GetHighValue<T>();
}
channelsptr[0] = channels[0];
AudioChannelsUpMix(&channelsptr, 2, ::SilentChannel<T>());
for (size_t channel = 0; channel < 2; channel++) {
for (size_t i = 0; i < arraySize; i++) {
if (channelsptr[channel][i] != GetHighValue<T>()) {
assert(false);
}
}
}
assert(true);
delete channels[0];
}
template<typename T>
void TestDownmixStereo()
{
const size_t arraySize = 1024;
nsTArray<const T*> inputptr;
nsTArray<T*> input;
T** output;
output = new T*[1];
output[0] = new T[arraySize];
input.SetLength(2);
inputptr.SetLength(2);
for (size_t channel = 0; channel < input.Length(); channel++) {
input[channel] = new T[arraySize];
for (size_t i = 0; i < arraySize; i++) {
input[channel][i] = channel == 0 ? GetLowValue<T>() : GetHighValue<T>();
}
inputptr[channel] = input[channel];
}
AudioChannelsDownMix(inputptr, output, 1, arraySize);
for (size_t i = 0; i < arraySize; i++) {
if (output[0][i] != GetSilentValue<T>()) {
assert(false);
}
}
assert(true);
delete output[0];
delete output;
}
int main(int argc, char* argv[]) {
TestInterleaveAndConvert<float, float>();
TestInterleaveAndConvert<float, int16_t>();
TestInterleaveAndConvert<int16_t, float>();
TestInterleaveAndConvert<int16_t, int16_t>();
TestDeinterleaveAndConvert<float, float>();
TestDeinterleaveAndConvert<float, int16_t>();
TestDeinterleaveAndConvert<int16_t, float>();
TestDeinterleaveAndConvert<int16_t, int16_t>();
TestUpmixStereo<float>();
TestUpmixStereo<int16_t>();
TestDownmixStereo<float>();
TestDownmixStereo<int16_t>();
return 0;
}

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

@ -6,7 +6,9 @@
GeckoCppUnitTests([
'TestAudioBuffers',
'TestAudioMixer'
'TestAudioMixer',
'TestAudioPacketizer',
'TestAudioSegment'
])
LOCAL_INCLUDES += [

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

@ -123,9 +123,6 @@ AudioTrackEncoder::AppendAudioSegment(const AudioSegment& aSegment)
return NS_OK;
}
static const int AUDIO_PROCESSING_FRAMES = 640; /* > 10ms of 48KHz audio */
static const uint8_t gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*AUDIO_PROCESSING_FRAMES] = {0};
/*static*/
void
AudioTrackEncoder::InterleaveTrackData(AudioChunk& aChunk,
@ -133,19 +130,29 @@ AudioTrackEncoder::InterleaveTrackData(AudioChunk& aChunk,
uint32_t aOutputChannels,
AudioDataValue* aOutput)
{
if (aChunk.mChannelData.Length() < aOutputChannels) {
// Up-mix. This might make the mChannelData have more than aChannels.
AudioChannelsUpMix(&aChunk.mChannelData, aOutputChannels, gZeroChannel);
}
if (aChunk.mChannelData.Length() > aOutputChannels) {
DownmixAndInterleave(aChunk.mChannelData, aChunk.mBufferFormat, aDuration,
aChunk.mVolume, aOutputChannels, aOutput);
} else {
InterleaveAndConvertBuffer(aChunk.mChannelData.Elements(),
aChunk.mBufferFormat, aDuration, aChunk.mVolume,
aOutputChannels, aOutput);
}
switch(aChunk.mBufferFormat) {
case AUDIO_FORMAT_S16: {
nsAutoTArray<const int16_t*, 2> array;
array.SetLength(aOutputChannels);
for (uint32_t i = 0; i < array.Length(); i++) {
array[i] = static_cast<const int16_t*>(aChunk.mChannelData[i]);
}
InterleaveTrackData(array, aDuration, aOutputChannels, aOutput, aChunk.mVolume);
break;
}
case AUDIO_FORMAT_FLOAT32: {
nsAutoTArray<const float*, 2> array;
array.SetLength(aOutputChannels);
for (uint32_t i = 0; i < array.Length(); i++) {
array[i] = static_cast<const float*>(aChunk.mChannelData[i]);
}
InterleaveTrackData(array, aDuration, aOutputChannels, aOutput, aChunk.mVolume);
break;
}
case AUDIO_FORMAT_SILENCE: {
MOZ_ASSERT(false, "To implement.");
}
};
}
/*static*/

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

@ -148,6 +148,28 @@ public:
uint32_t aTrackEvents,
const MediaSegment& aQueuedMedia) override;
template<typename T>
static
void InterleaveTrackData(nsTArray<const T*>& aInput,
int32_t aDuration,
uint32_t aOutputChannels,
AudioDataValue* aOutput,
float aVolume)
{
if (aInput.Length() < aOutputChannels) {
// Up-mix. This might make the mChannelData have more than aChannels.
AudioChannelsUpMix(&aInput, aOutputChannels, SilentChannel::ZeroChannel<T>());
}
if (aInput.Length() > aOutputChannels) {
DownmixAndInterleave(aInput, aDuration,
aVolume, aOutputChannels, aOutput);
} else {
InterleaveAndConvertBuffer(aInput.Elements(), aDuration, aVolume,
aOutputChannels, aOutput);
}
}
/**
* Interleaves the track data and stores the result into aOutput. Might need
* to up-mix or down-mix the channel data if the channels number of this chunk

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

@ -101,6 +101,7 @@ EXPORTS += [
'AudioChannelFormat.h',
'AudioCompactor.h',
'AudioMixer.h',
'AudioPacketizer.h',
'AudioSampleFormat.h',
'AudioSegment.h',
'AudioStream.h',

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

@ -42,45 +42,33 @@ AudioNodeExternalInputStream::Create(MediaStreamGraph* aGraph,
* aBlock must have been allocated with AllocateInputBlock and have a channel
* count that's a superset of the channels in aInput.
*/
template <typename T>
static void
CopyChunkToBlock(const AudioChunk& aInput, AudioChunk *aBlock,
CopyChunkToBlock(AudioChunk& aInput, AudioChunk *aBlock,
uint32_t aOffsetInBlock)
{
uint32_t blockChannels = aBlock->ChannelCount();
nsAutoTArray<const void*,2> channels;
nsAutoTArray<const T*,2> channels;
if (aInput.IsNull()) {
channels.SetLength(blockChannels);
PodZero(channels.Elements(), blockChannels);
} else {
channels.SetLength(aInput.ChannelCount());
PodCopy(channels.Elements(), aInput.mChannelData.Elements(), channels.Length());
const nsTArray<const T*>& inputChannels = aInput.ChannelData<T>();
channels.SetLength(inputChannels.Length());
PodCopy(channels.Elements(), inputChannels.Elements(), channels.Length());
if (channels.Length() != blockChannels) {
// We only need to upmix here because aBlock's channel count has been
// chosen to be a superset of the channel count of every chunk.
AudioChannelsUpMix(&channels, blockChannels, nullptr);
AudioChannelsUpMix(&channels, blockChannels, static_cast<T*>(nullptr));
}
}
uint32_t duration = aInput.GetDuration();
for (uint32_t c = 0; c < blockChannels; ++c) {
float* outputData = aBlock->ChannelFloatsForWrite(c) + aOffsetInBlock;
if (channels[c]) {
switch (aInput.mBufferFormat) {
case AUDIO_FORMAT_FLOAT32:
ConvertAudioSamplesWithScale(
static_cast<const float*>(channels[c]), outputData, duration,
aInput.mVolume);
break;
case AUDIO_FORMAT_S16:
ConvertAudioSamplesWithScale(
static_cast<const int16_t*>(channels[c]), outputData, duration,
aInput.mVolume);
break;
default:
NS_ERROR("Unhandled format");
}
ConvertAudioSamplesWithScale(channels[c], outputData, aInput.GetDuration(), aInput.mVolume);
} else {
PodZero(outputData, duration);
PodZero(outputData, aInput.GetDuration());
}
}
}
@ -111,7 +99,18 @@ static void ConvertSegmentToAudioBlock(AudioSegment* aSegment,
uint32_t duration = 0;
for (AudioSegment::ChunkIterator ci(*aSegment); !ci.IsEnded(); ci.Next()) {
CopyChunkToBlock(*ci, aBlock, duration);
switch (ci->mBufferFormat) {
case AUDIO_FORMAT_S16: {
CopyChunkToBlock<int16_t>(*ci, aBlock, duration);
break;
}
case AUDIO_FORMAT_FLOAT32: {
CopyChunkToBlock<float>(*ci, aBlock, duration);
break;
}
case AUDIO_FORMAT_SILENCE:
break;
}
duration += ci->GetDuration();
}
}

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

@ -430,7 +430,7 @@ AudioNodeStream::AccumulateInputChunk(uint32_t aInputIndex, const AudioChunk& aC
AudioChunk* aBlock,
nsTArray<float>* aDownmixBuffer)
{
nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channels;
nsAutoTArray<const float*,GUESS_AUDIO_CHANNELS> channels;
UpMixDownMixChunk(&aChunk, aBlock->mChannelData.Length(), channels, *aDownmixBuffer);
for (uint32_t c = 0; c < channels.Length(); ++c) {
@ -453,15 +453,17 @@ AudioNodeStream::AccumulateInputChunk(uint32_t aInputIndex, const AudioChunk& aC
void
AudioNodeStream::UpMixDownMixChunk(const AudioChunk* aChunk,
uint32_t aOutputChannelCount,
nsTArray<const void*>& aOutputChannels,
nsTArray<const float*>& aOutputChannels,
nsTArray<float>& aDownmixBuffer)
{
static const float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f};
aOutputChannels.AppendElements(aChunk->mChannelData);
for (uint32_t i = 0; i < aChunk->mChannelData.Length(); i++) {
aOutputChannels.AppendElement(static_cast<const float*>(aChunk->mChannelData[i]));
}
if (aOutputChannels.Length() < aOutputChannelCount) {
if (mChannelInterpretation == ChannelInterpretation::Speakers) {
AudioChannelsUpMix(&aOutputChannels, aOutputChannelCount, nullptr);
AudioChannelsUpMix(&aOutputChannels, aOutputChannelCount, SilentChannel::ZeroChannel<float>());
NS_ASSERTION(aOutputChannelCount == aOutputChannels.Length(),
"We called GetAudioChannelsSuperset to avoid this");
} else {

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

@ -183,7 +183,7 @@ protected:
AudioChunk* aBlock,
nsTArray<float>* aDownmixBuffer);
void UpMixDownMixChunk(const AudioChunk* aChunk, uint32_t aOutputChannelCount,
nsTArray<const void*>& aOutputChannels,
nsTArray<const float*>& aOutputChannels,
nsTArray<float>& aDownmixBuffer);
uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount);

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

@ -156,7 +156,7 @@ DelayBuffer::ReadChannels(const double aPerFrameDelays[WEBAUDIO_BLOCK_SIZE],
for (uint32_t channel = aFirstChannel;
channel < readChannelsEnd; ++channel) {
aOutputChunk->ChannelFloatsForWrite(channel)[i] += multiplier *
static_cast<const float*>(mUpmixChannels[channel])[readOffset];
mUpmixChannels[channel][readOffset];
}
}
@ -238,24 +238,23 @@ DelayBuffer::UpdateUpmixChannels(int aNewReadChunk, uint32_t aChannelCount,
return;
}
static const float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {};
NS_WARN_IF_FALSE(mHaveWrittenBlock || aNewReadChunk != mCurrentChunk,
"Smoothing is making feedback delay too small.");
mLastReadChunk = aNewReadChunk;
mUpmixChannels = mChunks[aNewReadChunk].mChannelData;
mUpmixChannels = mChunks[aNewReadChunk].ChannelData<float>();
MOZ_ASSERT(mUpmixChannels.Length() <= aChannelCount);
if (mUpmixChannels.Length() < aChannelCount) {
if (aChannelInterpretation == ChannelInterpretation::Speakers) {
AudioChannelsUpMix(&mUpmixChannels, aChannelCount, silenceChannel);
AudioChannelsUpMix(&mUpmixChannels,
aChannelCount, SilentChannel::ZeroChannel<float>());
MOZ_ASSERT(mUpmixChannels.Length() == aChannelCount,
"We called GetAudioChannelsSuperset to avoid this");
} else {
// Fill up the remaining channels with zeros
for (uint32_t channel = mUpmixChannels.Length();
channel < aChannelCount; ++channel) {
mUpmixChannels.AppendElement(silenceChannel);
mUpmixChannels.AppendElement(SilentChannel::ZeroChannel<float>());
}
}
}

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

@ -94,7 +94,7 @@ private:
// Circular buffer for capturing delayed samples.
FallibleTArray<AudioChunk> mChunks;
// Cache upmixed channel arrays.
nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> mUpmixChannels;
nsAutoTArray<const float*,GUESS_AUDIO_CHANNELS> mUpmixChannels;
double mSmoothingRate;
// Current delay, in fractional ticks
double mCurrentDelay;

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

@ -23,7 +23,7 @@ async protocol PSpeechSynthesisRequest
ForceEnd();
SetAudioOutputVolume(uint32_t aVolume);
SetAudioOutputVolume(float aVolume);
child:

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

@ -192,7 +192,7 @@ SpeechTaskChild::ForceEnd()
}
void
SpeechTaskChild::SetAudioOutputVolume(uint32_t aVolume)
SpeechTaskChild::SetAudioOutputVolume(float aVolume)
{
if (mActor) {
mActor->SendSetAudioOutputVolume(aVolume);

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

@ -92,7 +92,7 @@ public:
virtual void ForceEnd() override;
virtual void SetAudioOutputVolume(uint32_t aVolume) override;
virtual void SetAudioOutputVolume(float aVolume) override;
private:
SpeechSynthesisRequestChild* mActor;

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

@ -128,7 +128,7 @@ SpeechSynthesisRequestParent::RecvForceEnd()
}
bool
SpeechSynthesisRequestParent::RecvSetAudioOutputVolume(const uint32_t& aVolume)
SpeechSynthesisRequestParent::RecvSetAudioOutputVolume(const float& aVolume)
{
MOZ_ASSERT(mTask);
mTask->SetAudioOutputVolume(aVolume);

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

@ -70,7 +70,7 @@ protected:
virtual bool RecvForceEnd() override;
virtual bool RecvSetAudioOutputVolume(const uint32_t& aVolume) override;
virtual bool RecvSetAudioOutputVolume(const float& aVolume) override;
};
class SpeechTaskParent : public nsSpeechTask

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

@ -12,7 +12,7 @@ typedef unsigned short SpeechServiceType;
* required to implement these, although it could be helpful to use the
* cancel method for shutting down the speech resources.
*/
[scriptable, uuid(408251b0-1d7b-4876-888f-718859ce8c9d)]
[scriptable, uuid(c576de0c-8a3d-4570-be7e-9876d3e5bed2)]
interface nsISpeechTaskCallback : nsISupports
{
/**
@ -29,6 +29,12 @@ interface nsISpeechTaskCallback : nsISupports
* The user or application has canceled the speech.
*/
void onCancel();
/**
* The user or application has changed the volume of this speech.
* This is only used on indirect audio service type.
*/
void onVolumeChanged(in float aVolume);
};

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

@ -667,6 +667,10 @@ nsSpeechTask::CreateAudioChannelAgent()
mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(),
static_cast<int32_t>(AudioChannelService::GetDefaultAudioChannel()),
this);
float volume = 0.0f;
bool muted = true;
mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY, &volume, &muted);
WindowVolumeChanged(volume, muted);
}
void
@ -681,7 +685,7 @@ nsSpeechTask::DestroyAudioChannelAgent()
NS_IMETHODIMP
nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted)
{
SetAudioOutputVolume(mVolume * aVolume * aMuted);
SetAudioOutputVolume(aMuted ? 0.0 : mVolume * aVolume);
return NS_OK;
}
@ -693,11 +697,14 @@ nsSpeechTask::WindowAudioCaptureChanged()
}
void
nsSpeechTask::SetAudioOutputVolume(uint32_t aVolume)
nsSpeechTask::SetAudioOutputVolume(float aVolume)
{
if (mStream) {
mStream->SetAudioOutputVolume(this, aVolume);
}
if (mIndirectAudio) {
mCallback->OnVolumeChanged(aVolume);
}
}
} // namespace dom

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

@ -52,7 +52,7 @@ public:
void SetChosenVoiceURI(const nsAString& aUri);
virtual void SetAudioOutputVolume(uint32_t aVolume);
virtual void SetAudioOutputVolume(float aVolume);
bool IsPreCanceled()
{

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

@ -409,6 +409,12 @@ PicoCallbackRunnable::OnCancel()
return NS_OK;
}
NS_IMETHODIMP
PicoCallbackRunnable::OnVolumeChanged(float aVolume)
{
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN(nsPicoService)
NS_INTERFACE_MAP_ENTRY(nsISpeechService)
NS_INTERFACE_MAP_ENTRY(nsIObserver)

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

@ -91,6 +91,11 @@ public:
return NS_OK;
}
NS_IMETHOD OnVolumeChanged(float aVolume) override
{
return NS_OK;
}
private:
virtual ~FakeSynthCallback() { }

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

@ -103,6 +103,13 @@ SapiCallback::OnCancel()
return NS_OK;
}
NS_IMETHODIMP
SapiCallback::OnVolumeChanged(float aVolume)
{
mSapiClient->SetVolume(static_cast<USHORT>(aVolume * 100));
return NS_OK;
}
void
SapiCallback::OnSpeechEvent(const SPEVENT& speechEvent)
{

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

@ -249,6 +249,16 @@ nsNPAPIPlugin::PluginCrashed(const nsAString& pluginDumpID,
host->PluginCrashed(this, pluginDumpID, browserDumpID);
}
bool
nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag)
{
#ifdef MOZ_WIDGET_ANDROID
return false;
#else
return true;
#endif
}
inline PluginLibrary*
GetNewPluginLibrary(nsPluginTag *aPluginTag)
{
@ -260,7 +270,10 @@ GetNewPluginLibrary(nsPluginTag *aPluginTag)
return PluginModuleContentParent::LoadModule(aPluginTag->mId);
}
return PluginModuleChromeParent::LoadModule(aPluginTag->mFullPath.get(), aPluginTag->mId, aPluginTag);
if (nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
return PluginModuleChromeParent::LoadModule(aPluginTag->mFullPath.get(), aPluginTag->mId, aPluginTag);
}
return new PluginPRLibrary(aPluginTag->mFullPath.get(), aPluginTag->mLibrary);
}
// Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).

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

@ -53,6 +53,8 @@ public:
void PluginCrashed(const nsAString& pluginDumpID,
const nsAString& browserDumpID);
static bool RunPluginOOP(const nsPluginTag *aPluginTag);
nsresult Shutdown();
static nsresult RetainStream(NPStream *pstream, nsISupports **aRetainedPeer);

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

@ -1330,11 +1330,35 @@ nsPluginHost::FindNativePluginForExtension(const nsACString & aExtension,
return preferredPlugin;
}
static nsresult CreateNPAPIPlugin(nsPluginTag *aPluginTag,
nsNPAPIPlugin **aOutNPAPIPlugin)
{
// If this is an in-process plugin we'll need to load it here if we haven't already.
if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
if (aPluginTag->mFullPath.IsEmpty())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
file->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag->mFullPath));
nsPluginFile pluginFile(file);
PRLibrary* pluginLibrary = nullptr;
if (NS_FAILED(pluginFile.LoadPlugin(&pluginLibrary)) || !pluginLibrary)
return NS_ERROR_FAILURE;
aPluginTag->mLibrary = pluginLibrary;
}
nsresult rv;
rv = nsNPAPIPlugin::CreatePlugin(aPluginTag, aOutNPAPIPlugin);
return rv;
}
nsresult nsPluginHost::EnsurePluginLoaded(nsPluginTag* aPluginTag)
{
nsRefPtr<nsNPAPIPlugin> plugin = aPluginTag->mPlugin;
if (!plugin) {
nsresult rv = nsNPAPIPlugin::CreatePlugin(aPluginTag, getter_AddRefs(plugin));
nsresult rv = CreateNPAPIPlugin(aPluginTag, getter_AddRefs(plugin));
if (NS_FAILED(rv)) {
return rv;
}
@ -2232,6 +2256,14 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
*aPluginsChanged = true;
}
// Avoid adding different versions of the same plugin if they are running
// in-process, otherwise we risk undefined behaviour.
if (!nsNPAPIPlugin::RunPluginOOP(pluginTag)) {
if (HaveSamePlugin(pluginTag)) {
continue;
}
}
// Don't add the same plugin again if it hasn't changed
if (nsPluginTag* duplicate = FirstPluginWithPath(pluginTag->mFullPath)) {
if (pluginTag->mLastModifiedTime == duplicate->mLastModifiedTime) {

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

@ -150,7 +150,7 @@ class RespondWithHandler final : public PromiseNativeHandler
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
const RequestMode mRequestMode;
const bool mIsClientRequest;
const DebugOnly<bool> mIsClientRequest;
const bool mIsNavigationRequest;
public:
NS_DECL_ISUPPORTS
@ -272,8 +272,6 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
// If one of the following conditions is true, return a network error:
// * response's type is "error".
// * request's mode is not "no-cors" and response's type is "opaque".
// * request is a client request and response's type is neither "basic"
// nor "default".
// * request is not a navigation request and response's type is
// "opaqueredirect".
@ -282,19 +280,13 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
return;
}
MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin);
if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE);
return;
}
// TODO: remove this case as its no longer in the spec (bug 1184967)
if (mIsClientRequest && response->Type() != ResponseType::Basic &&
response->Type() != ResponseType::Default &&
response->Type() != ResponseType::Opaqueredirect) {
autoCancel.SetCancelStatus(NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION);
return;
}
if (!mIsNavigationRequest && response->Type() == ResponseType::Opaqueredirect) {
autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION);
return;

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

@ -3709,22 +3709,7 @@ public:
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
uint32_t corsMode;
internalChannel->GetCorsMode(&corsMode);
switch (corsMode) {
case nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN:
mRequestMode = RequestMode::Same_origin;
break;
case nsIHttpChannelInternal::CORS_MODE_NO_CORS:
mRequestMode = RequestMode::No_cors;
break;
case nsIHttpChannelInternal::CORS_MODE_CORS:
case nsIHttpChannelInternal::CORS_MODE_CORS_WITH_FORCED_PREFLIGHT:
mRequestMode = RequestMode::Cors;
break;
default:
MOZ_CRASH("Unexpected CORS mode");
}
mRequestMode = InternalRequest::MapChannelToRequestMode(channel);
// This is safe due to static_asserts at top of file.
uint32_t redirectMode;
@ -3757,6 +3742,8 @@ public:
mMethod = "GET";
mRequestMode = InternalRequest::MapChannelToRequestMode(channel);
if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
mRequestCredentials = RequestCredentials::Omit;
}

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

@ -4,8 +4,7 @@ self.addEventListener("install", function(event) {
event.waitUntil(
self.caches.open("origin-cache")
.then(c => {
return c.add(new Request(prefix + 'index-https.sjs',
{ redirect: 'manual' }));
return c.add(prefix + 'index-https.sjs');
})
);
});

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

@ -0,0 +1 @@
Access-Control-Allow-Origin: https://example.com

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

@ -6,10 +6,8 @@ self.addEventListener("install", function(event) {
.then(c => {
return Promise.all(
[
c.add(new Request(prefix + 'index.sjs',
{ redirect: 'manual' } )),
c.add(new Request(prefix + 'index-to-https.sjs',
{ redirect: 'manual' } ))
c.add(prefix + 'index.sjs'),
c.add(prefix + 'index-to-https.sjs')
]
);
})

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

@ -0,0 +1 @@
Access-Control-Allow-Origin: http://mochi.test:8888

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

@ -53,11 +53,13 @@ support-files =
fetch/origin/index.sjs
fetch/origin/index-to-https.sjs
fetch/origin/realindex.html
fetch/origin/realindex.html^headers^
fetch/origin/register.html
fetch/origin/unregister.html
fetch/origin/origin_test.js
fetch/origin/https/index-https.sjs
fetch/origin/https/realindex.html
fetch/origin/https/realindex.html^headers^
fetch/origin/https/register.html
fetch/origin/https/unregister.html
fetch/origin/https/origin_test.js

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

@ -270,28 +270,11 @@ IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
mData.mCbCrStride, mData.mCbCrStride * mData.mCbCrSize.height);
}
RefPtr<IDXGIResource> resource;
HANDLE shareHandleY;
textureY->QueryInterface((IDXGIResource**)byRef(resource));
hr = resource->GetSharedHandle(&shareHandleY);
HANDLE shareHandleCb;
textureCb->QueryInterface((IDXGIResource**)byRef(resource));
hr = resource->GetSharedHandle(&shareHandleCb);
HANDLE shareHandleCr;
textureCr->QueryInterface((IDXGIResource**)byRef(resource));
hr = resource->GetSharedHandle(&shareHandleCr);
mTextureClient = DXGIYCbCrTextureClient::Create(aClient->GetForwarder(),
TextureFlags::DEFAULT,
textureY,
textureCb,
textureCr,
shareHandleY,
shareHandleCb,
shareHandleCr,
GetSize(),
mData.mYSize,
mData.mCbCrSize);

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

@ -170,6 +170,7 @@ ImageContainer::ImageContainer(Mode flag)
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
mGenerationCounter(++sGenerationCounter),
mPaintCount(0),
mAttachCount(0),
mDroppedImageCount(0),
mImageFactory(new ImageFactory()),
mRecycleBin(new BufferRecycleBin()),
@ -234,6 +235,28 @@ ImageContainer::CreateImage(ImageFormat aFormat)
return mImageFactory->CreateImage(aFormat, mScaleHint, mRecycleBin);
}
void
ImageContainer::NotifyAttached()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!mAttachCount++) {
if (IsAsync()) {
ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this);
}
}
}
void
ImageContainer::NotifyDetached()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!--mAttachCount) {
if (IsAsync()) {
ImageBridgeChild::FlushAllImagesAsync(mImageClient);
}
}
}
void
ImageContainer::SetCurrentImageInternal(const nsTArray<NonOwningImage>& aImages)
{

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

@ -388,6 +388,18 @@ public:
*/
uint64_t GetAsyncContainerID() const;
/**
* We track when ImageContainers are attached to layers so that we can
* avoid sending images through ImageBridge if they won't be displayed.
*/
void NotifyAttached();
void NotifyDetached();
bool IsAttached() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return !!mAttachCount;
}
/**
* Returns if the container currently has an image.
* Can be called on any thread. This method takes mReentrantMonitor
@ -519,6 +531,8 @@ private:
// threadsafe.
uint32_t mPaintCount;
int32_t mAttachCount;
// See GetPaintDelay. Accessed only with mReentrantMonitor held.
TimeDuration mPaintDelay;

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

@ -19,11 +19,25 @@ ImageLayer::ImageLayer(LayerManager* aManager, void* aImplData)
{}
ImageLayer::~ImageLayer()
{}
{
if (mContainer) {
mContainer->NotifyDetached();
}
}
void ImageLayer::SetContainer(ImageContainer* aContainer)
{
if (aContainer == mContainer) {
return;
}
if (mContainer) {
mContainer->NotifyDetached();
}
mContainer = aContainer;
if (mContainer) {
mContainer->NotifyAttached();
}
}
void ImageLayer::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)

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

@ -667,9 +667,9 @@ DXGIYCbCrTextureClient::~DXGIYCbCrTextureClient()
already_AddRefed<DXGIYCbCrTextureClient>
DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
TextureFlags aFlags,
IUnknown* aTextureY,
IUnknown* aTextureCb,
IUnknown* aTextureCr,
IDirect3DTexture9* aTextureY,
IDirect3DTexture9* aTextureCb,
IDirect3DTexture9* aTextureCr,
HANDLE aHandleY,
HANDLE aHandleCb,
HANDLE aHandleCr,
@ -682,6 +682,13 @@ DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
return nullptr;
}
aTextureY->SetPrivateData(sD3D11TextureUsage,
new TextureMemoryMeasurer(aSizeY.width * aSizeY.height), sizeof(IUnknown*), D3DSPD_IUNKNOWN);
aTextureCb->SetPrivateData(sD3D11TextureUsage,
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height), sizeof(IUnknown*), D3DSPD_IUNKNOWN);
aTextureCr->SetPrivateData(sD3D11TextureUsage,
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height), sizeof(IUnknown*), D3DSPD_IUNKNOWN);
RefPtr<DXGIYCbCrTextureClient> texture =
new DXGIYCbCrTextureClient(aAllocator, aFlags);
texture->mHandles[0] = aHandleY;
@ -696,6 +703,59 @@ DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
return texture.forget();
}
already_AddRefed<DXGIYCbCrTextureClient>
DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
TextureFlags aFlags,
ID3D11Texture2D* aTextureY,
ID3D11Texture2D* aTextureCb,
ID3D11Texture2D* aTextureCr,
const gfx::IntSize& aSize,
const gfx::IntSize& aSizeY,
const gfx::IntSize& aSizeCbCr)
{
if (!aTextureY || !aTextureCb || !aTextureCr) {
return nullptr;
}
aTextureY->SetPrivateDataInterface(sD3D11TextureUsage,
new TextureMemoryMeasurer(aSize.width * aSize.height));
aTextureCb->SetPrivateDataInterface(sD3D11TextureUsage,
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
aTextureCr->SetPrivateDataInterface(sD3D11TextureUsage,
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
RefPtr<DXGIYCbCrTextureClient> texture =
new DXGIYCbCrTextureClient(aAllocator, aFlags);
RefPtr<IDXGIResource> resource;
aTextureY->QueryInterface((IDXGIResource**)byRef(resource));
HRESULT hr = resource->GetSharedHandle(&texture->mHandles[0]);
if (FAILED(hr)) {
return nullptr;
}
aTextureCb->QueryInterface((IDXGIResource**)byRef(resource));
hr = resource->GetSharedHandle(&texture->mHandles[1]);
if (FAILED(hr)) {
return nullptr;
}
aTextureCr->QueryInterface((IDXGIResource**)byRef(resource));
hr = resource->GetSharedHandle(&texture->mHandles[2]);
if (FAILED(hr)) {
return nullptr;
}
texture->mHoldRefs[0] = aTextureY;
texture->mHoldRefs[1] = aTextureCb;
texture->mHoldRefs[2] = aTextureCr;
texture->mSize = aSize;
texture->mSizeY = aSizeY;
texture->mSizeCbCr = aSizeCbCr;
return texture.forget();
}
bool
DXGIYCbCrTextureClient::Lock(OpenMode)
{

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

@ -12,6 +12,7 @@
#include "gfxWindowsPlatform.h"
#include "mozilla/GfxMessageUtils.h"
#include <d3d11.h>
#include "d3d9.h"
#include <vector>
namespace mozilla {
@ -109,9 +110,9 @@ public:
static already_AddRefed<DXGIYCbCrTextureClient>
Create(ISurfaceAllocator* aAllocator,
TextureFlags aFlags,
IUnknown* aTextureY,
IUnknown* aTextureCb,
IUnknown* aTextureCr,
IDirect3DTexture9* aTextureY,
IDirect3DTexture9* aTextureCb,
IDirect3DTexture9* aTextureCr,
HANDLE aHandleY,
HANDLE aHandleCb,
HANDLE aHandleCr,
@ -119,6 +120,17 @@ public:
const gfx::IntSize& aSizeY,
const gfx::IntSize& aSizeCbCr);
// Creates a TextureClient and init width.
static already_AddRefed<DXGIYCbCrTextureClient>
Create(ISurfaceAllocator* aAllocator,
TextureFlags aFlags,
ID3D11Texture2D* aTextureY,
ID3D11Texture2D* aTextureCb,
ID3D11Texture2D* aTextureCr,
const gfx::IntSize& aSize,
const gfx::IntSize& aSizeY,
const gfx::IntSize& aSizeCbCr);
// TextureClient
virtual bool IsAllocated() const override{ return !!mHoldRefs[0]; }

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

@ -407,6 +407,9 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(aContainer);
if (!aContainer->IsAttached()) {
return;
}
sImageBridgeChildSingleton->BeginTransaction();
aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
sImageBridgeChildSingleton->EndTransaction();
@ -475,6 +478,33 @@ void ImageBridgeChild::FlushAllImages(ImageClient* aClient,
waiter->WaitComplete();
}
static void FlushAllImagesAsyncInternal(ImageClient* aClient)
{
MOZ_ASSERT(aClient);
sImageBridgeChildSingleton->BeginTransaction();
aClient->FlushAllImages(nullptr);
sImageBridgeChildSingleton->EndTransaction();
}
//static
void ImageBridgeChild::FlushAllImagesAsync(ImageClient* aClient)
{
if (!IsCreated()) {
return;
}
MOZ_ASSERT(aClient);
MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown);
MOZ_ASSERT(!InImageBridgeChildThread());
if (InImageBridgeChildThread()) {
NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
return;
}
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&FlushAllImagesAsyncInternal, aClient));
}
void
ImageBridgeChild::BeginTransaction()
{

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

@ -221,6 +221,8 @@ public:
*/
static void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer);
static void FlushAllImagesAsync(ImageClient* aClient);
// CompositableForwarder
virtual void Connect(CompositableClient* aCompositable,

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

@ -319,7 +319,7 @@ AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembl
MOZ_ASSERT(masm.jumpRelocationTableBytes() == 0);
MOZ_ASSERT(masm.dataRelocationTableBytes() == 0);
MOZ_ASSERT(masm.preBarrierTableBytes() == 0);
MOZ_ASSERT(!masm.hasEnteredExitFrame());
MOZ_ASSERT(!masm.hasSelfReference());
// Copy over metadata, making sure to update all offsets on ARM.

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

@ -1367,7 +1367,7 @@ class MOZ_STACK_CLASS ModuleCompiler
return hn;
}
static bool match(const ExitDescriptor& lhs, const ExitDescriptor& rhs) {
return lhs.name_ == rhs.name_ && lhs.sig_ == rhs.sig_;
return lhs.name_ == rhs.name_ && *lhs.sig_ == *rhs.sig_;
}
};
@ -11453,7 +11453,7 @@ GenerateFFIIonExit(ModuleCompiler& m, const ModuleCompiler::ExitDescriptor& exit
}
AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
masm.callJitFromAsmJS(callee);
masm.callJitNoProfiler(callee);
AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
{

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

@ -821,7 +821,9 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn)
ParseNode* pn2;
if (opn->isKind(PNK_OBJECT)) {
if (opn2->isKind(PNK_MUTATEPROTO)) {
ParseNode* target = cloneLeftHandSide(opn2->pn_kid);
ParseNode* target = opn2->pn_kid->isKind(PNK_ASSIGN)
? cloneDestructuringDefault(opn2->pn_kid)
: cloneLeftHandSide(opn2->pn_kid);
if (!target)
return nullptr;
pn2 = handler.new_<UnaryNode>(PNK_MUTATEPROTO, JSOP_NOP, opn2->pn_pos, target);
@ -832,12 +834,9 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn)
ParseNode* tag = cloneParseTree(opn2->pn_left);
if (!tag)
return nullptr;
ParseNode* target;
if (opn2->pn_right->isKind(PNK_ASSIGN)) {
target = cloneDestructuringDefault(opn2->pn_right);
} else {
target = cloneLeftHandSide(opn2->pn_right);
}
ParseNode* target = opn2->pn_right->isKind(PNK_ASSIGN)
? cloneDestructuringDefault(opn2->pn_right)
: cloneLeftHandSide(opn2->pn_right);
if (!target)
return nullptr;

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

@ -1397,7 +1397,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
JSFunction::Flags flags;
switch (kind) {
case Expression:
flags = JSFunction::INTERPRETED_LAMBDA;
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_LAMBDA
: JSFunction::INTERPRETED_LAMBDA_GENERATOR);
break;
case Arrow:
flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
@ -1405,10 +1407,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
break;
case Method:
MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator);
if (generatorKind == NotGenerator)
flags = JSFunction::INTERPRETED_METHOD;
else
flags = JSFunction::INTERPRETED_METHOD_GENERATOR;
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_METHOD
: JSFunction::INTERPRETED_METHOD_GENERATOR);
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case ClassConstructor:
@ -1425,8 +1426,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
default:
flags = JSFunction::INTERPRETED_NORMAL;
break;
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_NORMAL
: JSFunction::INTERPRETED_GENERATOR);
}
fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,

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

@ -3786,7 +3786,11 @@ BaselineCompiler::emit_JSOP_RESUME()
// Push a fake return address on the stack. We will resume here when the
// generator returns.
Label genStart, returnTarget;
#ifdef JS_USE_LINK_REGISTER
masm.call(&genStart);
#else
masm.callAndPushReturnAddress(&genStart);
#endif
// Add an IC entry so the return offset -> pc mapping works.
if (!appendICEntry(ICEntry::Kind_Op, masm.currentOffset()))
@ -3794,6 +3798,9 @@ BaselineCompiler::emit_JSOP_RESUME()
masm.jump(&returnTarget);
masm.bind(&genStart);
#ifdef JS_USE_LINK_REGISTER
masm.pushReturnAddress();
#endif
// If profiler instrumentation is on, update lastProfilingFrame on
// current JitActivation

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

@ -10365,7 +10365,7 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
EmitBaselineCreateStubFrameDescriptor(masm, scratch);
masm.push(scratch);
masm.push(ICTailCallReg);
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
masm.enterFakeExitFrame(NativeExitFrameLayoutToken);
// Execute call.
masm.setupUnalignedABICall(scratch);
@ -10463,7 +10463,7 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
EmitBaselineCreateStubFrameDescriptor(masm, scratch);
masm.push(scratch);
masm.push(ICTailCallReg);
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
masm.enterFakeExitFrame(NativeExitFrameLayoutToken);
// Execute call.
masm.setupUnalignedABICall(scratch);

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

@ -2872,9 +2872,8 @@ CodeGenerator::visitCallNative(LCallNative* call)
masm.Push(argUintNReg);
// Construct native exit frame.
uint32_t safepointOffset;
masm.buildFakeExitFrame(tempReg, &safepointOffset);
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
uint32_t safepointOffset = masm.buildFakeExitFrame(tempReg);
masm.enterFakeExitFrame(NativeExitFrameLayoutToken);
markSafepointAt(safepointOffset, call);
@ -2991,9 +2990,8 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
masm.moveStackPtrTo(argObj);
// Construct native exit frame.
uint32_t safepointOffset;
masm.buildFakeExitFrame(argJSContext, &safepointOffset);
masm.enterFakeExitFrame(IonDOMMethodExitFrameLayout::Token());
uint32_t safepointOffset = masm.buildFakeExitFrame(argJSContext);
masm.enterFakeExitFrame(IonDOMMethodExitFrameLayoutToken);
markSafepointAt(safepointOffset, call);
@ -6313,7 +6311,7 @@ JitRuntime::generateLazyLinkStub(JSContext* cx)
size_t convertToExitFrame = JitFrameLayout::Size() - ExitFrameLayout::Size();
masm.addPtr(Imm32(convertToExitFrame << FRAMESIZE_SHIFT), descriptor);
masm.enterFakeExitFrame(LazyLinkExitFrameLayout::Token());
masm.enterFakeExitFrame(LazyLinkExitFrameLayoutToken);
masm.PushStubCode();
masm.setupUnalignedABICall(temp0);
@ -9735,9 +9733,8 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
// Rooting will happen at GC time.
masm.moveStackPtrTo(ObjectReg);
uint32_t safepointOffset;
masm.buildFakeExitFrame(JSContextReg, &safepointOffset);
masm.enterFakeExitFrame(IonDOMExitFrameLayout::GetterToken());
uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
masm.enterFakeExitFrame(IonDOMExitFrameLayoutGetterToken);
markSafepointAt(safepointOffset, ins);
@ -9825,9 +9822,8 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
// Rooting will happen at GC time.
masm.moveStackPtrTo(ObjectReg);
uint32_t safepointOffset;
masm.buildFakeExitFrame(JSContextReg, &safepointOffset);
masm.enterFakeExitFrame(IonDOMExitFrameLayout::SetterToken());
uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
masm.enterFakeExitFrame(IonDOMExitFrameLayoutSetterToken);
markSafepointAt(safepointOffset, ins);

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

@ -945,7 +945,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm,
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLNativeExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLNativeExitFrameLayoutToken);
// Construct and execute call.
masm.setupUnalignedABICall(scratchReg);
@ -1003,7 +1003,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm,
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLPropertyOpExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLPropertyOpExitFrameLayoutToken);
// Make the call.
masm.setupUnalignedABICall(scratchReg);
@ -1586,7 +1586,7 @@ EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayoutToken);
// Make the call.
masm.setupUnalignedABICall(scratch);
@ -2297,7 +2297,7 @@ EmitCallProxySet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayoutToken);
// Make the call.
masm.setupUnalignedABICall(scratch);
@ -2506,7 +2506,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLNativeExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLNativeExitFrameLayoutToken);
// Make the call
masm.setupUnalignedABICall(scratchReg);
@ -2570,7 +2570,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLSetterOpExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLSetterOpExitFrameLayoutToken);
// Make the call.
masm.setupUnalignedABICall(scratchReg);

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

@ -4358,26 +4358,39 @@ MaybeUnwrapElements(const MDefinition* elementsOrObj)
return elementsOrObj->toElements();
}
static inline const MDefinition*
GetElementsObject(const MDefinition* elementsOrObj)
{
if (elementsOrObj->type() == MIRType_Object)
return elementsOrObj;
const MDefinition* elements = MaybeUnwrapElements(elementsOrObj);
if (elements)
return elements->toElements()->input();
return nullptr;
}
// Gets the MDefinition of the target Object for the given store operation.
static inline const MDefinition*
GetStoreObject(const MDefinition* store)
{
switch (store->op()) {
case MDefinition::Op_StoreElement: {
const MDefinition* elementsOrObj = store->toStoreElement()->elements();
if (elementsOrObj->type() == MIRType_Object)
return elementsOrObj;
const MDefinition* elements = MaybeUnwrapElements(elementsOrObj);
if (elements)
return elements->toElements()->input();
return nullptr;
}
case MDefinition::Op_StoreElement:
return GetElementsObject(store->toStoreElement()->elements());
case MDefinition::Op_StoreElementHole:
return store->toStoreElementHole()->object();
case MDefinition::Op_StoreUnboxedObjectOrNull:
return GetElementsObject(store->toStoreUnboxedObjectOrNull()->elements());
case MDefinition::Op_StoreUnboxedString:
return GetElementsObject(store->toStoreUnboxedString()->elements());
case MDefinition::Op_StoreUnboxedScalar:
return GetElementsObject(store->toStoreUnboxedScalar()->elements());
default:
return nullptr;
}
@ -4438,6 +4451,30 @@ MInitializedLength::mightAlias(const MDefinition* store) const
return GenericLoadMightAlias(elements(), store);
}
bool
MLoadUnboxedObjectOrNull::mightAlias(const MDefinition* store) const
{
return GenericLoadMightAlias(elements(), store);
}
bool
MLoadUnboxedString::mightAlias(const MDefinition* store) const
{
return GenericLoadMightAlias(elements(), store);
}
bool
MLoadUnboxedScalar::mightAlias(const MDefinition* store) const
{
return GenericLoadMightAlias(elements(), store);
}
bool
MUnboxedArrayInitializedLength::mightAlias(const MDefinition* store) const
{
return GenericLoadMightAlias(object(), store);
}
bool
MGuardReceiverPolymorphic::congruentTo(const MDefinition* ins) const
{
@ -4988,15 +5025,46 @@ PropertyReadNeedsTypeBarrier(CompilerConstraintList* constraints,
return BarrierKind::NoBarrier;
}
static bool
ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
{
if (first->isSingleton() ||
second->isSingleton() ||
first->clasp() != second->clasp() ||
first->unknownProperties() ||
second->unknownProperties())
{
return false;
}
if (first->clasp() == &ArrayObject::class_) {
HeapTypeSetKey firstElements = first->property(JSID_VOID);
HeapTypeSetKey secondElements = second->property(JSID_VOID);
return firstElements.maybeTypes() && secondElements.maybeTypes() &&
firstElements.maybeTypes()->equals(secondElements.maybeTypes());
}
if (first->clasp() == &UnboxedArrayObject::class_) {
return first->group()->unboxedLayout().elementType() ==
second->group()->unboxedLayout().elementType();
}
return false;
}
BarrierKind
jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
CompilerConstraintList* constraints,
TypeSet::ObjectKey* key, PropertyName* name,
TemporaryTypeSet* observed, bool updateObserved)
{
if (!updateObserved)
return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
// If this access has never executed, try to add types to the observed set
// according to any property which exists on the object or its prototype.
if (updateObserved && observed->empty() && name) {
if (observed->empty() && name) {
JSObject* obj;
if (key->isSingleton())
obj = key->singleton();
@ -5029,6 +5097,30 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
}
}
// If any objects which could be observed are similar to ones that have
// already been observed, add them to the observed type set.
if (!key->unknownProperties()) {
HeapTypeSetKey property = key->property(name ? NameToId(name) : JSID_VOID);
if (property.maybeTypes() && !property.maybeTypes()->unknownObject()) {
for (size_t i = 0; i < property.maybeTypes()->getObjectCount(); i++) {
TypeSet::ObjectKey* key = property.maybeTypes()->getObject(i);
if (!key || observed->unknownObject())
continue;
for (size_t j = 0; j < observed->getObjectCount(); j++) {
TypeSet::ObjectKey* observedKey = observed->getObject(j);
if (observedKey && ObjectSubsumes(observedKey, key)) {
// Note: the return value here is ignored.
observed->addType(TypeSet::ObjectType(key),
GetJitContext()->temp->lifoAlloc());
break;
}
}
}
}
}
return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
}

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

@ -8008,6 +8008,7 @@ class MUnboxedArrayInitializedLength
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
bool mightAlias(const MDefinition* store) const override;
ALLOW_CLONE(MUnboxedArrayInitializedLength)
};
@ -8761,6 +8762,7 @@ class MLoadUnboxedObjectOrNull
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::UnboxedElement);
}
bool mightAlias(const MDefinition* store) const override;
ALLOW_CLONE(MLoadUnboxedObjectOrNull)
};
@ -8810,6 +8812,7 @@ class MLoadUnboxedString
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::UnboxedElement);
}
bool mightAlias(const MDefinition* store) const override;
ALLOW_CLONE(MLoadUnboxedString)
};
@ -9462,6 +9465,7 @@ class MLoadUnboxedScalar
return AliasSet::Store(AliasSet::UnboxedElement);
return AliasSet::Load(AliasSet::UnboxedElement);
}
bool mightAlias(const MDefinition* store) const override;
bool congruentTo(const MDefinition* ins) const override {
if (requiresBarrier_)
@ -12900,7 +12904,7 @@ class MRecompileCheck : public MNullaryInstruction
// All barriered operations - MMemoryBarrier, MCompareExchangeTypedArrayElement,
// MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as well as
// MLoadUnboxedScalar and MStoreUnboxedSclaar when they are marked as requiring
// MLoadUnboxedScalar and MStoreUnboxedScalar when they are marked as requiring
// a memory barrer - have the following attributes:
//
// - Not movable

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

@ -94,9 +94,8 @@ MacroAssembler::passABIArg(FloatRegister reg, MoveOp::Type type)
template <typename T> void
MacroAssembler::callWithABI(const T& fun, MoveOp::Type result)
{
profilerPreCall();
AutoProfilerCallInstrumentation profiler(*this);
callWithABINoProfiler(fun, result);
profilerPostReturn();
}
void
@ -152,30 +151,92 @@ MacroAssembler::signature() const
#endif
}
//}}} check_macroassembler_style
// ===============================================================
// Jit Frames.
uint32_t
MacroAssembler::callJitNoProfiler(Register callee)
{
#ifdef JS_USE_LINK_REGISTER
// The return address is pushed by the callee.
call(callee);
#else
callAndPushReturnAddress(callee);
#endif
return currentOffset();
}
uint32_t
MacroAssembler::callJit(Register callee)
{
AutoProfilerCallInstrumentation profiler(*this);
uint32_t ret = callJitNoProfiler(callee);
return ret;
}
uint32_t
MacroAssembler::callJit(JitCode* callee)
{
AutoProfilerCallInstrumentation profiler(*this);
call(callee);
return currentOffset();
}
void
MacroAssembler::makeFrameDescriptor(Register frameSizeReg, FrameType type)
{
// See JitFrames.h for a description of the frame descriptor format.
lshiftPtr(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
// The saved-frame bit is zero for new frames. See js::SavedStacks.
orPtr(Imm32(type), frameSizeReg);
}
void
MacroAssembler::pushStaticFrameDescriptor(FrameType type)
{
uint32_t descriptor = MakeFrameDescriptor(framePushed(), type);
Push(Imm32(descriptor));
}
uint32_t
MacroAssembler::buildFakeExitFrame(Register scratch)
{
mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
pushStaticFrameDescriptor(JitFrame_IonJS);
uint32_t retAddr = pushFakeReturnAddress(scratch);
MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
return retAddr;
}
// ===============================================================
// Exit frame footer.
void
MacroAssembler::PushStubCode()
{
exitCodePatch_ = PushWithPatch(ImmWord(-1));
// Make sure that we do not erase an existing self-reference.
MOZ_ASSERT(!hasSelfReference());
selfReferencePatch_ = PushWithPatch(ImmWord(-1));
}
void
MacroAssembler::enterExitFrame(const VMFunction* f)
{
linkExitFrame();
// Push the ioncode. (Bailout or VM wrapper)
// Push the JitCode pointer. (Keep the code alive, when on the stack)
PushStubCode();
// Push VMFunction pointer, to mark arguments.
Push(ImmPtr(f));
}
void
MacroAssembler::enterFakeExitFrame(JitCode* codeVal)
MacroAssembler::enterFakeExitFrame(enum ExitFrameTokenValues token)
{
linkExitFrame();
Push(ImmPtr(codeVal));
Push(Imm32(token));
Push(ImmPtr(nullptr));
}
@ -186,11 +247,14 @@ MacroAssembler::leaveExitFrame(size_t extraFrame)
}
bool
MacroAssembler::hasEnteredExitFrame() const
MacroAssembler::hasSelfReference() const
{
return exitCodePatch_.offset() != 0;
return selfReferencePatch_.offset() != 0;
}
//}}} check_macroassembler_style
// ===============================================================
} // namespace jit
} // namespace js

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

@ -1588,15 +1588,6 @@ MacroAssembler::loadStringChar(Register str, Register index, Register output)
bind(&done);
}
// Save an exit frame (which must be aligned to the stack pointer) to
// PerThreadData::jitTop of the main thread.
void
MacroAssembler::linkExitFrame()
{
AbsoluteAddress jitTop(GetJitContext()->runtime->addressOfJitTop());
storeStackPtr(jitTop);
}
static void
BailoutReportOverRecursed(JSContext* cx)
{
@ -1667,7 +1658,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
push(temp);
push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)));
// No GC things to mark on the stack, push a bare token.
enterFakeExitFrame(ExitFrameLayout::BareToken());
enterFakeExitFrame(ExitFrameLayoutBareToken);
// If monitorStub is non-null, handle resumeAddr appropriately.
Label noMonitor;
@ -2365,24 +2356,8 @@ void
MacroAssembler::link(JitCode* code)
{
MOZ_ASSERT(!oom());
// If this code can transition to C++ code and witness a GC, then we need to store
// the JitCode onto the stack in order to GC it correctly. exitCodePatch should
// be unset if the code never needed to push its JitCode*.
if (hasEnteredExitFrame()) {
exitCodePatch_.fixup(this);
PatchDataWithValueCheck(CodeLocationLabel(code, exitCodePatch_),
ImmPtr(code),
ImmPtr((void*)-1));
}
// Fix up the code pointers to be written for locations where profilerCallSite
// emitted moves of RIP to a register.
for (size_t i = 0; i < profilerCallSites_.length(); i++) {
CodeOffsetLabel offset = profilerCallSites_[i];
offset.fixup(this);
CodeLocationLabel location(code, offset);
PatchDataWithValueCheck(location, ImmPtr(location.raw()), ImmPtr((void*)-1));
}
linkSelfReference(code);
linkProfilerCallSites(code);
}
void
@ -2436,29 +2411,41 @@ MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition* maybeDef, Reg
}
}
void
MacroAssembler::profilerPreCallImpl()
MacroAssembler::AutoProfilerCallInstrumentation::AutoProfilerCallInstrumentation(
MacroAssembler& masm
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (!masm.emitProfilingInstrumentation_)
return;
Register reg = CallTempReg0;
Register reg2 = CallTempReg1;
push(reg);
push(reg2);
profilerPreCallImpl(reg, reg2);
pop(reg2);
pop(reg);
}
masm.push(reg);
masm.push(reg2);
void
MacroAssembler::profilerPreCallImpl(Register reg, Register reg2)
{
JitContext* icx = GetJitContext();
AbsoluteAddress profilingActivation(icx->runtime->addressOfProfilingActivation());
CodeOffsetLabel label = movWithPatch(ImmWord(uintptr_t(-1)), reg);
loadPtr(profilingActivation, reg2);
storePtr(reg, Address(reg2, JitActivation::offsetOfLastProfilingCallSite()));
CodeOffsetLabel label = masm.movWithPatch(ImmWord(uintptr_t(-1)), reg);
masm.loadPtr(profilingActivation, reg2);
masm.storePtr(reg, Address(reg2, JitActivation::offsetOfLastProfilingCallSite()));
appendProfilerCallSite(label);
masm.appendProfilerCallSite(label);
masm.pop(reg2);
masm.pop(reg);
}
void
MacroAssembler::linkProfilerCallSites(JitCode* code)
{
for (size_t i = 0; i < profilerCallSites_.length(); i++) {
CodeOffsetLabel offset = profilerCallSites_[i];
offset.fixup(this);
CodeLocationLabel location(code, offset);
PatchDataWithValueCheck(location, ImmPtr(location.raw()), ImmPtr((void*)-1));
}
}
void
@ -2546,11 +2533,11 @@ MacroAssembler::alignJitStackBasedOnNArgs(uint32_t nargs)
MacroAssembler::MacroAssembler(JSContext* cx, IonScript* ion,
JSScript* script, jsbytecode* pc)
: emitProfilingInstrumentation_(false),
framePushed_(0)
: framePushed_(0),
#ifdef DEBUG
, inCall_(false)
inCall_(false),
#endif
emitProfilingInstrumentation_(false)
{
constructRoot(cx);
jitContext_.emplace(cx, (js::jit::TempAllocator*)nullptr);
@ -2566,7 +2553,7 @@ MacroAssembler::MacroAssembler(JSContext* cx, IonScript* ion,
if (ion) {
setFramePushed(ion->frameSize());
if (pc && cx->runtime()->spsProfiler.enabled())
emitProfilingInstrumentation_ = true;
enableProfilingInstrumentation();
}
}
@ -2874,6 +2861,30 @@ MacroAssembler::callWithABINoProfiler(AsmJSImmPtr imm, MoveOp::Type result)
callWithABIPost(stackAdjust, result);
}
// ===============================================================
// Exit frame footer.
void
MacroAssembler::linkExitFrame()
{
AbsoluteAddress jitTop(GetJitContext()->runtime->addressOfJitTop());
storeStackPtr(jitTop);
}
void
MacroAssembler::linkSelfReference(JitCode* code)
{
// If this code can transition to C++ code and witness a GC, then we need to store
// the JitCode onto the stack in order to GC it correctly. exitCodePatch should
// be unset if the code never needed to push its JitCode*.
if (hasSelfReference()) {
selfReferencePatch_.fixup(this);
PatchDataWithValueCheck(CodeLocationLabel(code, selfReferencePatch_),
ImmPtr(code),
ImmPtr((void*)-1));
}
}
//}}} check_macroassembler_style
namespace js {

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

@ -172,6 +172,9 @@
namespace js {
namespace jit {
// Defined in JitFrames.h
enum ExitFrameTokenValues;
// The public entrypoint for emitting assembly. Note that a MacroAssembler can
// use cx->lifoAlloc, so take care not to interleave masm use with other
// lifoAlloc use if one will be destroyed before the other.
@ -320,21 +323,16 @@ class MacroAssembler : public MacroAssemblerSpecific
mozilla::Maybe<AutoJitContextAlloc> alloc_;
private:
// This field is used to manage profiling instrumentation output. If
// provided and enabled, then instrumentation will be emitted around call
// sites.
bool emitProfilingInstrumentation_;
// Labels for handling exceptions and failures.
NonAssertingLabel failureLabel_;
public:
MacroAssembler()
: emitProfilingInstrumentation_(false),
framePushed_(0)
: framePushed_(0),
#ifdef DEBUG
, inCall_(false)
inCall_(false),
#endif
emitProfilingInstrumentation_(false)
{
JitContext* jcx = GetJitContext();
JSContext* cx = jcx->cx;
@ -365,11 +363,11 @@ class MacroAssembler : public MacroAssemblerSpecific
// asm.js compilation handles its own JitContext-pushing
struct AsmJSToken {};
explicit MacroAssembler(AsmJSToken)
: emitProfilingInstrumentation_(false),
framePushed_(0)
: framePushed_(0),
#ifdef DEBUG
, inCall_(false)
inCall_(false),
#endif
emitProfilingInstrumentation_(false)
{
#if defined(JS_CODEGEN_ARM)
initWithAllocator();
@ -380,10 +378,6 @@ class MacroAssembler : public MacroAssemblerSpecific
#endif
}
void enableProfilingInstrumentation() {
emitProfilingInstrumentation_ = true;
}
void resetForNewCodeGenerator(TempAllocator& alloc);
void constructRoot(JSContext* cx) {
@ -490,6 +484,14 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void call(const CallSiteDesc& desc, const Register reg);
inline void call(const CallSiteDesc& desc, Label* label);
// Push the return address and make a call. On platforms where this function
// is not defined, push the link register (pushReturnAddress) at the entry
// point of the callee.
void callAndPushReturnAddress(Register reg) DEFINED_ON(mips32, x86_shared);
void callAndPushReturnAddress(Label* label) DEFINED_ON(mips32, x86_shared);
void pushReturnAddress() DEFINED_ON(arm, arm64);
public:
// ===============================================================
// ABI function calls.
@ -563,6 +565,96 @@ class MacroAssembler : public MacroAssemblerSpecific
uint32_t signature_;
#endif
public:
// ===============================================================
// Jit Frames.
//
// These functions are used to build the content of the Jit frames. See
// CommonFrameLayout class, and all its derivatives. The content should be
// pushed in the opposite order as the fields of the structures, such that
// the structures can be used to interpret the content of the stack.
// Call the Jit function, and push the return address (or let the callee
// push the return address).
//
// These functions return the offset of the return address, in order to use
// the return address to index the safepoints, which are used to list all
// live registers.
inline uint32_t callJitNoProfiler(Register callee);
inline uint32_t callJit(Register callee);
inline uint32_t callJit(JitCode* code);
// The frame descriptor is the second field of all Jit frames, pushed before
// calling the Jit function. It is a composite value defined in JitFrames.h
inline void makeFrameDescriptor(Register frameSizeReg, FrameType type);
// Push the frame descriptor, based on the statically known framePushed.
inline void pushStaticFrameDescriptor(FrameType type);
// This function emulates a call by pushing an exit frame on the stack,
// except that the fake-function is inlined within the body of the caller.
//
// This function assumes that the current frame is an IonJS frame.
//
// This function returns the offset of the /fake/ return address, in order to use
// the return address to index the safepoints, which are used to list all
// live registers.
//
// This function should be balanced with a call to adjustStack, to pop the
// exit frame and emulate the return statement of the inlined function.
inline uint32_t buildFakeExitFrame(Register scratch);
private:
// This function is used by buildFakeExitFrame to push a fake return address
// on the stack. This fake return address should never be used for resuming
// any execution, and can even be an invalid pointer into the instruction
// stream, as long as it does not alias any other.
uint32_t pushFakeReturnAddress(Register scratch) PER_SHARED_ARCH;
public:
// ===============================================================
// Exit frame footer.
//
// When calling outside the Jit we push an exit frame. To mark the stack
// correctly, we have to push additional information, called the Exit frame
// footer, which is used to identify how the stack is marked.
//
// See JitFrames.h, and MarkJitExitFrame in JitFrames.cpp.
// If the current piece of code might be garbage collected, then the exit
// frame footer must contain a pointer to the current JitCode, such that the
// garbage collector can keep the code alive as long this code is on the
// stack. This function pushes a placeholder which is replaced when the code
// is linked.
inline void PushStubCode();
// Return true if the code contains a self-reference which needs to be
// patched when the code is linked.
inline bool hasSelfReference() const;
// Push stub code and the VMFunction pointer.
inline void enterExitFrame(const VMFunction* f = nullptr);
// Push an exit frame token to identify which fake exit frame this footer
// corresponds to.
inline void enterFakeExitFrame(enum ExitFrameTokenValues token);
// Pop ExitFrame footer in addition to the extra frame.
inline void leaveExitFrame(size_t extraFrame = 0);
private:
// Save the top of the stack into PerThreadData::jitTop of the main thread,
// which should be the location of the latest exit frame.
void linkExitFrame();
// Patch the value of PushStubCode with the pointer to the finalized code.
void linkSelfReference(JitCode* code);
// If the JitCode that created this assembler needs to transition into the VM,
// we want to store the JitCode on the stack in order to mark it during a GC.
// This is a reference to a patch location where the JitCode* will be written.
CodeOffsetLabel selfReferencePatch_;
//}}} check_macroassembler_style
public:
@ -1058,76 +1150,10 @@ class MacroAssembler : public MacroAssemblerSpecific
void compareStrings(JSOp op, Register left, Register right, Register result,
Label* fail);
// If the JitCode that created this assembler needs to transition into the VM,
// we want to store the JitCode on the stack in order to mark it during a GC.
// This is a reference to a patch location where the JitCode* will be written.
private:
CodeOffsetLabel exitCodePatch_;
private:
void linkExitFrame();
public:
inline void PushStubCode();
// Push stub code, and the VMFunction pointer.
inline void enterExitFrame(const VMFunction* f = nullptr);
// The JitCode * argument here is one of the tokens defined in the various
// exit frame layout classes, e.g. NativeExitFrameLayout::Token().
inline void enterFakeExitFrame(JitCode* codeVal);
// Pop ExitFrame footer in addition to the extra frame.
inline void leaveExitFrame(size_t extraFrame = 0);
inline bool hasEnteredExitFrame() const;
// Generates code used to complete a bailout.
void generateBailoutTail(Register scratch, Register bailoutInfo);
// These functions exist as small wrappers around sites where execution can
// leave the currently running stream of instructions. They exist so that
// instrumentation may be put in place around them if necessary and the
// instrumentation is enabled. For the functions that return a uint32_t,
// they are returning the offset of the assembler just after the call has
// been made so that a safepoint can be made at that location.
// see above comment for what is returned
uint32_t callJit(Register callee) {
profilerPreCall();
MacroAssemblerSpecific::callJit(callee);
uint32_t ret = currentOffset();
profilerPostReturn();
return ret;
}
// see above comment for what is returned
uint32_t callWithExitFrame(Label* target) {
profilerPreCall();
MacroAssemblerSpecific::callWithExitFrame(target);
uint32_t ret = currentOffset();
profilerPostReturn();
return ret;
}
// see above comment for what is returned
uint32_t callWithExitFrame(JitCode* target) {
profilerPreCall();
MacroAssemblerSpecific::callWithExitFrame(target);
uint32_t ret = currentOffset();
profilerPostReturn();
return ret;
}
// see above comment for what is returned
uint32_t callWithExitFrame(JitCode* target, Register dynStack) {
profilerPreCall();
MacroAssemblerSpecific::callWithExitFrame(target, dynStack);
uint32_t ret = currentOffset();
profilerPostReturn();
return ret;
}
void branchTestObjectTruthy(bool truthy, Register objReg, Register scratch,
Label* slowCheck, Label* checked)
{
@ -1218,22 +1244,41 @@ class MacroAssembler : public MacroAssemblerSpecific
}
#endif // !JS_CODEGEN_ARM64
private:
// These two functions are helpers used around call sites throughout the
// assembler. They are called from the above call wrappers to emit the
// necessary instrumentation.
void profilerPreCall() {
if (!emitProfilingInstrumentation_)
return;
profilerPreCallImpl();
public:
void enableProfilingInstrumentation() {
emitProfilingInstrumentation_ = true;
}
void profilerPostReturn() {
if (!emitProfilingInstrumentation_)
return;
profilerPostReturnImpl();
private:
// This class is used to surround call sites throughout the assembler. This
// is used by callWithABI, and callJit functions, except if suffixed by
// NoProfiler.
class AutoProfilerCallInstrumentation {
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
public:
explicit AutoProfilerCallInstrumentation(MacroAssembler& masm
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoProfilerCallInstrumentation() {}
};
friend class AutoProfilerCallInstrumentation;
void appendProfilerCallSite(CodeOffsetLabel label) {
propagateOOM(profilerCallSites_.append(label));
}
// Fix up the code pointers to be written for locations where profilerCallSite
// emitted moves of RIP to a register.
void linkProfilerCallSites(JitCode* code);
// This field is used to manage profiling instrumentation output. If
// provided and enabled, then instrumentation will be emitted around call
// sites.
bool emitProfilingInstrumentation_;
// Record locations of the call sites.
Vector<CodeOffsetLabel, 0, SystemAllocPolicy> profilerCallSites_;
public:
void loadBaselineOrIonRaw(Register script, Register dest, Label* failure);
void loadBaselineOrIonNoArgCheck(Register callee, Register dest, Label* failure);
@ -1545,10 +1590,6 @@ class MacroAssembler : public MacroAssemblerSpecific
bind(&ok);
#endif
}
void profilerPreCallImpl();
void profilerPreCallImpl(Register reg, Register reg2);
void profilerPostReturnImpl() {}
};
static inline Assembler::DoubleCondition

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

@ -1865,31 +1865,6 @@ MacroAssemblerARM::ma_vstr(VFPRegister src, Register base, Register index, int32
return ma_vstr(src, Address(scratch, offset), cc);
}
void
MacroAssemblerARMCompat::buildFakeExitFrame(Register scratch, uint32_t* offset)
{
DebugOnly<uint32_t> initialDepth = asMasm().framePushed();
uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor)); // descriptor_
enterNoPool(2);
DebugOnly<uint32_t> offsetBeforePush = currentOffset();
asMasm().Push(pc); // actually pushes $pc + 8.
// Consume an additional 4 bytes. The start of the next instruction will
// then be 8 bytes after the instruction for Push(pc); this offset can
// therefore be fed to the safepoint.
ma_nop();
uint32_t pseudoReturnOffset = currentOffset();
leaveNoPool();
MOZ_ASSERT(asMasm().framePushed() == initialDepth + ExitFrameLayout::Size());
MOZ_ASSERT(pseudoReturnOffset - offsetBeforePush == 8);
*offset = pseudoReturnOffset;
}
bool
MacroAssemblerARMCompat::buildOOLFakeExitFrame(void* fakeReturnAddr)
{
@ -1902,59 +1877,6 @@ MacroAssemblerARMCompat::buildOOLFakeExitFrame(void* fakeReturnAddr)
return true;
}
void
MacroAssemblerARMCompat::callWithExitFrame(Label* target)
{
uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor)); // descriptor
ma_callJitHalfPush(target);
}
void
MacroAssemblerARMCompat::callWithExitFrame(JitCode* target)
{
uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor)); // descriptor
addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
RelocStyle rs;
if (HasMOVWT())
rs = L_MOVWT;
else
rs = L_LDR;
ScratchRegisterScope scratch(asMasm());
ma_movPatchable(ImmPtr(target->raw()), scratch, Always, rs);
ma_callJitHalfPush(scratch);
}
void
MacroAssemblerARMCompat::callWithExitFrame(JitCode* target, Register dynStack)
{
ma_add(Imm32(asMasm().framePushed()), dynStack);
makeFrameDescriptor(dynStack, JitFrame_IonJS);
asMasm().Push(dynStack); // descriptor
addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
RelocStyle rs;
if (HasMOVWT())
rs = L_MOVWT;
else
rs = L_LDR;
ScratchRegisterScope scratch(asMasm());
ma_movPatchable(ImmPtr(target->raw()), scratch, Always, rs);
ma_callJitHalfPush(scratch);
}
void
MacroAssemblerARMCompat::callJit(Register callee)
{
MOZ_ASSERT((asMasm().framePushed() & 7) == 4);
ma_callJitHalfPush(callee);
}
void
MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic)
{
@ -3808,36 +3730,6 @@ MacroAssemblerARMCompat::storeTypeTag(ImmTag tag, const BaseIndex& dest)
ma_sub(base, Imm32(NUNBOX32_TYPE_OFFSET + dest.offset), base);
}
// ARM says that all reads of pc will return 8 higher than the address of the
// currently executing instruction. This means we are correctly storing the
// address of the instruction after the call in the register.
//
// Also ION is breaking the ARM EABI here (sort of). The ARM EABI says that a
// function call should move the pc into the link register, then branch to the
// function, and *sp is data that is owned by the caller, not the callee. The
// ION ABI says *sp should be the address that we will return to when leaving
// this function.
void
MacroAssemblerARM::ma_callJitHalfPush(const Register r)
{
// The stack is unaligned by 4 bytes. We push the pc to the stack to align
// the stack before the call, when we return the pc is poped and the stack
// is restored to its unaligned state.
as_blx(r);
}
void
MacroAssemblerARM::ma_callJitHalfPush(Label* label)
{
// The stack is unaligned by 4 bytes. The callee will push the lr to the stack to align
// the stack after the call, when we return the pc is poped and the stack
// is restored to its unaligned state.
// leave the stack as-is so the callee-side can push when necessary.
as_bl(label, Always);
}
void
MacroAssemblerARM::ma_call(ImmPtr dest)
{
@ -4964,14 +4856,6 @@ MacroAssemblerARMCompat::profilerExitFrame()
branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
}
void
MacroAssemblerARMCompat::callAndPushReturnAddress(Label* label)
{
AutoForbidPools afp(this, 2);
ma_push(pc);
asMasm().call(label);
}
MacroAssembler&
MacroAssemblerARM::asMasm()
{
@ -5186,9 +5070,14 @@ MacroAssembler::call(JitCode* c)
ScratchRegisterScope scratch(*this);
ma_movPatchable(ImmPtr(c->raw()), scratch, Always, rs);
ma_callJitHalfPush(scratch);
callJitNoProfiler(scratch);
}
void
MacroAssembler::pushReturnAddress()
{
push(lr);
}
// ===============================================================
// ABI function calls.
@ -5307,4 +5196,28 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
callWithABIPost(stackAdjust, result);
}
// ===============================================================
// Jit Frames.
uint32_t
MacroAssembler::pushFakeReturnAddress(Register scratch)
{
// On ARM any references to the pc, adds an additional 8 to it, which
// correspond to 2 instructions of 4 bytes. Thus we use an additional nop
// to pad until we reach the pushed pc.
//
// Note: In practice this should not be necessary, as this fake return
// address is never used for resuming any execution. Thus theoriticaly we
// could just do a Push(pc), and ignore the nop as well as the pool.
enterNoPool(2);
DebugOnly<uint32_t> offsetBeforePush = currentOffset();
Push(pc); // actually pushes $pc + 8.
ma_nop();
uint32_t pseudoReturnOffset = currentOffset();
leaveNoPool();
MOZ_ASSERT(pseudoReturnOffset - offsetBeforePush == 8);
return pseudoReturnOffset;
}
//}}} check_macroassembler_style

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

@ -429,13 +429,6 @@ class MacroAssemblerARM : public Assembler
BufferOffset ma_vstr(VFPRegister src, Register base, Register index, int32_t shift,
int32_t offset, Condition cc = Always);
// Calls an ion function, assuming that the stack is currently not 8 byte
// aligned.
void ma_callJitHalfPush(const Register reg);
// Calls an ion function, assuming that the stack is currently not 8 byte
// aligned.
void ma_callJitHalfPush(Label* label);
void ma_call(ImmPtr dest);
// Float registers can only be loaded/stored in continuous runs when using
@ -532,8 +525,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
MOZ_CRASH("NYI-IC");
}
void callAndPushReturnAddress(Label* label);
void branch(JitCode* c) {
BufferOffset bo = m_buffer.nextOffset();
addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
@ -1188,30 +1179,12 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void storeTypeTag(ImmTag tag, const Address& dest);
void storeTypeTag(ImmTag tag, const BaseIndex& dest);
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
ma_lsl(Imm32(FRAMESIZE_SHIFT), frameSizeReg, frameSizeReg);
ma_orr(Imm32(type), frameSizeReg);
}
void handleFailureWithHandlerTail(void* handler);
/////////////////////////////////////////////////////////////////
// Common interface.
/////////////////////////////////////////////////////////////////
public:
// Builds an exit frame on the stack, with a return address to an internal
// non-function. Returns offset to be passed to markSafepointAt().
void buildFakeExitFrame(Register scratch, uint32_t* offset);
void callWithExitFrame(Label* target);
void callWithExitFrame(JitCode* target);
void callWithExitFrame(JitCode* target, Register dynStack);
// Makes a call using the only two methods that it is sane for
// independent code to make a call.
void callJit(Register callee);
void callJitFromAsmJS(Register callee) { as_blx(callee); }
void add32(Register src, Register dest);
void add32(Imm32 imm, Register dest);
void add32(Imm32 imm, const Address& dest);
@ -1818,10 +1791,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void loadAsmJSHeapRegisterFromGlobalData() {
loadPtr(Address(GlobalReg, AsmJSHeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg);
}
void pushReturnAddress() {
push(lr);
}
// Instrumentation for entering and leaving the profiler.
void profilerEnterFrame(Register framePtr, Register scratch);
void profilerExitFrame();

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

@ -287,7 +287,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.push(scratch);
masm.push(Imm32(0)); // Fake return address.
// No GC things to mark on the stack, push a bare token.
masm.enterFakeExitFrame(ExitFrameLayout::BareToken());
masm.enterFakeExitFrame(ExitFrameLayoutBareToken);
masm.push(framePtr); // BaselineFrame
masm.push(r0); // jitcode
@ -348,7 +348,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
// Call the function.
masm.ma_callJitHalfPush(r0);
masm.callJitNoProfiler(r0);
if (type == EnterJitBaseline) {
// Baseline OSR will return here.
@ -540,9 +540,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
masm.andPtr(Imm32(CalleeTokenMask), r1);
masm.ma_ldr(DTRAddr(r1, DtrOffImm(JSFunction::offsetOfNativeOrScript())), r3);
masm.loadBaselineOrIonRaw(r3, r3, nullptr);
masm.ma_callJitHalfPush(r3);
uint32_t returnOffset = masm.currentOffset();
uint32_t returnOffset = masm.callJitNoProfiler(r3);
// arg1
// ...

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

@ -36,52 +36,6 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
Csel(dest, dest, wzr, GreaterThan);
}
void
MacroAssemblerCompat::buildFakeExitFrame(Register scratch, uint32_t* offset)
{
mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor)); // descriptor_
enterNoPool(3);
Label fakeCallsite;
Adr(ARMRegister(scratch, 64), &fakeCallsite);
asMasm().Push(scratch);
bind(&fakeCallsite);
uint32_t pseudoReturnOffset = currentOffset();
leaveNoPool();
MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
*offset = pseudoReturnOffset;
}
void
MacroAssemblerCompat::callWithExitFrame(Label* target)
{
uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
Push(Imm32(descriptor)); // descriptor
asMasm().call(target);
}
void
MacroAssemblerCompat::callWithExitFrame(JitCode* target)
{
uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor));
asMasm().call(target);
}
void
MacroAssemblerCompat::callWithExitFrame(JitCode* target, Register dynStack)
{
add32(Imm32(framePushed()), dynStack);
makeFrameDescriptor(dynStack, JitFrame_IonJS);
Push(dynStack); // descriptor
asMasm().call(target);
}
void
MacroAssembler::alignFrameForICArguments(MacroAssembler::AfterICSaveLive& aic)
{
@ -287,25 +241,6 @@ MacroAssemblerCompat::branchValueIsNurseryObject(Condition cond, ValueOperand va
temp, ImmWord(nursery.nurserySize()), label);
}
void
MacroAssemblerCompat::callAndPushReturnAddress(Label* label)
{
// FIXME: Jandem said he would refactor the code to avoid making
// this instruction required, but probably forgot about it.
// Instead of implementing this function, we should make it unnecessary.
Label ret;
{
vixl::UseScratchRegisterScope temps(this);
const ARMRegister scratch64 = temps.AcquireX();
Adr(scratch64, &ret);
asMasm().Push(scratch64.asUnsized());
}
Bl(label);
bind(&ret);
}
void
MacroAssemblerCompat::breakpoint()
{
@ -515,6 +450,12 @@ MacroAssembler::call(JitCode* c)
blr(scratch64);
}
void
MacroAssembler::pushReturnAddress()
{
push(lr);
}
// ===============================================================
// ABI function calls.
@ -625,6 +566,24 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
callWithABIPost(stackAdjust, result);
}
// ===============================================================
// Jit Frames.
uint32_t
MacroAssembler::pushFakeReturnAddress(Register scratch)
{
enterNoPool(3);
Label fakeCallsite;
Adr(ARMRegister(scratch, 64), &fakeCallsite);
Push(scratch);
bind(&fakeCallsite);
uint32_t pseudoReturnOffset = currentOffset();
leaveNoPool();
return = pseudoReturnOffset;
}
//}}} check_macroassembler_style
} // namespace jit

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

@ -207,9 +207,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
vixl::MacroAssembler::Pop(r0, r1, r2, r3);
}
void pushReturnAddress() {
push(lr);
}
void pop(const ValueOperand& v) {
pop(v.valueReg());
}
@ -2640,12 +2637,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void handleFailureWithHandlerTail(void* handler);
// FIXME: This is the same on all platforms. Can be common code?
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
lshiftPtr(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
orPtr(Imm32(type), frameSizeReg);
}
// FIXME: See CodeGeneratorX64 calls to noteAsmJSGlobalAccess.
void patchAsmJSGlobalAccess(CodeOffsetLabel patchAt, uint8_t* code,
uint8_t* globalData, unsigned globalDataOffset)
@ -2665,20 +2656,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label);
void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label);
// Builds an exit frame on the stack, with a return address to an internal
// non-function. Returns offset to be passed to markSafepointAt().
void buildFakeExitFrame(Register scratch, uint32_t* offset);
void callWithExitFrame(Label* target);
void callWithExitFrame(JitCode* target);
void callWithExitFrame(JitCode* target, Register dynStack);
void callJit(Register callee) {
// AArch64 cannot read from the PC, so pushing must be handled callee-side.
syncStackPtr();
Blr(ARMRegister(callee, 64));
}
void appendCallSite(const CallSiteDesc& desc) {
MOZ_CRASH("appendCallSite");
}
@ -2687,12 +2664,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
MOZ_CRASH("callExit");
}
void callJitFromAsmJS(Register reg) {
Blr(ARMRegister(reg, 64));
}
void callAndPushReturnAddress(Label* label);
void profilerEnterFrame(Register framePtr, Register scratch) {
AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
loadPtr(activation, scratch);

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

@ -189,7 +189,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.makeFrameDescriptor(r19, JitFrame_BaselineJS);
masm.asVIXL().Push(x19, xzr); // Push xzr for a fake return address.
// No GC things to mark: push a bare token.
masm.enterFakeExitFrame(ExitFrameLayout::BareToken());
masm.enterFakeExitFrame(ExitFrameLayoutBareToken);
masm.push(BaselineFrameReg, reg_code);
@ -225,7 +225,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
// Call function.
// Since AArch64 doesn't have the pc register available, the callee must push lr.
masm.call(reg_code);
masm.callJitNoProfiler(reg_code);
// Baseline OSR will return here.
if (type == EnterJitBaseline)
@ -405,8 +405,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
// Load the address of the code that is getting called.
masm.Ldr(x3, MemOperand(x5, JSFunction::offsetOfNativeOrScript()));
masm.loadBaselineOrIonRaw(r3, r3, nullptr);
masm.call(r3);
uint32_t returnOffset = masm.currentOffset();
uint32_t returnOffset = masm.callJitNoProfiler(r3);
// Clean up!
// Get the size of the stack frame, and clean up the later fixed frame.

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

@ -1498,25 +1498,6 @@ MacroAssemblerMIPS::ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label* label,
branchWithCode(getBranchCode(testKind, fcc), label, jumpKind);
}
void
MacroAssemblerMIPSCompat::buildFakeExitFrame(Register scratch, uint32_t* offset)
{
mozilla::DebugOnly<uint32_t> initialDepth = asMasm().framePushed();
CodeLabel cl;
ma_li(scratch, cl.dest());
uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor));
asMasm().Push(scratch);
bind(cl.src());
*offset = currentOffset();
MOZ_ASSERT(asMasm().framePushed() == initialDepth + ExitFrameLayout::Size());
addCodeLabel(cl);
}
bool
MacroAssemblerMIPSCompat::buildOOLFakeExitFrame(void* fakeReturnAddr)
{
@ -1528,45 +1509,6 @@ MacroAssemblerMIPSCompat::buildOOLFakeExitFrame(void* fakeReturnAddr)
return true;
}
void
MacroAssemblerMIPSCompat::callWithExitFrame(Label* target)
{
uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor)); // descriptor
ma_callJitHalfPush(target);
}
void
MacroAssemblerMIPSCompat::callWithExitFrame(JitCode* target)
{
uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
asMasm().Push(Imm32(descriptor)); // descriptor
addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
ma_callJitHalfPush(ScratchRegister);
}
void
MacroAssemblerMIPSCompat::callWithExitFrame(JitCode* target, Register dynStack)
{
ma_addu(dynStack, dynStack, Imm32(asMasm().framePushed()));
makeFrameDescriptor(dynStack, JitFrame_IonJS);
asMasm().Push(dynStack); // descriptor
addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
ma_callJitHalfPush(ScratchRegister);
}
void
MacroAssemblerMIPSCompat::callJit(Register callee)
{
MOZ_ASSERT((asMasm().framePushed() & 7) == 4);
ma_callJitHalfPush(callee);
}
void
MacroAssemblerMIPSCompat::add32(Register src, Register dest)
{
@ -3063,28 +3005,6 @@ MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, const BaseIndex& dest)
as_sw(ScratchRegister, SecondScratchReg, TAG_OFFSET);
}
// This macrosintruction calls the ion code and pushes the return address to
// the stack in the case when stack is not alligned.
void
MacroAssemblerMIPS::ma_callJitHalfPush(const Register r)
{
// This is a MIPS hack to push return address during jalr delay slot.
as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
as_jalr(r);
as_sw(ra, StackPointer, 0);
}
// This macrosintruction calls the ion code and pushes the return address to
// the stack in the case when stack is not alligned.
void
MacroAssemblerMIPS::ma_callJitHalfPush(Label* label)
{
// This is a MIPS hack to push return address during jalr delay slot.
as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
ma_bal(label, DontFillDelaySlot);
as_sw(ra, StackPointer, 0);
}
void
MacroAssemblerMIPS::ma_call(ImmPtr dest)
{
@ -3518,7 +3438,25 @@ MacroAssembler::call(JitCode* c)
BufferOffset bo = m_buffer.nextOffset();
addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
ma_callJitHalfPush(ScratchRegister);
callJitNoProfiler(ScratchRegister);
}
void
MacroAssembler::callAndPushReturnAddress(Register callee)
{
// Push return address during jalr delay slot.
as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
as_jalr(callee);
as_sw(ra, StackPointer, 0);
}
void
MacroAssembler::callAndPushReturnAddress(Label* label)
{
// Push return address during jalr delay slot.
as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
as_jalr(label);
as_sw(ra, StackPointer, 0);
}
// ===============================================================
@ -3622,4 +3560,21 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
callWithABIPost(stackAdjust, result);
}
// ===============================================================
// Jit Frames.
uint32_t
MacroAssembler::pushFakeReturnAddress(Register scratch)
{
CodeLabel cl;
ma_li(scratch, cl.dest());
Push(scratch);
bind(cl.src());
uint32_t retAddr = currentOffset();
addCodeLabel(cl);
return retAddr;
}
//}}} check_macroassembler_style

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

@ -315,10 +315,6 @@ class MacroAssemblerMIPS : public Assembler
FPConditionBit fcc = FCC0);
public:
// calls an ion function, assuming that the stack is currently not 8 byte aligned
void ma_callJitHalfPush(const Register reg);
void ma_callJitHalfPush(Label* label);
void ma_call(ImmPtr dest);
void ma_jump(ImmPtr dest);
@ -375,10 +371,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
MOZ_CRASH("NYI-IC");
}
void callAndPushReturnAddress(Label* label) {
ma_callJitHalfPush(label);
}
void branch(JitCode* c) {
BufferOffset bo = m_buffer.nextOffset();
addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
@ -890,11 +882,6 @@ public:
void storeTypeTag(ImmTag tag, Address dest);
void storeTypeTag(ImmTag tag, const BaseIndex& dest);
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
ma_sll(frameSizeReg, frameSizeReg, Imm32(FRAMESIZE_SHIFT));
ma_or(frameSizeReg, frameSizeReg, Imm32(type));
}
void handleFailureWithHandlerTail(void* handler);
/////////////////////////////////////////////////////////////////
@ -1117,19 +1104,6 @@ public:
MOZ_CRASH("NYI");
}
// Builds an exit frame on the stack, with a return address to an internal
// non-function. Returns offset to be passed to markSafepointAt().
void buildFakeExitFrame(Register scratch, uint32_t* offset);
void callWithExitFrame(Label* target);
void callWithExitFrame(JitCode* target);
void callWithExitFrame(JitCode* target, Register dynStack);
// Makes a call using the only two methods that it is sane for indep code
// to make a call.
void callJit(Register callee);
void callJitFromAsmJS(Register callee) { callJit(callee); }
void add32(Register src, Register dest);
void add32(Imm32 imm, Register dest);
void add32(Imm32 imm, const Address& dest);

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

@ -241,7 +241,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.storePtr(zero, Address(StackPointer, 0)); // fake return address
// No GC things to mark, push a bare token.
masm.enterFakeExitFrame(ExitFrameLayout::BareToken());
masm.enterFakeExitFrame(ExitFrameLayoutBareToken);
masm.reserveStack(2 * sizeof(uintptr_t));
masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame
@ -303,7 +303,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
// Call the function with pushing return address to stack.
masm.ma_callJitHalfPush(reg_code);
masm.callJitNoProfiler(reg_code);
if (type == EnterJitBaseline) {
// Baseline OSR will return here.
@ -497,9 +497,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
masm.andPtr(Imm32(CalleeTokenMask), calleeTokenReg);
masm.loadPtr(Address(calleeTokenReg, JSFunction::offsetOfNativeOrScript()), t1);
masm.loadBaselineOrIonRaw(t1, t1, nullptr);
masm.ma_callJitHalfPush(t1);
uint32_t returnOffset = masm.currentOffset();
uint32_t returnOffset = masm.callJitNoProfiler(t1);
// arg1
// ...

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

@ -193,17 +193,6 @@ class MacroAssemblerNone : public Assembler
uint32_t labelOffsetToPatchOffset(uint32_t) { MOZ_CRASH(); }
CodeOffsetLabel labelForPatch() { MOZ_CRASH(); }
template <typename T> void call(T) { MOZ_CRASH(); }
template <typename T, typename S> void call(T, S) { MOZ_CRASH(); }
void callAndPushReturnAddress(Label* label) { MOZ_CRASH(); }
void callWithExitFrame(Label*) { MOZ_CRASH(); }
void callWithExitFrame(JitCode*) { MOZ_CRASH(); }
void callWithExitFrame(JitCode*, Register) { MOZ_CRASH(); }
void callJit(Register callee) { MOZ_CRASH(); }
void callJitFromAsmJS(Register callee) { MOZ_CRASH(); }
void nop() { MOZ_CRASH(); }
void breakpoint() { MOZ_CRASH(); }
void abiret() { MOZ_CRASH(); }
@ -449,7 +438,6 @@ class MacroAssemblerNone : public Assembler
void incrementInt32Value(Address) { MOZ_CRASH(); }
void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); }
void handleFailureWithHandlerTail(void*) { MOZ_CRASH(); }
void makeFrameDescriptor(Register, FrameType) { MOZ_CRASH(); }
void branchPtrInNurseryRange(Condition, Register, Register, Label*) { MOZ_CRASH(); }
void branchValueIsNurseryObject(Condition, ValueOperand, Register, Label*) { MOZ_CRASH(); }

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

@ -914,7 +914,6 @@ class AssemblerShared
Vector<AsmJSAbsoluteLink, 0, SystemAllocPolicy> asmJSAbsoluteLinks_;
protected:
Vector<CodeOffsetLabel, 0, SystemAllocPolicy> profilerCallSites_;
bool enoughMemory_;
bool embedsNurseryPointers_;
@ -936,10 +935,6 @@ class AssemblerShared
return !enoughMemory_;
}
void appendProfilerCallSite(CodeOffsetLabel label) {
enoughMemory_ &= profilerCallSites_.append(label);
}
bool embedsNurseryPointers() const {
return embedsNurseryPointers_;
}

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