merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Iris Hsiao 2017-04-12 11:16:46 +08:00
Родитель e580f2db96 85e118ae7d
Коммит 944f87c575
110 изменённых файлов: 3106 добавлений и 1002 удалений

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

@ -240,6 +240,10 @@ function chromeFileExists(aURI) {
}
add_task(function* checkAllTheCSS() {
// Since we later in this test use Services.console.getMessageArray(),
// better to not have some messages from previous tests in the array.
Services.console.reset();
let appDir = Services.dirsvc.get("GreD", Ci.nsIFile);
// This asynchronously produces a list of URLs (sadly, mostly sync on our
// test infrastructure because it runs against jarfiles there, and

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

@ -9,7 +9,7 @@ add_task(function* setup() {
/**
* For loading the initial about:blank in e10s mode, it will be loaded with
* NullPrincipal, and we also test if the firstPartyDomain of the origin
* attributes is NULL_PRINCIPAL_FIRST_PARTY_DOMAIN.
* attributes is got from the origin itself.
*/
add_task(function* test_remote_window_open_aboutBlank() {
let win = yield BrowserTestUtils.openNewBrowserWindow({ remote: true });
@ -17,15 +17,17 @@ add_task(function* test_remote_window_open_aboutBlank() {
Assert.ok(browser.isRemoteBrowser, "should be a remote browser");
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
yield ContentTask.spawn(browser, {}, function* () {
info("origin " + content.document.nodePrincipal.origin);
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of remote about:blank should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectAttrs.firstPartyDomain,
"remote about:blank should have firstPartyDomain set");
expectDomain,
"remote about:blank should have firstPartyDomain set to " + expectDomain);
});
win.close();
@ -75,15 +77,17 @@ add_task(function* test_remote_window_open_data_uri() {
return url == "data:text/plain,hello";
});
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
yield ContentTask.spawn(browser, {}, function* () {
info("origin: " + content.document.nodePrincipal.origin);
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of data: document should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectAttrs.firstPartyDomain,
"data: URI should have firstPartyDomain set");
expectDomain,
"data: URI should have firstPartyDomain set to " + expectDomain);
});
win.close();
@ -103,8 +107,7 @@ add_task(function* test_remote_window_open_data_uri2() {
browser.loadURI(DATA_URI);
yield BrowserTestUtils.browserLoaded(browser, true);
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
yield ContentTask.spawn(browser, {}, function* () {
info("origin " + content.document.nodePrincipal.origin);
let iframe = content.document.getElementById("iframe1");
@ -112,12 +115,15 @@ add_task(function* test_remote_window_open_data_uri2() {
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of data: document should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectAttrs.firstPartyDomain,
"data: URI should have firstPartyDomain set");
expectDomain,
"data: URI should have firstPartyDomain set to " + expectDomain);
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
expectAttrs.firstPartyDomain,
expectDomain,
"iframe should inherit firstPartyDomain from parent document.");
Assert.equal(iframe.contentDocument.cookie, "test2=foo", "iframe should have cookies");
});

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

@ -13,15 +13,17 @@ add_task(function* test_remote_window_open_js_uri() {
Assert.ok(browser.isRemoteBrowser, "should be a remote browser");
browser.loadURI(`javascript:1;`);
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
yield ContentTask.spawn(browser, {}, function* () {
info("origin " + content.document.nodePrincipal.origin);
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of remote javascript: should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectAttrs.firstPartyDomain,
"remote javascript: should have firstPartyDomain set");
expectDomain,
"remote javascript: should have firstPartyDomain set to " + expectDomain);
});
win.close();
@ -46,18 +48,22 @@ add_task(function* test_remote_window_open_js_uri2() {
return url == "http://example.com/";
});
let attrs = { firstPartyDomain: "1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla" };
yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
yield ContentTask.spawn(browser, {}, function* () {
info("origin " + content.document.nodePrincipal.origin);
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of remote javascript: should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectAttrs.firstPartyDomain,
"remote javascript: should have firstPartyDomain set");
expectDomain,
"remote javascript: should have firstPartyDomain set to " + expectDomain);
let iframe = content.document.getElementById("iframe1");
info("iframe principal: " + iframe.contentDocument.nodePrincipal.origin);
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
expectDomain,
"iframe should have firstPartyDomain set to " + expectDomain);
});
win.close();

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

@ -82,7 +82,7 @@ fi
AC_SUBST(MOZ_NO_DEBUG_RTL)
MOZ_DEBUG_ENABLE_DEFS="DEBUG TRACING"
MOZ_DEBUG_ENABLE_DEFS="DEBUG"
MOZ_ARG_WITH_STRING(debug-label,
[ --with-debug-label=LABELS
Define DEBUG_<value> for each comma-separated

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

@ -49,10 +49,9 @@ NullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom)
NullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty)
{
OriginAttributes attrs = nsDocShell::Cast(aDocShell)->GetOriginAttributes();
attrs.SetFirstPartyDomain(aIsFirstParty, NS_LITERAL_CSTRING(NULL_PRINCIPAL_FIRST_PARTY_DOMAIN));
RefPtr<NullPrincipal> nullPrin = new NullPrincipal();
nsresult rv = nullPrin->Init(attrs);
nsresult rv = nullPrin->Init(attrs, aIsFirstParty);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
return nullPrin.forget();
}
@ -93,6 +92,33 @@ NullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI)
return NS_OK;
}
nsresult
NullPrincipal::Init(const OriginAttributes& aOriginAttributes, bool aIsFirstParty)
{
mURI = NullPrincipalURI::Create();
NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_AVAILABLE);
nsAutoCString originNoSuffix;
DebugOnly<nsresult> rv = mURI->GetSpec(originNoSuffix);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsAutoCString path;
rv = mURI->GetPath(path);
MOZ_ASSERT(NS_SUCCEEDED(rv));
OriginAttributes attrs(aOriginAttributes);
if (aIsFirstParty) {
// remove the '{}' characters from both ends.
path.Mid(path, 1, path.Length() - 2);
path.AppendLiteral(".mozilla");
attrs.SetFirstPartyDomain(true, path);
}
FinishInit(originNoSuffix, attrs);
return NS_OK;
}
nsresult
NullPrincipal::GetScriptLocation(nsACString &aStr)
{

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

@ -57,7 +57,7 @@ public:
// Create NullPrincipal with origin attributes from docshell.
// If aIsFirstParty is true, and the pref 'privacy.firstparty.isolate' is also
// enabled, the mFirstPartyDomain value of the origin attributes will be set
// to NULL_PRINCIPAL_FIRST_PARTY_DOMAIN.
// to an unique value.
static already_AddRefed<NullPrincipal>
CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false);
@ -81,6 +81,12 @@ public:
bool MayLoadInternal(nsIURI* aURI) override;
nsCOMPtr<nsIURI> mURI;
private:
// If aIsFirstParty is true, this NullPrincipal will be initialized base on
// the aOriginAttributes with FirstPartyDomain set to an unique value, and this
// value is generated from mURI.path, with ".mozilla" appending at the end.
nsresult Init(const mozilla::OriginAttributes& aOriginAttributes, bool aIsFirstParty);
};
#endif // NullPrincipal_h__

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

@ -3271,7 +3271,7 @@ nsRange::AutoInvalidateSelection::~AutoInvalidateSelection()
mIsNested = false;
::InvalidateAllFrames(mCommonAncestor);
nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
if (commonAncestor != mCommonAncestor) {
if (commonAncestor && commonAncestor != mCommonAncestor) {
::InvalidateAllFrames(commonAncestor);
}
}

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

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<script>
try { o1 = document.createElement('tr'); } catch(e) {};
try { o2 = document.createElement('div'); } catch(e) {};
try { o3 = document.createElement('hr'); } catch(e) {};
try { o4 = document.createElement('textarea'); } catch(e) {};
try { o5 = document.getSelection(); } catch(e) {};
try { o6 = document.createRange(); } catch(e) {};
try { document.documentElement.appendChild(o2); } catch(e) {};
try { document.documentElement.appendChild(o3); } catch(e) {};
try { o2.appendChild(o4); } catch(e) {};
try { o3.outerHTML = "<noscript contenteditable='true'>"; } catch(e) {};
try { o4.select(); } catch(e) {};
try { o5.addRange(o6); } catch(e) {};
try { document.documentElement.appendChild(o1); } catch(e) {};
try { o5.selectAllChildren(o1); } catch(e) {};
try { o6.selectNode(o1); } catch(e) {};
</script>
</head>
</html>

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

@ -81,3 +81,4 @@ load 1290904.html
load 1343886-1.html
load 1343886-2.xml
load 1343886-3.xml
asserts(0-3) load 1350972.html

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

@ -12,6 +12,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIOutputStream.h"
#include "nsIScriptError.h"
#include "nsITimedChannel.h"
#include "nsIUnicodeDecoder.h"
#include "nsIUnicodeEncoder.h"
#include "nsContentPolicyUtils.h"
@ -108,6 +109,12 @@ NS_IMETHODIMP
CancelChannelRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: When bug 1204254 is implemented, this time marker should be moved to
// the point where the body of the network request is complete.
mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
mChannel->SaveTimeStampsToUnderlyingChannel();
mChannel->Cancel(mStatus);
mRegistration->MaybeScheduleUpdate();
return NS_OK;
@ -230,6 +237,9 @@ public:
return NS_OK;
}
mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
mChannel->SaveTimeStampsToUnderlyingChannel();
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(underlyingChannel, "service-worker-synthesized-response", nullptr);

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

@ -14,6 +14,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIPushErrorReporter.h"
#include "nsISupportsImpl.h"
#include "nsITimedChannel.h"
#include "nsIUploadChannel2.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
@ -1297,6 +1298,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
nsCString mMethod;
nsString mClientId;
bool mIsReload;
bool mMarkLaunchServiceWorkerEnd;
RequestCache mCacheMode;
RequestMode mRequestMode;
RequestRedirect mRequestRedirect;
@ -1315,13 +1317,15 @@ public:
const nsACString& aScriptSpec,
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
const nsAString& aDocumentId,
bool aIsReload)
bool aIsReload,
bool aMarkLaunchServiceWorkerEnd)
: ExtendableFunctionalEventWorkerRunnable(
aWorkerPrivate, aKeepAliveToken, aRegistration)
, mInterceptedChannel(aChannel)
, mScriptSpec(aScriptSpec)
, mClientId(aDocumentId)
, mIsReload(aIsReload)
, mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
, mCacheMode(RequestCache::Default)
, mRequestMode(RequestMode::No_cors)
, mRequestRedirect(RequestRedirect::Follow)
@ -1474,6 +1478,12 @@ public:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
if (mMarkLaunchServiceWorkerEnd) {
mInterceptedChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
}
mInterceptedChannel->SetDispatchFetchEventEnd(TimeStamp::Now());
return DispatchFetchEvent(aCx, aWorkerPrivate);
}
@ -1502,6 +1512,10 @@ private:
NS_IMETHOD Run() override
{
AssertIsOnMainThread();
mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
mChannel->SaveTimeStampsToUnderlyingChannel();
nsresult rv = mChannel->ResetInterception();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to resume intercepted network request");
@ -1577,6 +1591,8 @@ private:
event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
event->SetTrusted(true);
mInterceptedChannel->SetHandleFetchEventStart(TimeStamp::Now());
nsresult rv2 =
DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
event, nullptr);
@ -1647,9 +1663,20 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsCOMPtr<nsIRunnable> failRunnable =
NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
nsresult rv = SpawnWorkerIfNeeded(FetchEvent, failRunnable, aLoadGroup);
aChannel->SetLaunchServiceWorkerStart(TimeStamp::Now());
aChannel->SetDispatchFetchEventStart(TimeStamp::Now());
bool newWorkerCreated = false;
nsresult rv = SpawnWorkerIfNeeded(FetchEvent,
failRunnable,
&newWorkerCreated,
aLoadGroup);
NS_ENSURE_SUCCESS(rv, rv);
if (!newWorkerCreated) {
aChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
}
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
@ -1658,10 +1685,11 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
RefPtr<FetchEventRunnable> r =
new FetchEventRunnable(mWorkerPrivate, token, handle,
mInfo->ScriptSpec(), regInfo,
aDocumentId, aIsReload);
aDocumentId, aIsReload, newWorkerCreated);
rv = r->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -1684,6 +1712,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsresult
ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
bool* aNewWorkerCreated,
nsILoadGroup* aLoadGroup)
{
AssertIsOnMainThread();
@ -1694,6 +1723,12 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
// the overriden load group when intercepting a fetch.
MOZ_ASSERT_IF(aWhy == FetchEvent, aLoadGroup);
// Defaults to no new worker created, but if there is one, we'll set the value
// to true at the end of this function.
if (aNewWorkerCreated) {
*aNewWorkerCreated = false;
}
if (mWorkerPrivate) {
mWorkerPrivate->UpdateOverridenLoadGroup(aLoadGroup);
RenewKeepAliveToken(aWhy);
@ -1800,6 +1835,10 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
RenewKeepAliveToken(aWhy);
if (aNewWorkerCreated) {
*aNewWorkerCreated = true;
}
return NS_OK;
}

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

@ -196,6 +196,7 @@ private:
nsresult
SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
bool* aNewWorkerCreated = nullptr,
nsILoadGroup* aLoadGroup = nullptr);
~ServiceWorkerPrivate();

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

@ -3,6 +3,8 @@ skip-if = os == 'android'
support-files =
chrome_helpers.js
empty.js
fetch.js
hello.html
serviceworker.html
serviceworkerinfo_iframe.html
serviceworkermanager_iframe.html
@ -10,6 +12,7 @@ support-files =
worker.js
worker2.js
[test_devtools_serviceworker_interception.html]
[test_privateBrowsing.html]
[test_serviceworkerinfo.xul]
[test_serviceworkermanager.xul]

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

@ -0,0 +1,168 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1168875 - test devtools serviceworker interception.</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet"
type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
// Constants
const Ci = Components.interfaces;
const workerScope = "http://mochi.test:8888/chrome/dom/workers/test/serviceworkers/";
const workerURL = workerScope + "fetch.js";
const contentPage = workerScope + "hello.html";
function createTestWindow(aURL) {
var mainwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var win = mainwindow.OpenBrowserWindow(contentPage);
return new Promise(aResolve => {
win.addEventListener("DOMContentLoaded", function callback() {
if (win.content.location.href != aURL) {
win.gBrowser.loadURI(aURL);
return;
}
win.removeEventListener("DOMContentLoaded", callback);
aResolve(win.content);
});
});
}
function executeTest(aWindow) {
var registration;
return Promise.resolve()
// Should not be intercepted.
.then(_ => fetchAndCheckTimedChannel(aWindow, false, true, "hello.html"))
// Regist a service worker.
.then(_ => register(aWindow, workerURL, workerScope))
.then(r => registration = r)
// Should be intercpeted and synthesized.
.then(_ => fetchAndCheckTimedChannel(aWindow, true, false, "fake.html"))
// Should be intercepted but still fetch from network.
.then(_ => fetchAndCheckTimedChannel(aWindow, true, true,
"hello.html?ForBypassingHttpCache"))
// Tear down
.then(_ => registration.unregister());
}
function register(aWindow, aURL, aScope) {
return aWindow.navigator.serviceWorker.register(aURL, {scope: aScope})
.then(r => {
var worker = r.installing;
return new Promise(function(aResolve) {
worker.onstatechange = function() {
if (worker.state == "activated") {
aResolve(r);
}
}
});
});
}
function fetchAndCheckTimedChannel(aWindow, aIntercepted, aFetch, aURL) {
var resolveFunction;
var promise = new Promise(aResolve => resolveFunction = aResolve);
var topic = aFetch ? "http-on-examine-response"
: "service-worker-synthesized-response";
function observer(aSubject) {
var channel = aSubject.QueryInterface(Ci.nsIChannel);
ok(channel.URI.spec.endsWith(aURL));
var tc = aSubject.QueryInterface(Ci.nsITimedChannel);
// Check service worker related timings.
var serviceWorkerTimings = [{start: tc.launchServiceWorkerStartTime,
end: tc.launchServiceWorkerEndTime},
{start: tc.dispatchFetchEventStartTime,
end: tc.dispatchFetchEventEndTime},
{start: tc.handleFetchEventStartTime,
end: tc.handleFetchEventEndTime}];
if (aIntercepted) {
serviceWorkerTimings.reduce((aPreviousTimings, aCurrentTimings) => {
ok(aPreviousTimings.start <= aCurrentTimings.start,
"Start time order check.");
ok(aPreviousTimings.end <= aCurrentTimings.end,
"End time order check.");
ok(aCurrentTimings.start <= aCurrentTimings.end,
"Start time should be smaller than end time.");
return aCurrentTimings;
});
} else {
serviceWorkerTimings.forEach(aTimings => {
is(aTimings.start, 0);
is(aTimings.end, 0);
});
}
// Check network related timings.
var networkTimings = [tc.domainLookupStartTime,
tc.domainLookupEndTime,
tc.connectStartTime,
tc.connectEndTime,
tc.requestStartTime,
tc.responseStartTime,
tc.responseEndTime];
if (aFetch) {
networkTimings.reduce((aPreviousTiming, aCurrentTiming) => {
ok(aPreviousTiming <= aCurrentTiming);
return aCurrentTiming;
});
} else {
networkTimings.forEach(aTiming => is(aTiming, 0));
}
SpecialPowers.removeObserver(observer, topic);
resolveFunction();
}
SpecialPowers.addObserver(observer, topic, false);
// return promise;
return Promise.all([aWindow.fetch(aURL), promise]);
}
function runTest() {
return Promise.resolve()
.then(_ => createTestWindow(contentPage))
.then(w => executeTest(w))
.catch(e => ok(false, "Some test failed with error " + e))
.then(_ => SimpleTest.finish());
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
]}, runTest);
</script>
</pre>
</body>
</html>

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

@ -78,40 +78,5 @@ DrawEventRecorderFile::Close()
mOutputFile.close();
}
DrawEventRecorderMemory::DrawEventRecorderMemory()
: DrawEventRecorderPrivate(nullptr)
{
mOutputStream = &mMemoryStream;
WriteHeader();
}
void
DrawEventRecorderMemory::Flush()
{
mOutputStream->flush();
}
size_t
DrawEventRecorderMemory::RecordingSize()
{
return mMemoryStream.tellp();
}
bool
DrawEventRecorderMemory::CopyRecording(char* aBuffer, size_t aBufferLen)
{
return !!mMemoryStream.read(aBuffer, aBufferLen);
}
void
DrawEventRecorderMemory::WipeRecording()
{
mMemoryStream.str(std::string());
mMemoryStream.clear();
WriteHeader();
}
} // namespace gfx
} // namespace mozilla

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

@ -103,53 +103,6 @@ private:
std::ofstream mOutputFile;
};
class DrawEventRecorderMemory final : public DrawEventRecorderPrivate
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory)
/**
* Constructs a DrawEventRecorder that stores the recording in memory.
*/
DrawEventRecorderMemory();
/**
* @return the current size of the recording (in chars).
*/
size_t RecordingSize();
/**
* Copies at most aBufferLen chars of the recording into aBuffer.
*
* @param aBuffer buffer to receive the recording chars
* @param aBufferLen length of aBuffer
* @return true if copied successfully
*/
bool CopyRecording(char* aBuffer, size_t aBufferLen);
/**
* Wipes the internal recording buffer, but the recorder does NOT forget which
* objects it has recorded. This can be used so that a recording can be copied
* and processed in chunks, releasing memory as it goes.
*/
void WipeRecording();
/**
* Gets a readable reference of the underlying stream, reset to the beginning.
*/
std::istream& GetInputStream() {
mMemoryStream.seekg(0);
return mMemoryStream;
}
private:
~DrawEventRecorderMemory() {};
void Flush() final;
std::stringstream mMemoryStream;
};
} // namespace gfx
} // namespace mozilla

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

@ -30,6 +30,16 @@ interface imgICache : nsISupports
*/
void clearCache(in boolean chrome);
/**
* Evict images from the cache.
*
* @param uri The URI to remove.
* @param doc The document to remove the cache entry for.
* @throws NS_ERROR_NOT_AVAILABLE if \a uri was unable to be removed from
* the cache.
*/
[noscript] void removeEntry(in nsIURI uri, [optional] in nsIDOMDocument doc);
/**
* Find Properties
* Used to get properties such as 'type' and 'content-disposition'

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

@ -1369,6 +1369,29 @@ imgLoader::ClearCache(bool chrome)
}
NS_IMETHODIMP
imgLoader::RemoveEntry(nsIURI* aURI,
nsIDOMDocument* aDOMDoc)
{
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDoc);
if (aURI) {
OriginAttributes attrs;
if (doc) {
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
if (principal) {
attrs = principal->OriginAttributesRef();
}
}
nsresult rv = NS_OK;
ImageCacheKey key(aURI, attrs, doc, rv);
if (NS_SUCCEEDED(rv) && RemoveFromCache(key)) {
return NS_OK;
}
}
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
imgLoader::FindEntryProperties(nsIURI* uri,
nsIDOMDocument* aDOMDoc,
@ -2169,6 +2192,18 @@ imgLoader::LoadImage(nsIURI* aURI,
request->SetCacheEntry(entry);
if (mCacheTracker) {
if (MOZ_UNLIKELY(!entry->GetExpirationState()->IsTracked())) {
bool inCache = false;
RefPtr<imgCacheEntry> e;
if (cache.Get(key, getter_AddRefs(e)) && e) {
inCache = (e == entry);
}
gfxCriticalNoteOnce << "entry with no proxies is no in tracker "
<< "request->HasConsumers() "
<< (request->HasConsumers() ? "true" : "false")
<< " inCache " << (inCache ? "true" : "false");
}
mCacheTracker->MarkUsed(entry);
}
}

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

@ -2414,16 +2414,16 @@ js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind co
// For 6.1.3.2.2 and 6.1.3.2.3, steps 7-16 corresponds to steps 11-20.
// Steps 7-8.
RootedValue value(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Steps 9-10.
RootedValue doneVal(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
bool done = ToBoolean(doneVal);
// Steps 9-10.
RootedValue value(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 11.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)

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

@ -244,9 +244,9 @@ class LoopControl : public BreakableControl
loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
int loopSlots;
if (loopKind == StatementKind::Spread || loopKind == StatementKind::ForOfLoop)
if (loopKind == StatementKind::Spread)
loopSlots = 3;
else if (loopKind == StatementKind::ForInLoop)
else if (loopKind == StatementKind::ForInLoop || loopKind == StatementKind::ForOfLoop)
loopSlots = 2;
else
loopSlots = 0;
@ -269,6 +269,20 @@ class LoopControl : public BreakableControl
return canIonOsr_;
}
MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
// This doesn't pop stack values, nor handle any other controls.
// Should be called on the toplevel of the loop.
MOZ_ASSERT(bce->stackDepth == stackDepth_);
MOZ_ASSERT(bce->innermostNestableControl == this);
if (!bce->newSrcNote(SRC_BREAK))
return false;
if (!bce->emitJump(JSOP_GOTO, &breaks))
return false;
return true;
}
MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
MOZ_ASSERT(continueTarget.offset != -1);
if (!patchBreaks(bce))
@ -2080,11 +2094,11 @@ class ForOfLoopControl : public LoopControl
}
bool emitPrepareForNonLocalJump(BytecodeEmitter* bce, bool isTarget) {
// Pop unnecessary values from the stack. Effectively this means
// Pop unnecessary value from the stack. Effectively this means
// leaving try-catch block. However, the performing IteratorClose can
// reach the depth for try-catch, and effectively re-enter the
// try-catch block.
if (!bce->emitPopN(2)) // ITER
if (!bce->emit1(JSOP_POP)) // ITER
return false;
// Clear ITER slot on the stack to tell catch block to avoid performing
@ -2100,11 +2114,9 @@ class ForOfLoopControl : public LoopControl
if (isTarget) {
// At the level of the target block, there's bytecode after the
// loop that will pop the iterator and the value, so push
// undefineds to balance the stack.
// an undefined to balance the stack.
if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF
return false;
if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF UNDEF
return false;
} else {
if (!bce->emit1(JSOP_POP)) //
return false;
@ -2780,7 +2792,7 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ false)) // ...
return false;
} else {
npops += 3;
npops += 2;
}
break;
@ -2805,7 +2817,7 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ true)) // ... UNDEF UNDEF UNDEF
if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ true)) // ... UNDEF UNDEF
return false;
}
@ -7026,11 +7038,9 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
int32_t iterDepth = stackDepth;
// For-of loops have both the iterator, the result, and the result.value
// on the stack. Push undefineds to balance the stack.
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT UNDEF
// For-of loops have both the iterator and the result.value on the stack.
// Push an undefined to balance the stack.
if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
return false;
ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
@ -7041,11 +7051,11 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
return false;
JumpList initialJump;
if (!emitJump(JSOP_GOTO, &initialJump)) // ITER RESULT UNDEF
if (!emitJump(JSOP_GOTO, &initialJump)) // ITER UNDEF
return false;
JumpTarget top{ -1 };
if (!emitLoopHead(nullptr, &top)) // ITER RESULT UNDEF
if (!emitLoopHead(nullptr, &top)) // ITER UNDEF
return false;
// If the loop had an escaping lexical declaration, replace the current
@ -7062,7 +7072,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
if (!emit1(JSOP_RECREATELEXICALENV)) // ITER RESULT UNDEF
if (!emit1(JSOP_RECREATELEXICALENV)) // ITER UNDEF
return false;
}
@ -7078,21 +7088,49 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
auto loopDepth = this->stackDepth;
#endif
if (!emit1(JSOP_POP)) // ITER
return false;
if (!emit1(JSOP_DUP)) // ITER ITER
return false;
if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter))
return false; // ITER RESULT
if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
return false;
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
return false;
IfThenElseEmitter ifDone(this);
if (!ifDone.emitIf()) // ITER RESULT
return false;
// Remove RESULT from the stack to release it.
if (!emit1(JSOP_POP)) // ITER
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
return false;
// If the iteration is done, leave loop here, instead of the branch at
// the end of the loop.
if (!loopInfo.emitSpecialBreakForDone(this)) // ITER UNDEF
return false;
if (!ifDone.emitEnd()) // ITER RESULT
return false;
// Emit code to assign result.value to the iteration variable.
//
// Note that ES 13.7.5.13, step 5.c says getting result.value does not
// call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
if (!emit1(JSOP_POP)) // ITER RESULT
return false;
if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
return false;
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER RESULT VALUE
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER VALUE
return false;
if (!loopInfo.emitBeginCodeNeedingIteratorClose(this))
return false;
if (!emitInitializeForInOrOfTarget(forOfHead)) // ITER RESULT VALUE
if (!emitInitializeForInOrOfTarget(forOfHead)) // ITER VALUE
return false;
MOZ_ASSERT(stackDepth == loopDepth,
@ -7100,14 +7138,14 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
"operation");
// Remove VALUE from the stack to release it.
if (!emit1(JSOP_POP)) // ITER RESULT
if (!emit1(JSOP_POP)) // ITER
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT UNDEF
if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
return false;
// Perform the loop body.
ParseNode* forBody = forOfLoop->pn_right;
if (!emitTree(forBody)) // ITER RESULT UNDEF
if (!emitTree(forBody)) // ITER UNDEF
return false;
MOZ_ASSERT(stackDepth == loopDepth,
@ -7119,29 +7157,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
// Set offset for continues.
loopInfo.continueTarget = { offset() };
if (!emitLoopEntry(forHeadExpr, initialJump)) // ITER RESULT UNDEF
if (!emitLoopEntry(forHeadExpr, initialJump)) // ITER UNDEF
return false;
if (!emit1(JSOP_SWAP)) // ITER UNDEF RESULT
if (!emit1(JSOP_FALSE)) // ITER UNDEF FALSE
return false;
if (!emit1(JSOP_POP)) // ITER UNDEF
return false;
if (!emitDupAt(1)) // ITER UNDEF ITER
return false;
if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter)) // ITER UNDEF RESULT
return false;
if (!emit1(JSOP_SWAP)) // ITER RESULT UNDEF
return false;
if (!emitDupAt(1)) // ITER RESULT UNDEF RESULT
return false;
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT UNDEF DONE
return false;
if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
return false; // ITER RESULT UNDEF
return false; // ITER UNDEF
MOZ_ASSERT(this->stackDepth == loopDepth);
}
@ -7156,7 +7178,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
return false;
return emitPopN(3); //
return emitPopN(2); //
}
bool
@ -7566,9 +7588,7 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
return false;
// Push a dummy result so that we properly enter iteration midstream.
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT VALUE
if (!emit1(JSOP_UNDEFINED)) // ITER VALUE
return false;
// Enter the block before the loop body, after evaluating the obj.
@ -7606,31 +7626,56 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
int loopDepth = this->stackDepth;
#endif
// Emit code to assign result.value to the iteration variable.
if (!emit1(JSOP_POP)) // ITER RESULT
if (!emit1(JSOP_POP)) // ITER
return false;
if (!emit1(JSOP_DUP)) // ITER ITER
return false;
if (!emitIteratorNext(forHead)) // ITER RESULT
return false;
if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
return false;
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER RESULT VALUE
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
return false;
IfThenElseEmitter ifDone(this);
if (!ifDone.emitIf()) // ITER RESULT
return false;
// Remove RESULT from the stack to release it.
if (!emit1(JSOP_POP)) // ITER
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
return false;
// If the iteration is done, leave loop here, instead of the branch at
// the end of the loop.
if (!loopInfo.emitSpecialBreakForDone(this)) // ITER UNDEF
return false;
if (!ifDone.emitEnd()) // ITER RESULT
return false;
// Emit code to assign result.value to the iteration variable.
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER VALUE
return false;
// Notice: Comprehension for-of doesn't perform IteratorClose, since it's
// not in the spec.
if (!emitAssignment(loopVariableName, JSOP_NOP, nullptr)) // ITER RESULT VALUE
if (!emitAssignment(loopVariableName, JSOP_NOP, nullptr)) // ITER VALUE
return false;
// Remove VALUE from the stack to release it.
if (!emit1(JSOP_POP)) // ITER RESULT
if (!emit1(JSOP_POP)) // ITER
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT UNDEF
if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
return false;
// The stack should be balanced around the assignment opcode sequence.
MOZ_ASSERT(this->stackDepth == loopDepth);
// Emit code for the loop body.
if (!emitTree(forBody)) // ITER RESULT UNDEF
if (!emitTree(forBody)) // ITER UNDEF
return false;
// The stack should be balanced around the assignment opcode sequence.
@ -7642,25 +7687,13 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
if (!emitLoopEntry(forHeadExpr, jmp))
return false;
if (!emit1(JSOP_SWAP)) // ITER UNDEF RESULT
return false;
if (!emit1(JSOP_POP)) // ITER UNDEF
return false;
if (!emitDupAt(1)) // ITER UNDEF ITER
return false;
if (!emitIteratorNext(forHead)) // ITER UNDEF RESULT
return false;
if (!emit1(JSOP_SWAP)) // ITER RESULT UNDEF
return false;
if (!emitDupAt(1)) // ITER RESULT UNDEF RESULT
return false;
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT UNDEF DONE
if (!emit1(JSOP_FALSE)) // ITER VALUE FALSE
return false;
JumpList beq;
JumpTarget breakTarget{ -1 };
if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget)) // ITER RESULT UNDEF
return false;
if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
return false; // ITER VALUE
MOZ_ASSERT(this->stackDepth == loopDepth);
@ -7681,7 +7714,7 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
}
// Pop the result and the iter.
return emitPopN(3); //
return emitPopN(2); //
}
bool

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

@ -5973,11 +5973,6 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
if (!matchInOrOf(&isForIn, &isForOf))
return false;
if (iterKind == IteratorKind::Async && !isForOf) {
error(JSMSG_FOR_AWAIT_NOT_OF);
return false;
}
// If we don't encounter 'in'/'of', we have a for(;;) loop. We've handled
// the init expression; the caller handles the rest. Allow the Operand
// modifier when regetting: Operand must be used to examine the ';' in
@ -6125,15 +6120,19 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
MOZ_ASSERT(headKind == PNK_FORIN || headKind == PNK_FOROF || headKind == PNK_FORHEAD);
if (iterKind == IteratorKind::Async && headKind != PNK_FOROF) {
errorAt(begin, JSMSG_FOR_AWAIT_NOT_OF);
return null();
}
if (isForEach && headKind != PNK_FORIN) {
errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
Node forHead;
if (headKind == PNK_FORHEAD) {
Node init = startNode;
if (isForEach) {
errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
// Look for an operand: |for (;| means we might have already examined
// this semicolon with that modifier.
MUST_MATCH_TOKEN_MOD(TOK_SEMI, TokenStream::Operand, JSMSG_SEMI_AFTER_FOR_INIT);
@ -6189,11 +6188,6 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
stmt.refineForKind(StatementKind::ForInLoop);
iflags |= JSITER_ENUMERATE;
} else {
if (isForEach) {
errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
stmt.refineForKind(StatementKind::ForOfLoop);
}

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

@ -0,0 +1,18 @@
if (typeof TypedObject === 'undefined')
quit();
var uint8 = TypedObject.uint8;
function check(v) {
return v.toSource();
}
function test() {
var fake1 = {};
var fake2 = [];
fake2.toSource = uint8;
var a = [fake1, fake2];
for (var i = 0; i < 1000; i++) try {
check(a[i % 2]);
} catch (e) {}
}
test();

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

@ -0,0 +1,132 @@
let values = [-Infinity, Infinity, NaN, 0, -0, -0.1, 0.1, 0.5, -1.6, 1.6, 13.37];
function unary(name) {
print(name);
let imports = {
math: {
func: Math[name],
}
};
let f32 = x => Math.fround(Math[name](Math.fround(x)));
let f64 = Math[name];
let i = wasmEvalText(`(module
(import $f32 "math" "func" (param f32) (result f32))
(import $f64 "math" "func" (param f64) (result f64))
(table $t 10 anyfunc)
(type $f_f (func (param f32) (result f32)))
(type $d_d (func (param f64) (result f64)))
(elem (i32.const 0) $f32 $f64)
(func (export "f32") (param f32) (result f32)
get_local 0
call $f32
)
(func (export "f32_t") (param f32) (result f32)
get_local 0
i32.const 0
call_indirect $f_f
)
(func (export "f64") (param f64) (result f64)
get_local 0
call $f64
)
(func (export "f64_t") (param f64) (result f64)
get_local 0
i32.const 1
call_indirect $d_d
)
)`, imports).exports;
for (let v of values) {
assertEq(i.f32(v), f32(v));
assertEq(i.f32_t(v), f32(v));
assertEq(i.f64(v), f64(v));
assertEq(i.f64_t(v), f64(v));
}
}
function binary(name) {
print(name);
let imports = {
math: {
func: Math[name]
}
};
let f32 = (x, y) => Math.fround(Math[name](Math.fround(x), Math.fround(y)));
let f64 = Math[name];
let i = wasmEvalText(`(module
(import $f32 "math" "func" (param f32) (param f32) (result f32))
(import $f64 "math" "func" (param f64) (param f64) (result f64))
(table $t 10 anyfunc)
(type $ff_f (func (param f32) (param f32) (result f32)))
(type $dd_d (func (param f64) (param f64) (result f64)))
(elem (i32.const 0) $f32 $f64)
(func (export "f32") (param f32) (param f32) (result f32)
get_local 0
get_local 1
call $f32
)
(func (export "f32_t") (param f32) (param f32) (result f32)
get_local 0
get_local 1
i32.const 0
call_indirect $ff_f
)
(func (export "f64") (param f64) (param f64) (result f64)
get_local 0
get_local 1
call $f64
)
(func (export "f64_t") (param f64) (param f64) (result f64)
get_local 0
get_local 1
i32.const 1
call_indirect $dd_d
)
)`, imports).exports;
for (let v of values) {
for (let w of values) {
assertEq(i.f32(v, w), f32(v, w));
assertEq(i.f64(v, w), f64(v, w));
}
}
}
unary('sin');
unary('sin');
unary('tan');
unary('cos');
unary('exp');
unary('log');
unary('asin');
unary('atan');
unary('acos');
unary('log10');
unary('log2');
unary('log1p');
unary('expm1');
unary('sinh');
unary('tanh');
unary('cosh');
unary('asinh');
unary('atanh');
unary('acosh');
unary('sign');
unary('trunc');
unary('cbrt');
binary('atan2');
binary('hypot');
binary('pow');
print('done');

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

@ -13,10 +13,10 @@ const Table = WebAssembly.Table;
function normalize(stack)
{
var wasmFrameTypes = [
{re:/^entry trampoline \(in wasm\)$/, sub:">"},
{re:/^wasm-function\[(\d+)\] \(.*\)$/, sub:"$1"},
{re:/^(fast|slow) FFI trampoline \(in wasm\)$/, sub:"<"},
{re:/ \(in wasm\)$/, sub:""}
{re:/^entry trampoline \(in wasm\)$/, sub:">"},
{re:/^wasm-function\[(\d+)\] \(.*\)$/, sub:"$1"},
{re:/^(fast|slow) FFI trampoline (to native |)\(in wasm\)$/, sub:"<"},
{re:/ \(in wasm\)$/, sub:""}
];
var framesIn = stack.split(',');
@ -113,6 +113,16 @@ test(
{"":{foo:()=>{}}},
["", ">", "1,>", "0,1,>", "<,0,1,>", "0,1,>", "1,>", ">", ""]);
test(`(module
(import $f32 "Math" "sin" (param f32) (result f32))
(func (export "") (param f32) (result f32)
get_local 0
call $f32
)
)`,
this,
["", ">", "1,>", "<,1,>", "1,>", ">", ""]);
function testError(code, error, expect)
{
enableGeckoProfiling();

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

@ -516,10 +516,9 @@ HasLiveStackValueAtDepth(JSScript* script, jsbytecode* pc, uint32_t stackDepth)
break;
case JSTRY_FOR_OF:
// For-of loops have the iterator, the result object, and the value
// of the result object on stack. The iterator is below the result
// object and the value.
if (stackDepth == tn->stackDepth - 2)
// For-of loops have the iterator and the result.value on stack.
// The iterator is below the result.value.
if (stackDepth == tn->stackDepth - 1)
return true;
break;

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

@ -937,7 +937,7 @@ ControlFlowGenerator::processWhileOrForInLoop(jssrcnote* sn)
size_t stackPhiCount;
if (SN_TYPE(sn) == SRC_FOR_OF)
stackPhiCount = 3;
stackPhiCount = 2;
else if (SN_TYPE(sn) == SRC_FOR_IN)
stackPhiCount = 1;
else

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

@ -769,11 +769,11 @@ PropertyNameToExtraName(PropertyName* name)
#endif // DEBUG
enum {
enum ABIArgType {
ArgType_General = 0x1,
ArgType_Double = 0x2,
ArgType_Float32 = 0x3,
ArgType_Int64 = 0x4,
ArgType_Int64 = 0x4,
RetType_Shift = 0x0,
ArgType_Shift = 0x3,
@ -828,6 +828,9 @@ enum ABIFunctionType
// double f(double, double)
Args_Double_DoubleDouble = Args_Double_Double | (ArgType_Double << (ArgType_Shift * 2)),
// float f(float, float)
Args_Float32_Float32Float32 = Args_Float32_Float32 | (ArgType_Float32 << (ArgType_Shift * 2)),
// double f(int, double)
Args_Double_IntDouble = Args_Double_None |
(ArgType_Double << (ArgType_Shift * 1)) |
@ -856,7 +859,6 @@ enum ABIFunctionType
(ArgType_General << (ArgType_Shift * 2)) |
(ArgType_Double << (ArgType_Shift * 3)) |
(ArgType_General << (ArgType_Shift * 4))
};
enum class BarrierKind : uint32_t {

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

@ -5424,6 +5424,11 @@ InlinePropertyTable::trimTo(const ObjectVector& targets, const BoolVector& choic
if (choiceSet[i])
continue;
// If the target wasn't a function we would have veto'ed it
// and it will not be in the entries list.
if (!targets[i]->is<JSFunction>())
continue;
JSFunction* target = &targets[i]->as<JSFunction>();
// Eliminate all entries containing the vetoed function from the map.

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

@ -2291,6 +2291,19 @@ ToMIRType(MIRType t)
return t;
}
static inline MIRType
ToMIRType(ABIArgType argType)
{
switch (argType & ArgType_Mask) {
case ArgType_General: return MIRType::Int32;
case ArgType_Double: return MIRType::Double;
case ArgType_Float32: return MIRType::Float32;
case ArgType_Int64: return MIRType::Int64;
default: break;
}
MOZ_CRASH("unexpected argType");
}
template <class VecT>
class ABIArgIter
{

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

@ -2446,6 +2446,7 @@ typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t
typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
int32_t arg3);
typedef float (*Prototype_Float32_Float32)(float arg0);
typedef float (*Prototype_Float32_Float32Float32)(float arg0, float arg1);
typedef float (*Prototype_Float32_IntInt)(int arg0, int arg1);
typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
@ -2634,6 +2635,21 @@ Simulator::softwareInterrupt(SimInstruction* instr)
setCallResultFloat(fresult);
break;
}
case Args_Float32_Float32Float32: {
float fval0, fval1;
if (UseHardFpABI()) {
get_float_from_s_register(0, &fval0);
get_float_from_s_register(1, &fval1);
} else {
fval0 = mozilla::BitwiseCast<float>(arg0);
fval1 = mozilla::BitwiseCast<float>(arg1);
}
Prototype_Float32_Float32Float32 target = reinterpret_cast<Prototype_Float32_Float32Float32>(external);
float fresult = target(fval0, fval1);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultFloat(fresult);
break;
}
case Args_Float32_IntInt: {
Prototype_Float32_IntInt target = reinterpret_cast<Prototype_Float32_IntInt>(external);
float fresult = target(arg0, arg1);

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

@ -161,6 +161,14 @@ struct ImmPtr
{
void* value;
struct NoCheckToken {};
explicit ImmPtr(void* value, NoCheckToken) : value(value)
{
// A special unchecked variant for contexts where we know it is safe to
// use an immptr. This is assuming the caller knows what they're doing.
}
explicit ImmPtr(const void* value) : value(const_cast<void*>(value))
{
// To make code serialization-safe, wasm compilation should only
@ -202,7 +210,6 @@ struct ImmPtr
{
MOZ_ASSERT(!IsCompilingWasm());
}
};
// The same as ImmPtr except that the intention is to patch this

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

@ -594,7 +594,7 @@ MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of i
MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method")
// Async Iteration
MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop should be used with 'of'")
MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_SYNTAXERR, "'for await' loop should be used with 'of'")
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")

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

@ -376,6 +376,7 @@ UNIFIED_SOURCES += [
'wasm/WasmIonCompile.cpp',
'wasm/WasmJS.cpp',
'wasm/WasmModule.cpp',
'wasm/WasmRuntime.cpp',
'wasm/WasmSignalHandlers.cpp',
'wasm/WasmStubs.cpp',
'wasm/WasmTable.cpp',

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

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

@ -0,0 +1,26 @@
// |reftest| skip-if(release_or_beta)
var AsyncGenerator = async function*(){}.constructor;
function assertSyntaxError(code) {
var functionCode = `async function* f() { ${code} }`;
assertThrowsInstanceOf(() => AsyncGenerator(code), SyntaxError, "AsyncGenerator:" + code);
assertThrowsInstanceOf(() => eval(functionCode), SyntaxError, "eval:" + functionCode);
var ieval = eval;
assertThrowsInstanceOf(() => ieval(functionCode), SyntaxError, "indirect eval:" + functionCode);
}
assertSyntaxError(`for await (;;) ;`);
for (var decl of ["", "var", "let", "const"]) {
for (var head of ["a", "a = 0", "a, b", "[a]", "[a] = 0", "{a}", "{a} = 0"]) {
// Ends with C-style for loop syntax.
assertSyntaxError(`for await (${decl} ${head} ;;) ;`);
// Ends with for-in loop syntax.
assertSyntaxError(`for await (${decl} ${head} in null) ;`);
}
}
if (typeof reportCompare === "function")
reportCompare(0, 0);

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

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

@ -870,12 +870,11 @@ skip script test262/language/statements/async-generator/yield-star-async-next.js
skip script test262/language/statements/async-generator/yield-star-async-return.js
skip script test262/language/statements/async-generator/yield-star-async-throw.js
skip script test262/language/module-code/namespace/internals/delete-non-exported.js
# https://github.com/tc39/test262/pull/947
skip script test262/intl402/NumberFormat/11.1.1_32.js
# https://github.com/tc39/test262/pull/947
skip script test262/intl402/DateTimeFormat/prototype/formatToParts/length.js
# https://github.com/tc39/test262/pull/947
skip script test262/intl402/PluralRules/this-not-ignored.js
# https://github.com/tc39/test262/pull/961
skip script test262/language/statements/async-generator/yield-star-sync-return.js
skip script test262/language/statements/async-generator/yield-star-sync-throw.js
skip script test262/language/statements/async-generator/yield-star-sync-next.js

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

@ -267,6 +267,9 @@ JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
if (!caches().init())
return false;
if (!wasm().init())
return false;
return true;
}
@ -279,6 +282,8 @@ JSRuntime::destroyRuntime()
sharedIntlData.ref().destroyInstance();
wasm().destroy();
if (gcInitialized) {
/*
* Finish any in-progress GCs first. This ensures the parseWaitingOnGC

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

@ -54,6 +54,7 @@
#include "vm/Stack.h"
#include "vm/Stopwatch.h"
#include "vm/Symbol.h"
#include "wasm/WasmRuntime.h"
#ifdef _MSC_VER
#pragma warning(push)
@ -534,6 +535,13 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
/* AsmJSCache callbacks are runtime-wide. */
js::UnprotectedData<JS::AsmJSCacheOps> asmJSCacheOps;
private:
// All runtime data needed for wasm and defined in wasm/WasmRuntime.h.
js::ActiveThreadData<js::wasm::Runtime> wasmRuntime_;
public:
js::wasm::Runtime& wasm() { return wasmRuntime_.ref(); }
private:
js::UnprotectedData<const JSPrincipals*> trustedPrincipals_;
public:

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

@ -1837,6 +1837,7 @@ JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state)
if (activation_->isWasm()) {
new (storage()) wasm::ProfilingFrameIterator(*activation_->asWasm(), state);
// Set savedPrevJitTop_ to the actual jitTop_ from the runtime.
AutoNoteSingleThreadedRegion anstr;
savedPrevJitTop_ = activation_->cx()->jitTop;
return;
}

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

@ -111,7 +111,8 @@ StaticallyLink(CodeSegment& cs, const LinkData& linkData, JSContext* cx)
const Uint32Vector& offsets = linkData.symbolicLinks[imm];
for (size_t i = 0; i < offsets.length(); i++) {
uint8_t* patchAt = cs.base() + offsets[i];
void* target = AddressOf(imm);
ABIFunctionType unused;
void* target = wasm::AddressOf(imm, &unused);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
PatchedImmPtr(target),
PatchedImmPtr((void*)-1));
@ -295,62 +296,6 @@ FuncImport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
return sig_.sizeOfExcludingThis(mallocSizeOf);
}
CodeRange::CodeRange(Kind kind, Offsets offsets)
: begin_(offsets.begin),
ret_(0),
end_(offsets.end),
funcIndex_(0),
funcLineOrBytecode_(0),
funcBeginToNormalEntry_(0),
kind_(kind)
{
MOZ_ASSERT(begin_ <= end_);
#ifdef DEBUG
switch (kind_) {
case Entry:
case DebugTrap:
case FarJumpIsland:
case Inline:
case Throw:
case Interrupt:
break;
case Function:
case TrapExit:
case ImportJitExit:
case ImportInterpExit:
MOZ_CRASH("should use more specific constructor");
}
#endif
}
CodeRange::CodeRange(Kind kind, CallableOffsets offsets)
: begin_(offsets.begin),
ret_(offsets.ret),
end_(offsets.end),
funcIndex_(0),
funcLineOrBytecode_(0),
funcBeginToNormalEntry_(0),
kind_(kind)
{
MOZ_ASSERT(begin_ < ret_);
MOZ_ASSERT(ret_ < end_);
MOZ_ASSERT(kind_ == ImportJitExit || kind_ == ImportInterpExit || kind_ == TrapExit);
}
CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets)
: begin_(offsets.begin),
ret_(offsets.ret),
end_(offsets.end),
funcIndex_(funcIndex),
funcLineOrBytecode_(funcLineOrBytecode),
funcBeginToNormalEntry_(offsets.normalEntry - begin_),
kind_(Function)
{
MOZ_ASSERT(begin_ < ret_);
MOZ_ASSERT(ret_ < end_);
MOZ_ASSERT(offsets.normalEntry - begin_ <= UINT8_MAX);
}
static size_t
StringLengthWithNullChar(const char* chars)
{

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

@ -218,119 +218,6 @@ class FuncImport
typedef Vector<FuncImport, 0, SystemAllocPolicy> FuncImportVector;
// A CodeRange describes a single contiguous range of code within a wasm
// module's code segment. A CodeRange describes what the code does and, for
// function bodies, the name and source coordinates of the function.
class CodeRange
{
public:
enum Kind {
Function, // function definition
Entry, // calls into wasm from C++
ImportJitExit, // fast-path calling from wasm into JIT code
ImportInterpExit, // slow-path calling from wasm into C++ interp
TrapExit, // calls C++ to report and jumps to throw stub
DebugTrap, // calls C++ to handle debug event
FarJumpIsland, // inserted to connect otherwise out-of-range insns
Inline, // stub that is jumped-to within prologue/epilogue
Throw, // special stack-unwinding stub
Interrupt // stub executes asynchronously to interrupt wasm
};
private:
// All fields are treated as cacheable POD:
uint32_t begin_;
uint32_t ret_;
uint32_t end_;
uint32_t funcIndex_;
uint32_t funcLineOrBytecode_;
uint8_t funcBeginToNormalEntry_;
Kind kind_ : 8;
public:
CodeRange() = default;
CodeRange(Kind kind, Offsets offsets);
CodeRange(Kind kind, CallableOffsets offsets);
CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets);
// All CodeRanges have a begin and end.
uint32_t begin() const {
return begin_;
}
uint32_t end() const {
return end_;
}
// Other fields are only available for certain CodeRange::Kinds.
Kind kind() const {
return kind_;
}
bool isFunction() const {
return kind() == Function;
}
bool isImportExit() const {
return kind() == ImportJitExit || kind() == ImportInterpExit;
}
bool isTrapExit() const {
return kind() == TrapExit;
}
bool isInline() const {
return kind() == Inline;
}
bool isThunk() const {
return kind() == FarJumpIsland;
}
// Every CodeRange except entry and inline stubs are callable and have a
// return statement. Asynchronous frame iteration needs to know the offset
// of the return instruction to calculate the frame pointer.
uint32_t ret() const {
MOZ_ASSERT(isFunction() || isImportExit() || isTrapExit());
return ret_;
}
// Function CodeRanges have two entry points: one for normal calls (with a
// known signature) and one for table calls (which involves dynamic
// signature checking).
uint32_t funcTableEntry() const {
MOZ_ASSERT(isFunction());
return begin_;
}
uint32_t funcNormalEntry() const {
MOZ_ASSERT(isFunction());
return begin_ + funcBeginToNormalEntry_;
}
uint32_t funcIndex() const {
MOZ_ASSERT(isFunction());
return funcIndex_;
}
uint32_t funcLineOrBytecode() const {
MOZ_ASSERT(isFunction());
return funcLineOrBytecode_;
}
// A sorted array of CodeRanges can be looked up via BinarySearch and PC.
struct PC {
size_t offset;
explicit PC(size_t offset) : offset(offset) {}
bool operator==(const CodeRange& rhs) const {
return offset >= rhs.begin() && offset < rhs.end();
}
bool operator<(const CodeRange& rhs) const {
return offset < rhs.begin();
}
};
};
WASM_DECLARE_POD_VECTOR(CodeRange, CodeRangeVector)
// A wasm module can either use no memory, a unshared memory (ArrayBuffer) or
// shared memory (SharedArrayBuffer).

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

@ -553,6 +553,7 @@ ProfilingFrameIterator::initFromExitFP()
break;
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
case CodeRange::ImportNativeExit:
case CodeRange::TrapExit:
case CodeRange::DebugTrap:
case CodeRange::Inline:
@ -591,9 +592,23 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// If pc isn't in the instance's code, we must have exited the code via an
// exit trampoline or signal handler.
code_ = activation_->compartment()->wasm.lookupCode(state.pc);
const CodeRange* codeRange = nullptr;
uint8_t* codeBase = nullptr;
if (!code_) {
MOZ_ASSERT(done());
return;
// Optimized builtin exits (see MaybeGetMatchingBuiltin in
// WasmInstance.cpp) are outside module's code.
AutoNoteSingleThreadedRegion anstr;
if (BuiltinThunk* thunk = activation_->cx()->runtime()->wasm().lookupBuiltin(state.pc)) {
codeRange = &thunk->codeRange;
codeBase = (uint8_t*) thunk->base;
} else {
MOZ_ASSERT(done());
return;
}
} else {
codeRange = code_->lookupRange(state.pc);
codeBase = code_->segment().base();
}
// When the pc is inside the prologue/epilogue, the innermost call's Frame
@ -606,10 +621,9 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
uint8_t* pc = (uint8_t*)state.pc;
void** sp = (void**)state.sp;
const CodeRange* codeRange = code_->lookupRange(pc);
uint32_t offsetInModule = pc - code_->segment().base();
MOZ_ASSERT(offsetInModule >= codeRange->begin());
MOZ_ASSERT(offsetInModule < codeRange->end());
uint32_t offsetInCode = pc - codeBase;
MOZ_ASSERT(offsetInCode >= codeRange->begin());
MOZ_ASSERT(offsetInCode < codeRange->end());
// Compute the offset of the pc from the (normal) entry of the code range.
// The stack state of the pc for the entire table-entry is equivalent to
@ -618,12 +632,12 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// pc-at-normal-entry case.
uint32_t offsetFromEntry;
if (codeRange->isFunction()) {
if (offsetInModule < codeRange->funcNormalEntry())
if (offsetInCode < codeRange->funcNormalEntry())
offsetFromEntry = 0;
else
offsetFromEntry = offsetInModule - codeRange->funcNormalEntry();
offsetFromEntry = offsetInCode - codeRange->funcNormalEntry();
} else {
offsetFromEntry = offsetInModule - codeRange->begin();
offsetFromEntry = offsetInCode - codeRange->begin();
}
switch (codeRange->kind()) {
@ -631,6 +645,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
case CodeRange::FarJumpIsland:
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
case CodeRange::ImportNativeExit:
case CodeRange::TrapExit:
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
if (offsetFromEntry == BeforePushRetAddr || codeRange->isThunk()) {
@ -658,11 +673,11 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
callerPC_ = ReturnAddressFromFP(sp);
callerFP_ = fp;
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
} else if (offsetInModule == codeRange->ret() - PoppedFP) {
} else if (offsetInCode == codeRange->ret() - PoppedFP) {
// The callerFP field of the Frame has been popped into fp.
callerPC_ = sp[1];
callerFP_ = fp;
} else if (offsetInModule == codeRange->ret()) {
} else if (offsetInCode == codeRange->ret()) {
// Both the TLS and callerFP fields have been popped and fp now
// points to the caller's frame.
callerPC_ = sp[0];
@ -740,6 +755,7 @@ ProfilingFrameIterator::operator++()
case CodeRange::Function:
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
case CodeRange::ImportNativeExit:
case CodeRange::TrapExit:
case CodeRange::DebugTrap:
case CodeRange::Inline:
@ -769,6 +785,7 @@ ProfilingFrameIterator::label() const
// devtools/client/performance/modules/logic/frame-utils.js
static const char* importJitDescription = "fast FFI trampoline (in wasm)";
static const char* importInterpDescription = "slow FFI trampoline (in wasm)";
static const char* importNativeDescription = "fast FFI trampoline to native (in wasm)";
static const char* trapDescription = "trap handling (in wasm)";
static const char* debugTrapDescription = "debug trap handling (in wasm)";
@ -779,6 +796,8 @@ ProfilingFrameIterator::label() const
return importJitDescription;
case ExitReason::ImportInterp:
return importInterpDescription;
case ExitReason::ImportNative:
return importNativeDescription;
case ExitReason::Trap:
return trapDescription;
case ExitReason::DebugTrap:
@ -789,6 +808,7 @@ ProfilingFrameIterator::label() const
case CodeRange::Function: return code_->profilingLabel(codeRange_->funcIndex());
case CodeRange::Entry: return "entry trampoline (in wasm)";
case CodeRange::ImportJitExit: return importJitDescription;
case CodeRange::ImportNativeExit: return importNativeDescription;
case CodeRange::ImportInterpExit: return importInterpDescription;
case CodeRange::TrapExit: return trapDescription;
case CodeRange::DebugTrap: return debugTrapDescription;

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

@ -89,6 +89,7 @@ enum class ExitReason : uint32_t
None, // default state, the pc is in wasm code
ImportJit, // fast-path call directly into JIT code
ImportInterp, // slow-path call into C++ Invoke()
ImportNative, // fast-path call directly into native C++ code
Trap, // call to trap handler for the trap in WasmActivation::trap
DebugTrap // call to debug trap handler
};

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

@ -414,6 +414,7 @@ ModuleGenerator::patchCallSites()
}
}
masm_.flushBuffer();
return true;
}

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

@ -19,7 +19,9 @@
#include "wasm/WasmInstance.h"
#include "jit/BaselineJIT.h"
#include "jit/InlinableNatives.h"
#include "jit/JitCommon.h"
#include "wasm/WasmModule.h"
#include "jsobjinlines.h"
@ -315,6 +317,128 @@ Instance::currentMemory_i32(Instance* instance)
return byteLength / wasm::PageSize;
}
// asm.js has the ability to call directly into Math builtins, which wasm can't
// do. Instead, wasm code generators have to pass the builtins as function
// imports, resulting in slow import calls.
//
// However, we can optimize this by detecting that an import is just a JSNative
// builtin and have wasm call straight to the builtin's C++ code, since the
// ABIs perfectly match at the call site.
//
// Even though we could call into float32 variants of the math functions, we
// do not do it, so as not to change the results.
#define FOREACH_UNCACHED_MATH_BUILTIN(_) \
_(math_sin, MathSin) \
_(math_tan, MathTan) \
_(math_cos, MathCos) \
_(math_exp, MathExp) \
_(math_log, MathLog) \
_(math_asin, MathASin) \
_(math_atan, MathATan) \
_(math_acos, MathACos) \
_(math_log10, MathLog10) \
_(math_log2, MathLog2) \
_(math_log1p, MathLog1P) \
_(math_expm1, MathExpM1) \
_(math_sinh, MathSinH) \
_(math_tanh, MathTanH) \
_(math_cosh, MathCosH) \
_(math_asinh, MathASinH) \
_(math_atanh, MathATanH) \
_(math_acosh, MathACosH) \
_(math_sign, MathSign) \
_(math_trunc, MathTrunc) \
_(math_cbrt, MathCbrt)
#define UNARY_FLOAT_WRAPPER(func) \
float func##_f32(float x) { \
return float(func(double(x))); \
}
#define BINARY_FLOAT_WRAPPER(func) \
float func##_f32(float x, float y) { \
return float(func(double(x), double(y))); \
}
#define DEFINE_FLOAT_WRAPPER(name, _) UNARY_FLOAT_WRAPPER(name##_uncached)
FOREACH_UNCACHED_MATH_BUILTIN(DEFINE_FLOAT_WRAPPER)
BINARY_FLOAT_WRAPPER(ecmaAtan2)
BINARY_FLOAT_WRAPPER(ecmaHypot)
BINARY_FLOAT_WRAPPER(ecmaPow)
#undef DEFINE_FLOAT_WRAPPER
#undef BINARY_FLOAT_WRAPPER
#undef UNARY_FLOAT_WRAPPER
static void*
IsMatchingBuiltin(HandleFunction f, const Sig& sig)
{
if (!f->isNative() || !f->jitInfo() || f->jitInfo()->type() != JSJitInfo::InlinableNative)
return nullptr;
ExprType ret = sig.ret();
const ValTypeVector& args = sig.args();
#define UNARY_BUILTIN(double_func, float_func) \
if (args.length() != 1) \
break; \
if (args[0] == ValType::F64 && ret == ExprType::F64) \
return JS_FUNC_TO_DATA_PTR(void*, double_func); \
if (args[0] == ValType::F32 && ret == ExprType::F32) \
return JS_FUNC_TO_DATA_PTR(void*, float_func); \
break;
#define BINARY_BUILTIN(double_func, float_func) \
if (args.length() != 2) \
break; \
if (args[0] == ValType::F64 && args[1] == ValType::F64 && ret == ExprType::F64) \
return JS_FUNC_TO_DATA_PTR(void*, double_func); \
if (args[0] == ValType::F32 && args[1] == ValType::F32 && ret == ExprType::F32) \
return JS_FUNC_TO_DATA_PTR(void*, float_func); \
break;
switch (f->jitInfo()->inlinableNative) {
#define MAKE_CASE(funcName, inlinableNative) \
case InlinableNative::inlinableNative: \
UNARY_BUILTIN(funcName##_uncached, funcName##_uncached_f32)
FOREACH_UNCACHED_MATH_BUILTIN(MAKE_CASE)
case InlinableNative::MathATan2:
BINARY_BUILTIN(ecmaAtan2, ecmaAtan2_f32)
case InlinableNative::MathHypot:
BINARY_BUILTIN(ecmaHypot, ecmaHypot_f32)
case InlinableNative::MathPow:
BINARY_BUILTIN(ecmaPow, ecmaPow_f32)
default:
break;
}
#undef MAKE_CASE
#undef UNARY_BUILTIN
#undef BINARY_BUILTIN
#undef FOREACH_UNCACHED_MATH_BUILTIN
return nullptr;
}
static void*
MaybeGetMatchingBuiltin(JSContext* cx, HandleFunction f, const Sig& sig)
{
void* funcPtr = IsMatchingBuiltin(f, sig);
if (!funcPtr)
return nullptr;
void* thunkPtr = nullptr;
if (!cx->runtime()->wasm().getBuiltinThunk(cx, funcPtr, sig, &thunkPtr))
return nullptr;
return thunkPtr;
}
Instance::Instance(JSContext* cx,
Handle<WasmInstanceObject*> object,
UniqueCode code,
@ -355,6 +479,11 @@ Instance::Instance(JSContext* cx,
import.code = calleeInstance.codeSegment().base() + codeRange.funcNormalEntry();
import.baselineScript = nullptr;
import.obj = calleeInstanceObj;
} else if (void* thunk = MaybeGetMatchingBuiltin(cx, f, fi.sig())) {
import.tls = tlsData();
import.code = thunk;
import.baselineScript = nullptr;
import.obj = f;
} else {
import.tls = tlsData();
import.code = codeBase() + fi.interpExitCodeOffset();

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

@ -77,21 +77,13 @@ class Instance
FuncImportTls& funcImportTls(const FuncImport& fi);
TableTls& tableTls(const TableDesc& td) const;
// Import call slow paths which are called directly from wasm code.
friend void* AddressOf(SymbolicAddress);
static int32_t callImport_void(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_f64(Instance*, int32_t, int32_t, uint64_t*);
static uint32_t growMemory_i32(Instance* instance, uint32_t delta);
static uint32_t currentMemory_i32(Instance* instance);
bool callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval);
// Only WasmInstanceObject can call the private trace function.
friend class js::WasmInstanceObject;
void tracePrivate(JSTracer* trc);
bool callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval);
public:
Instance(JSContext* cx,
HandleWasmInstanceObject object,
@ -165,6 +157,15 @@ class Instance
Table::SeenSet* seenTables,
size_t* code,
size_t* data) const;
public:
// Functions to be called directly from wasm code.
static int32_t callImport_void(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_f64(Instance*, int32_t, int32_t, uint64_t*);
static uint32_t growMemory_i32(Instance* instance, uint32_t delta);
static uint32_t currentMemory_i32(Instance* instance);
};
typedef UniquePtr<Instance> UniqueInstance;

691
js/src/wasm/WasmRuntime.cpp Normal file
Просмотреть файл

@ -0,0 +1,691 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2017 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wasm/WasmRuntime.h"
#include "mozilla/BinarySearch.h"
#include "fdlibm.h"
#include "jslibmath.h"
#include "jit/MacroAssembler.h"
#include "wasm/WasmInstance.h"
#include "wasm/WasmStubs.h"
#include "vm/Debugger-inl.h"
#include "vm/Stack-inl.h"
using namespace js;
using namespace jit;
using namespace wasm;
using mozilla::BinarySearchIf;
using mozilla::IsNaN;
static const unsigned BUILTIN_THUNK_LIFO_SIZE = 128;
static const CodeKind BUILTIN_THUNK_CODEKIND = CodeKind::OTHER_CODE;
#if defined(JS_CODEGEN_ARM)
extern "C" {
extern MOZ_EXPORT int64_t
__aeabi_idivmod(int, int);
extern MOZ_EXPORT int64_t
__aeabi_uidivmod(int, int);
}
#endif
static void*
WasmHandleExecutionInterrupt()
{
WasmActivation* activation = JSContext::innermostWasmActivation();
// wasm::Compartment requires notification when execution is interrupted in
// the compartment. Only the innermost compartment has been interrupted;
// enclosing compartments necessarily exited through an exit stub.
activation->compartment()->wasm.setInterrupted(true);
bool success = CheckForInterrupt(activation->cx());
activation->compartment()->wasm.setInterrupted(false);
// Preserve the invariant that having a non-null resumePC means that we are
// handling an interrupt.
void* resumePC = activation->resumePC();
activation->setResumePC(nullptr);
// Return the resumePC if execution can continue or null if execution should
// jump to the throw stub.
return success ? resumePC : nullptr;
}
static bool
WasmHandleDebugTrap()
{
WasmActivation* activation = JSContext::innermostWasmActivation();
MOZ_ASSERT(activation);
JSContext* cx = activation->cx();
FrameIterator iter(activation);
MOZ_ASSERT(iter.debugEnabled());
const CallSite* site = iter.debugTrapCallsite();
MOZ_ASSERT(site);
if (site->kind() == CallSite::EnterFrame) {
if (!iter.instance()->enterFrameTrapsEnabled())
return true;
DebugFrame* frame = iter.debugFrame();
frame->setIsDebuggee();
frame->observe(cx);
// TODO call onEnterFrame
JSTrapStatus status = Debugger::onEnterFrame(cx, frame);
if (status == JSTRAP_RETURN) {
// Ignoring forced return (JSTRAP_RETURN) -- changing code execution
// order is not yet implemented in the wasm baseline.
// TODO properly handle JSTRAP_RETURN and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onEnterFrame");
return false;
}
return status == JSTRAP_CONTINUE;
}
if (site->kind() == CallSite::LeaveFrame) {
DebugFrame* frame = iter.debugFrame();
frame->updateReturnJSValue();
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
frame->leave(cx);
return ok;
}
DebugFrame* frame = iter.debugFrame();
Code& code = iter.instance()->code();
MOZ_ASSERT(code.hasBreakpointTrapAtOffset(site->lineOrBytecode()));
if (code.stepModeEnabled(frame->funcIndex())) {
RootedValue result(cx, UndefinedValue());
JSTrapStatus status = Debugger::onSingleStep(cx, &result);
if (status == JSTRAP_RETURN) {
// TODO properly handle JSTRAP_RETURN.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onSingleStep");
return false;
}
if (status != JSTRAP_CONTINUE)
return false;
}
if (code.hasBreakpointSite(site->lineOrBytecode())) {
RootedValue result(cx, UndefinedValue());
JSTrapStatus status = Debugger::onTrap(cx, &result);
if (status == JSTRAP_RETURN) {
// TODO properly handle JSTRAP_RETURN.
JS_ReportErrorASCII(cx, "Unexpected resumption value from breakpoint handler");
return false;
}
if (status != JSTRAP_CONTINUE)
return false;
}
return true;
}
static WasmActivation*
WasmHandleThrow()
{
JSContext* cx = TlsContext.get();
WasmActivation* activation = cx->wasmActivationStack();
MOZ_ASSERT(activation);
// FrameIterator iterates down wasm frames in the activation starting at
// WasmActivation::exitFP. Pass Unwind::True to pop WasmActivation::exitFP
// once each time FrameIterator is incremented, ultimately leaving exitFP
// null when the FrameIterator is done(). This is necessary to prevent a
// DebugFrame from being observed again after we just called onLeaveFrame
// (which would lead to the frame being re-added to the map of live frames,
// right as it becomes trash).
FrameIterator iter(activation, FrameIterator::Unwind::True);
if (iter.done())
return activation;
// Live wasm code on the stack is kept alive (in wasm::TraceActivations) by
// marking the instance of every wasm::Frame found by FrameIterator.
// However, as explained above, we're popping frames while iterating which
// means that a GC during this loop could collect the code of frames whose
// code is still on the stack. This is actually mostly fine: as soon as we
// return to the throw stub, the entire stack will be popped as a whole,
// returning to the C++ caller. However, we must keep the throw stub alive
// itself which is owned by the innermost instance.
RootedWasmInstanceObject keepAlive(cx, iter.instance()->object());
for (; !iter.done(); ++iter) {
if (!iter.debugEnabled())
continue;
DebugFrame* frame = iter.debugFrame();
frame->clearReturnJSValue();
// Assume JSTRAP_ERROR status if no exception is pending --
// no onExceptionUnwind handlers must be fired.
if (cx->isExceptionPending()) {
JSTrapStatus status = Debugger::onExceptionUnwind(cx, frame);
if (status == JSTRAP_RETURN) {
// Unexpected trap return -- raising error since throw recovery
// is not yet implemented in the wasm baseline.
// TODO properly handle JSTRAP_RETURN and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onExceptionUnwind");
}
}
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, false);
if (ok) {
// Unexpected success from the handler onLeaveFrame -- raising error
// since throw recovery is not yet implemented in the wasm baseline.
// TODO properly handle success and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected success from onLeaveFrame");
}
frame->leave(cx);
}
return activation;
}
static void
WasmReportTrap(int32_t trapIndex)
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0);
Trap trap = Trap(trapIndex);
unsigned errorNumber;
switch (trap) {
case Trap::Unreachable:
errorNumber = JSMSG_WASM_UNREACHABLE;
break;
case Trap::IntegerOverflow:
errorNumber = JSMSG_WASM_INTEGER_OVERFLOW;
break;
case Trap::InvalidConversionToInteger:
errorNumber = JSMSG_WASM_INVALID_CONVERSION;
break;
case Trap::IntegerDivideByZero:
errorNumber = JSMSG_WASM_INT_DIVIDE_BY_ZERO;
break;
case Trap::IndirectCallToNull:
errorNumber = JSMSG_WASM_IND_CALL_TO_NULL;
break;
case Trap::IndirectCallBadSig:
errorNumber = JSMSG_WASM_IND_CALL_BAD_SIG;
break;
case Trap::ImpreciseSimdConversion:
errorNumber = JSMSG_SIMD_FAILED_CONVERSION;
break;
case Trap::OutOfBounds:
errorNumber = JSMSG_WASM_OUT_OF_BOUNDS;
break;
case Trap::StackOverflow:
errorNumber = JSMSG_OVER_RECURSED;
break;
default:
MOZ_CRASH("unexpected trap");
}
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber);
}
static void
WasmReportOutOfBounds()
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS);
}
static void
WasmReportUnalignedAccess()
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNALIGNED_ACCESS);
}
static int32_t
CoerceInPlace_ToInt32(MutableHandleValue val)
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
int32_t i32;
if (!ToInt32(cx, val, &i32))
return false;
val.set(Int32Value(i32));
return true;
}
static int32_t
CoerceInPlace_ToNumber(MutableHandleValue val)
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
double dbl;
if (!ToNumber(cx, val, &dbl))
return false;
val.set(DoubleValue(dbl));
return true;
}
static int64_t
DivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
int64_t x = ((uint64_t)x_hi << 32) + x_lo;
int64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(x != INT64_MIN || y != -1);
MOZ_ASSERT(y != 0);
return x / y;
}
static int64_t
UDivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
uint64_t x = ((uint64_t)x_hi << 32) + x_lo;
uint64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(y != 0);
return x / y;
}
static int64_t
ModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
int64_t x = ((uint64_t)x_hi << 32) + x_lo;
int64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(x != INT64_MIN || y != -1);
MOZ_ASSERT(y != 0);
return x % y;
}
static int64_t
UModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
uint64_t x = ((uint64_t)x_hi << 32) + x_lo;
uint64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(y != 0);
return x % y;
}
static int64_t
TruncateDoubleToInt64(double input)
{
// Note: INT64_MAX is not representable in double. It is actually
// INT64_MAX + 1. Therefore also sending the failure value.
if (input >= double(INT64_MAX) || input < double(INT64_MIN) || IsNaN(input))
return 0x8000000000000000;
return int64_t(input);
}
static uint64_t
TruncateDoubleToUint64(double input)
{
// Note: UINT64_MAX is not representable in double. It is actually UINT64_MAX + 1.
// Therefore also sending the failure value.
if (input >= double(UINT64_MAX) || input <= -1.0 || IsNaN(input))
return 0x8000000000000000;
return uint64_t(input);
}
static double
Int64ToDouble(int32_t x_hi, uint32_t x_lo)
{
int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
return double(x);
}
static float
Int64ToFloat32(int32_t x_hi, uint32_t x_lo)
{
int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
return float(x);
}
static double
Uint64ToDouble(int32_t x_hi, uint32_t x_lo)
{
uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
return double(x);
}
static float
Uint64ToFloat32(int32_t x_hi, uint32_t x_lo)
{
uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
return float(x);
}
template <class F>
static inline void*
FuncCast(F* funcPtr, ABIFunctionType abiType)
{
void* pf = JS_FUNC_TO_DATA_PTR(void*, funcPtr);
#ifdef JS_SIMULATOR
pf = Simulator::RedirectNativeFunction(pf, abiType);
#endif
return pf;
}
void*
wasm::AddressOf(SymbolicAddress imm, ABIFunctionType* abiType)
{
switch (imm) {
case SymbolicAddress::HandleExecutionInterrupt:
*abiType = Args_General0;
return FuncCast(WasmHandleExecutionInterrupt, *abiType);
case SymbolicAddress::HandleDebugTrap:
*abiType = Args_General0;
return FuncCast(WasmHandleDebugTrap, *abiType);
case SymbolicAddress::HandleThrow:
*abiType = Args_General0;
return FuncCast(WasmHandleThrow, *abiType);
case SymbolicAddress::ReportTrap:
*abiType = Args_General1;
return FuncCast(WasmReportTrap, *abiType);
case SymbolicAddress::ReportOutOfBounds:
*abiType = Args_General0;
return FuncCast(WasmReportOutOfBounds, *abiType);
case SymbolicAddress::ReportUnalignedAccess:
*abiType = Args_General0;
return FuncCast(WasmReportUnalignedAccess, *abiType);
case SymbolicAddress::CallImport_Void:
*abiType = Args_General4;
return FuncCast(Instance::callImport_void, *abiType);
case SymbolicAddress::CallImport_I32:
*abiType = Args_General4;
return FuncCast(Instance::callImport_i32, *abiType);
case SymbolicAddress::CallImport_I64:
*abiType = Args_General4;
return FuncCast(Instance::callImport_i64, *abiType);
case SymbolicAddress::CallImport_F64:
*abiType = Args_General4;
return FuncCast(Instance::callImport_f64, *abiType);
case SymbolicAddress::CoerceInPlace_ToInt32:
*abiType = Args_General1;
return FuncCast(CoerceInPlace_ToInt32, *abiType);
case SymbolicAddress::CoerceInPlace_ToNumber:
*abiType = Args_General1;
return FuncCast(CoerceInPlace_ToNumber, *abiType);
case SymbolicAddress::ToInt32:
*abiType = Args_Int_Double;
return FuncCast<int32_t (double)>(JS::ToInt32, *abiType);
case SymbolicAddress::DivI64:
*abiType = Args_General4;
return FuncCast(DivI64, *abiType);
case SymbolicAddress::UDivI64:
*abiType = Args_General4;
return FuncCast(UDivI64, *abiType);
case SymbolicAddress::ModI64:
*abiType = Args_General4;
return FuncCast(ModI64, *abiType);
case SymbolicAddress::UModI64:
*abiType = Args_General4;
return FuncCast(UModI64, *abiType);
case SymbolicAddress::TruncateDoubleToUint64:
*abiType = Args_Int64_Double;
return FuncCast(TruncateDoubleToUint64, *abiType);
case SymbolicAddress::TruncateDoubleToInt64:
*abiType = Args_Int64_Double;
return FuncCast(TruncateDoubleToInt64, *abiType);
case SymbolicAddress::Uint64ToDouble:
*abiType = Args_Double_IntInt;
return FuncCast(Uint64ToDouble, *abiType);
case SymbolicAddress::Uint64ToFloat32:
*abiType = Args_Float32_IntInt;
return FuncCast(Uint64ToFloat32, *abiType);
case SymbolicAddress::Int64ToDouble:
*abiType = Args_Double_IntInt;
return FuncCast(Int64ToDouble, *abiType);
case SymbolicAddress::Int64ToFloat32:
*abiType = Args_Float32_IntInt;
return FuncCast(Int64ToFloat32, *abiType);
#if defined(JS_CODEGEN_ARM)
case SymbolicAddress::aeabi_idivmod:
*abiType = Args_General2;
return FuncCast(__aeabi_idivmod, *abiType);
case SymbolicAddress::aeabi_uidivmod:
*abiType = Args_General2;
return FuncCast(__aeabi_uidivmod, *abiType);
case SymbolicAddress::AtomicCmpXchg:
*abiType = Args_General5;
return FuncCast(atomics_cmpxchg_asm_callout, *abiType);
case SymbolicAddress::AtomicXchg:
*abiType = Args_General4;
return FuncCast(atomics_xchg_asm_callout, *abiType);
case SymbolicAddress::AtomicFetchAdd:
*abiType = Args_General4;
return FuncCast(atomics_add_asm_callout, *abiType);
case SymbolicAddress::AtomicFetchSub:
*abiType = Args_General4;
return FuncCast(atomics_sub_asm_callout, *abiType);
case SymbolicAddress::AtomicFetchAnd:
*abiType = Args_General4;
return FuncCast(atomics_and_asm_callout, *abiType);
case SymbolicAddress::AtomicFetchOr:
*abiType = Args_General4;
return FuncCast(atomics_or_asm_callout, *abiType);
case SymbolicAddress::AtomicFetchXor:
*abiType = Args_General4;
return FuncCast(atomics_xor_asm_callout, *abiType);
#endif
case SymbolicAddress::ModD:
*abiType = Args_Double_DoubleDouble;
return FuncCast(NumberMod, *abiType);
case SymbolicAddress::SinD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(sin, *abiType);
case SymbolicAddress::CosD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(cos, *abiType);
case SymbolicAddress::TanD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(tan, *abiType);
case SymbolicAddress::ASinD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::asin, *abiType);
case SymbolicAddress::ACosD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::acos, *abiType);
case SymbolicAddress::ATanD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::atan, *abiType);
case SymbolicAddress::CeilD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::ceil, *abiType);
case SymbolicAddress::CeilF:
*abiType = Args_Float32_Float32;
return FuncCast<float (float)>(fdlibm::ceilf, *abiType);
case SymbolicAddress::FloorD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::floor, *abiType);
case SymbolicAddress::FloorF:
*abiType = Args_Float32_Float32;
return FuncCast<float (float)>(fdlibm::floorf, *abiType);
case SymbolicAddress::TruncD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::trunc, *abiType);
case SymbolicAddress::TruncF:
*abiType = Args_Float32_Float32;
return FuncCast<float (float)>(fdlibm::truncf, *abiType);
case SymbolicAddress::NearbyIntD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::nearbyint, *abiType);
case SymbolicAddress::NearbyIntF:
*abiType = Args_Float32_Float32;
return FuncCast<float (float)>(fdlibm::nearbyintf, *abiType);
case SymbolicAddress::ExpD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::exp, *abiType);
case SymbolicAddress::LogD:
*abiType = Args_Double_Double;
return FuncCast<double (double)>(fdlibm::log, *abiType);
case SymbolicAddress::PowD:
*abiType = Args_Double_DoubleDouble;
return FuncCast(ecmaPow, *abiType);
case SymbolicAddress::ATan2D:
*abiType = Args_Double_DoubleDouble;
return FuncCast(ecmaAtan2, *abiType);
case SymbolicAddress::GrowMemory:
*abiType = Args_General2;
return FuncCast(Instance::growMemory_i32, *abiType);
case SymbolicAddress::CurrentMemory:
*abiType = Args_General1;
return FuncCast(Instance::currentMemory_i32, *abiType);
case SymbolicAddress::Limit:
break;
}
MOZ_CRASH("Bad SymbolicAddress");
}
static bool
GenerateBuiltinThunk(JSContext* cx, void* func, ABIFunctionType abiType, UniqueBuiltinThunk* thunk)
{
if (!cx->compartment()->ensureJitCompartmentExists(cx))
return false;
LifoAlloc lifo(BUILTIN_THUNK_LIFO_SIZE);
TempAllocator tempAlloc(&lifo);
MacroAssembler masm(MacroAssembler::WasmToken(), tempAlloc);
CallableOffsets offsets = GenerateBuiltinImportExit(masm, abiType, func);
masm.finish();
if (masm.oom())
return false;
// The executable allocator operates on pointer-aligned sizes.
uint32_t codeLength = AlignBytes(masm.bytesNeeded(), sizeof(void*));
ExecutablePool* pool = nullptr;
ExecutableAllocator& allocator = cx->runtime()->jitRuntime()->execAlloc();
uint8_t* codeBase = (uint8_t*) allocator.alloc(cx, codeLength, &pool, BUILTIN_THUNK_CODEKIND);
if (!codeBase)
return false;
{
AutoWritableJitCode awjc(cx->runtime(), codeBase, codeLength);
AutoFlushICache afc("GenerateBuiltinThunk");
masm.executableCopy(codeBase);
memset(codeBase + masm.bytesNeeded(), 0, codeLength - masm.bytesNeeded());
MOZ_ASSERT(!masm.numSymbolicAccesses(), "doesn't need any patching");
}
*thunk = js::MakeUnique<BuiltinThunk>(codeBase, codeLength, pool, offsets);
return !!*thunk;
}
struct BuiltinMatcher
{
const uint8_t* address;
explicit BuiltinMatcher(const uint8_t* address) : address(address) {}
int operator()(const UniqueBuiltinThunk& thunk) const {
if (address < thunk->base)
return -1;
if (uintptr_t(address) >= uintptr_t(thunk->base) + thunk->size)
return 1;
return 0;
}
};
bool
wasm::Runtime::getBuiltinThunk(JSContext* cx, void* funcPtr, ABIFunctionType abiType,
void** thunkPtr)
{
TypedFuncPtr lookup(funcPtr, abiType);
auto ptr = builtinThunkMap_.lookupForAdd(lookup);
if (ptr) {
*thunkPtr = ptr->value();
return true;
}
UniqueBuiltinThunk thunk;
if (!GenerateBuiltinThunk(cx, funcPtr, abiType, &thunk))
return false;
// Maintain sorted order of thunk addresses.
size_t i;
size_t size = builtinThunkVector_.length();
if (BinarySearchIf(builtinThunkVector_, 0, size, BuiltinMatcher(thunk->base), &i))
MOZ_CRASH("clobbering memory");
*thunkPtr = thunk->base;
return builtinThunkVector_.insert(builtinThunkVector_.begin() + i, Move(thunk)) &&
builtinThunkMap_.add(ptr, lookup, *thunkPtr);
}
static ABIFunctionType
ToABIFunctionType(const Sig& sig)
{
const ValTypeVector& args = sig.args();
ExprType ret = sig.ret();
uint32_t abiType;
switch (ret) {
case ExprType::F32: abiType = ArgType_Float32 << RetType_Shift; break;
case ExprType::F64: abiType = ArgType_Double << RetType_Shift; break;
default: MOZ_CRASH("unhandled ret type");
}
for (size_t i = 0; i < args.length(); i++) {
switch (args[i]) {
case ValType::F32: abiType |= (ArgType_Float32 << (ArgType_Shift * (i + 1))); break;
case ValType::F64: abiType |= (ArgType_Double << (ArgType_Shift * (i + 1))); break;
default: MOZ_CRASH("unhandled arg type");
}
}
return ABIFunctionType(abiType);
}
bool
wasm::Runtime::getBuiltinThunk(JSContext* cx, void* funcPtr, const Sig& sig, void** thunkPtr)
{
ABIFunctionType abiType = ToABIFunctionType(sig);
#ifdef JS_SIMULATOR
funcPtr = Simulator::RedirectNativeFunction(funcPtr, abiType);
#endif
return getBuiltinThunk(cx, funcPtr, abiType, thunkPtr);
}
BuiltinThunk*
wasm::Runtime::lookupBuiltin(void* pc)
{
size_t index;
size_t length = builtinThunkVector_.length();
if (!BinarySearchIf(builtinThunkVector_, 0, length, BuiltinMatcher((uint8_t*)pc), &index))
return nullptr;
return builtinThunkVector_[index].get();
}
void
wasm::Runtime::destroy()
{
builtinThunkVector_.clear();
if (builtinThunkMap_.initialized())
builtinThunkMap_.clear();
}
BuiltinThunk::~BuiltinThunk()
{
executablePool->release(size, BUILTIN_THUNK_CODEKIND);
}

102
js/src/wasm/WasmRuntime.h Normal file
Просмотреть файл

@ -0,0 +1,102 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2017 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_runtime_h
#define wasm_runtime_h
#include "NamespaceImports.h"
#include "jit/IonTypes.h"
#include "wasm/WasmTypes.h"
using mozilla::HashGeneric;
namespace js {
namespace jit {
class ExecutablePool;
}
namespace wasm {
void*
AddressOf(SymbolicAddress imm, jit::ABIFunctionType*);
struct TypedFuncPtr
{
void* funcPtr;
jit::ABIFunctionType abiType;
TypedFuncPtr(void* funcPtr, jit::ABIFunctionType abiType)
: funcPtr(funcPtr),
abiType(abiType)
{}
typedef TypedFuncPtr Lookup;
static HashNumber hash(const Lookup& l) {
return HashGeneric(l.funcPtr, uint32_t(l.abiType));
}
static bool match(const TypedFuncPtr& lhs, const Lookup& rhs) {
return lhs.funcPtr == rhs.funcPtr && lhs.abiType == rhs.abiType;
}
};
typedef HashMap<TypedFuncPtr, void*, TypedFuncPtr, SystemAllocPolicy> BuiltinThunkMap;
struct BuiltinThunk
{
jit::ExecutablePool* executablePool;
CodeRange codeRange;
size_t size;
uint8_t* base;
BuiltinThunk(uint8_t* base, size_t size, jit::ExecutablePool* executablePool,
CallableOffsets offsets)
: executablePool(executablePool),
codeRange(CodeRange(CodeRange::ImportNativeExit, offsets)),
size(size),
base(base)
{}
~BuiltinThunk();
};
typedef UniquePtr<BuiltinThunk> UniqueBuiltinThunk;
typedef Vector<UniqueBuiltinThunk, 4, SystemAllocPolicy> BuiltinThunkVector;
// wasm::Runtime contains all the needed information for wasm that has the
// lifetime of a JSRuntime.
class Runtime
{
BuiltinThunkMap builtinThunkMap_;
BuiltinThunkVector builtinThunkVector_;
bool getBuiltinThunk(JSContext* cx, void* funcPtr, jit::ABIFunctionType type, void** thunkPtr);
public:
bool init() { return builtinThunkMap_.init(); }
void destroy();
bool getBuiltinThunk(JSContext* cx, void* funcPtr, const Sig& sig, void** thunkPtr);
BuiltinThunk* lookupBuiltin(void* pc);
};
} // namespace wasm
} // namespace js
#endif // wasm_runtime_h

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

@ -108,7 +108,7 @@ class AutoSetHandlingSegFault
# define R13_sig(p) ((p)->sc_r13)
# define R14_sig(p) ((p)->sc_r14)
# define R15_sig(p) ((p)->sc_r15)
#elif defined(__linux__) || defined(SOLARIS)
#elif defined(__linux__) || defined(__sun)
# if defined(__linux__)
# define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i])
# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP])
@ -1530,5 +1530,6 @@ js::wasm::IsPCInWasmCode(void *pc)
if (!activation)
return false;
return !!activation->compartment()->wasm.lookupCode(pc);
return !!activation->compartment()->wasm.lookupCode(pc) ||
!!activation->cx()->runtime()->wasm().lookupBuiltin(pc);
}

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

@ -31,6 +31,15 @@ using namespace js::wasm;
using mozilla::ArrayLength;
static void
FinishOffsets(MacroAssembler& masm, Offsets* offsets)
{
// On old ARM hardware, constant pools could be inserted and they need to
// be flushed before considering the size of the masm.
masm.flushBuffer();
offsets->end = masm.size();
}
static void
AssertStackAlignment(MacroAssembler& masm, uint32_t alignment, uint32_t addBeforeAssert = 0)
{
@ -331,7 +340,7 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe)
masm.move32(Imm32(true), ReturnReg);
masm.ret();
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -498,7 +507,7 @@ wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, Si
masm.wasmEmitTrapOutOfLineCode();
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -625,7 +634,7 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3
GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, &offsets);
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -858,6 +867,94 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
MOZ_ASSERT(masm.framePushed() == 0);
FinishOffsets(masm, &offsets);
return offsets;
}
struct ABIFunctionArgs
{
ABIFunctionType abiType;
size_t len;
explicit ABIFunctionArgs(ABIFunctionType sig)
: abiType(ABIFunctionType(sig >> ArgType_Shift))
{
len = 0;
uint32_t i = uint32_t(abiType);
while (i) {
i = i >> ArgType_Shift;
len++;
}
}
size_t length() const { return len; }
MIRType operator[](size_t i) const {
MOZ_ASSERT(i < len);
uint32_t abi = uint32_t(abiType);
while (i--)
abi = abi >> ArgType_Shift;
return ToMIRType(ABIArgType(abi));
}
};
CallableOffsets
wasm::GenerateBuiltinImportExit(MacroAssembler& masm, ABIFunctionType abiType, void* func)
{
masm.setFramePushed(0);
ABIFunctionArgs args(abiType);
uint32_t framePushed = StackDecrementForCall(masm, ABIStackAlignment, args);
CallableOffsets offsets;
GenerateExitPrologue(masm, framePushed, ExitReason::ImportNative, &offsets);
// Copy out and convert caller arguments, if needed.
unsigned offsetToCallerStackArgs = sizeof(Frame) + masm.framePushed();
Register scratch = ABINonArgReturnReg0;
for (ABIArgIter<ABIFunctionArgs> i(args); !i.done(); i++) {
if (i->argInRegister()) {
#ifdef JS_CODEGEN_ARM
// Non hard-fp passes the args values in GPRs.
if (!UseHardFpABI() && IsFloatingPointType(i.mirType())) {
FloatRegister input = i->fpu();
if (i.mirType() == MIRType::Float32) {
masm.ma_vxfer(input, Register::FromCode(input.id()));
} else if (i.mirType() == MIRType::Double) {
uint32_t regId = input.singleOverlay().id();
masm.ma_vxfer(input, Register::FromCode(regId), Register::FromCode(regId + 1));
}
}
#endif
continue;
}
Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
Address dst(masm.getStackPointer(), i->offsetFromArgBase());
StackCopy(masm, i.mirType(), scratch, src, dst);
}
masm.call(ImmPtr(func, ImmPtr::NoCheckToken()));
#if defined(JS_CODEGEN_X86)
// x86 passes the return value on the x87 FP stack.
Operand op(esp, 0);
MIRType retType = ToMIRType(ABIArgType(abiType & ArgType_Mask));
if (retType == MIRType::Float32) {
masm.fstp32(op);
masm.loadFloat32(op, ReturnFloat32Reg);
} else if (retType == MIRType::Double) {
masm.fstp(op);
masm.loadDouble(op, ReturnDoubleReg);
}
#elif defined(JS_CODEGEN_ARM)
// Non hard-fp passes the return values in GPRs.
MIRType retType = ToMIRType(ABIArgType(abiType & ArgType_Mask));
if (!UseHardFpABI() && IsFloatingPointType(retType))
masm.ma_vxfer(r0, r1, d0);
#endif
GenerateExitEpilogue(masm, framePushed, ExitReason::ImportNative, &offsets);
offsets.end = masm.currentOffset();
return offsets;
}
@ -896,7 +993,7 @@ wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel)
GenerateExitEpilogue(masm, framePushed, ExitReason::Trap, &offsets);
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -926,7 +1023,7 @@ GenerateGenericMemoryAccessTrap(MacroAssembler& masm, SymbolicAddress reporter,
masm.call(reporter);
masm.jump(throwLabel);
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -1109,7 +1206,7 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
# error "Unknown architecture!"
#endif
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -1147,7 +1244,7 @@ wasm::GenerateThrowStub(MacroAssembler& masm, Label* throwLabel)
masm.mov(ImmWord(0), ReturnReg);
masm.ret();
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}
@ -1198,6 +1295,6 @@ wasm::GenerateDebugTrapStub(MacroAssembler& masm, Label* throwLabel)
GenerateExitEpilogue(masm, 0, ExitReason::DebugTrap, &offsets);
offsets.end = masm.currentOffset();
FinishOffsets(masm, &offsets);
return offsets;
}

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

@ -23,7 +23,11 @@
namespace js {
namespace jit { class MacroAssembler; class Label; }
namespace jit {
class MacroAssembler;
class Label;
enum ABIFunctionType;
}
namespace wasm {
@ -43,6 +47,9 @@ GenerateImportInterpExit(jit::MacroAssembler& masm, const FuncImport& fi, uint32
extern CallableOffsets
GenerateImportJitExit(jit::MacroAssembler& masm, const FuncImport& fi, jit::Label* throwLabel);
extern CallableOffsets
GenerateBuiltinImportExit(jit::MacroAssembler& masm, jit::ABIFunctionType abiType, void* func);
extern CallableOffsets
GenerateTrapExit(jit::MacroAssembler& masm, Trap trap, jit::Label* throwLabel);

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

@ -18,29 +18,16 @@
#include "wasm/WasmTypes.h"
#include "mozilla/MathAlgorithms.h"
#include "fdlibm.h"
#include "jslibmath.h"
#include "jsmath.h"
#include "jit/MacroAssembler.h"
#include "js/Conversions.h"
#include "vm/Interpreter.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmInstance.h"
#include "wasm/WasmSerialize.h"
#include "wasm/WasmSignalHandlers.h"
#include "vm/Debugger-inl.h"
#include "vm/Stack-inl.h"
#include "jsobjinlines.h"
using namespace js;
using namespace js::jit;
using namespace js::wasm;
using mozilla::IsNaN;
using mozilla::IsPowerOfTwo;
void
@ -67,346 +54,6 @@ Val::writePayload(uint8_t* dst) const
}
}
#if defined(JS_CODEGEN_ARM)
extern "C" {
extern MOZ_EXPORT int64_t
__aeabi_idivmod(int, int);
extern MOZ_EXPORT int64_t
__aeabi_uidivmod(int, int);
}
#endif
static void*
WasmHandleExecutionInterrupt()
{
WasmActivation* activation = JSContext::innermostWasmActivation();
// wasm::Compartment requires notification when execution is interrupted in
// the compartment. Only the innermost compartment has been interrupted;
// enclosing compartments necessarily exited through an exit stub.
activation->compartment()->wasm.setInterrupted(true);
bool success = CheckForInterrupt(activation->cx());
activation->compartment()->wasm.setInterrupted(false);
// Preserve the invariant that having a non-null resumePC means that we are
// handling an interrupt.
void* resumePC = activation->resumePC();
activation->setResumePC(nullptr);
// Return the resumePC if execution can continue or null if execution should
// jump to the throw stub.
return success ? resumePC : nullptr;
}
static bool
WasmHandleDebugTrap()
{
WasmActivation* activation = JSContext::innermostWasmActivation();
MOZ_ASSERT(activation);
JSContext* cx = activation->cx();
FrameIterator iter(activation);
MOZ_ASSERT(iter.debugEnabled());
const CallSite* site = iter.debugTrapCallsite();
MOZ_ASSERT(site);
if (site->kind() == CallSite::EnterFrame) {
if (!iter.instance()->enterFrameTrapsEnabled())
return true;
DebugFrame* frame = iter.debugFrame();
frame->setIsDebuggee();
frame->observe(cx);
// TODO call onEnterFrame
JSTrapStatus status = Debugger::onEnterFrame(cx, frame);
if (status == JSTRAP_RETURN) {
// Ignoring forced return (JSTRAP_RETURN) -- changing code execution
// order is not yet implemented in the wasm baseline.
// TODO properly handle JSTRAP_RETURN and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onEnterFrame");
return false;
}
return status == JSTRAP_CONTINUE;
}
if (site->kind() == CallSite::LeaveFrame) {
DebugFrame* frame = iter.debugFrame();
frame->updateReturnJSValue();
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
frame->leave(cx);
return ok;
}
DebugFrame* frame = iter.debugFrame();
Code& code = iter.instance()->code();
MOZ_ASSERT(code.hasBreakpointTrapAtOffset(site->lineOrBytecode()));
if (code.stepModeEnabled(frame->funcIndex())) {
RootedValue result(cx, UndefinedValue());
JSTrapStatus status = Debugger::onSingleStep(cx, &result);
if (status == JSTRAP_RETURN) {
// TODO properly handle JSTRAP_RETURN.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onSingleStep");
return false;
}
if (status != JSTRAP_CONTINUE)
return false;
}
if (code.hasBreakpointSite(site->lineOrBytecode())) {
RootedValue result(cx, UndefinedValue());
JSTrapStatus status = Debugger::onTrap(cx, &result);
if (status == JSTRAP_RETURN) {
// TODO properly handle JSTRAP_RETURN.
JS_ReportErrorASCII(cx, "Unexpected resumption value from breakpoint handler");
return false;
}
if (status != JSTRAP_CONTINUE)
return false;
}
return true;
}
static WasmActivation*
WasmHandleThrow()
{
JSContext* cx = TlsContext.get();
WasmActivation* activation = cx->wasmActivationStack();
MOZ_ASSERT(activation);
// FrameIterator iterates down wasm frames in the activation starting at
// WasmActivation::exitFP. Pass Unwind::True to pop WasmActivation::exitFP
// once each time FrameIterator is incremented, ultimately leaving exitFP
// null when the FrameIterator is done(). This is necessary to prevent a
// DebugFrame from being observed again after we just called onLeaveFrame
// (which would lead to the frame being re-added to the map of live frames,
// right as it becomes trash).
FrameIterator iter(activation, FrameIterator::Unwind::True);
if (iter.done())
return activation;
// Live wasm code on the stack is kept alive (in wasm::TraceActivations) by
// marking the instance of every wasm::Frame found by FrameIterator.
// However, as explained above, we're popping frames while iterating which
// means that a GC during this loop could collect the code of frames whose
// code is still on the stack. This is actually mostly fine: as soon as we
// return to the throw stub, the entire stack will be popped as a whole,
// returning to the C++ caller. However, we must keep the throw stub alive
// itself which is owned by the innermost instance.
RootedWasmInstanceObject keepAlive(cx, iter.instance()->object());
for (; !iter.done(); ++iter) {
if (!iter.debugEnabled())
continue;
DebugFrame* frame = iter.debugFrame();
frame->clearReturnJSValue();
// Assume JSTRAP_ERROR status if no exception is pending --
// no onExceptionUnwind handlers must be fired.
if (cx->isExceptionPending()) {
JSTrapStatus status = Debugger::onExceptionUnwind(cx, frame);
if (status == JSTRAP_RETURN) {
// Unexpected trap return -- raising error since throw recovery
// is not yet implemented in the wasm baseline.
// TODO properly handle JSTRAP_RETURN and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onExceptionUnwind");
}
}
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, false);
if (ok) {
// Unexpected success from the handler onLeaveFrame -- raising error
// since throw recovery is not yet implemented in the wasm baseline.
// TODO properly handle success and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected success from onLeaveFrame");
}
frame->leave(cx);
}
return activation;
}
static void
WasmReportTrap(int32_t trapIndex)
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0);
Trap trap = Trap(trapIndex);
unsigned errorNumber;
switch (trap) {
case Trap::Unreachable:
errorNumber = JSMSG_WASM_UNREACHABLE;
break;
case Trap::IntegerOverflow:
errorNumber = JSMSG_WASM_INTEGER_OVERFLOW;
break;
case Trap::InvalidConversionToInteger:
errorNumber = JSMSG_WASM_INVALID_CONVERSION;
break;
case Trap::IntegerDivideByZero:
errorNumber = JSMSG_WASM_INT_DIVIDE_BY_ZERO;
break;
case Trap::IndirectCallToNull:
errorNumber = JSMSG_WASM_IND_CALL_TO_NULL;
break;
case Trap::IndirectCallBadSig:
errorNumber = JSMSG_WASM_IND_CALL_BAD_SIG;
break;
case Trap::ImpreciseSimdConversion:
errorNumber = JSMSG_SIMD_FAILED_CONVERSION;
break;
case Trap::OutOfBounds:
errorNumber = JSMSG_WASM_OUT_OF_BOUNDS;
break;
case Trap::StackOverflow:
errorNumber = JSMSG_OVER_RECURSED;
break;
default:
MOZ_CRASH("unexpected trap");
}
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber);
}
static void
WasmReportOutOfBounds()
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS);
}
static void
WasmReportUnalignedAccess()
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_UNALIGNED_ACCESS);
}
static int32_t
CoerceInPlace_ToInt32(MutableHandleValue val)
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
int32_t i32;
if (!ToInt32(cx, val, &i32))
return false;
val.set(Int32Value(i32));
return true;
}
static int32_t
CoerceInPlace_ToNumber(MutableHandleValue val)
{
JSContext* cx = JSContext::innermostWasmActivation()->cx();
double dbl;
if (!ToNumber(cx, val, &dbl))
return false;
val.set(DoubleValue(dbl));
return true;
}
static int64_t
DivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
int64_t x = ((uint64_t)x_hi << 32) + x_lo;
int64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(x != INT64_MIN || y != -1);
MOZ_ASSERT(y != 0);
return x / y;
}
static int64_t
UDivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
uint64_t x = ((uint64_t)x_hi << 32) + x_lo;
uint64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(y != 0);
return x / y;
}
static int64_t
ModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
int64_t x = ((uint64_t)x_hi << 32) + x_lo;
int64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(x != INT64_MIN || y != -1);
MOZ_ASSERT(y != 0);
return x % y;
}
static int64_t
UModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
{
uint64_t x = ((uint64_t)x_hi << 32) + x_lo;
uint64_t y = ((uint64_t)y_hi << 32) + y_lo;
MOZ_ASSERT(y != 0);
return x % y;
}
static int64_t
TruncateDoubleToInt64(double input)
{
// Note: INT64_MAX is not representable in double. It is actually
// INT64_MAX + 1. Therefore also sending the failure value.
if (input >= double(INT64_MAX) || input < double(INT64_MIN) || IsNaN(input))
return 0x8000000000000000;
return int64_t(input);
}
static uint64_t
TruncateDoubleToUint64(double input)
{
// Note: UINT64_MAX is not representable in double. It is actually UINT64_MAX + 1.
// Therefore also sending the failure value.
if (input >= double(UINT64_MAX) || input <= -1.0 || IsNaN(input))
return 0x8000000000000000;
return uint64_t(input);
}
static double
Int64ToDouble(int32_t x_hi, uint32_t x_lo)
{
int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
return double(x);
}
static float
Int64ToFloat32(int32_t x_hi, uint32_t x_lo)
{
int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
return float(x);
}
static double
Uint64ToDouble(int32_t x_hi, uint32_t x_lo)
{
uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
return double(x);
}
static float
Uint64ToFloat32(int32_t x_hi, uint32_t x_lo)
{
uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
return float(x);
}
template <class F>
static inline void*
FuncCast(F* pf, ABIFunctionType type)
{
void *pv = JS_FUNC_TO_DATA_PTR(void*, pf);
#ifdef JS_SIMULATOR
pv = Simulator::RedirectNativeFunction(pv, type);
#endif
return pv;
}
bool
wasm::IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode)
{
@ -432,125 +79,6 @@ wasm::IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode)
}
}
void*
wasm::AddressOf(SymbolicAddress imm)
{
switch (imm) {
case SymbolicAddress::HandleExecutionInterrupt:
return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
case SymbolicAddress::HandleDebugTrap:
return FuncCast(WasmHandleDebugTrap, Args_General0);
case SymbolicAddress::HandleThrow:
return FuncCast(WasmHandleThrow, Args_General0);
case SymbolicAddress::ReportTrap:
return FuncCast(WasmReportTrap, Args_General1);
case SymbolicAddress::ReportOutOfBounds:
return FuncCast(WasmReportOutOfBounds, Args_General0);
case SymbolicAddress::ReportUnalignedAccess:
return FuncCast(WasmReportUnalignedAccess, Args_General0);
case SymbolicAddress::CallImport_Void:
return FuncCast(Instance::callImport_void, Args_General4);
case SymbolicAddress::CallImport_I32:
return FuncCast(Instance::callImport_i32, Args_General4);
case SymbolicAddress::CallImport_I64:
return FuncCast(Instance::callImport_i64, Args_General4);
case SymbolicAddress::CallImport_F64:
return FuncCast(Instance::callImport_f64, Args_General4);
case SymbolicAddress::CoerceInPlace_ToInt32:
return FuncCast(CoerceInPlace_ToInt32, Args_General1);
case SymbolicAddress::CoerceInPlace_ToNumber:
return FuncCast(CoerceInPlace_ToNumber, Args_General1);
case SymbolicAddress::ToInt32:
return FuncCast<int32_t (double)>(JS::ToInt32, Args_Int_Double);
case SymbolicAddress::DivI64:
return FuncCast(DivI64, Args_General4);
case SymbolicAddress::UDivI64:
return FuncCast(UDivI64, Args_General4);
case SymbolicAddress::ModI64:
return FuncCast(ModI64, Args_General4);
case SymbolicAddress::UModI64:
return FuncCast(UModI64, Args_General4);
case SymbolicAddress::TruncateDoubleToUint64:
return FuncCast(TruncateDoubleToUint64, Args_Int64_Double);
case SymbolicAddress::TruncateDoubleToInt64:
return FuncCast(TruncateDoubleToInt64, Args_Int64_Double);
case SymbolicAddress::Uint64ToDouble:
return FuncCast(Uint64ToDouble, Args_Double_IntInt);
case SymbolicAddress::Uint64ToFloat32:
return FuncCast(Uint64ToFloat32, Args_Float32_IntInt);
case SymbolicAddress::Int64ToDouble:
return FuncCast(Int64ToDouble, Args_Double_IntInt);
case SymbolicAddress::Int64ToFloat32:
return FuncCast(Int64ToFloat32, Args_Float32_IntInt);
#if defined(JS_CODEGEN_ARM)
case SymbolicAddress::aeabi_idivmod:
return FuncCast(__aeabi_idivmod, Args_General2);
case SymbolicAddress::aeabi_uidivmod:
return FuncCast(__aeabi_uidivmod, Args_General2);
case SymbolicAddress::AtomicCmpXchg:
return FuncCast(atomics_cmpxchg_asm_callout, Args_General5);
case SymbolicAddress::AtomicXchg:
return FuncCast(atomics_xchg_asm_callout, Args_General4);
case SymbolicAddress::AtomicFetchAdd:
return FuncCast(atomics_add_asm_callout, Args_General4);
case SymbolicAddress::AtomicFetchSub:
return FuncCast(atomics_sub_asm_callout, Args_General4);
case SymbolicAddress::AtomicFetchAnd:
return FuncCast(atomics_and_asm_callout, Args_General4);
case SymbolicAddress::AtomicFetchOr:
return FuncCast(atomics_or_asm_callout, Args_General4);
case SymbolicAddress::AtomicFetchXor:
return FuncCast(atomics_xor_asm_callout, Args_General4);
#endif
case SymbolicAddress::ModD:
return FuncCast(NumberMod, Args_Double_DoubleDouble);
case SymbolicAddress::SinD:
return FuncCast<double (double)>(sin, Args_Double_Double);
case SymbolicAddress::CosD:
return FuncCast<double (double)>(cos, Args_Double_Double);
case SymbolicAddress::TanD:
return FuncCast<double (double)>(tan, Args_Double_Double);
case SymbolicAddress::ASinD:
return FuncCast<double (double)>(fdlibm::asin, Args_Double_Double);
case SymbolicAddress::ACosD:
return FuncCast<double (double)>(fdlibm::acos, Args_Double_Double);
case SymbolicAddress::ATanD:
return FuncCast<double (double)>(fdlibm::atan, Args_Double_Double);
case SymbolicAddress::CeilD:
return FuncCast<double (double)>(fdlibm::ceil, Args_Double_Double);
case SymbolicAddress::CeilF:
return FuncCast<float (float)>(fdlibm::ceilf, Args_Float32_Float32);
case SymbolicAddress::FloorD:
return FuncCast<double (double)>(fdlibm::floor, Args_Double_Double);
case SymbolicAddress::FloorF:
return FuncCast<float (float)>(fdlibm::floorf, Args_Float32_Float32);
case SymbolicAddress::TruncD:
return FuncCast<double (double)>(fdlibm::trunc, Args_Double_Double);
case SymbolicAddress::TruncF:
return FuncCast<float (float)>(fdlibm::truncf, Args_Float32_Float32);
case SymbolicAddress::NearbyIntD:
return FuncCast<double (double)>(fdlibm::nearbyint, Args_Double_Double);
case SymbolicAddress::NearbyIntF:
return FuncCast<float (float)>(fdlibm::nearbyintf, Args_Float32_Float32);
case SymbolicAddress::ExpD:
return FuncCast<double (double)>(fdlibm::exp, Args_Double_Double);
case SymbolicAddress::LogD:
return FuncCast<double (double)>(fdlibm::log, Args_Double_Double);
case SymbolicAddress::PowD:
return FuncCast(ecmaPow, Args_Double_DoubleDouble);
case SymbolicAddress::ATan2D:
return FuncCast(ecmaAtan2, Args_Double_DoubleDouble);
case SymbolicAddress::GrowMemory:
return FuncCast<uint32_t (Instance*, uint32_t)>(Instance::growMemory_i32, Args_General2);
case SymbolicAddress::CurrentMemory:
return FuncCast<uint32_t (Instance*)>(Instance::currentMemory_i32, Args_General1);
case SymbolicAddress::Limit:
break;
}
MOZ_CRASH("Bad SymbolicAddress");
}
static uint32_t
GetCPUID()
{
@ -1139,3 +667,76 @@ DebugFrame::leave(JSContext* cx)
observing_ = false;
}
}
CodeRange::CodeRange(Kind kind, Offsets offsets)
: begin_(offsets.begin),
ret_(0),
end_(offsets.end),
funcIndex_(0),
funcLineOrBytecode_(0),
funcBeginToNormalEntry_(0),
kind_(kind)
{
MOZ_ASSERT(begin_ <= end_);
#ifdef DEBUG
switch (kind_) {
case Entry:
case DebugTrap:
case FarJumpIsland:
case Inline:
case Throw:
case Interrupt:
break;
case Function:
case TrapExit:
case ImportJitExit:
case ImportNativeExit:
case ImportInterpExit:
MOZ_CRASH("should use more specific constructor");
}
#endif
}
CodeRange::CodeRange(Kind kind, CallableOffsets offsets)
: begin_(offsets.begin),
ret_(offsets.ret),
end_(offsets.end),
funcIndex_(0),
funcLineOrBytecode_(0),
funcBeginToNormalEntry_(0),
kind_(kind)
{
MOZ_ASSERT(begin_ < ret_);
MOZ_ASSERT(ret_ < end_);
#ifdef DEBUG
switch (kind_) {
case TrapExit:
case ImportJitExit:
case ImportNativeExit:
case ImportInterpExit:
break;
case Entry:
case DebugTrap:
case FarJumpIsland:
case Inline:
case Throw:
case Interrupt:
case Function:
MOZ_CRASH("should use more specific constructor");
}
#endif
}
CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets)
: begin_(offsets.begin),
ret_(offsets.ret),
end_(offsets.end),
funcIndex_(funcIndex),
funcLineOrBytecode_(funcLineOrBytecode),
funcBeginToNormalEntry_(offsets.normalEntry - begin_),
kind_(Function)
{
MOZ_ASSERT(begin_ < ret_);
MOZ_ASSERT(ret_ < end_);
MOZ_ASSERT(offsets.normalEntry - begin_ <= UINT8_MAX);
}

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

@ -97,7 +97,6 @@ typedef int32_t I32x4[4];
typedef float F32x4[4];
class Code;
class CodeRange;
class GlobalSegment;
class Memory;
class Module;
@ -820,6 +819,120 @@ struct FuncOffsets : CallableOffsets
}
};
// A CodeRange describes a single contiguous range of code within a wasm
// module's code segment. A CodeRange describes what the code does and, for
// function bodies, the name and source coordinates of the function.
class CodeRange
{
public:
enum Kind {
Function, // function definition
Entry, // calls into wasm from C++
ImportJitExit, // fast-path calling from wasm into JIT code
ImportInterpExit, // slow-path calling from wasm into C++ interp
ImportNativeExit, // fast-path calling from wasm into a C++ native
TrapExit, // calls C++ to report and jumps to throw stub
DebugTrap, // calls C++ to handle debug event
FarJumpIsland, // inserted to connect otherwise out-of-range insns
Inline, // stub that is jumped-to within prologue/epilogue
Throw, // special stack-unwinding stub
Interrupt // stub executes asynchronously to interrupt wasm
};
private:
// All fields are treated as cacheable POD:
uint32_t begin_;
uint32_t ret_;
uint32_t end_;
uint32_t funcIndex_;
uint32_t funcLineOrBytecode_;
uint8_t funcBeginToNormalEntry_;
Kind kind_ : 8;
public:
CodeRange() = default;
CodeRange(Kind kind, Offsets offsets);
CodeRange(Kind kind, CallableOffsets offsets);
CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets);
// All CodeRanges have a begin and end.
uint32_t begin() const {
return begin_;
}
uint32_t end() const {
return end_;
}
// Other fields are only available for certain CodeRange::Kinds.
Kind kind() const {
return kind_;
}
bool isFunction() const {
return kind() == Function;
}
bool isImportExit() const {
return kind() == ImportJitExit || kind() == ImportInterpExit || kind() == ImportNativeExit;
}
bool isTrapExit() const {
return kind() == TrapExit;
}
bool isInline() const {
return kind() == Inline;
}
bool isThunk() const {
return kind() == FarJumpIsland;
}
// Every CodeRange except entry and inline stubs are callable and have a
// return statement. Asynchronous frame iteration needs to know the offset
// of the return instruction to calculate the frame pointer.
uint32_t ret() const {
MOZ_ASSERT(isFunction() || isImportExit() || isTrapExit());
return ret_;
}
// Function CodeRanges have two entry points: one for normal calls (with a
// known signature) and one for table calls (which involves dynamic
// signature checking).
uint32_t funcTableEntry() const {
MOZ_ASSERT(isFunction());
return begin_;
}
uint32_t funcNormalEntry() const {
MOZ_ASSERT(isFunction());
return begin_ + funcBeginToNormalEntry_;
}
uint32_t funcIndex() const {
MOZ_ASSERT(isFunction());
return funcIndex_;
}
uint32_t funcLineOrBytecode() const {
MOZ_ASSERT(isFunction());
return funcLineOrBytecode_;
}
// A sorted array of CodeRanges can be looked up via BinarySearch and PC.
struct PC {
size_t offset;
explicit PC(size_t offset) : offset(offset) {}
bool operator==(const CodeRange& rhs) const {
return offset >= rhs.begin() && offset < rhs.end();
}
bool operator<(const CodeRange& rhs) const {
return offset < rhs.begin();
}
};
};
WASM_DECLARE_POD_VECTOR(CodeRange, CodeRangeVector)
// A wasm::Trap represents a wasm-defined trap that can occur during execution
// which triggers a WebAssembly.RuntimeError. Generated code may jump to a Trap
// symbolically, passing the bytecode offset to report as the trap offset. The
@ -1019,9 +1132,6 @@ enum class SymbolicAddress
bool
IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode);
void*
AddressOf(SymbolicAddress imm);
// Assumptions captures ambient state that must be the same when compiling and
// deserializing a module for the compiled code to be valid. If it's not, then
// the module must be recompiled from scratch.

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

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import sys
import logging
import os
import time
import tempfile
@ -340,6 +341,8 @@ def run_test_harness(parser, options):
dm_args['adbPath'] = options.adb_path
if not dm_args['host']:
dm_args['deviceSerial'] = options.deviceSerial
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
dm_args['logLevel'] = logging.DEBUG
try:
dm = mozdevice.DroidADB(**dm_args)

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

@ -4,6 +4,33 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('findbugs-exclude.xml'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('lint*'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('mobile*'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('ua-update.json.in'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('assets/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('omnijar/**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('src/androidTest/**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
with Files('src/test/**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
for var in ('APP_NAME', 'APP_VERSION'):
DEFINES[var] = CONFIG['MOZ_%s' % var]

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

@ -4,6 +4,117 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('*.java.*'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('*Manifest*'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('adjust-sdk-sandbox.token'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('android-services.mozbuild'):
BUG_COMPONENT = ('Android Background Services', 'Android Sync')
with Files('geckoview.ddf'):
BUG_COMPONENT = ('Firefox for Android', 'GeckoView')
with Files('crashreporter/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('java/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('java/org/mozilla/gecko/activitystream/**'):
BUG_COMPONENT = ('Firefox for Android', 'Awesomescreen')
with Files('java/org/mozilla/gecko/cleanup/**'):
BUG_COMPONENT = ('Android Background Services', 'Firefox Health Report Service')
with Files('java/org/mozilla/gecko/distribution/**'):
BUG_COMPONENT = ('Firefox for Android', 'Distributions')
with Files('java/org/mozilla/gecko/firstrun/**'):
BUG_COMPONENT = ('Firefox for Android', 'First Run')
with Files('java/org/mozilla/gecko/home/**'):
BUG_COMPONENT = ('Firefox for Android', 'Awesomescreen')
with Files('java/org/mozilla/gecko/icons/**'):
BUG_COMPONENT = ('Firefox for Android', 'Favicon Handling')
with Files('java/org/mozilla/gecko/javaaddons/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('java/org/mozilla/gecko/mdns/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('java/org/mozilla/gecko/media/**'):
BUG_COMPONENT = ('Firefox for Android', 'Audio/Video')
with Files('java/org/mozilla/gecko/mdns/**'):
BUG_COMPONENT = ('Firefox for Android', 'Settings and Preferences')
with Files('java/org/mozilla/gecko/reader/**'):
BUG_COMPONENT = ('Firefox for Android', 'Reader View')
with Files('java/org/mozilla/gecko/restrictions/**'):
BUG_COMPONENT = ('Firefox for Android', 'Family Friendly Browsing')
with Files('java/org/mozilla/gecko/telemetry/**'):
BUG_COMPONENT = ('Firefox for Android', 'Metrics')
with Files('java/org/mozilla/gecko/text/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('java/org/mozilla/gecko/webapps/**'):
BUG_COMPONENT = ('Firefox for Android', 'Web Apps')
with Files('java/org/mozilla/gecko/*LocaleManager*'):
BUG_COMPONENT = ('Firefox for Android', 'Locale switching and selection')
with Files('java/org/mozilla/gecko/*ChromeCast*'):
BUG_COMPONENT = ('Firefox for Android', 'Screencasting')
with Files('java/org/mozilla/gecko/*DynamicToolbar*'):
BUG_COMPONENT = ('Firefox for Android', 'Graphics, Panning and Zooming')
with Files('java/org/mozilla/gecko/*Presentation*'):
BUG_COMPONENT = ('Firefox for Android', 'Screencasting')
with Files('java/org/mozilla/gecko/*GuestSession*'):
BUG_COMPONENT = ('Firefox for Android', 'Profile Handling')
with Files('locales/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('resources/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('resources/anim/**'):
BUG_COMPONENT = ('Firefox for Android', 'Overlays')
with Files('resources/raw/*favicon*'):
BUG_COMPONENT = ('Firefox for Android', 'Favicon Handling')
with Files('resources/xml*/*preference*'):
BUG_COMPONENT = ('Firefox for Android', 'Settings and Preferences')
with Files('resources/menu/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('resources/menu/*home*'):
BUG_COMPONENT = ('Firefox for Android', 'Awesomescreen')
with Files('resources/menu/*activitystream*'):
BUG_COMPONENT = ('Firefox for Android', 'Awesomescreen')
with Files('resources/menu/browsersearch_contextmenu.xml'):
BUG_COMPONENT = ('Firefox for Android', 'Awesomescreen')
DIRS += ['locales']
GENERATED_FILES += [

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

@ -4,6 +4,13 @@
# 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/.
# NOTE: I think there are a few other possible components in this directory
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('geckoview/**'):
BUG_COMPONENT = ('Firefox for Android', 'GeckoView')
DIRS += ['geckoview']
DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE']

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

@ -4,6 +4,12 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('extensions/**'):
BUG_COMPONENT = ('Toolkit', 'WebExtensions: Android')
XPIDL_SOURCES += [
'SessionStore.idl',
]

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

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
# Only include the following system add-ons if building Aurora or Nightly
if not CONFIG['RELEASE_OR_BETA']:
DIRS += [

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

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
if not CONFIG['MOZ_ANDROID_EXCLUDE_FONTS']:
RESOURCE_FILES.fonts += [
'CharisSILCompact-B.ttf',

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

@ -39,7 +39,7 @@ public class GeckoViewActivity extends Activity {
mGeckoView.setContentListener(new MyGeckoViewContent());
mGeckoView.setProgressListener(new MyGeckoViewProgress());
final GeckoProfile profile = GeckoProfile.get(getApplicationContext());
final GeckoProfile profile = GeckoProfile.get(this);
GeckoThread.initMainProcess(profile, /* args */ null, /* debugging */ false);
GeckoThread.launch();

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

@ -4,3 +4,5 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')

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

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
jar = add_java_jar('javaaddons-1.0')
jar.sources = [
'java/org/mozilla/javaaddons/JavaAddonInterfaceV1.java',

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

@ -4,4 +4,7 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
JAR_MANIFESTS += ['jar.mn']

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

@ -4,6 +4,19 @@
# 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/.
# Most files are General, a few exceptions
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('DownloadNotifications.jsm'):
BUG_COMPONENT = ('Firefox for Android', 'Download Manager')
with Files('HomeProvider.jsm'):
BUG_COMPONENT = ('Firefox for Android', 'Data Providers')
with Files('geckoview/**'):
BUG_COMPONENT = ('Firefox for Android', 'GeckoView')
DIRS += ['geckoview']
EXTRA_JS_MODULES += [

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

@ -4,6 +4,51 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('bouncer/**'):
BUG_COMPONENT = ('Firefox for Android', 'Distributions')
with Files('branding/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('build/**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('config/**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('docs/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
with Files('geckoview/**'):
BUG_COMPONENT = ('Firefox for Android', 'GeckoView')
with Files('geckoview/src/main/aidl/**'):
BUG_COMPONENT = ('Firefox for Android', 'Audio/Video')
with Files('geckoview/src/main/java/org/mozilla/gecko/mozglue/**'):
BUG_COMPONENT = ('Firefox for Android', 'Audio/Video')
with Files('geckoview_example/**'):
BUG_COMPONENT = ('Firefox for Android', 'GeckoView')
with Files('gradle/**'):
BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
with Files('search/**'):
BUG_COMPONENT = ('Firefox for Android', 'Search Activity')
with Files('services/**'):
BUG_COMPONENT = ('Android Background Services', 'Android Sync')
with Files('themes/**'):
BUG_COMPONENT = ('Firefox for Android', 'Theme and Visual Design')
with Files('thirdparty/**'):
BUG_COMPONENT = ('Firefox for Android', 'General')
CONFIGURE_SUBST_FILES += ['installer/Makefile']
DIRS += [

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

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Android Background Services', 'Geolocation')
include('stumbler_sources.mozbuild')
stumbler_jar = add_java_jar('stumbler')

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

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Android Background Services', 'Build & Test')
TEST_DIRS += [
'junit3',
]

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

@ -4,6 +4,19 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
with Files('chrome/**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
with Files('junit3/**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
# Ideally split this up, but testing catches many files
with Files('robocop/**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
if not CONFIG['MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE']:

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

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
ANDROID_APK_NAME = 'javaaddons-test'
ANDROID_APK_PACKAGE = 'org.mozilla.javaaddons.test'

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

@ -4,6 +4,10 @@
# 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/.
# catch all for new files
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Testing')
if not CONFIG['MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE']:
TEST_DIRS += [
'background',

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

@ -4,4 +4,7 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox for Android', 'Locale Switching')
JAR_MANIFESTS += ['jar.mn']

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

@ -1,7 +1,7 @@
diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private.h
--- a/modules/fdlibm/src/math_private.h
+++ b/modules/fdlibm/src/math_private.h
@@ -33,16 +33,21 @@
@@ -33,16 +33,23 @@
* to dig two 32 bit words out of the 64 bit IEEE floating point
* value. That is non-ANSI, and, moreover, the gcc instruction
* scheduler gets it wrong. We instead use the following macros.
@ -10,8 +10,10 @@ diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private
* endianness at run time.
*/
+#ifdef WIN32
+#ifndef u_int32_t
+#define u_int32_t uint32_t
+#endif
+#ifndef u_int64_t
+#define u_int64_t uint64_t
+#endif
+

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

@ -38,8 +38,10 @@
* endianness at run time.
*/
#ifdef WIN32
#ifndef u_int32_t
#define u_int32_t uint32_t
#endif
#ifndef u_int64_t
#define u_int64_t uint64_t
#endif

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

@ -10,6 +10,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsXULAppAPI.h"
@ -478,10 +479,11 @@ bool
Preferences::InitStaticMembers()
{
#ifndef MOZ_B2G
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
#endif
if (!sShutdown && !sPreferences) {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPrefService> prefService =
do_GetService(NS_PREFSERVICE_CONTRACTID);
}

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

@ -14,12 +14,16 @@ interface nsIURI;
%{C++
#include "nsIConsoleReportCollector.h"
namespace mozilla {
class TimeStamp;
namespace dom {
class ChannelInfo;
}
}
%}
native TimeStamp(mozilla::TimeStamp);
[ptr] native ChannelInfo(mozilla::dom::ChannelInfo);
/**
@ -97,6 +101,30 @@ interface nsIInterceptedChannel : nsISupports
[noscript]
readonly attribute nsIConsoleReportCollector consoleReportCollector;
/**
* Save the timestamps of various service worker interception phases.
*/
[noscript]
void SetLaunchServiceWorkerStart(in TimeStamp aTimeStamp);
[noscript]
void SetLaunchServiceWorkerEnd(in TimeStamp aTimeStamp);
[noscript]
void SetDispatchFetchEventStart(in TimeStamp aTimeStamp);
[noscript]
void SetDispatchFetchEventEnd(in TimeStamp aTimeStamp);
[noscript]
void SetHandleFetchEventStart(in TimeStamp aTimeStamp);
[noscript]
void SetHandleFetchEventEnd(in TimeStamp aTimeStamp);
[noscript]
void SaveTimeStampsToUnderlyingChannel();
%{C++
already_AddRefed<nsIConsoleReportCollector>
GetConsoleReportCollector()

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

@ -26,6 +26,15 @@ interface nsITimedChannel : nsISupports {
[noscript] readonly attribute TimeStamp channelCreation;
[noscript] readonly attribute TimeStamp asyncOpen;
// The following are only set when the request is intercepted by a service
// worker no matter the response is synthesized.
[noscript] attribute TimeStamp launchServiceWorkerStart;
[noscript] attribute TimeStamp launchServiceWorkerEnd;
[noscript] attribute TimeStamp dispatchFetchEventStart;
[noscript] attribute TimeStamp dispatchFetchEventEnd;
[noscript] attribute TimeStamp handleFetchEventStart;
[noscript] attribute TimeStamp handleFetchEventEnd;
// The following are only set when the document is not (only) read from the
// cache
[noscript] readonly attribute TimeStamp domainLookupStart;
@ -66,6 +75,12 @@ interface nsITimedChannel : nsISupports {
// All following are PRTime versions of the above.
readonly attribute PRTime channelCreationTime;
readonly attribute PRTime asyncOpenTime;
readonly attribute PRTime launchServiceWorkerStartTime;
readonly attribute PRTime launchServiceWorkerEndTime;
readonly attribute PRTime dispatchFetchEventStartTime;
readonly attribute PRTime dispatchFetchEventEndTime;
readonly attribute PRTime handleFetchEventStartTime;
readonly attribute PRTime handleFetchEventEndTime;
readonly attribute PRTime domainLookupStartTime;
readonly attribute PRTime domainLookupEndTime;
readonly attribute PRTime connectStartTime;

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

@ -656,10 +656,6 @@ bool NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport = false);
#define ABOUT_URI_FIRST_PARTY_DOMAIN \
"about.ef2a7dd5-93bc-417f-a698-142c3116864f.mozilla"
// Unique first-party domain for separating null principal.
#define NULL_PRINCIPAL_FIRST_PARTY_DOMAIN \
"1f1841ad-0395-48ba-aec4-c98ee3f6e614.mozilla"
/**
* Determines whether appcache should be checked for a given URI.
*/

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

@ -19,6 +19,7 @@ using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using RequestHeaderTuples from "mozilla/net/PHttpChannelParams.h";
using struct nsHttpAtom from "nsHttp.h";
using class nsHttpResponseHead from "nsHttpResponseHead.h";
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
namespace mozilla {
namespace net {
@ -132,6 +133,12 @@ struct HttpChannelOpenArgs
uint64_t contentWindowId;
nsCString preferredAlternativeType;
uint64_t topLevelOuterContentWindowId;
TimeStamp launchServiceWorkerStart;
TimeStamp launchServiceWorkerEnd;
TimeStamp dispatchFetchEventStart;
TimeStamp dispatchFetchEventEnd;
TimeStamp handleFetchEventStart;
TimeStamp handleFetchEventEnd;
};
struct HttpChannelConnectArgs

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

@ -3617,6 +3617,84 @@ HttpBaseChannel::TimingAllowCheck(nsIPrincipal *aOrigin, bool *_retval)
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetLaunchServiceWorkerStart(TimeStamp* _retval) {
MOZ_ASSERT(_retval);
*_retval = mLaunchServiceWorkerStart;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetLaunchServiceWorkerStart(TimeStamp aTimeStamp) {
mLaunchServiceWorkerStart = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetLaunchServiceWorkerEnd(TimeStamp* _retval) {
MOZ_ASSERT(_retval);
*_retval = mLaunchServiceWorkerEnd;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetLaunchServiceWorkerEnd(TimeStamp aTimeStamp) {
mLaunchServiceWorkerEnd = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetDispatchFetchEventStart(TimeStamp* _retval) {
MOZ_ASSERT(_retval);
*_retval = mDispatchFetchEventStart;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetDispatchFetchEventStart(TimeStamp aTimeStamp) {
mDispatchFetchEventStart = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetDispatchFetchEventEnd(TimeStamp* _retval) {
MOZ_ASSERT(_retval);
*_retval = mDispatchFetchEventEnd;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetDispatchFetchEventEnd(TimeStamp aTimeStamp) {
mDispatchFetchEventEnd = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetHandleFetchEventStart(TimeStamp* _retval) {
MOZ_ASSERT(_retval);
*_retval = mHandleFetchEventStart;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetHandleFetchEventStart(TimeStamp aTimeStamp) {
mHandleFetchEventStart = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetHandleFetchEventEnd(TimeStamp* _retval) {
MOZ_ASSERT(_retval);
*_retval = mHandleFetchEventEnd;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetHandleFetchEventEnd(TimeStamp aTimeStamp) {
mHandleFetchEventEnd = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetDomainLookupStart(TimeStamp* _retval) {
*_retval = mTransactionTimings.domainLookupStart;
@ -3701,6 +3779,12 @@ HttpBaseChannel::Get##name##Time(PRTime* _retval) { \
IMPL_TIMING_ATTR(ChannelCreation)
IMPL_TIMING_ATTR(AsyncOpen)
IMPL_TIMING_ATTR(LaunchServiceWorkerStart)
IMPL_TIMING_ATTR(LaunchServiceWorkerEnd)
IMPL_TIMING_ATTR(DispatchFetchEventStart)
IMPL_TIMING_ATTR(DispatchFetchEventEnd)
IMPL_TIMING_ATTR(HandleFetchEventStart)
IMPL_TIMING_ATTR(HandleFetchEventEnd)
IMPL_TIMING_ATTR(DomainLookupStart)
IMPL_TIMING_ATTR(DomainLookupEnd)
IMPL_TIMING_ATTR(ConnectStart)

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

@ -560,6 +560,12 @@ protected:
TimeStamp mAsyncOpenTime;
TimeStamp mCacheReadStart;
TimeStamp mCacheReadEnd;
TimeStamp mLaunchServiceWorkerStart;
TimeStamp mLaunchServiceWorkerEnd;
TimeStamp mDispatchFetchEventStart;
TimeStamp mDispatchFetchEventEnd;
TimeStamp mHandleFetchEventStart;
TimeStamp mHandleFetchEventEnd;
// copied from the transaction before we null out mTransaction
// so that the timing can still be queried from OnStopRequest
TimingStruct mTransactionTimings;

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

@ -2423,6 +2423,13 @@ HttpChannelChild::ContinueAsyncOpen()
return NS_ERROR_FAILURE;
}
openArgs.launchServiceWorkerStart() = mLaunchServiceWorkerStart;
openArgs.launchServiceWorkerEnd() = mLaunchServiceWorkerEnd;
openArgs.dispatchFetchEventStart() = mDispatchFetchEventStart;
openArgs.dispatchFetchEventEnd() = mDispatchFetchEventEnd;
openArgs.handleFetchEventStart() = mHandleFetchEventStart;
openArgs.handleFetchEventEnd() = mHandleFetchEventEnd;
// This must happen before the constructor message is sent. Otherwise messages
// from the parent could arrive quickly and be delivered to the wrong event
// target.

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

@ -132,7 +132,13 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
a.suspendAfterSynthesizeResponse(),
a.allowStaleCacheContent(), a.contentTypeHint(),
a.channelId(), a.contentWindowId(), a.preferredAlternativeType(),
a.topLevelOuterContentWindowId());
a.topLevelOuterContentWindowId(),
a.launchServiceWorkerStart(),
a.launchServiceWorkerEnd(),
a.dispatchFetchEventStart(),
a.dispatchFetchEventEnd(),
a.handleFetchEventStart(),
a.handleFetchEventEnd());
}
case HttpChannelCreationArgs::THttpChannelConnectArgs:
{
@ -331,7 +337,13 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
const uint64_t& aChannelId,
const uint64_t& aContentWindowId,
const nsCString& aPreferredAlternativeType,
const uint64_t& aTopLevelOuterContentWindowId)
const uint64_t& aTopLevelOuterContentWindowId,
const TimeStamp& aLaunchServiceWorkerStart,
const TimeStamp& aLaunchServiceWorkerEnd,
const TimeStamp& aDispatchFetchEventStart,
const TimeStamp& aDispatchFetchEventEnd,
const TimeStamp& aHandleFetchEventStart,
const TimeStamp& aHandleFetchEventEnd)
{
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
if (!uri) {
@ -540,6 +552,13 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
mChannel->SetInitialRwin(aInitialRwin);
mChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
mChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
mChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
mChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
mChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
mChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
mChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd);
nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
do_QueryObject(mChannel);
nsCOMPtr<nsIApplicationCacheService> appCacheService =

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

@ -149,7 +149,13 @@ protected:
const uint64_t& aChannelId,
const uint64_t& aContentWindowId,
const nsCString& aPreferredAlternativeType,
const uint64_t& aTopLevelOuterContentWindowId);
const uint64_t& aTopLevelOuterContentWindowId,
const TimeStamp& aLaunchServiceWorkerStart,
const TimeStamp& aLaunchServiceWorkerEnd,
const TimeStamp& aDispatchFetchEventStart,
const TimeStamp& aDispatchFetchEventEnd,
const TimeStamp& aHandleFetchEventStart,
const TimeStamp& aHandleFetchEventEnd);
virtual mozilla::ipc::IPCResult RecvSetPriority(const int16_t& priority) override;
virtual mozilla::ipc::IPCResult RecvSetClassOfService(const uint32_t& cos) override;

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

@ -10,6 +10,7 @@
#include "nsInputStreamPump.h"
#include "nsIPipe.h"
#include "nsIStreamListener.h"
#include "nsITimedChannel.h"
#include "nsHttpChannel.h"
#include "HttpChannelChild.h"
#include "nsHttpResponseHead.h"
@ -131,6 +132,40 @@ InterceptedChannelBase::SetReleaseHandle(nsISupports* aHandle)
return NS_OK;
}
NS_IMETHODIMP
InterceptedChannelBase::SaveTimeStampsToUnderlyingChannel()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIChannel> underlyingChannel;
nsresult rv = GetChannel(getter_AddRefs(underlyingChannel));
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsITimedChannel> timedChannel =
do_QueryInterface(underlyingChannel);
MOZ_ASSERT(timedChannel);
rv = timedChannel->SetLaunchServiceWorkerStart(mLaunchServiceWorkerStart);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = timedChannel->SetLaunchServiceWorkerEnd(mLaunchServiceWorkerEnd);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = timedChannel->SetDispatchFetchEventStart(mDispatchFetchEventStart);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = timedChannel->SetDispatchFetchEventEnd(mDispatchFetchEventEnd);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = timedChannel->SetHandleFetchEventStart(mHandleFetchEventStart);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = timedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return rv;
}
/* static */
already_AddRefed<nsIURI>
InterceptedChannelBase::SecureUpgradeChannelURI(nsIChannel* aChannel)

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

@ -48,6 +48,13 @@ protected:
MOZ_MUST_USE nsresult DoSynthesizeHeader(const nsACString& aName,
const nsACString& aValue);
TimeStamp mLaunchServiceWorkerStart;
TimeStamp mLaunchServiceWorkerEnd;
TimeStamp mDispatchFetchEventStart;
TimeStamp mDispatchFetchEventEnd;
TimeStamp mHandleFetchEventStart;
TimeStamp mHandleFetchEventEnd;
virtual ~InterceptedChannelBase();
public:
explicit InterceptedChannelBase(nsINetworkInterceptController* aController);
@ -62,6 +69,50 @@ public:
NS_IMETHOD GetConsoleReportCollector(nsIConsoleReportCollector** aCollectorOut) override;
NS_IMETHOD SetReleaseHandle(nsISupports* aHandle) override;
NS_IMETHODIMP
SetLaunchServiceWorkerStart(TimeStamp aTimeStamp) override
{
mLaunchServiceWorkerStart = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
SetLaunchServiceWorkerEnd(TimeStamp aTimeStamp) override
{
mLaunchServiceWorkerEnd = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
SetDispatchFetchEventStart(TimeStamp aTimeStamp) override
{
mDispatchFetchEventStart = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
SetDispatchFetchEventEnd(TimeStamp aTimeStamp) override
{
mDispatchFetchEventEnd = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
SetHandleFetchEventStart(TimeStamp aTimeStamp) override
{
mHandleFetchEventStart = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
SetHandleFetchEventEnd(TimeStamp aTimeStamp) override
{
mHandleFetchEventEnd = aTimeStamp;
return NS_OK;
}
NS_IMETHODIMP SaveTimeStampsToUnderlyingChannel() override;
static already_AddRefed<nsIURI>
SecureUpgradeChannelURI(nsIChannel* aChannel);
};

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

@ -582,6 +582,90 @@ NullHttpChannel::GetAsyncOpen(mozilla::TimeStamp *aAsyncOpen)
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetLaunchServiceWorkerStart(mozilla::TimeStamp *_retval)
{
MOZ_ASSERT(_retval);
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetLaunchServiceWorkerStart(mozilla::TimeStamp aTimeStamp)
{
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetLaunchServiceWorkerEnd(mozilla::TimeStamp *_retval)
{
MOZ_ASSERT(_retval);
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetLaunchServiceWorkerEnd(mozilla::TimeStamp aTimeStamp)
{
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetDispatchFetchEventStart(mozilla::TimeStamp *_retval)
{
MOZ_ASSERT(_retval);
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetDispatchFetchEventStart(mozilla::TimeStamp aTimeStamp)
{
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetDispatchFetchEventEnd(mozilla::TimeStamp *_retval)
{
MOZ_ASSERT(_retval);
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetDispatchFetchEventEnd(mozilla::TimeStamp aTimeStamp)
{
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetHandleFetchEventStart(mozilla::TimeStamp *_retval)
{
MOZ_ASSERT(_retval);
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetHandleFetchEventStart(mozilla::TimeStamp aTimeStamp)
{
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetHandleFetchEventEnd(mozilla::TimeStamp *_retval)
{
MOZ_ASSERT(_retval);
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetHandleFetchEventEnd(mozilla::TimeStamp aTimeStamp)
{
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetDomainLookupStart(mozilla::TimeStamp *aDomainLookupStart)
{
@ -772,6 +856,12 @@ NullHttpChannel::Get##name##Time(PRTime* _retval) { \
IMPL_TIMING_ATTR(ChannelCreation)
IMPL_TIMING_ATTR(AsyncOpen)
IMPL_TIMING_ATTR(LaunchServiceWorkerStart)
IMPL_TIMING_ATTR(LaunchServiceWorkerEnd)
IMPL_TIMING_ATTR(DispatchFetchEventStart)
IMPL_TIMING_ATTR(DispatchFetchEventEnd)
IMPL_TIMING_ATTR(HandleFetchEventStart)
IMPL_TIMING_ATTR(HandleFetchEventEnd)
IMPL_TIMING_ATTR(DomainLookupStart)
IMPL_TIMING_ATTR(DomainLookupEnd)
IMPL_TIMING_ATTR(ConnectStart)

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

@ -5367,6 +5367,18 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
}
}
if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(newChannel);
if (timedChannel) {
timedChannel->SetLaunchServiceWorkerStart(mLaunchServiceWorkerStart);
timedChannel->SetLaunchServiceWorkerEnd(mLaunchServiceWorkerEnd);
timedChannel->SetDispatchFetchEventStart(mDispatchFetchEventStart);
timedChannel->SetDispatchFetchEventEnd(mDispatchFetchEventEnd);
timedChannel->SetHandleFetchEventStart(mHandleFetchEventStart);
timedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd);
}
}
return NS_OK;
}

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

@ -30,7 +30,7 @@ EXPORTS += [
'nsSAXXMLReader.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'nsSAXAttributes.cpp',
'nsSAXLocator.cpp',
'nsSAXXMLReader.cpp',

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

@ -146,7 +146,7 @@ android-api-15-gradle/opt:
- name: public/android/maven
path: /home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/android/geckoview_example.apk
- name: public/build/geckoview_example.apk
path: /home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
type: file
- name: public/build

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

@ -241,6 +241,7 @@ android-opt-tests:
android-gradle-tests:
- mochitest-chrome
- robocop
- geckoview
android-x86-tests:
- mochitest-chrome

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

@ -606,6 +606,7 @@ mochitest-clipboard:
suite: mochitest/clipboard
treeherder-symbol: tc-M(cl)
loopback-video: true
docker-image: {"in-tree": "desktop1604-test"}
instance-size: xlarge
e10s:
by-test-platform:
@ -914,6 +915,7 @@ mochitest-style:
suite: mochitest/plain-style
treeherder-symbol: tc-M(s)
loopback-video: true
docker-image: {"in-tree": "desktop1604-test"}
e10s: both
run-on-projects:
by-test-platform:
@ -936,6 +938,7 @@ mochitest-chrome-style:
suite: mochitest/chrome-style
treeherder-symbol: tc-M(cs)
loopback-video: true
docker-image: {"in-tree": "desktop1604-test"}
run-on-projects:
by-test-platform:
linux64-stylo/.*: [ 'stylo', 'autoland', 'mozilla-inbound', 'mozilla-central', 'try' ]
@ -1096,6 +1099,21 @@ robocop:
extra-options:
- --test-suite=robocop
geckoview:
description: "Geckoview run"
suite: geckoview
treeherder-symbol: tc(gv)
instance-size: xlarge
loopback-video: true
e10s: false
mozharness:
script: android_emulator_unittest.py
no-read-buildbot-config: true
config:
- android/androidarm_4_3.py
extra-options:
- --test-suite=geckoview
talos-chrome:
description: "Talos chrome"
suite: talos

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

@ -341,7 +341,10 @@ def set_target(config, tests):
if build_platform.startswith('macosx'):
target = 'target.dmg'
elif build_platform.startswith('android'):
target = 'target.apk'
if 'geckoview' in test['test-name']:
target = 'geckoview_example.apk'
else:
target = 'target.apk'
elif build_platform.startswith('win'):
target = 'firefox-{}.en-US.{}.zip'.format(
get_firefox_version(),

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

@ -7,6 +7,7 @@ from argparse import ArgumentParser, SUPPRESS
from distutils.util import strtobool
from itertools import chain
from urlparse import urlparse
import logging
import json
import os
import tempfile
@ -957,6 +958,9 @@ class AndroidArguments(ArgumentContainer):
device_args['port'] = options.devicePort
elif options.deviceSerial:
device_args['deviceSerial'] = options.deviceSerial
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
device_args['logLevel'] = logging.DEBUG
options.dm = DroidADB(**device_args)
if not options.remoteTestRoot:

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

@ -61,6 +61,7 @@ TEST_HARNESS_FILES.testing.mochitest += [
'nested_setup.js',
'pywebsocket_wrapper.py',
'redirect.html',
'rungeckoview.py',
'runrobocop.py',
'runtests.py',
'runtestsremote.py',

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

@ -0,0 +1,255 @@
# 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/.
import posixpath
import shutil
import sys
import tempfile
import time
import traceback
from optparse import OptionParser
import mozcrash
import mozdevice
import mozlog
from mozprofile import Profile
class GeckoviewOptions(OptionParser):
def __init__(self):
OptionParser.__init__(self)
self.add_option("--utility-path",
action="store", type="string", dest="utility_path",
default=None,
help="absolute path to directory containing utility programs")
self.add_option("--symbols-path",
action="store", type="string", dest="symbols_path",
default=None,
help="absolute path to directory containing breakpad symbols, \
or the URL of a zip file containing symbols")
self.add_option("--appname",
action="store", type="string", dest="app",
default="org.mozilla.geckoview_example",
help="geckoview_example package name")
self.add_option("--deviceIP",
action="store", type="string", dest="deviceIP",
default=None,
help="ip address of remote device to test")
self.add_option("--deviceSerial",
action="store", type="string", dest="deviceSerial",
default=None,
help="serial ID of remote device to test")
self.add_option("--adbpath",
action="store", type="string", dest="adbPath",
default="adb",
help="Path to adb binary.")
self.add_option("--remoteTestRoot",
action="store", type="string", dest="remoteTestRoot",
default=None,
help="remote directory to use as test root \
(eg. /mnt/sdcard/tests or /data/local/tests)")
class GeckoviewTestRunner:
"""
A quick-and-dirty test harness to verify the geckoview_example
app starts without crashing.
"""
def __init__(self, log, dm, options):
self.log = log
self.dm = dm
self.options = options
self.appname = self.options.app.split('/')[-1]
self.logcat = None
self.build_profile()
self.log.debug("options=%s" % vars(options))
def build_profile(self):
test_root = self.dm.deviceRoot
self.remote_profile = posixpath.join(test_root, 'gv-profile')
self.dm.mkDirs(posixpath.join(self.remote_profile, "x"))
profile = Profile()
self.dm.pushDir(profile.profile, self.remote_profile)
self.log.debug("profile %s -> %s" %
(str(profile.profile), str(self.remote_profile)))
def installed(self):
"""
geckoview_example installed
"""
installed = self.dm.shellCheckOutput(['pm', 'list', 'packages', self.appname])
if self.appname not in installed:
return (False, "%s not installed" % self.appname)
return (True, "%s installed" % self.appname)
def start(self):
"""
geckoview_example starts
"""
try:
self.dm.stopApplication(self.appname)
self.dm.recordLogcat()
cmd = ['am', 'start', '-a', 'android.intent.action.MAIN', '-n',
'org.mozilla.geckoview_example/org.mozilla.geckoview_example.GeckoViewActivity',
'--es', 'args', '-profile %s' % self.remote_profile]
env = {}
env["MOZ_CRASHREPORTER"] = 1
env["MOZ_CRASHREPORTER_NO_REPORT"] = 1
env["XPCOM_DEBUG_BREAK"] = "stack"
env["DISABLE_UNSAFE_CPOW_WARNINGS"] = 1
env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = 1
env["MOZ_IN_AUTOMATION"] = 1
env["R_LOG_VERBOSE"] = 1
env["R_LOG_LEVEL"] = 6
env["R_LOG_DESTINATION"] = "stderr"
i = 0
for key, value in env.iteritems():
cmd.append("--es")
cmd.append("env%d" % i)
cmd.append("%s=%s" % (key, str(value)))
i = i + 1
self.dm.shellCheckOutput(cmd)
except mozdevice.DMError:
return (False, "Exception during %s startup" % self.appname)
return (True, "%s started" % self.appname)
def started(self):
"""
startup logcat messages
"""
expected = [
"zerdatime",
"Displayed %s/.GeckoViewActivity" % self.appname
]
# wait up to 60 seconds for startup
for wait_time in xrange(60):
time.sleep(1)
self.logcat = self.dm.getLogcat()
for line in self.logcat:
for e in expected:
if e in line:
self.log.debug(line.strip())
expected.remove(e)
if len(expected) == 0:
return (True, "All expected logcat messages found")
for e in expected:
self.log.error("missing from logcat: '%s'" % e)
return (False, "'%s' not found in logcat" % expected[0])
def run_tests(self):
"""
Run simple tests to verify that the geckoview_example app starts.
"""
all_tests = [self.installed, self.start, self.started]
self.log.suite_start(all_tests)
pass_count = 0
fail_count = 0
for test in all_tests:
self.test_name = test.__doc__.strip()
self.log.test_start(self.test_name)
expected = 'PASS'
(passed, message) = test()
if passed:
pass_count = pass_count + 1
else:
fail_count = fail_count + 1
status = 'PASS' if passed else 'FAIL'
self.log.test_end(self.test_name, status, expected, message)
self.log.info("Passed: %d" % pass_count)
self.log.info("Failed: %d" % fail_count)
self.log.suite_end()
return 0 if passed else 1
def check_for_crashes(self):
if self.logcat:
if mozcrash.check_for_java_exception(self.logcat, self.test_name):
return True
symbols_path = self.options.symbols_path
try:
dump_dir = tempfile.mkdtemp()
remote_dir = posixpath.join(self.remote_profile, 'minidumps')
if not self.dm.dirExists(remote_dir):
# If crash reporting is enabled (MOZ_CRASHREPORTER=1), the
# minidumps directory is automatically created when the app
# (first) starts, so its lack of presence is a hint that
# something went wrong.
print "Automation Error: No crash directory (%s) found on remote device" % \
remote_dir
# Whilst no crash was found, the run should still display as a failure
return True
self.dm.getDirectory(remote_dir, dump_dir)
crashed = mozcrash.log_crashes(self.log, dump_dir, symbols_path, test=self.test_name)
finally:
try:
shutil.rmtree(dump_dir)
except:
self.log.warn("unable to remove directory: %s" % dump_dir)
return crashed
def cleanup(self):
"""
Cleanup at end of job run.
"""
self.log.debug("Cleaning up...")
self.dm.stopApplication(self.appname)
crashed = self.check_for_crashes()
self.dm.removeDir(self.remote_profile)
self.log.debug("Cleanup complete.")
return crashed
def run_test_harness(log, parser, options):
device_args = {'deviceRoot': options.remoteTestRoot}
device_args['adbPath'] = options.adbPath
if options.deviceIP:
device_args['host'] = options.deviceIP
device_args['port'] = options.devicePort
elif options.deviceSerial:
device_args['deviceSerial'] = options.deviceSerial
device_args['packageName'] = options.app
dm = mozdevice.DroidADB(**device_args)
runner = GeckoviewTestRunner(log, dm, options)
result = -1
try:
result = runner.run_tests()
except KeyboardInterrupt:
log.info("rungeckoview.py | Received keyboard interrupt")
result = -1
except:
traceback.print_exc()
log.error(
"rungeckoview.py | Received unexpected exception while running tests")
result = 1
finally:
try:
crashed = runner.cleanup()
if not result:
result = crashed
except mozdevice.DMError:
# ignore device error while cleaning up
pass
return result
def main(args=sys.argv[1:]):
parser = GeckoviewOptions()
mozlog.commandline.add_logging_group(parser)
options, args = parser.parse_args()
if args:
print >>sys.stderr, """Usage: %s""" % sys.argv[0]
sys.exit(1)
log = mozlog.commandline.setup_logging("rungeckoview", options,
{"tbpl": sys.stdout})
return run_test_harness(log, parser, options)
if __name__ == "__main__":
sys.exit(main())

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

@ -356,6 +356,14 @@ config = {
"--startup-timeout=300",
],
},
"geckoview": {
"run_filename": "rungeckoview.py",
"testsdir": "mochitest",
"options": [
"--utility-path=%(utility_path)s",
"--symbols-path=%(symbols_path)s",
],
},
}, # end suite_definitions
"download_minidump_stackwalk": True,

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

@ -94,6 +94,12 @@ TinderBoxPrintRe = {
'fail_group': "Failed",
'known_fail_group': "Skipped",
},
"geckoview_summary": {
'regex': re.compile(r'''(Passed|Failed): (\d+)'''),
'pass_group': "Passed",
'fail_group': "Failed",
'known_fail_group': None,
},
"harness_error": {
'full_regex': re.compile(r"(?:TEST-UNEXPECTED-FAIL|PROCESS-CRASH) \| .* \| (application crashed|missing output line for total leaks!|negative leaks caught!|\d+ bytes leaked)"),

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

@ -439,6 +439,7 @@ You can set this by:
'mochitest-plain-clipboard': 'mochitest',
'mochitest-plain-gpu': 'mochitest',
'mochitest-gl': 'mochitest',
'geckoview': 'mochitest',
'jsreftest': 'reftest',
'crashtest': 'reftest',
'reftest-debug': 'reftest',

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