Merge m-c to fx-team, a=merge

This commit is contained in:
Wes Kocher 2016-07-26 16:55:01 -07:00
commit f050631553
104 changed files with 2017 additions and 582 deletions

View File

@ -10784,7 +10784,8 @@ nsDocShell::DoURILoad(nsIURI* aURI,
// only inherit if we have a triggeringPrincipal
bool inherit = false;
// Get triggeringPrincipal. This code should be updated by bug 1181370.
// Getting the right triggeringPrincipal needs to be updated and is only
// ready for use once bug 1182569 landed.
// Until then, we cannot rely on the triggeringPrincipal for TYPE_DOCUMENT
// or TYPE_SUBDOCUMENT loads. Notice the triggeringPrincipal falls back to
// systemPrincipal below.

View File

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8"></head>
<body>
<b>Frame 1</b><br/>
<a href="#"" id="testlink" onclick="parent.frames[1].frames[0].location='http://test2.mochi.test:8888/tests/docshell/test/navigation/file_triggeringprincipal_subframe_nav.html'">click me</a>
<script type="application/javascript">
// make sure to set document.domain to the same domain as the subframe
window.onload = function() {
document.domain = 'mochi.test';
};
window.addEventListener('message', receiveMessage, false);
function receiveMessage(event) {
// make sure to get the right start command, otherwise
// let the parent know and fail the test
if (event.data.start !== 'startTest') {
window.removeEventListener("message", receiveMessage, false);
window.parent.postMessage({triggeringPrincipalURI: 'false'}, '*');
}
// click the link to navigate the subframe
document.getElementById('testlink').click();
}
</script>
</body>
</html>

View File

@ -0,0 +1,8 @@
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8"></head>
<body>
<b>Frame 2</b><br/>
<iframe src="http://test2.mochi.test:8888/tests/docshell/test/navigation/file_triggeringprincipal_subframe.html"></iframe>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html>
<head><meta charset='utf-8'></head>
<body>
<b>Sub Frame 2</b><br/>
<script type='application/javascript'>
// make sure to set document.domain to same domain as frame 1
window.onload = function() {
document.domain = 'mochi.test';
// let Frame 1 know that we are ready to run the test
window.parent.parent.frames[0].postMessage({start: 'startTest'}, '*');
};
</script>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8"></head>
<body onload="checkResults()">
<b>Sub Frame 2 Navigated</b><br/>
<script type='application/javascript'>
function checkResults() {
// query the uri of the loadingPrincipal and the TriggeringPrincipal and pass
// that information on to the parent for verification.
var channel = SpecialPowers.wrap(document).docShell.currentDocumentChannel;
var triggeringPrincipalURI = channel.loadInfo.triggeringPrincipal.URI.asciiSpec;
var loadingPrincipalURI = channel.loadInfo.loadingPrincipal.URI.asciiSpec;
var referrerURI = document.referrer;
window.parent.parent.postMessage({triggeringPrincipalURI,
loadingPrincipalURI,
referrerURI}, '*');
}
</script>
</body>
</html>

View File

@ -22,6 +22,10 @@ support-files =
navigate.html
open.html
parent.html
file_triggeringprincipal_frame_1.html
file_triggeringprincipal_frame_2.html
file_triggeringprincipal_subframe.html
file_triggeringprincipal_subframe_nav.html
[test_bug13871.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' #RANDOM # Bug 1136180 disabled on B2G Desktop and Mulet for intermittent failures
@ -48,3 +52,4 @@ skip-if = (buildapp == 'b2g' && debug) || (toolkit == 'android') || (debug && e1
skip-if = (buildapp == 'b2g' && debug) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
[test_sibling-matching-parent.html]
[test_sibling-off-domain.html]
[test_triggeringprincipal_frame_nav.html]

View File

@ -0,0 +1,69 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Bug 1181370 - Test triggeringPrincipal for iframe navigations</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe style="width:100%;" id="testframe1"></iframe>
<iframe style="width:100%;" id="testframe2"></iframe>
<script class="testbody" type="text/javascript">
/* Description of the test:
*
* +------------------------------------+
* | +----------+ +--------------+ |
* | | Frame 1 | | Frame 2 | |
* | +----------+ | | |
* | | +----------+ | |
* | | | Subframe | | |
* | | +----------+ | |
* | +--------------+ |
* +------------------------------------+
*
* Frame1: test1.mochi.test
* Frame2: test2.mochi.test
* Subframe: test2.mochi.test
*
* (*) Frame1 and Subframe set their document.domain to mochi.test
* (*) Frame1 navigates the Subframe
* (*) TriggeringPrincipal for the Subframe navigation should be
* ==> test1.mochi.test
* (*) LoadingPrincipal for the Subframe navigation should be
* ==> test2.mochi.test
*/
const BASEURL1 = "http://test1.mochi.test:8888/tests/docshell/test/navigation/";
const BASEURL2 = "http://test2.mochi.test:8888/tests/docshell/test/navigation/";
const TRIGGERINGPRINCIPALURI = BASEURL1 + "file_triggeringprincipal_frame_1.html";
const LOADINGPRINCIPALURI = BASEURL2 + "file_triggeringprincipal_frame_2.html";
SimpleTest.waitForExplicitFinish();
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
is(event.data.triggeringPrincipalURI, TRIGGERINGPRINCIPALURI,
"TriggeringPrincipal should be the navigating iframe (Frame 1)");
is(event.data.loadingPrincipalURI, LOADINGPRINCIPALURI,
"LoadingPrincipal should be the enclosing iframe (Frame 2)");
is(event.data.referrerURI, TRIGGERINGPRINCIPALURI,
"Referrer and TriggeringPrincipal should be identical (Frame 1)");
window.removeEventListener("message", receiveMessage, false);
SimpleTest.finish();
}
var frame1 = document.getElementById("testframe1");
frame1.src = BASEURL1 + "file_triggeringprincipal_frame_1.html";
var frame2 = document.getElementById("testframe2");
frame2.src = BASEURL2 + "file_triggeringprincipal_frame_2.html";
</script>
</body>
</html>

View File

@ -701,8 +701,8 @@ void
Element::Scroll(double aXScroll, double aYScroll)
{
// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
CSSIntPoint scrollPos(mozilla::ToZeroIfNonfinite(aXScroll),
mozilla::ToZeroIfNonfinite(aYScroll));
auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
mozilla::ToZeroIfNonfinite(aYScroll));
Scroll(scrollPos, ScrollOptions());
}
@ -741,8 +741,8 @@ Element::ScrollBy(double aXScrollDif, double aYScrollDif)
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
scrollPos += CSSIntPoint(mozilla::ToZeroIfNonfinite(aXScrollDif),
mozilla::ToZeroIfNonfinite(aYScrollDif));
scrollPos += CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),
mozilla::ToZeroIfNonfinite(aYScrollDif));
Scroll(scrollPos, ScrollOptions());
}
}

View File

@ -1332,12 +1332,17 @@ Navigator::SendBeacon(const nsAString& aUrl,
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL |
nsIChannel::LOAD_CLASSIFY_URI;
// No need to use CORS for sendBeacon unless it's a BLOB
nsSecurityFlags securityFlags = (!aData.IsNull() && aData.Value().IsBlob())
? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel),
uri,
doc,
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
nsILoadInfo::SEC_COOKIES_INCLUDE,
securityFlags,
nsIContentPolicy::TYPE_BEACON,
nullptr, // aLoadGroup
nullptr, // aCallbacks

View File

@ -2808,7 +2808,7 @@ CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredR
transform.HasNonIntegerTranslation())
return false;
transform.NudgeToIntegers();
nsIntPoint offset = aOffset + nsIntPoint(transform._31, transform._32);
IntPoint offset = aOffset + IntPoint::Truncate(transform._31, transform._32);
Layer* child = aLayer->GetFirstChild();
if (child) {

View File

@ -7724,8 +7724,8 @@ void
nsGlobalWindow::Scroll(double aXScroll, double aYScroll)
{
// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
CSSIntPoint scrollPos(mozilla::ToZeroIfNonfinite(aXScroll),
mozilla::ToZeroIfNonfinite(aYScroll));
auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
mozilla::ToZeroIfNonfinite(aYScroll));
ScrollTo(scrollPos, ScrollOptions());
}
@ -7733,8 +7733,8 @@ void
nsGlobalWindow::ScrollTo(double aXScroll, double aYScroll)
{
// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
CSSIntPoint scrollPos(mozilla::ToZeroIfNonfinite(aXScroll),
mozilla::ToZeroIfNonfinite(aYScroll));
auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
mozilla::ToZeroIfNonfinite(aYScroll));
ScrollTo(scrollPos, ScrollOptions());
}
@ -7803,8 +7803,8 @@ nsGlobalWindow::ScrollBy(double aXScrollDif, double aYScrollDif)
if (sf) {
// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
CSSIntPoint scrollDif(mozilla::ToZeroIfNonfinite(aXScrollDif),
mozilla::ToZeroIfNonfinite(aYScrollDif));
auto scrollDif = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),
mozilla::ToZeroIfNonfinite(aYScrollDif));
// It seems like it would make more sense for ScrollBy to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.

View File

@ -133,46 +133,58 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
// push/replaceState) matches the principal's URI, use the document's
// current URI as the referrer. If they don't match, use the principal's
// URI.
//
// The triggering principal for this load should be the principal of the
// incumbent document (which matches where the referrer information is
// coming from) when there is an incumbent document, and the subject
// principal otherwise. Note that the URI in the triggering principal
// may not match the referrer URI in various cases, notably including
// the cases when the incumbent document's document URI was modified
// after the document was loaded.
nsCOMPtr<nsIDocument> doc;
nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI, principalURI;
nsCOMPtr<nsPIDOMWindowInner> incumbent =
do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
if (incumbent) {
doc = incumbent->GetDoc();
}
nsCOMPtr<nsIDocument> doc = incumbent ? incumbent->GetDoc() : nullptr;
if (doc) {
nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI, principalURI;
docOriginalURI = doc->GetOriginalURI();
docCurrentURI = doc->GetDocumentURI();
rv = doc->NodePrincipal()->GetURI(getter_AddRefs(principalURI));
NS_ENSURE_SUCCESS(rv, rv);
owner = doc->NodePrincipal();
referrerPolicy = doc->GetReferrerPolicy();
}
bool urisEqual = false;
if (docOriginalURI && docCurrentURI && principalURI) {
principalURI->Equals(docOriginalURI, &urisEqual);
}
if (urisEqual) {
sourceURI = docCurrentURI;
}
else {
// Use principalURI as long as it is not an nsNullPrincipalURI.
// We could add a method such as GetReferrerURI to principals to make this
// cleaner, but given that we need to start using Source Browsing Context
// for referrer (see Bug 960639) this may be wasted effort at this stage.
if (principalURI) {
bool isNullPrincipalScheme;
rv = principalURI->SchemeIs(NS_NULLPRINCIPAL_SCHEME,
&isNullPrincipalScheme);
if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
sourceURI = principalURI;
bool urisEqual = false;
if (docOriginalURI && docCurrentURI && principalURI) {
principalURI->Equals(docOriginalURI, &urisEqual);
}
if (urisEqual) {
sourceURI = docCurrentURI;
}
else {
// Use principalURI as long as it is not an nsNullPrincipalURI.
// We could add a method such as GetReferrerURI to principals to make this
// cleaner, but given that we need to start using Source Browsing Context
// for referrer (see Bug 960639) this may be wasted effort at this stage.
if (principalURI) {
bool isNullPrincipalScheme;
rv = principalURI->SchemeIs(NS_NULLPRINCIPAL_SCHEME,
&isNullPrincipalScheme);
if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
sourceURI = principalURI;
}
}
}
}
owner = nsContentUtils::SubjectPrincipal();
else {
// No document; determine triggeringPrincipal by quering the
// subjectPrincipal, wich is the principal of the current JS
// compartment, or a null principal in case there is no
// compartment yet.
owner = nsContentUtils::SubjectPrincipal();
}
}
// Create load info

View File

@ -4820,8 +4820,8 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
// Scale the image size to the dest rect, and adjust the source rect to match.
gfxSize scale(aDest.width / aSrc.width, aDest.height / aSrc.height);
nsIntSize scaledImageSize(std::ceil(aImgSize.width * scale.width),
std::ceil(aImgSize.height * scale.height));
IntSize scaledImageSize = IntSize::Ceil(aImgSize.width * scale.width,
aImgSize.height * scale.height);
aSrc.Scale(scale.width, scale.height);
// We're wrapping tempTarget's (our) DrawTarget here, so we need to restore
@ -5045,7 +5045,7 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& aWindow, double aX,
matrix._22, matrix._31, matrix._32));
} else {
drawDT =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(ceil(sw), ceil(sh)),
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize::Ceil(sw, sh),
SurfaceFormat::B8G8R8A8);
if (!drawDT || !drawDT->IsValid()) {
aError.Throw(NS_ERROR_FAILURE);

View File

@ -60,10 +60,10 @@ nsresult RawReader::ReadMetadata(MediaInfo* aInfo,
// Determine and verify frame display size.
float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) /
mMetadata.aspectDenominator;
nsIntSize display(mMetadata.frameWidth, mMetadata.frameHeight);
nsIntSize display(uint32_t(mMetadata.frameWidth), uint32_t(mMetadata.frameHeight));
ScaleDisplayByAspectRatio(display, pixelAspectRatio);
mPicture = nsIntRect(0, 0, mMetadata.frameWidth, mMetadata.frameHeight);
nsIntSize frameSize(mMetadata.frameWidth, mMetadata.frameHeight);
nsIntSize frameSize(uint32_t(mMetadata.frameWidth), uint32_t(mMetadata.frameHeight));
if (!IsValidVideoRegion(frameSize, mPicture, display)) {
// Video track's frame sizes will overflow. Fail.
return NS_ERROR_FAILURE;

View File

@ -181,7 +181,7 @@ AttachToContainerAsSurfaceTexture(ImageContainer* container,
RefPtr<Image> img = new SurfaceTextureImage(
surfTex,
gfx::IntSize(rect.width, rect.height),
gfx::IntSize::Truncate(rect.width, rect.height),
instance->OriginPos());
*out_image = img;
}
@ -222,7 +222,7 @@ nsPluginInstanceOwner::GetImageContainer()
// into, set y-flip flags, etc, so we do this at the beginning.
float resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution)).Size();
mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
mInstance->NotifySize(nsIntSize::Truncate(screenSize.width, screenSize.height));
container = LayerManager::CreateImageContainer();
@ -1584,7 +1584,7 @@ nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInf
RefPtr<Image> img = new SurfaceTextureImage(
aVideoInfo->mSurfaceTexture,
gfx::IntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height),
gfx::IntSize::Truncate(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height),
gl::OriginPos::BottomLeft);
container->SetCurrentImageInTransaction(img);

View File

@ -147,7 +147,7 @@ SVGFETurbulenceElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
gfxPoint offset = firstPeriodInFilterSpace.TopLeft();
FilterPrimitiveDescription descr(PrimitiveType::Turbulence);
descr.Attributes().Set(eTurbulenceOffset, IntPoint(offset.x, offset.y));
descr.Attributes().Set(eTurbulenceOffset, IntPoint::Truncate(offset.x, offset.y));
descr.Attributes().Set(eTurbulenceBaseFrequency, frequencyInFilterSpace);
descr.Attributes().Set(eTurbulenceSeed, seed);
descr.Attributes().Set(eTurbulenceNumOctaves, octaves);

View File

@ -1,52 +0,0 @@
/*
* TestSever customized specifically for the needs of:
* Bug 1111834 - sendBeacon() should not follow 30x redirect after preflight
*
* Here is a sequence of the test:
* [1] preflight channel (identified by the queryString 'beacon' and method 'OPTIONS')
* [2] actual channel (identified by the queryString 'beacon') which gets redirected
* [3] should never happen (the actual redirected request)
* [4] xhr request (identified by the queryString 'verifyRedirectDidNotSucceed')
* which checks if the state was not changed from 'green' to 'red'. If the channel
* woulnd't be blocked correctly the redirected channel would set the state to 'red'.
*
*/
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache, must-revalidate", false);
// [Sequence 4]
if (request.queryString === "verifyRedirectDidNotSucceed") {
var redirectState = getState("redirectState");
response.write(redirectState);
return;
}
var originHeader = request.getHeader("origin");
response.setHeader("Cache-Control", "no-cache, must-revalidate", false);
response.setHeader("Access-Control-Allow-Headers", "content-type", false);
response.setHeader("Access-Control-Allow-Methods", "POST, GET", false);
response.setHeader("Access-Control-Allow-Origin", originHeader, false);
response.setHeader("Access-Control-Allow-Credentials", "true", false);
// [Sequence 1,2]
if (request.queryString === "beacon") {
setState("redirectState", "green");
// [1]
if (request.method == "OPTIONS") {
response.setStatusLine(null, 200, "OK");
return;
}
// [Sequence 2]
var newLocation =
"http://mochi.test:8888/tests/dom/tests/mochitest/beacon/beacon-cors-redirect-handler.sjs?redirected";
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", newLocation, false);
return;
}
// [Sequence 3]
setState("redirectState", "red");
response.setStatusLine(null, 200, "OK");
}

View File

@ -1,6 +1,6 @@
/*
* TestSever customized specifically for the needs of:
* Bug 1080987 - navigator.sendBeacon() needs to sent origin header
* Bug 1280692 - navigator.sendBeacon() should not send origin header
*/
function handleRequest(request, response)
@ -26,9 +26,16 @@ function handleRequest(request, response)
// case BEACON-REQUEST: get the beacon header and
// store the header on the server.
var header = request.getHeader("origin");
var header = "reset";
try {
header = request.getHeader("origin");
}
catch(e) {
header = "no-header";
}
setState("originHeader", header);
// if there is an xhr-request waiting, return the header now.
getObjectState("xhr-response", function(xhrResponse) {
if (!xhrResponse) {

View File

@ -0,0 +1,47 @@
/*
* TestSever customized specifically for the needs of:
* Bug 1280692 - sendBeacon() should follow 30x redirect
*
* Here is a sequence of the test:
* [1] sendBeacon (identified by the queryString 'beacon') which gets redirected
* [2] redirected sendBeacon (identified by the queryString 'redirected') which
* updates the state idniciating that redirected sendBeacon succeeds.
* [3] xhr request (identified by the queryString 'verifyRedirectDidSucceed')
* which checks if the state was not changed from 'reset' to 'gree'. If the channel
* woulnd't be blocked correctly the redirected channel would set the state to 'red'.
*
*/
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache, must-revalidate", false);
// [Sequence 3]
if (request.queryString === "verifyRedirectDidSucceed") {
var redirectState = getState("redirectState");
response.write(redirectState);
return;
}
// [Sequence 1]
if (request.queryString === "beacon") {
setState("redirectState", "reset");
var newLocation =
"http://mochi.test:8888/tests/dom/tests/mochitest/beacon/beacon-redirect-handler.sjs?redirected";
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", newLocation, false);
return;
}
// [Sequence 2]
if (request.queryString === "redirected") {
setState("redirectState", "green");
response.setStatusLine(null, 200, "OK");
return;
}
// we should never get here, but just in case let's
// set the state to something unexpected
setState("redirectState", "red");
response.setStatusLine(null, 200, "OK");
}

View File

@ -4,13 +4,11 @@ support-files = beacon-frame.html
beacon-handler.sjs
beacon-preflight-handler.sjs
beacon-originheader-handler.sjs
beacon-cors-redirect-handler.sjs
beacon-redirect-handler.sjs
[test_beacon.html]
[test_beaconFrame.html]
[test_beaconPreflight.html]
[test_beaconPreflightFailure.html]
[test_beaconPreflightWithCustomContentType.html]
[test_beaconContentPolicy.html]
[test_beaconOriginHeader.html]
[test_beaconCORSRedirect.html]
[test_beaconRedirect.html]

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1080987 - navigator.sendBeacon() needs to sent origin header</title>
<title>Bug 1280692 - navigator.sendBeacon() should not send origin header</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
@ -17,18 +17,21 @@
SimpleTest.waitForExplicitFinish();
const BEACON_URL = "http://example.com/tests/dom/tests/mochitest/beacon/beacon-originheader-handler.sjs";
const ORIGIN_HEADER = "http://mochi.test:8888";
// no origin header should be sent with sendBeacon request;
// server returns any origin-header or 'no-header' if there is no header sent.
const ORIGIN_HEADER = "no-header";
/* Description of the test:
* We call sendBeacon() cross origin and make sure that the
* origin header is actually set in the request.
* origin header is actually *not* set in the request.
*
* Since sendBeacon() does not expect any response, we are storing the
* Since sendBeacon() does not expect any response, we are storing any
* header on the server (*.sjs) and use an XMLHttpRequest to actually
* retrieve the header back from the server. We assert that the header
* is indeed correct. Since sendBeacon() and also the XMLHttpRequest()
* are performed in an asynchronous fashion, there is no guarantee that
* the sendBeacon() is actually executed before the XMLHttpRequest().
* retrieve the potentially set header back from the server. We assert
* that the header is indeed *not* sent with the request. Since sendBeacon()
* and also the XMLHttpRequest() are performed in an asynchronous fashion,
* there is no guarantee that the sendBeacon() is actually executed before
* the XMLHttpRequest().
* Hence the xhr-response might be processed asynchronously.
*/
@ -38,7 +41,7 @@ function queryHeaderFromServer() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "beacon-originheader-handler.sjs?queryheader", true);
xhr.onload = function() {
is(xhr.responseText, ORIGIN_HEADER, "SendBeacon sends right origin header");
is(xhr.responseText, ORIGIN_HEADER, "SendBeacon should not send origin header");
SimpleTest.finish();
};
xhr.onerror = function() {

View File

@ -1,56 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=936340
-->
<head>
<title>Test for Bug 936340</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=936340">Mozilla Bug 936340</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var beaconUrl = "http://example.com/tests/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs?beacon";
var intervalID = null;
function queryIfBeaconSucceeded() {
clearInterval(intervalID);
var xhr = new XMLHttpRequest();
xhr.open("GET", "beacon-preflight-handler.sjs?verify", true);
xhr.onload = function() {
is(xhr.responseText, "green", "SendBeacon should have succeeded after preflight!");
SimpleTest.finish();
};
xhr.onerror = function() {
ok(false, "xhr request returned error");
SimpleTest.finish();
};
xhr.send();
}
// not enabled by default yet.
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({'set': [["beacon.enabled", true]]}, beginTest);
function beginTest() {
var abv = new Uint8Array([0,1,2,3]);
var sent = navigator.sendBeacon(beaconUrl, abv);
ok(sent, "sending the beacon should start successfully");
// we have to make sure sending the beacon did not fail, so
// we have to wait for 2 seconds before we can query the result.
intervalID = setInterval(queryIfBeaconSucceeded, 2000);
}
</script>
</pre>
</body>
</html>

View File

@ -1,56 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1207556
-->
<head>
<title>Test for Bug 1207556</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1207556">Mozilla Bug 1207556</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var beaconUrl = "http://example.com/tests/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs?fail";
var intervalID = null;
function queryIfBeaconSucceeded() {
clearInterval(intervalID);
var xhr = new XMLHttpRequest();
xhr.open("GET", "beacon-preflight-handler.sjs?verify", true);
xhr.onload = function() {
is(xhr.responseText, "green", "SendBeacon should have failed because of a failed preflight!");
SimpleTest.finish();
};
xhr.onerror = function() {
ok(false, "xhr request returned error");
SimpleTest.finish();
};
xhr.send();
}
// not enabled by default yet.
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({'set': [["beacon.enabled", true]]}, beginTest);
function beginTest() {
var abv = new Uint8Array([0,1,2,3]);
var sent = navigator.sendBeacon(beaconUrl, abv);
ok(sent, "sending the beacon should start successfully");
// we have to make sure sending the beacon did not fail, so
// we have to wait for 2 seconds before we can query the result.
intervalID = setInterval(queryIfBeaconSucceeded, 2000);
}
</script>
</pre>
</body>
</html>

View File

@ -1,7 +1,7 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1111834 - sendBeacon() should not follow 30x redirect after preflight</title>
<title>Bug 1280692 - sendBeacon() should follow 30x redirect</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
@ -15,13 +15,13 @@
<script class="testbody" type="text/javascript">
/* Description of the test:
* We do perform a non simple sendBeacon request. After the preflight channel returns correctly
* the actual channel is about to follow a 30x cross origin redirect, which is forbidden by the spec.
* We do perform a non simple sendBeacon request which should not use CORS and should follow
* a 30x cross origin redirect, which is allowed by the spec.
*/
SimpleTest.waitForExplicitFinish();
const BEACON_URL = "http://example.com/tests/dom/tests/mochitest/beacon/beacon-cors-redirect-handler.sjs?beacon";
const BEACON_URL = "http://example.com/tests/dom/tests/mochitest/beacon/beacon-redirect-handler.sjs?beacon";
SpecialPowers.pushPrefEnv({'set': [["beacon.enabled", true]]}, runTest);
@ -30,9 +30,9 @@ var intervalID = null;
function queryIfRedirectSucceeded() {
clearInterval(intervalID);
var xhr = new XMLHttpRequest();
xhr.open("GET", "beacon-cors-redirect-handler.sjs?verifyRedirectDidNotSucceed", true);
xhr.open("GET", "beacon-redirect-handler.sjs?verifyRedirectDidSucceed", true);
xhr.onload = function() {
is(xhr.responseText, "green", "SendBeacon does not follow cross origin redirects after preflight!");
is(xhr.responseText, "green", "SendBeacon should follow cross origin redirects!");
SimpleTest.finish();
};
xhr.onerror = function() {
@ -46,7 +46,7 @@ function runTest() {
var data = new Uint8Array([0,1,2,3]);
navigator.sendBeacon(BEACON_URL, data);
// we have to make sure the channel did not follow the redirect hence
// we have to make sure the channel did follow the redirect hence
// we have to wait for 2 seconds before we can query the result.
intervalID = setInterval(queryIfRedirectSucceeded, 2000);
}

View File

@ -339,7 +339,7 @@ DrawTargetD2D1::MaskSurface(const Pattern &aSource,
return;
}
IntSize size = IntSize(bitmap->GetSize().width, bitmap->GetSize().height);
IntSize size = IntSize::Truncate(bitmap->GetSize().width, bitmap->GetSize().height);
Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));

View File

@ -538,7 +538,7 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
SkPaint shadowPaint;
shadowPaint.setXfermodeMode(GfxOpToSkiaOp(aOperator));
IntPoint shadowDest = RoundedToInt(aDest + aOffset);
auto shadowDest = IntPoint::Round(aDest + aOffset);
SkBitmap blurMask;
if (!UsingSkiaGPU() &&
@ -569,7 +569,7 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
}
// Composite the original image after the shadow
IntPoint dest = RoundedToInt(aDest);
auto dest = IntPoint::Round(aDest);
mCanvas->drawBitmap(bitmap, dest.x, dest.y, &paint);
mCanvas->restore();

View File

@ -33,6 +33,36 @@ template<> struct IsPixel<gfx::UnknownUnits> : TrueType {};
namespace gfx {
/// Use this for parameters of functions to allow implicit conversions to
/// integer types but not floating point types.
/// We use this wrapper to prevent IntSize and IntPoint's constructors to
/// take foating point values as parameters, and not require their constructors
/// to have implementations for each permutation of integer types.
template<typename T>
struct IntParam {
constexpr MOZ_IMPLICIT IntParam(char val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(unsigned char val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(short val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(unsigned short val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(int val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(unsigned int val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(long val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(unsigned long val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(long long val) : value(val) {}
constexpr MOZ_IMPLICIT IntParam(unsigned long long val) : value(val) {}
template<typename Unit>
constexpr MOZ_IMPLICIT IntParam(IntCoordTyped<Unit> val) : value(val) {}
// Disable the evil ones!
MOZ_IMPLICIT IntParam(float val) = delete;
MOZ_IMPLICIT IntParam(double val) = delete;
T value;
};
template<class units, class> struct PointTyped;
template<class units, class> struct SizeTyped;
template<class units>
struct IntPointTyped :
public BasePoint< int32_t, IntPointTyped<units>, IntCoordTyped<units> >,
@ -40,16 +70,33 @@ struct IntPointTyped :
static_assert(IsPixel<units>::value,
"'units' must be a coordinate system tag");
typedef IntParam<int32_t> ToInt;
typedef IntCoordTyped<units> Coord;
typedef BasePoint< int32_t, IntPointTyped<units>, IntCoordTyped<units> > Super;
constexpr IntPointTyped() : Super() {}
constexpr IntPointTyped(int32_t aX, int32_t aY) : Super(Coord(aX), Coord(aY)) {}
// The mixed-type constructors (int, Coord) and (Coord, int) are needed to
// avoid ambiguities because Coord is implicitly convertible to int.
constexpr IntPointTyped(int32_t aX, Coord aY) : Super(Coord(aX), aY) {}
constexpr IntPointTyped(Coord aX, int32_t aY) : Super(aX, Coord(aY)) {}
constexpr IntPointTyped(Coord aX, Coord aY) : Super(aX, aY) {}
constexpr IntPointTyped(ToInt aX, ToInt aY) : Super(Coord(aX.value), Coord(aY.value)) {}
static IntPointTyped<units> Round(float aX, float aY) {
return IntPointTyped(int32_t(floorf(aX + 0.5)), int32_t(floorf(aY + 0.5)));
}
static IntPointTyped<units> Ceil(float aX, float aY) {
return IntPointTyped(int32_t(ceil(aX)), int32_t(ceil(aY)));
}
static IntPointTyped<units> Floor(float aX, float aY) {
return IntPointTyped(int32_t(floorf(aX)), int32_t(floorf(aY)));
}
static IntPointTyped<units> Truncate(float aX, float aY) {
return IntPointTyped(int32_t(aX), int32_t(aY));
}
static IntPointTyped<units> Round(const PointTyped<units, float>& aPoint);
static IntPointTyped<units> Ceil(const PointTyped<units, float>& aPoint);
static IntPointTyped<units> Floor(const PointTyped<units, float>& aPoint);
static IntPointTyped<units> Truncate(const PointTyped<units, float>& aPoint);
// XXX When all of the code is ported, the following functions to convert to and from
// unknown types should be removed.
@ -99,14 +146,12 @@ typedef PointTyped<UnknownUnits, double> PointDouble;
template<class units>
IntPointTyped<units> RoundedToInt(const PointTyped<units>& aPoint) {
return IntPointTyped<units>(int32_t(floorf(aPoint.x + 0.5f)),
int32_t(floorf(aPoint.y + 0.5f)));
return IntPointTyped<units>::Round(aPoint.x, aPoint.y);
}
template<class units>
IntPointTyped<units> TruncatedToInt(const PointTyped<units>& aPoint) {
return IntPointTyped<units>(int32_t(aPoint.x),
int32_t(aPoint.y));
return IntPointTyped<units>::Truncate(aPoint.x, aPoint.y);
}
template<class units, class F = Float>
@ -134,6 +179,34 @@ struct Point3DTyped :
typedef Point3DTyped<UnknownUnits> Point3D;
typedef Point3DTyped<UnknownUnits, double> PointDouble3D;
template<typename units>
IntPointTyped<units>
IntPointTyped<units>::Round(const PointTyped<units, float>& aPoint)
{
return IntPointTyped::Round(aPoint.x, aPoint.y);
}
template<typename units>
IntPointTyped<units>
IntPointTyped<units>::Ceil(const PointTyped<units, float>& aPoint)
{
return IntPointTyped::Ceil(aPoint.x, aPoint.y);
}
template<typename units>
IntPointTyped<units>
IntPointTyped<units>::Floor(const PointTyped<units, float>& aPoint)
{
return IntPointTyped::Floor(aPoint.x, aPoint.y);
}
template<typename units>
IntPointTyped<units>
IntPointTyped<units>::Truncate(const PointTyped<units, float>& aPoint)
{
return IntPointTyped::Truncate(aPoint.x, aPoint.y);
}
template<class units, class F = Float>
struct Point4DTyped :
public BasePoint4D< F, Point4DTyped<units, F> > {
@ -170,10 +243,32 @@ struct IntSizeTyped :
static_assert(IsPixel<units>::value,
"'units' must be a coordinate system tag");
typedef IntParam<int32_t> ToInt;
typedef BaseSize< int32_t, IntSizeTyped<units> > Super;
constexpr IntSizeTyped() : Super() {}
constexpr IntSizeTyped(int32_t aWidth, int32_t aHeight) : Super(aWidth, aHeight) {}
constexpr IntSizeTyped(ToInt aWidth, ToInt aHeight) : Super(aWidth.value, aHeight.value) {}
static IntSizeTyped<units> Round(float aWidth, float aHeight) {
return IntSizeTyped(int32_t(floorf(aWidth + 0.5)), int32_t(floorf(aHeight + 0.5)));
}
static IntSizeTyped<units> Truncate(float aWidth, float aHeight) {
return IntSizeTyped(int32_t(aWidth), int32_t(aHeight));
}
static IntSizeTyped<units> Ceil(float aWidth, float aHeight) {
return IntSizeTyped(int32_t(ceil(aWidth)), int32_t(ceil(aHeight)));
}
static IntSizeTyped<units> Floor(float aWidth, float aHeight) {
return IntSizeTyped(int32_t(floorf(aWidth)), int32_t(floorf(aHeight)));
}
static IntSizeTyped<units> Round(const SizeTyped<units, float>& aSize);
static IntSizeTyped<units> Ceil(const SizeTyped<units, float>& aSize);
static IntSizeTyped<units> Floor(const SizeTyped<units, float>& aSize);
static IntSizeTyped<units> Truncate(const SizeTyped<units, float>& aSize);
// XXX When all of the code is ported, the following functions to convert to and from
// unknown types should be removed.
@ -222,6 +317,26 @@ IntSizeTyped<units> RoundedToInt(const SizeTyped<units>& aSize) {
int32_t(floorf(aSize.height + 0.5f)));
}
template<typename units> IntSizeTyped<units>
IntSizeTyped<units>::Round(const SizeTyped<units, float>& aSize) {
return IntSizeTyped::Round(aSize.width, aSize.height);
}
template<typename units> IntSizeTyped<units>
IntSizeTyped<units>::Ceil(const SizeTyped<units, float>& aSize) {
return IntSizeTyped::Ceil(aSize.width, aSize.height);
}
template<typename units> IntSizeTyped<units>
IntSizeTyped<units>::Floor(const SizeTyped<units, float>& aSize) {
return IntSizeTyped::Floor(aSize.width, aSize.height);
}
template<typename units> IntSizeTyped<units>
IntSizeTyped<units>::Truncate(const SizeTyped<units, float>& aSize) {
return IntSizeTyped::Truncate(aSize.width, aSize.height);
}
} // namespace gfx
} // namespace mozilla

View File

@ -22,7 +22,7 @@ SharedSurface_IOSurface::Create(const RefPtr<MacIOSurface>& ioSurf,
MOZ_ASSERT(ioSurf);
MOZ_ASSERT(gl);
gfx::IntSize size(ioSurf->GetWidth(), ioSurf->GetHeight());
auto size = gfx::IntSize::Truncate(ioSurf->GetWidth(), ioSurf->GetHeight());
typedef SharedSurface_IOSurface ptrT;
UniquePtr<ptrT> ret( new ptrT(ioSurf, gl, size, hasAlpha) );
@ -214,8 +214,8 @@ SurfaceFactory_IOSurface::Create(GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::ClientIPCAllocator>& allocator,
const layers::TextureFlags& flags)
{
gfx::IntSize maxDims(MacIOSurface::GetMaxWidth(),
MacIOSurface::GetMaxHeight());
auto maxDims = gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(),
MacIOSurface::GetMaxHeight());
typedef SurfaceFactory_IOSurface ptrT;
UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, maxDims) );

View File

@ -631,7 +631,7 @@ Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
if (aTransform.CanDraw2D(&matrix2D) &&
!matrix2D.HasNonTranslation() &&
matrix2D.HasNonIntegerTranslation()) {
IntPoint snappedTranslation = RoundedToInt(matrix2D.GetTranslation());
auto snappedTranslation = IntPoint::Round(matrix2D.GetTranslation());
Matrix snappedMatrix = Matrix::Translation(snappedTranslation.x,
snappedTranslation.y);
result = Matrix4x4::From2D(snappedMatrix);
@ -663,8 +663,7 @@ Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
// Compute the transformed snap by rounding the values of
// transformed origin.
IntPoint transformedSnapXY =
RoundedToInt(Point(transformedOrigin.x, transformedOrigin.y));
auto transformedSnapXY = IntPoint::Round(transformedOrigin.x, transformedOrigin.y);
Matrix4x4 inverse = aTransform;
inverse.Invert();
// see Matrix4x4::ProjectPoint()
@ -722,9 +721,9 @@ Layer::SnapTransform(const Matrix4x4& aTransform,
aTransform.Is2D(&matrix2D) &&
gfxSize(1.0, 1.0) <= aSnapRect.Size() &&
matrix2D.PreservesAxisAlignedRectangles()) {
IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft()));
IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight()));
IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight()));
auto transformedTopLeft = IntPoint::Round(matrix2D * ToPoint(aSnapRect.TopLeft()));
auto transformedTopRight = IntPoint::Round(matrix2D * ToPoint(aSnapRect.TopRight()));
auto transformedBottomRight = IntPoint::Round(matrix2D * ToPoint(aSnapRect.BottomRight()));
Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
transformedTopLeft, transformedTopRight, transformedBottomRight);
@ -1028,7 +1027,7 @@ Layer::TransformRectToRenderTarget(const LayerIntRect& aRect)
bool
Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
nsIntPoint* aLayerOffset)
IntPoint* aLayerOffset)
{
MOZ_ASSERT(aLayerOffset, "invalid offset pointer");
@ -1046,7 +1045,7 @@ Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
}
// The offset of |layer| to its parent.
IntPoint currentLayerOffset = RoundedToInt(matrix.GetTranslation());
auto currentLayerOffset = IntPoint::Round(matrix.GetTranslation());
// Translate the accumulated visible region of |this| by the offset of
// |layer|.
@ -1073,7 +1072,7 @@ Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
// Retreive the translation from sibling to |layer|. The accumulated
// visible region is currently oriented with |layer|.
IntPoint siblingOffset = RoundedToInt(siblingMatrix.GetTranslation());
auto siblingOffset = IntPoint::Round(siblingMatrix.GetTranslation());
nsIntRegion siblingVisibleRegion(sibling->GetLocalVisibleRegion().ToUnknownRegion());
// Translate the siblings region to |layer|'s origin.
siblingVisibleRegion.MoveBy(-siblingOffset.x, -siblingOffset.y);
@ -1092,7 +1091,7 @@ Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
offset += currentLayerOffset;
}
*aLayerOffset = nsIntPoint(offset.x, offset.y);
*aLayerOffset = IntPoint(offset.x, offset.y);
return true;
}

View File

@ -1387,7 +1387,7 @@ public:
* visible regions of higher siblings of this layer and each ancestor.
*
* Note translation values for offsets of visible regions and accumulated
* aLayerOffset are integer rounded using Point's RoundedToInt.
* aLayerOffset are integer rounded using IntPoint::Round.
*
* @param aResult - the resulting visible region of this layer.
* @param aLayerOffset - this layer's total offset from the root layer.

View File

@ -36,7 +36,7 @@ CreateSourceSurfaceFromLockedMacIOSurface(MacIOSurface* aSurface)
: SurfaceFormat::B8G8R8A8;
RefPtr<DataSourceSurface> dataSurface =
Factory::CreateDataSourceSurface(IntSize(ioWidth, ioHeight), format);
Factory::CreateDataSourceSurface(IntSize::Truncate(ioWidth, ioHeight), format);
if (NS_WARN_IF(!dataSurface)) {
return nullptr;
}
@ -75,14 +75,14 @@ CreateSourceSurfaceFromLockedMacIOSurface(MacIOSurface* aSurface)
PlanarYCbCrData data;
data.mYChannel = (uint8_t*)aSurface->GetBaseAddressOfPlane(0);
data.mYStride = aSurface->GetBytesPerRow(0);
data.mYSize = IntSize(ioWidth, ioHeight);
data.mYSize = IntSize::Truncate(ioWidth, ioHeight);
data.mCbChannel = cbPlane.get();
data.mCrChannel = crPlane.get();
data.mCbCrStride = cbCrWidth;
data.mCbCrSize = IntSize(cbCrWidth, cbCrHeight);
data.mCbCrSize = IntSize::Truncate(cbCrWidth, cbCrHeight);
data.mPicSize = data.mYSize;
ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize::Truncate(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
} else if (ioFormat == SurfaceFormat::YUV422) {
/* Convert to YV16 */
size_t cbCrWidth = (ioWidth+1)>>1;
@ -128,14 +128,14 @@ CreateSourceSurfaceFromLockedMacIOSurface(MacIOSurface* aSurface)
PlanarYCbCrData data;
data.mYChannel = ALIGNEDPTR_32(yPlane.get());
data.mYStride = cbCrStride * 2;
data.mYSize = IntSize(ioWidth, ioHeight);
data.mYSize = IntSize::Truncate(ioWidth, ioHeight);
data.mCbChannel = ALIGNEDPTR_32(cbPlane.get());
data.mCrChannel = ALIGNEDPTR_32(crPlane.get());
data.mCbCrStride = cbCrStride;
data.mCbCrSize = IntSize(cbCrWidth, cbCrHeight);
data.mCbCrSize = IntSize::Truncate(cbCrWidth, cbCrHeight);
data.mPicSize = data.mYSize;
ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize::Truncate(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
} else {
unsigned char* ioData = (unsigned char*)aSurface->GetBaseAddress();

View File

@ -25,7 +25,8 @@ public:
MacIOSurface* GetSurface() { return mSurface; }
gfx::IntSize GetSize() override {
return gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
return gfx::IntSize::Truncate(mSurface->GetDevicePixelWidth(),
mSurface->GetDevicePixelHeight());
}
virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;

View File

@ -158,7 +158,7 @@ public:
const gfx::IntSize& GetTileSize() const { return mTileSize; }
gfx::IntSize GetScaledTileSize() const { return RoundedToInt(gfx::Size(mTileSize) / mResolution); }
gfx::IntSize GetScaledTileSize() const { return gfx::IntSize::Round(gfx::Size(mTileSize) / mResolution); }
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }

View File

@ -267,7 +267,7 @@ HitTestingTreeNode::HitTest(const ParentLayerPoint& aPoint) const
if (!pointInLayerPixels) {
return HitTestResult::HitNothing;
}
LayerIntPoint point = RoundedToInt(pointInLayerPixels.ref());
auto point = LayerIntPoint::Round(pointInLayerPixels.ref());
// test against event regions in Layer coordinate space
if (!mEventRegions.mHitRegion.Contains(point.x, point.y)) {

View File

@ -430,7 +430,7 @@ APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
{
LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
point = ApplyCallbackTransform(point / aScale, aGuid) * aScale;
return gfx::RoundedToInt(point);
return LayoutDeviceIntPoint::Round(point);
}
void
@ -471,7 +471,7 @@ APZCCallbackHelper::DispatchSynthesizedMouseEvent(EventMessage aMsg,
WidgetMouseEvent event(true, aMsg, aWidget,
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
event.mRefPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
event.mRefPoint = LayoutDeviceIntPoint::Truncate(aRefPoint.x, aRefPoint.y);
event.mTime = aTime;
event.button = WidgetMouseEvent::eLeftButton;
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;

View File

@ -256,7 +256,7 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIPresShell>& aPresShell,
// waiting for a touchend don't trigger.
WidgetTouchEvent cancelTouchEvent(true, eTouchCancel, widget.get());
cancelTouchEvent.mModifiers = WidgetModifiersToDOMModifiers(aModifiers);
LayoutDeviceIntPoint ldPoint = RoundedToInt(point * widget->GetDefaultScale());
auto ldPoint = LayoutDeviceIntPoint::Round(point * widget->GetDefaultScale());
cancelTouchEvent.mTouches.AppendElement(new mozilla::dom::Touch(mLastTouchIdentifier,
ldPoint, LayoutDeviceIntPoint(), 0, 0));
APZCCallbackHelper::DispatchWidgetEvent(cancelTouchEvent);

View File

@ -360,9 +360,9 @@ DrawSurfaceWithTextureCoords(DrawTarget *aDest,
// Compute a transform that maps sourceRect to aDestRect.
Matrix matrix =
gfxUtils::TransformRectToRect(sourceRect,
gfx::IntPoint(aDestRect.x, aDestRect.y),
gfx::IntPoint(aDestRect.XMost(), aDestRect.y),
gfx::IntPoint(aDestRect.XMost(), aDestRect.YMost()));
gfx::IntPoint::Truncate(aDestRect.x, aDestRect.y),
gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.y),
gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.YMost()));
// Only use REPEAT if aTextureCoords is outside (0, 0, 1, 1).
gfx::Rect unitRect(0, 0, 1, 1);
@ -626,7 +626,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
if (sourceMask) {
RefPtr<DrawTarget> transformDT =
dest->CreateSimilarDrawTarget(IntSize(transformBounds.width, transformBounds.height),
dest->CreateSimilarDrawTarget(IntSize::Truncate(transformBounds.width, transformBounds.height),
SurfaceFormat::B8G8R8A8);
new3DTransform.PostTranslate(-transformBounds.x, -transformBounds.y, 0);
if (transformDT &&

View File

@ -936,7 +936,7 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
RefPtr<SourceSurface> untransformedSurf = untransformedDT->Snapshot();
RefPtr<DrawTarget> xformDT =
untransformedDT->CreateSimilarDrawTarget(IntSize(xformBounds.width, xformBounds.height),
untransformedDT->CreateSimilarDrawTarget(IntSize::Truncate(xformBounds.width, xformBounds.height),
SurfaceFormat::B8G8R8A8);
RefPtr<SourceSurface> xformSurf;
if(xformDT && untransformedSurf &&

View File

@ -849,7 +849,12 @@ already_AddRefed<PersistentBufferProvider>
ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat)
{
if (gfxPrefs::PersistentBufferProviderSharedEnabled()) {
// Don't use a shared buffer provider if compositing is considered "not cheap"
// because the canvas will most likely be flattened into a thebes layer instead
// of being sent to the compositor, in which case rendering into shared memory
// is wasteful.
if (IsCompositingCheap() &&
gfxPrefs::PersistentBufferProviderSharedEnabled()) {
RefPtr<PersistentBufferProvider> provider
= PersistentBufferProviderShared::Create(aSize, aFormat, AsShadowForwarder());
if (provider) {

View File

@ -360,10 +360,11 @@ DeallocateTextureClient(TextureDeallocParams params)
void TextureClient::Destroy(bool aForceSync)
{
if (mActor) {
if (mActor && !mIsLocked) {
mActor->Lock();
}
mBorrowedDrawTarget = nullptr;
mReadLock = nullptr;
CancelWaitFenceHandleOnImageBridge();
@ -519,7 +520,9 @@ TextureClient::Unlock()
mUpdated = true;
}
mData->Unlock();
if (mData) {
mData->Unlock();
}
mIsLocked = false;
mOpenMode = OpenMode::OPEN_NONE;

View File

@ -726,7 +726,7 @@ CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
gfx::Matrix4x4 transform = aContainer->GetEffectiveTransform();
DebugOnly<gfx::Matrix> transform2d;
MOZ_ASSERT(transform.Is2D(&transform2d) && !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
sourcePoint += gfx::IntPoint(transform._41, transform._42);
sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42);
sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();

View File

@ -251,13 +251,13 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
// a giant layer if it is a leaf.
Matrix4x4 transform = GetAccTransformIn3DContext(aLayer);
Matrix transform2d;
Maybe<nsIntPoint> integerTranslation;
Maybe<IntPoint> integerTranslation;
// If aLayer has a simple transform (only an integer translation) then we
// can easily convert aOpaqueRegion into pre-transform coordinates and include
// that region.
if (transform.Is2D(&transform2d)) {
if (transform2d.IsIntegerTranslation()) {
integerTranslation = Some(TruncatedToInt(transform2d.GetTranslation()));
integerTranslation = Some(IntPoint::Truncate(transform2d.GetTranslation()));
localOpaque = aOpaqueRegion;
localOpaque.MoveBy(-*integerTranslation);
}

View File

@ -34,7 +34,7 @@ PrintTargetWindows::CreateOrNull(HDC aDC)
(::GetDeviceCaps(aDC, HORZRES) * POINTS_PER_INCH_FLOAT) / heightDPI;
float height =
(::GetDeviceCaps(aDC, VERTRES) * POINTS_PER_INCH_FLOAT) / heightDPI;
IntSize size(width, height);
IntSize size = IntSize::Truncate(width, height);
if (!Factory::CheckSurfaceSize(size)) {
return nullptr;

View File

@ -520,8 +520,8 @@ ClippedImage::OptimalImageSizeForDest(const gfxSize& aDest,
// First, we select a scale that's good for ClippedImage. An integer
// multiple of the size of the clipping region is always fine.
nsIntSize scale(ceil(aDest.width / mClip.width),
ceil(aDest.height / mClip.height));
IntSize scale = IntSize::Ceil(aDest.width / mClip.width,
aDest.height / mClip.height);
if (forceUniformScaling) {
scale.width = scale.height = max(scale.height, scale.width);
@ -537,8 +537,8 @@ ClippedImage::OptimalImageSizeForDest(const gfxSize& aDest,
// To get our final result, we take the inner image's desired size and
// determine how large the clipped region would be at that scale. (Again, we
// ensure an integer multiple of the size of the clipping region.)
nsIntSize finalScale(ceil(double(innerDesiredSize.width) / imgWidth),
ceil(double(innerDesiredSize.height) / imgHeight));
IntSize finalScale = IntSize::Ceil(double(innerDesiredSize.width) / imgWidth,
double(innerDesiredSize.height) / imgHeight);
return mClip.Size() * finalScale;
}

View File

@ -1823,7 +1823,7 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
return IntSize(0, 0);
}
IntSize destSize(ceil(aDest.width), ceil(aDest.height));
IntSize destSize = IntSize::Ceil(aDest.width, aDest.height);
if (aSamplingFilter == SamplingFilter::GOOD &&
CanDownscaleDuringDecode(destSize, aFlags)) {

View File

@ -1302,7 +1302,7 @@ VectorImage::OptimalImageSizeForDest(const gfxSize& aDest,
"Unexpected destination size");
// We can rescale SVGs freely, so just return the provided destination size.
return nsIntSize(ceil(aDest.width), ceil(aDest.height));
return nsIntSize::Ceil(aDest.width, aDest.height);
}
already_AddRefed<imgIContainer>

View File

@ -111,7 +111,6 @@ class AsmJSGlobal
Which which_;
union {
struct {
uint32_t globalDataOffset_;
VarInitKind initKind_;
union {
ValType importType_;
@ -150,10 +149,6 @@ class AsmJSGlobal
Which which() const {
return pod.which_;
}
uint32_t varGlobalDataOffset() const {
MOZ_ASSERT(pod.which_ == Variable);
return pod.u.var.globalDataOffset_;
}
VarInitKind varInitKind() const {
MOZ_ASSERT(pod.which_ == Variable);
return pod.u.var.initKind_;
@ -1447,7 +1442,6 @@ class MOZ_STACK_CLASS ModuleValidator
}
unsigned varOrConstIndex() const {
MOZ_ASSERT(which_ == Variable || which_ == ConstantImport);
MOZ_ASSERT(u.varOrConst.index_ != -1u);
return u.varOrConst.index_;
}
bool isConst() const {
@ -1851,7 +1845,7 @@ class MOZ_STACK_CLASS ModuleValidator
MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit)));
uint32_t index;
if (!mg_.allocateGlobal(type.canonicalToValType(), isConst, &index))
if (!mg_.addGlobal(type.canonicalToValType(), isConst, &index))
return false;
Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
@ -1868,7 +1862,6 @@ class MOZ_STACK_CLASS ModuleValidator
AsmJSGlobal g(AsmJSGlobal::Variable, nullptr);
g.pod.u.var.initKind_ = AsmJSGlobal::InitConstant;
g.pod.u.var.u.val_ = lit.value();
g.pod.u.var.globalDataOffset_ = mg_.global(index).globalDataOffset;
return asmJSMetadata_->asmJSGlobals.append(Move(g));
}
bool addGlobalVarImport(PropertyName* var, PropertyName* field, Type type, bool isConst) {
@ -1880,7 +1873,7 @@ class MOZ_STACK_CLASS ModuleValidator
uint32_t index;
ValType valType = type.canonicalToValType();
if (!mg_.allocateGlobal(valType, isConst, &index))
if (!mg_.addGlobal(valType, isConst, &index))
return false;
Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
@ -1895,7 +1888,6 @@ class MOZ_STACK_CLASS ModuleValidator
AsmJSGlobal g(AsmJSGlobal::Variable, Move(fieldChars));
g.pod.u.var.initKind_ = AsmJSGlobal::InitImport;
g.pod.u.var.u.importType_ = valType;
g.pod.u.var.globalDataOffset_ = mg_.global(index).globalDataOffset;
return asmJSMetadata_->asmJSGlobals.append(Move(g));
}
bool addArrayView(PropertyName* var, Scalar::Type vt, PropertyName* maybeField) {
@ -3905,7 +3897,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
case ModuleValidator::Global::ConstantImport:
case ModuleValidator::Global::Variable: {
*type = global->varOrConstType();
return f.encoder().writeExpr(Expr::LoadGlobal) &&
return f.encoder().writeExpr(Expr::GetGlobal) &&
f.encoder().writeVarU32(global->varOrConstIndex());
}
case ModuleValidator::Global::Function:
@ -4197,7 +4189,7 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
Type globType = global->varOrConstType();
if (!(rhsType <= globType))
return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars());
if (!f.encoder().writeExpr(Expr::StoreGlobal))
if (!f.encoder().writeExpr(Expr::SetGlobal))
return false;
if (!f.encoder().writeVarU32(global->varOrConstIndex()))
return false;
@ -7817,25 +7809,9 @@ CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata, HandleValue bufferVal,
}
static bool
TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata& metadata,
MutableHandleWasmInstanceObject instanceObj, MutableHandleObject exportObj)
GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal,
HandleValue importVal, MutableHandle<FunctionVector> funcImports, ValVector* valImports)
{
HandleValue globalVal = args.get(0);
HandleValue importVal = args.get(1);
HandleValue bufferVal = args.get(2);
RootedArrayBufferObjectMaybeShared buffer(cx);
RootedWasmMemoryObject memory(cx);
if (module.metadata().usesMemory()) {
if (!CheckBuffer(cx, metadata, bufferVal, &buffer))
return false;
memory = WasmMemoryObject::create(cx, buffer, nullptr);
if (!memory)
return false;
}
Vector<Val> valImports(cx);
Rooted<FunctionVector> ffis(cx, FunctionVector(cx));
if (!ffis.resize(metadata.numFFIs))
return false;
@ -7843,12 +7819,10 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
for (const AsmJSGlobal& global : metadata.asmJSGlobals) {
switch (global.which()) {
case AsmJSGlobal::Variable: {
// We don't have any global data into which to write the imported
// values until after instantiation, so save them in a Vector.
Val val;
if (!ValidateGlobalVariable(cx, global, importVal, &val))
return false;
if (!valImports.append(val))
if (!valImports->append(val))
return false;
break;
}
@ -7884,14 +7858,40 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
}
}
Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
for (const AsmJSImport& import : metadata.asmJSImports) {
if (!funcs.append(ffis[import.ffiIndex()]))
if (!funcImports.append(ffis[import.ffiIndex()]))
return false;
}
return true;
}
static bool
TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata& metadata,
MutableHandleWasmInstanceObject instanceObj, MutableHandleObject exportObj)
{
HandleValue globalVal = args.get(0);
HandleValue importVal = args.get(1);
HandleValue bufferVal = args.get(2);
RootedArrayBufferObjectMaybeShared buffer(cx);
RootedWasmMemoryObject memory(cx);
if (module.metadata().usesMemory()) {
if (!CheckBuffer(cx, metadata, bufferVal, &buffer))
return false;
memory = WasmMemoryObject::create(cx, buffer, nullptr);
if (!memory)
return false;
}
ValVector valImports;
Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
if (!GetImports(cx, metadata, globalVal, importVal, &funcs, &valImports))
return false;
RootedWasmTableObject table(cx);
if (!module.instantiate(cx, funcs, table, memory, nullptr, instanceObj))
if (!module.instantiate(cx, funcs, table, memory, valImports, nullptr, instanceObj))
return false;
RootedValue exportObjVal(cx);
@ -7900,16 +7900,6 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
MOZ_RELEASE_ASSERT(exportObjVal.isObject());
exportObj.set(&exportObjVal.toObject());
// Now write the imported values into global data.
uint8_t* globalData = instanceObj->instance().codeSegment().globalData();
uint32_t valIndex = 0;
for (const AsmJSGlobal& global : metadata.asmJSGlobals) {
if (global.which() == AsmJSGlobal::Variable)
valImports[valIndex++].writePayload(globalData + global.varGlobalDataOffset());
}
MOZ_ASSERT(valIndex == valImports.length());
return true;
}

View File

@ -195,11 +195,13 @@ enum class AstExprKind
ComparisonOperator,
Const,
ConversionOperator,
GetGlobal,
GetLocal,
If,
Load,
Nop,
Return,
SetGlobal,
SetLocal,
Store,
TernaryOperator,
@ -290,6 +292,41 @@ class AstSetLocal : public AstExpr
}
};
class AstGetGlobal : public AstExpr
{
AstRef global_;
public:
static const AstExprKind Kind = AstExprKind::GetGlobal;
explicit AstGetGlobal(AstRef global)
: AstExpr(Kind),
global_(global)
{}
AstRef& global() {
return global_;
}
};
class AstSetGlobal : public AstExpr
{
AstRef global_;
AstExpr& value_;
public:
static const AstExprKind Kind = AstExprKind::SetGlobal;
AstSetGlobal(AstRef global, AstExpr& value)
: AstExpr(Kind),
global_(global),
value_(value)
{}
AstRef& global() {
return global_;
}
AstExpr& value() const {
return value_;
}
};
class AstBlock : public AstExpr
{
Expr expr_;
@ -527,14 +564,42 @@ class AstResizable
const Maybe<uint32_t>& maximum() const { return maximum_; }
};
class AstGlobal : public AstNode
{
AstName name_;
uint32_t flags_;
ValType type_;
Maybe<AstExpr*> init_;
public:
AstGlobal() : flags_(0), type_(ValType::Limit)
{}
explicit AstGlobal(AstName name, ValType type, uint32_t flags,
Maybe<AstExpr*> init = Maybe<AstExpr*>())
: name_(name), flags_(flags), type_(type), init_(init)
{}
AstName name() const { return name_; }
uint32_t flags() const { return flags_; }
ValType type() const { return type_; }
bool hasInit() const { return !!init_; }
AstExpr& init() const { MOZ_ASSERT(hasInit()); return **init_; }
};
typedef AstVector<AstGlobal*> AstGlobalVector;
class AstImport : public AstNode
{
AstName name_;
AstName module_;
AstName field_;
DefinitionKind kind_;
AstRef funcSig_;
AstResizable resizable_;
AstGlobal global_;
public:
AstImport(AstName name, AstName module, AstName field, AstRef funcSig)
@ -543,30 +608,48 @@ class AstImport : public AstNode
AstImport(AstName name, AstName module, AstName field, DefinitionKind kind, AstResizable resizable)
: name_(name), module_(module), field_(field), kind_(kind), resizable_(resizable)
{}
AstImport(AstName name, AstName module, AstName field, AstGlobal global)
: name_(name), module_(module), field_(field), kind_(DefinitionKind::Global), global_(global)
{}
AstName name() const { return name_; }
AstName module() const { return module_; }
AstName field() const { return field_; }
DefinitionKind kind() const { return kind_; }
AstRef& funcSig() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return funcSig_; }
AstResizable resizable() const { MOZ_ASSERT(kind_ != DefinitionKind::Function); return resizable_; }
AstRef& funcSig() {
MOZ_ASSERT(kind_ == DefinitionKind::Function);
return funcSig_;
}
AstResizable resizable() const {
MOZ_ASSERT(kind_ == DefinitionKind::Memory || kind_ == DefinitionKind::Table);
return resizable_;
}
const AstGlobal& global() const {
MOZ_ASSERT(kind_ == DefinitionKind::Global);
return global_;
}
};
class AstExport : public AstNode
{
AstName name_;
DefinitionKind kind_;
AstRef func_;
AstRef ref_;
public:
AstExport(AstName name, AstRef func)
: name_(name), kind_(DefinitionKind::Function), func_(func)
AstExport(AstName name, DefinitionKind kind, AstRef ref)
: name_(name), kind_(kind), ref_(ref)
{}
explicit AstExport(AstName name, DefinitionKind kind)
: name_(name), kind_(kind)
{}
AstName name() const { return name_; }
DefinitionKind kind() const { return kind_; }
AstRef& func() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return func_; }
AstRef& ref() {
MOZ_ASSERT(kind_ == DefinitionKind::Function || kind_ == DefinitionKind::Global);
return ref_;
}
};
class AstDataSegment : public AstNode
@ -586,14 +669,15 @@ typedef AstVector<AstDataSegment*> AstDataSegmentVector;
class AstElemSegment : public AstNode
{
uint32_t offset_;
AstExpr* offset_;
AstRefVector elems_;
public:
AstElemSegment(uint32_t offset, AstRefVector&& elems)
AstElemSegment(AstExpr* offset, AstRefVector&& elems)
: offset_(offset), elems_(Move(elems))
{}
uint32_t offset() const { return offset_; }
AstExpr* offset() const { return offset_; }
AstRefVector& elems() { return elems_; }
const AstRefVector& elems() const { return elems_; }
};
@ -636,6 +720,7 @@ class AstModule : public AstNode
FuncVector funcs_;
AstDataSegmentVector dataSegments_;
AstElemSegmentVector elemSegments_;
AstGlobalVector globals_;
public:
explicit AstModule(LifoAlloc& lifo)
@ -646,7 +731,8 @@ class AstModule : public AstNode
exports_(lifo),
funcs_(lifo),
dataSegments_(lifo),
elemSegments_(lifo)
elemSegments_(lifo),
globals_(lifo)
{}
bool init() {
return sigMap_.init();
@ -727,18 +813,24 @@ class AstModule : public AstNode
const FuncVector& funcs() const {
return funcs_;
}
const ImportVector& imports() const {
return imports_;
}
bool append(AstImport* imp) {
return imports_.append(imp);
}
const ImportVector& imports() const {
return imports_;
}
bool append(AstExport* exp) {
return exports_.append(exp);
}
const ExportVector& exports() const {
return exports_;
}
bool append(AstGlobal* glob) {
return globals_.append(glob);
}
const AstGlobalVector& globals() const {
return globals_;
}
};
class AstUnaryOperator final : public AstExpr

View File

@ -5468,28 +5468,49 @@ BaseCompiler::emitGetGlobal()
const GlobalDesc& global = mg_.globals[id];
switch (global.type) {
if (global.isConstant()) {
Val value = global.constantValue();
switch (value.type()) {
case ValType::I32:
pushI32(value.i32());
break;
case ValType::I64:
pushI64(value.i64());
break;
case ValType::F32:
pushF32(value.f32());
break;
case ValType::F64:
pushF64(value.f64());
break;
default:
MOZ_CRASH("Global constant type");
}
return true;
}
switch (global.type()) {
case ValType::I32: {
RegI32 rv = needI32();
loadGlobalVarI32(global.globalDataOffset, rv);
loadGlobalVarI32(global.offset(), rv);
pushI32(rv);
break;
}
case ValType::I64: {
RegI64 rv = needI64();
loadGlobalVarI64(global.globalDataOffset, rv);
loadGlobalVarI64(global.offset(), rv);
pushI64(rv);
break;
}
case ValType::F32: {
RegF32 rv = needF32();
loadGlobalVarF32(global.globalDataOffset, rv);
loadGlobalVarF32(global.offset(), rv);
pushF32(rv);
break;
}
case ValType::F64: {
RegF64 rv = needF64();
loadGlobalVarF64(global.globalDataOffset, rv);
loadGlobalVarF64(global.offset(), rv);
pushF64(rv);
break;
}
@ -5513,28 +5534,28 @@ BaseCompiler::emitSetGlobal()
const GlobalDesc& global = mg_.globals[id];
switch (global.type) {
switch (global.type()) {
case ValType::I32: {
RegI32 rv = popI32();
storeGlobalVarI32(global.globalDataOffset, rv);
storeGlobalVarI32(global.offset(), rv);
pushI32(rv);
break;
}
case ValType::I64: {
RegI64 rv = popI64();
storeGlobalVarI64(global.globalDataOffset, rv);
storeGlobalVarI64(global.offset(), rv);
pushI64(rv);
break;
}
case ValType::F32: {
RegF32 rv = popF32();
storeGlobalVarF32(global.globalDataOffset, rv);
storeGlobalVarF32(global.offset(), rv);
pushF32(rv);
break;
}
case ValType::F64: {
RegF64 rv = popF64();
storeGlobalVarF64(global.globalDataOffset, rv);
storeGlobalVarF64(global.offset(), rv);
pushF64(rv);
break;
}
@ -6036,9 +6057,9 @@ BaseCompiler::emitBody()
CHECK_NEXT(emitGetLocal());
case Expr::SetLocal:
CHECK_NEXT(emitSetLocal());
case Expr::LoadGlobal:
case Expr::GetGlobal:
CHECK_NEXT(emitGetGlobal());
case Expr::StoreGlobal:
case Expr::SetGlobal:
CHECK_NEXT(emitSetGlobal());
// Select

View File

@ -28,6 +28,7 @@ static const uint32_t MagicNumber = 0x6d736100; // "\0asm"
static const uint32_t EncodingVersion = 0x0b;
static const char TypeSectionId[] = "type";
static const char GlobalSectionId[] = "global";
static const char ImportSectionId[] = "import";
static const char FunctionSectionId[] = "function";
static const char TableSectionId[] = "table";
@ -70,7 +71,8 @@ enum class DefinitionKind
{
Function = 0x00,
Table = 0x01,
Memory = 0x02
Memory = 0x02,
Global = 0x03
};
enum class ResizableFlags
@ -80,6 +82,12 @@ enum class ResizableFlags
AllowedMask = 0x3
};
enum class GlobalFlags
{
IsMutable = 0x1,
AllowedMask = 0x1
};
enum class Expr
{
// Control flow operators
@ -271,13 +279,15 @@ enum class Expr
// i64.eqz.
I64Eqz = 0xba,
// Global access.
GetGlobal = 0xc0,
SetGlobal = 0xc1,
// ------------------------------------------------------------------------
// The rest of these operators are currently only emitted internally when
// compiling asm.js and are rejected by wasm validation.
// asm.js-specific operators
LoadGlobal = 0xc0,
StoreGlobal,
I32Min,
I32Max,
I32Neg,

View File

@ -329,10 +329,10 @@ wasm::Classify(Expr expr)
case Expr::Select:
return ExprKind::Select;
case Expr::GetLocal:
case Expr::LoadGlobal:
case Expr::GetGlobal:
return ExprKind::GetVar;
case Expr::SetLocal:
case Expr::StoreGlobal:
case Expr::SetGlobal:
return ExprKind::SetVar;
case Expr::Call:
return ExprKind::Call;

View File

@ -1211,7 +1211,7 @@ ExprIter<Policy>::readGetGlobal(const GlobalDescVector& globals, uint32_t* id)
if (Validate && validateId >= globals.length())
return fail("get_global index out of range");
if (!push(ToExprType(globals[validateId].type)))
if (!push(ToExprType(globals[validateId].type())))
return false;
if (Output)
@ -1233,7 +1233,10 @@ ExprIter<Policy>::readSetGlobal(const GlobalDescVector& globals, uint32_t* id, V
if (Validate && validateId >= globals.length())
return fail("set_global index out of range");
if (!topWithType(ToExprType(globals[validateId].type), value))
if (Validate && !globals[validateId].isMutable())
return fail("can't write an immutable global");
if (!topWithType(ToExprType(globals[validateId].type()), value))
return false;
if (Output)

View File

@ -1391,6 +1391,71 @@ AstDecodeMemorySection(AstDecodeContext& c)
return true;
}
static bool
AstDecodeGlobal(AstDecodeContext& c, uint32_t i, AstGlobal* global)
{
AstName name;
if (!AstDecodeGenerateName(c, AstName(u"global"), i, &name))
return false;
ValType type;
if (!c.d.readValType(&type))
return AstDecodeFail(c, "bad global type");
uint32_t flags;
if (!c.d.readVarU32(&flags))
return AstDecodeFail(c, "expected flags");
if (flags & ~uint32_t(GlobalFlags::AllowedMask))
return AstDecodeFail(c, "unexpected bits set in flags");
if (!AstDecodeExpr(c))
return false;
AstDecodeStackItem item = c.iter().getResult();
MOZ_ASSERT(item.popped == 0);
if (!item.expr)
return AstDecodeFail(c, "missing initializer expression");
AstExpr* init = item.expr;
if (!AstDecodeEnd(c))
return AstDecodeFail(c, "missing initializer end");
item = c.iter().getResult();
MOZ_ASSERT(item.terminationKind == AstDecodeTerminationKind::End);
*global = AstGlobal(name, type, flags, Some(init));
return true;
}
static bool
AstDecodeGlobalSection(AstDecodeContext& c)
{
uint32_t sectionStart, sectionSize;
if (!c.d.startSection(GlobalSectionId, &sectionStart, &sectionSize))
return AstDecodeFail(c, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t numGlobals;
if (!c.d.readVarU32(&numGlobals))
return AstDecodeFail(c, "expected number of globals");
for (uint32_t i = 0; i < numGlobals; i++) {
auto* global = new(c.lifo) AstGlobal;
if (!AstDecodeGlobal(c, i, global))
return false;
if (!c.module().append(global))
return false;
}
if (!c.d.finishSection(sectionStart, sectionSize))
return AstDecodeFail(c, "globals section byte size mismatch");
return true;
}
static bool
AstDecodeFunctionExport(AstDecodeContext& c, AstExport** export_)
{
@ -1405,7 +1470,8 @@ AstDecodeFunctionExport(AstDecodeContext& c, AstExport** export_)
if (!AstDecodeName(c, &fieldName))
return AstDecodeFail(c, "expected export name");
*export_ = new(c.lifo) AstExport(fieldName, AstRef(AstName(), funcIndex));
*export_ = new(c.lifo) AstExport(fieldName, DefinitionKind::Function,
AstRef(AstName(), funcIndex));
if (!*export_)
return false;
@ -1647,6 +1713,9 @@ wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length,
if (!AstDecodeMemorySection(c))
return false;
if (!AstDecodeGlobalSection(c))
return false;
if (!AstDecodeExportSection(c))
return false;

View File

@ -1565,9 +1565,9 @@ PrintExport(WasmPrintContext& c, AstExport& export_, const AstModule::FuncVector
if (!c.buffer.append("memory"))
return false;
} else {
const AstFunc* func = funcs[export_.func().index()];
const AstFunc* func = funcs[export_.ref().index()];
if (func->name().empty()) {
if (!PrintInt32(c, export_.func().index()))
if (!PrintInt32(c, export_.ref().index()))
return false;
} else {
if (!PrintName(c, func->name()))

View File

@ -1174,9 +1174,9 @@ RenderExport(WasmRenderContext& c, AstExport& export_, const AstModule::FuncVect
if (!c.buffer.append("memory"))
return false;
} else {
const AstFunc* func = funcs[export_.func().index()];
const AstFunc* func = funcs[export_.ref().index()];
if (func->name().empty()) {
if (!RenderInt32(c, export_.func().index()))
if (!RenderInt32(c, export_.ref().index()))
return false;
} else {
if (!RenderName(c, func->name()))

View File

@ -417,6 +417,7 @@ Metadata::serializedSize() const
SerializedVectorSize(funcImports) +
SerializedVectorSize(funcExports) +
SerializedVectorSize(sigIds) +
SerializedPodVectorSize(globals) +
SerializedPodVectorSize(tables) +
SerializedPodVectorSize(memoryAccesses) +
SerializedPodVectorSize(boundsChecks) +
@ -435,6 +436,7 @@ Metadata::serialize(uint8_t* cursor) const
cursor = SerializeVector(cursor, funcImports);
cursor = SerializeVector(cursor, funcExports);
cursor = SerializeVector(cursor, sigIds);
cursor = SerializePodVector(cursor, globals);
cursor = SerializePodVector(cursor, tables);
cursor = SerializePodVector(cursor, memoryAccesses);
cursor = SerializePodVector(cursor, boundsChecks);
@ -454,6 +456,7 @@ Metadata::deserialize(const uint8_t* cursor)
(cursor = DeserializeVector(cursor, &funcImports)) &&
(cursor = DeserializeVector(cursor, &funcExports)) &&
(cursor = DeserializeVector(cursor, &sigIds)) &&
(cursor = DeserializePodVector(cursor, &globals)) &&
(cursor = DeserializePodVector(cursor, &tables)) &&
(cursor = DeserializePodVector(cursor, &memoryAccesses)) &&
(cursor = DeserializePodVector(cursor, &boundsChecks)) &&
@ -472,6 +475,7 @@ Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
return SizeOfVectorExcludingThis(funcImports, mallocSizeOf) +
SizeOfVectorExcludingThis(funcExports, mallocSizeOf) +
SizeOfVectorExcludingThis(sigIds, mallocSizeOf) +
globals.sizeOfExcludingThis(mallocSizeOf) +
tables.sizeOfExcludingThis(mallocSizeOf) +
memoryAccesses.sizeOfExcludingThis(mallocSizeOf) +
boundsChecks.sizeOfExcludingThis(mallocSizeOf) +

View File

@ -424,7 +424,6 @@ typedef Vector<char16_t, 64> TwoByteName;
// Metadata is built incrementally by ModuleGenerator and then shared immutably
// between modules.
class MetadataCacheablePod
{
static const uint32_t NO_START_FUNCTION = UINT32_MAX;
@ -467,6 +466,7 @@ struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
FuncImportVector funcImports;
FuncExportVector funcExports;
SigWithIdVector sigIds;
GlobalDescVector globals;
TableDescVector tables;
MemoryAccessVector memoryAccesses;
BoundsCheckVector boundsChecks;

View File

@ -236,6 +236,10 @@ DecodeExpr(FunctionDecoder& f)
return f.iter().readGetLocal(f.locals(), nullptr);
case Expr::SetLocal:
return f.iter().readSetLocal(f.locals(), nullptr, nullptr);
case Expr::GetGlobal:
return f.iter().readGetGlobal(f.mg().globals(), nullptr);
case Expr::SetGlobal:
return f.iter().readSetGlobal(f.mg().globals(), nullptr, nullptr);
case Expr::Select:
return f.iter().readSelect(nullptr, nullptr, nullptr, nullptr);
case Expr::Block:
@ -746,6 +750,48 @@ DecodeResizableTable(Decoder& d, ModuleGeneratorData* init)
return init->tables.append(table);
}
static bool
DecodeGlobalType(Decoder& d, ValType* type, bool* isMutable)
{
if (!d.readValType(type))
return Fail(d, "bad global type");
if (*type == ValType::I64 && !IsI64Implemented())
return Fail(d, "int64 NYI");
uint32_t flags;
if (!d.readVarU32(&flags))
return Fail(d, "expected flags");
if (flags & ~uint32_t(GlobalFlags::AllowedMask))
return Fail(d, "unexpected bits set in flags");
*isMutable = flags & uint32_t(GlobalFlags::IsMutable);
return true;
}
static bool
GlobalIsJSCompatible(Decoder& d, ValType type, bool isMutable)
{
switch (type) {
case ValType::I32:
case ValType::F32:
case ValType::F64:
break;
case ValType::I64:
if (!JitOptions.wasmTestMode)
return Fail(d, "can't import/export an Int64 global to JS");
break;
default:
return Fail(d, "unexpected variable type in global import/export");
}
if (isMutable)
return Fail(d, "can't import/export mutable globals in the MVP");
return true;
}
static bool
DecodeImport(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportVector* imports)
{
@ -810,6 +856,17 @@ DecodeImport(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportVector
return false;
break;
}
case DefinitionKind::Global: {
ValType type;
bool isMutable;
if (!DecodeGlobalType(d, &type, &isMutable))
return false;
if (!GlobalIsJSCompatible(d, type, isMutable))
return false;
if (!init->globals.append(GlobalDesc(type, isMutable, init->globals.length())))
return false;
break;
}
default:
return Fail(d, "unsupported import kind");
}
@ -946,6 +1003,105 @@ DecodeMemorySection(Decoder& d, bool newFormat, ModuleGeneratorData* init, bool*
return true;
}
static bool
DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected,
InitExpr* init)
{
Expr expr;
if (!d.readExpr(&expr))
return Fail(d, "failed to read initializer type");
switch (expr) {
case Expr::I32Const: {
int32_t i32;
if (!d.readVarS32(&i32))
return Fail(d, "failed to read initializer i32 expression");
*init = InitExpr(Val(uint32_t(i32)));
break;
}
case Expr::I64Const: {
int64_t i64;
if (!d.readVarS64(&i64))
return Fail(d, "failed to read initializer i64 expression");
*init = InitExpr(Val(uint64_t(i64)));
break;
}
case Expr::F32Const: {
float f32;
if (!d.readFixedF32(&f32))
return Fail(d, "failed to read initializer f32 expression");
*init = InitExpr(Val(f32));
break;
}
case Expr::F64Const: {
double f64;
if (!d.readFixedF64(&f64))
return Fail(d, "failed to read initializer f64 expression");
*init = InitExpr(Val(f64));
break;
}
case Expr::GetGlobal: {
uint32_t i;
if (!d.readVarU32(&i))
return Fail(d, "failed to read get_global index in initializer expression");
if (i >= globals.length())
return Fail(d, "global index out of range in initializer expression");
if (!globals[i].isImport() || globals[i].isMutable())
return Fail(d, "initializer expression must reference a global immutable import");
*init = InitExpr(i, globals[i].type());
break;
}
default: {
return Fail(d, "unexpected initializer expression");
}
}
if (expected != init->type())
return Fail(d, "type mismatch: initializer type and expected type don't match");
Expr end;
if (!d.readExpr(&end) || end != Expr::End)
return Fail(d, "failed to read end of initializer expression");
return true;
}
static bool
DecodeGlobalSection(Decoder& d, ModuleGeneratorData* init)
{
uint32_t sectionStart, sectionSize;
if (!d.startSection(GlobalSectionId, &sectionStart, &sectionSize))
return Fail(d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t numGlobals;
if (!d.readVarU32(&numGlobals))
return Fail(d, "expected number of globals");
if (numGlobals > MaxGlobals)
return Fail(d, "too many globals");
for (uint32_t i = 0; i < numGlobals; i++) {
ValType type;
bool isMutable;
if (!DecodeGlobalType(d, &type, &isMutable))
return false;
InitExpr initializer;
if (!DecodeInitializerExpression(d, init->globals, type, &initializer))
return false;
if (!init->globals.append(GlobalDesc(initializer, isMutable)))
return false;
}
if (!d.finishSection(sectionStart, sectionSize))
return Fail(d, "globals section byte size mismatch");
return true;
}
typedef HashSet<const char*, CStringHasher, SystemAllocPolicy> CStringSet;
static UniqueChars
@ -1032,6 +1188,20 @@ DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet
return mg.addMemoryExport(Move(fieldName));
}
case DefinitionKind::Global: {
uint32_t globalIndex;
if (!d.readVarU32(&globalIndex))
return Fail(d, "expected global index");
if (globalIndex >= mg.globals().length())
return Fail(d, "exported global index out of bounds");
const GlobalDesc& global = mg.globals()[globalIndex];
if (!GlobalIsJSCompatible(d, global.type(), global.isMutable()))
return false;
return mg.addGlobalExport(Move(fieldName), globalIndex);
}
default:
return Fail(d, "unexpected export kind");
}
@ -1133,7 +1303,6 @@ DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex)
static bool
DecodeStartSection(Decoder& d, ModuleGenerator& mg)
{
uint32_t sectionStart, sectionSize;
if (!d.startSection(StartSectionId, &sectionStart, &sectionSize))
return Fail(d, "failed to start section");
@ -1207,7 +1376,7 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen
return true;
}
return mg.addElemSegment(ElemSegment(0, 0, Move(oldElems)));
return mg.addElemSegment(ElemSegment(0, InitExpr(Val(uint32_t(0))), Move(oldElems)));
}
uint32_t sectionStart, sectionSize;
@ -1231,17 +1400,10 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen
if (seg.tableIndex >= mg.tables().length())
return Fail(d, "table index out of range");
Expr expr;
if (!d.readExpr(&expr))
return Fail(d, "failed to read initializer expression");
if (!DecodeInitializerExpression(d, mg.globals(), ValType::I32, &seg.offset))
return false;
if (expr != Expr::I32Const)
return Fail(d, "expected i32.const initializer expression");
if (!d.readVarU32(&seg.offset))
return Fail(d, "expected elem segment destination offset");
if (seg.offset < prevEnd)
if (seg.offset.isVal() && seg.offset.val().i32() < prevEnd)
return Fail(d, "elem segments must be disjoint and ordered");
uint32_t numElems;
@ -1249,8 +1411,11 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen
return Fail(d, "expected segment size");
uint32_t tableLength = mg.tables()[seg.tableIndex].initial;
if (seg.offset > tableLength || tableLength - seg.offset < numElems)
return Fail(d, "element segment does not fit");
if (seg.offset.isVal()) {
uint32_t offset = seg.offset.val().i32();
if (offset > tableLength || tableLength - offset < numElems)
return Fail(d, "element segment does not fit");
}
if (!seg.elems.resize(numElems))
return false;
@ -1262,7 +1427,8 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen
return Fail(d, "table element out of range");
}
prevEnd = seg.offset + seg.elems.length();
if (seg.offset.isVal())
prevEnd = seg.offset.val().i32() + seg.elems.length();
if (!mg.addElemSegment(Move(seg)))
return false;
@ -1459,6 +1625,9 @@ wasm::Compile(const ShareableBytes& bytecode, CompileArgs&& args, UniqueChars* e
if (!DecodeMemorySection(d, newFormat, init.get(), &memoryExported))
return nullptr;
if (!DecodeGlobalSection(d, init.get()))
return nullptr;
ModuleGenerator mg(Move(imports));
if (!mg.init(Move(init), Move(args)))
return nullptr;

View File

@ -172,6 +172,13 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, CompileArgs&& args,
sig.id = SigIdDesc::immediate(sig);
}
}
for (GlobalDesc& global : shared_->globals) {
if (global.isConstant())
continue;
if (!allocateGlobal(&global))
return false;
}
} else {
MOZ_ASSERT(shared_->sigs.length() == MaxSigs);
MOZ_ASSERT(shared_->tables.length() == MaxTables);
@ -590,11 +597,11 @@ ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* g
}
bool
ModuleGenerator::allocateGlobal(ValType type, bool isConst, uint32_t* index)
ModuleGenerator::allocateGlobal(GlobalDesc* global)
{
MOZ_ASSERT(!startedFuncDefs_);
unsigned width = 0;
switch (type) {
switch (global->type()) {
case ValType::I32:
case ValType::F32:
width = 4;
@ -621,8 +628,22 @@ ModuleGenerator::allocateGlobal(ValType type, bool isConst, uint32_t* index)
if (!allocateGlobalBytes(width, width, &offset))
return false;
global->setOffset(offset);
return true;
}
bool
ModuleGenerator::addGlobal(ValType type, bool isConst, uint32_t* index)
{
MOZ_ASSERT(isAsmJS());
MOZ_ASSERT(!startedFuncDefs_);
*index = shared_->globals.length();
return shared_->globals.append(GlobalDesc(type, offset, isConst));
GlobalDesc global(type, !isConst, *index);
if (!allocateGlobal(&global))
return false;
return shared_->globals.append(global);
}
void
@ -713,7 +734,7 @@ ModuleGenerator::funcImport(uint32_t funcImportIndex) const
bool
ModuleGenerator::addFuncExport(UniqueChars fieldName, uint32_t funcIndex)
{
return exports_.emplaceBack(Move(fieldName), funcIndex) &&
return exports_.emplaceBack(Move(fieldName), funcIndex, DefinitionKind::Function) &&
exportedFuncs_.put(funcIndex);
}
@ -731,6 +752,12 @@ ModuleGenerator::addMemoryExport(UniqueChars fieldName)
return exports_.emplaceBack(Move(fieldName), DefinitionKind::Memory);
}
bool
ModuleGenerator::addGlobalExport(UniqueChars fieldName, uint32_t globalIndex)
{
return exports_.emplaceBack(Move(fieldName), globalIndex, DefinitionKind::Global);
}
bool
ModuleGenerator::setStartFunction(uint32_t funcIndex)
{
@ -869,8 +896,6 @@ ModuleGenerator::finishFuncDefs()
bool
ModuleGenerator::addElemSegment(ElemSegment&& seg)
{
MOZ_ASSERT(seg.offset + seg.elems.length() <= shared_->tables[seg.tableIndex].initial);
if (externalTable_) {
for (uint32_t funcIndex : seg.elems) {
if (!exportedFuncs_.put(funcIndex))
@ -915,7 +940,7 @@ ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncInd
uint32_t tableIndex = shared_->asmJSSigToTableIndex[sigIndex];
MOZ_ASSERT(shared_->tables[tableIndex].initial == elemFuncIndices.length());
return elemSegments_.emplaceBack(tableIndex, 0, Move(elemFuncIndices));
return elemSegments_.emplaceBack(tableIndex, InitExpr(Val(uint32_t(0))), Move(elemFuncIndices));
}
SharedModule
@ -970,6 +995,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
metadata_->minMemoryLength = shared_->minMemoryLength;
metadata_->maxMemoryLength = shared_->maxMemoryLength;
metadata_->tables = Move(shared_->tables);
metadata_->globals = Move(shared_->globals);
// These Vectors can get large and the excess capacity can be significant,
// so realloc them down to size.

View File

@ -136,6 +136,7 @@ class MOZ_STACK_CLASS ModuleGenerator
MOZ_MUST_USE bool finishLinkData(Bytes& code);
MOZ_MUST_USE bool addFuncImport(const Sig& sig, uint32_t globalDataOffset);
MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
public:
explicit ModuleGenerator(ImportVector&& imports);
@ -165,8 +166,7 @@ class MOZ_STACK_CLASS ModuleGenerator
const SigWithId& funcSig(uint32_t funcIndex) const;
// Globals:
MOZ_MUST_USE bool allocateGlobal(ValType type, bool isConst, uint32_t* index);
const GlobalDesc& global(unsigned index) const { return shared_->globals[index]; }
const GlobalDescVector& globals() const { return shared_->globals; }
// Imports:
uint32_t numFuncImports() const;
@ -176,6 +176,7 @@ class MOZ_STACK_CLASS ModuleGenerator
MOZ_MUST_USE bool addFuncExport(UniqueChars fieldName, uint32_t funcIndex);
MOZ_MUST_USE bool addTableExport(UniqueChars fieldName);
MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
MOZ_MUST_USE bool addGlobalExport(UniqueChars fieldName, uint32_t globalIndex);
// Function definitions:
MOZ_MUST_USE bool startFuncDefs();
@ -201,6 +202,7 @@ class MOZ_STACK_CLASS ModuleGenerator
MOZ_MUST_USE bool initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices);
void initMemoryUsage(MemoryUsage memoryUsage);
void bumpMinMemoryLength(uint32_t newMinMemoryLength);
MOZ_MUST_USE bool addGlobal(ValType type, bool isConst, uint32_t* index);
// Finish compilation, provided the list of imports and source bytecode.
// Both these Vectors may be empty (viz., b/c asm.js does different things

View File

@ -203,51 +203,6 @@ Instance::toggleProfiling(JSContext* cx)
return true;
}
static bool
ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64)
{
if (!v.isObject()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL,
"i64 JS value must be an object");
return false;
}
RootedObject obj(cx, &v.toObject());
int32_t* i32 = (int32_t*)i64;
RootedValue val(cx);
if (!JS_GetProperty(cx, obj, "low", &val))
return false;
if (!ToInt32(cx, val, &i32[0]))
return false;
if (!JS_GetProperty(cx, obj, "high", &val))
return false;
if (!ToInt32(cx, val, &i32[1]))
return false;
return true;
}
static JSObject*
CreateI64Object(JSContext* cx, int64_t i64)
{
RootedObject result(cx, JS_NewPlainObject(cx));
if (!result)
return nullptr;
RootedValue val(cx, Int32Value(uint32_t(i64)));
if (!JS_DefineProperty(cx, result, "low", val, JSPROP_ENUMERATE))
return nullptr;
val = Int32Value(uint32_t(i64 >> 32));
if (!JS_DefineProperty(cx, result, "high", val, JSPROP_ENUMERATE))
return nullptr;
return result;
}
bool
Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval)
@ -423,7 +378,8 @@ Instance::Instance(JSContext* cx,
const ShareableBytes* maybeBytecode,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports)
Handle<FunctionVector> funcImports,
const ValVector& globalImports)
: codeSegment_(Move(codeSegment)),
metadata_(&metadata),
maybeBytecode_(maybeBytecode),
@ -442,6 +398,40 @@ Instance::Instance(JSContext* cx,
exit.baselineScript = nullptr;
}
uint8_t* globalData = codeSegment_->globalData();
for (size_t i = 0; i < metadata.globals.length(); i++) {
const GlobalDesc& global = metadata.globals[i];
if (global.isConstant())
continue;
uint8_t* globalAddr = globalData + global.offset();
switch (global.kind()) {
case GlobalKind::Import: {
globalImports[global.importIndex()].writePayload(globalAddr);
break;
}
case GlobalKind::Variable: {
const InitExpr& init = global.initExpr();
switch (init.kind()) {
case InitExpr::Kind::Constant: {
init.val().writePayload(globalAddr);
break;
}
case InitExpr::Kind::GetGlobal: {
const GlobalDesc& imported = metadata.globals[init.globalIndex()];
globalImports[imported.importIndex()].writePayload(globalAddr);
break;
}
}
break;
}
case GlobalKind::Constant: {
MOZ_CRASH("skipped at the top");
}
}
}
if (memory)
*addressOfMemoryBase() = memory->buffer().dataPointerEither().unwrap();

View File

@ -89,7 +89,8 @@ class Instance
const ShareableBytes* maybeBytecode,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports);
Handle<FunctionVector> funcImports,
const ValVector& globalImports);
~Instance();
bool init(JSContext* cx);
void trace(JSTracer* trc);

View File

@ -1848,8 +1848,46 @@ EmitGetGlobal(FunctionCompiler& f)
return false;
const GlobalDesc& global = f.mg().globals[id];
f.iter().setResult(f.loadGlobalVar(global.globalDataOffset, global.isConst,
ToMIRType(global.type)));
if (!global.isConstant()) {
f.iter().setResult(f.loadGlobalVar(global.offset(), !global.isMutable(),
ToMIRType(global.type())));
return true;
}
Val value = global.constantValue();
MIRType mirType = ToMIRType(value.type());
MDefinition* result;
switch (value.type()) {
case ValType::I32:
result = f.constant(Int32Value(value.i32()), mirType);
break;
case ValType::I64:
result = f.constant(value.i64());
break;
case ValType::F32:
result = f.constant(Float32Value(value.f32()), mirType);
break;
case ValType::F64:
result = f.constant(DoubleValue(value.f64()), mirType);
break;
case ValType::I8x16:
result = f.constant(SimdConstant::CreateX16(value.i8x16()), mirType);
break;
case ValType::I16x8:
result = f.constant(SimdConstant::CreateX8(value.i16x8()), mirType);
break;
case ValType::I32x4:
result = f.constant(SimdConstant::CreateX4(value.i32x4()), mirType);
break;
case ValType::F32x4:
result = f.constant(SimdConstant::CreateX4(value.f32x4()), mirType);
break;
default:
MOZ_CRASH("unexpected type in EmitGetGlobal");
}
f.iter().setResult(result);
return true;
}
@ -1862,7 +1900,9 @@ EmitSetGlobal(FunctionCompiler& f)
return false;
const GlobalDesc& global = f.mg().globals[id];
f.storeGlobalVar(global.globalDataOffset, value);
MOZ_ASSERT(global.isMutable());
f.storeGlobalVar(global.offset(), value);
return true;
}
@ -2829,9 +2869,9 @@ EmitExpr(FunctionCompiler& f)
return EmitGetLocal(f);
case Expr::SetLocal:
return EmitSetLocal(f);
case Expr::LoadGlobal:
case Expr::GetGlobal:
return EmitGetGlobal(f);
case Expr::StoreGlobal:
case Expr::SetGlobal:
return EmitSetGlobal(f);
// Select

View File

@ -22,11 +22,14 @@
#include "asmjs/WasmInstance.h"
#include "asmjs/WasmModule.h"
#include "jit/JitOptions.h"
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"
using namespace js;
using namespace js::jit;
using namespace js::wasm;
bool
@ -89,15 +92,21 @@ GetProperty(JSContext* cx, HandleObject obj, const char* chars, MutableHandleVal
static bool
GetImports(JSContext* cx,
const Module& module,
HandleObject importObj,
const ImportVector& imports,
MutableHandle<FunctionVector> funcImports,
MutableHandleWasmTableObject tableImport,
MutableHandleWasmMemoryObject memoryImport)
MutableHandleWasmMemoryObject memoryImport,
ValVector* globalImports)
{
const ImportVector& imports = module.imports();
if (!imports.empty() && !importObj)
return Throw(cx, "no import object given");
const Metadata& metadata = module.metadata();
uint32_t globalIndex = 0;
const GlobalDescVector& globals = metadata.globals;
for (const Import& import : imports) {
RootedValue v(cx);
if (!GetProperty(cx, importObj, import.module.get(), &v))
@ -135,9 +144,53 @@ GetImports(JSContext* cx,
MOZ_ASSERT(!memoryImport);
memoryImport.set(&v.toObject().as<WasmMemoryObject>());
break;
case DefinitionKind::Global:
Val val;
const GlobalDesc& global = globals[globalIndex++];
MOZ_ASSERT(global.importIndex() == globalIndex - 1);
MOZ_ASSERT(!global.isMutable());
switch (global.type()) {
case ValType::I32: {
int32_t i32;
if (!ToInt32(cx, v, &i32))
return false;
val = Val(uint32_t(i32));
break;
}
case ValType::I64: {
MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in JS");
int64_t i64;
if (!ReadI64Object(cx, v, &i64))
return false;
val = Val(uint64_t(i64));
break;
}
case ValType::F32: {
double d;
if (!ToNumber(cx, v, &d))
return false;
val = Val(float(d));
break;
}
case ValType::F64: {
double d;
if (!ToNumber(cx, v, &d))
return false;
val = Val(d);
break;
}
default: {
MOZ_CRASH("unexpected import value type");
}
}
if (!globalImports->append(val))
return false;
}
}
MOZ_ASSERT(globalIndex == globals.length() || !globals[globalIndex].isImport());
return true;
}
@ -184,10 +237,11 @@ wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj
Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
RootedWasmTableObject table(cx);
RootedWasmMemoryObject memory(cx);
if (!GetImports(cx, importObj, module->imports(), &funcs, &table, &memory))
ValVector globals;
if (!GetImports(cx, *module, importObj, &funcs, &table, &memory, &globals))
return false;
return module->instantiate(cx, funcs, table, memory, nullptr, instanceObj);
return module->instantiate(cx, funcs, table, memory, globals, nullptr, instanceObj);
}
static bool
@ -511,12 +565,13 @@ WasmInstanceObject::construct(JSContext* cx, unsigned argc, Value* vp)
Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
RootedWasmTableObject table(cx);
RootedWasmMemoryObject memory(cx);
if (!GetImports(cx, importObj, module.imports(), &funcs, &table, &memory))
ValVector globals;
if (!GetImports(cx, module, importObj, &funcs, &table, &memory, &globals))
return false;
RootedObject instanceProto(cx, &cx->global()->getPrototype(JSProto_WasmInstance).toObject());
RootedWasmInstanceObject instanceObj(cx);
if (!module.instantiate(cx, funcs, table, memory, instanceProto, &instanceObj))
if (!module.instantiate(cx, funcs, table, memory, globals, instanceProto, &instanceObj))
return false;
args.rval().setObject(*instanceObj);

View File

@ -21,15 +21,62 @@
#include "asmjs/WasmInstance.h"
#include "asmjs/WasmJS.h"
#include "asmjs/WasmSerialize.h"
#include "jit/JitOptions.h"
#include "vm/ArrayBufferObject-inl.h"
#include "vm/Debugger-inl.h"
using namespace js;
using namespace js::jit;
using namespace js::wasm;
const char wasm::InstanceExportField[] = "exports";
JSObject*
js::wasm::CreateI64Object(JSContext* cx, int64_t i64)
{
RootedObject result(cx, JS_NewPlainObject(cx));
if (!result)
return nullptr;
RootedValue val(cx, Int32Value(uint32_t(i64)));
if (!JS_DefineProperty(cx, result, "low", val, JSPROP_ENUMERATE))
return nullptr;
val = Int32Value(uint32_t(i64 >> 32));
if (!JS_DefineProperty(cx, result, "high", val, JSPROP_ENUMERATE))
return nullptr;
return result;
}
bool
js::wasm::ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64)
{
if (!v.isObject()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL,
"i64 JS value must be an object");
return false;
}
RootedObject obj(cx, &v.toObject());
int32_t* i32 = (int32_t*)i64;
RootedValue val(cx);
if (!JS_GetProperty(cx, obj, "low", &val))
return false;
if (!ToInt32(cx, val, &i32[0]))
return false;
if (!JS_GetProperty(cx, obj, "high", &val))
return false;
if (!ToInt32(cx, val, &i32[1]))
return false;
return true;
}
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
// On MIPS, CodeLabels are instruction immediates so InternalLinks only
// patch instruction immediates.
@ -158,25 +205,32 @@ Import::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
func.sizeOfExcludingThis(mallocSizeOf);
}
Export::Export(UniqueChars fieldName, uint32_t funcIndex)
Export::Export(UniqueChars fieldName, uint32_t index, DefinitionKind kind)
: fieldName_(Move(fieldName))
{
pod.kind_ = DefinitionKind::Function;
pod.funcIndex_ = funcIndex;
pod.kind_ = kind;
pod.index_ = index;
}
Export::Export(UniqueChars fieldName, DefinitionKind kind)
: fieldName_(Move(fieldName))
{
pod.kind_ = kind;
pod.funcIndex_ = 0;
pod.index_ = 0;
}
uint32_t
Export::funcIndex() const
{
MOZ_ASSERT(pod.kind_ == DefinitionKind::Function);
return pod.funcIndex_;
return pod.index_;
}
uint32_t
Export::globalIndex() const
{
MOZ_ASSERT(pod.kind_ == DefinitionKind::Global);
return pod.index_;
}
size_t
@ -212,6 +266,7 @@ size_t
ElemSegment::serializedSize() const
{
return sizeof(tableIndex) +
sizeof(offset) +
SerializedPodVectorSize(elems);
}
@ -219,6 +274,7 @@ uint8_t*
ElemSegment::serialize(uint8_t* cursor) const
{
cursor = WriteBytes(cursor, &tableIndex, sizeof(tableIndex));
cursor = WriteBytes(cursor, &offset, sizeof(offset));
cursor = SerializePodVector(cursor, elems);
return cursor;
}
@ -227,6 +283,7 @@ const uint8_t*
ElemSegment::deserialize(const uint8_t* cursor)
{
(cursor = ReadBytes(cursor, &tableIndex, sizeof(tableIndex))) &&
(cursor = ReadBytes(cursor, &offset, sizeof(offset))) &&
(cursor = DeserializePodVector(cursor, &elems));
return cursor;
}
@ -351,7 +408,7 @@ Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
bool
Module::initElems(JSContext* cx, HandleWasmInstanceObject instanceObj,
HandleWasmTableObject tableObj) const
const ValVector& globalImports, HandleWasmTableObject tableObj) const
{
Instance& instance = instanceObj->instance();
const CodeSegment& codeSegment = instance.codeSegment();
@ -369,20 +426,53 @@ Module::initElems(JSContext* cx, HandleWasmInstanceObject instanceObj,
}
// Now that all tables have been initialized, write elements.
Vector<uint32_t> prevEnds(cx);
if (!prevEnds.appendN(0, tables.length()))
return false;
for (const ElemSegment& seg : elemSegments_) {
Table& table = *tables[seg.tableIndex];
MOZ_ASSERT(seg.offset + seg.elems.length() <= table.length());
uint32_t offset;
switch (seg.offset.kind()) {
case InitExpr::Kind::Constant: {
offset = seg.offset.val().i32();
break;
}
case InitExpr::Kind::GetGlobal: {
const GlobalDesc& global = metadata_->globals[seg.offset.globalIndex()];
offset = globalImports[global.importIndex()].i32();
break;
}
}
uint32_t& prevEnd = prevEnds[seg.tableIndex];
if (offset < prevEnd) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL,
"elem segments must be disjoint and ordered");
return false;
}
uint32_t tableLength = instance.metadata().tables[seg.tableIndex].initial;
if (offset > tableLength || tableLength - offset < seg.elems.length()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL,
"element segment does not fit");
return false;
}
if (tableObj) {
MOZ_ASSERT(seg.tableIndex == 0);
for (uint32_t i = 0; i < seg.elems.length(); i++) {
if (!tableObj->setInstance(cx, seg.offset + i, instanceObj))
if (!tableObj->setInstance(cx, offset + i, instanceObj))
return false;
}
}
for (uint32_t i = 0; i < seg.elems.length(); i++)
table.array()[seg.offset + i] = codeSegment.code() + seg.elems[i];
table.array()[offset + i] = codeSegment.code() + seg.elems[i];
prevEnd = offset + seg.elems.length();
}
return true;
@ -468,11 +558,54 @@ Module::instantiateTable(JSContext* cx, HandleWasmTableObject tableImport,
return true;
}
static bool
ExportGlobalValue(JSContext* cx, const GlobalDescVector& globals, uint32_t globalIndex,
const ValVector& globalImports, MutableHandleValue jsval)
{
const GlobalDesc& global = globals[globalIndex];
// Imports are located upfront in the globals array.
Val val;
switch (global.kind()) {
case GlobalKind::Import: val = globalImports[globalIndex]; break;
case GlobalKind::Variable: MOZ_CRASH("mutable variables can't be exported");
case GlobalKind::Constant: val = global.constantValue(); break;
}
switch (global.type()) {
case ValType::I32: {
jsval.set(Int32Value(val.i32()));
return true;
}
case ValType::I64: {
MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
RootedObject obj(cx, CreateI64Object(cx, val.i64()));
if (!obj)
return false;
jsval.set(ObjectValue(*obj));
return true;
}
case ValType::F32: {
jsval.set(DoubleValue(double(val.f32())));
return true;
}
case ValType::F64: {
jsval.set(DoubleValue(val.f64()));
return true;
}
default: {
break;
}
}
MOZ_CRASH("unexpected type when creating global exports");
}
static bool
CreateExportObject(JSContext* cx,
HandleWasmInstanceObject instanceObj,
MutableHandleWasmTableObject tableObj,
HandleWasmMemoryObject memoryObj,
const ValVector& globalImports,
const ExportVector& exports,
MutableHandleObject exportObj)
{
@ -523,6 +656,11 @@ CreateExportObject(JSContext* cx,
val = ObjectValue(memoryObj->buffer());
break;
}
case DefinitionKind::Global: {
if (!ExportGlobalValue(cx, metadata.globals, exp.globalIndex(), globalImports, &val))
return false;
break;
}
}
if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
@ -537,6 +675,7 @@ Module::instantiate(JSContext* cx,
Handle<FunctionVector> funcImports,
HandleWasmTableObject tableImport,
HandleWasmMemoryObject memoryImport,
const ValVector& globalImports,
HandleObject instanceProto,
MutableHandleWasmInstanceObject instanceObj) const
{
@ -580,7 +719,8 @@ Module::instantiate(JSContext* cx,
maybeBytecode,
memory,
Move(tables),
funcImports);
funcImports,
globalImports);
if (!instance)
return false;
@ -594,7 +734,7 @@ Module::instantiate(JSContext* cx,
RootedObject exportObj(cx);
RootedWasmTableObject table(cx, tableImport);
if (!CreateExportObject(cx, instanceObj, &table, memory, exports_, &exportObj))
if (!CreateExportObject(cx, instanceObj, &table, memory, globalImports, exports_, &exportObj))
return false;
JSAtom* atom = Atomize(cx, InstanceExportField, strlen(InstanceExportField));
@ -611,7 +751,7 @@ Module::instantiate(JSContext* cx,
// initialization as the final step after the instance is fully live since
// it is observable (in the case of an imported Table object).
if (!initElems(cx, instanceObj, table))
if (!initElems(cx, instanceObj, globalImports, table))
return false;
// Done! Notify the Debugger of the new Instance.

View File

@ -26,6 +26,18 @@
namespace js {
namespace wasm {
// Creates a JS object containing two fields (low: low 32 bits; high: high 32
// bits) of a given Int64 value. For testing purposes only.
JSObject*
CreateI64Object(JSContext* cx, int64_t i64);
// Reads an int64 from a JS object with the same shape as described in the
// comment above. For testing purposes only.
bool
ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64);
// LinkData contains all the metadata necessary to patch all the locations
// that depend on the absolute address of a CodeSegment.
//
@ -113,18 +125,19 @@ class Export
CacheableChars fieldName_;
struct CacheablePod {
DefinitionKind kind_;
uint32_t funcIndex_;
uint32_t index_;
} pod;
public:
Export() = default;
explicit Export(UniqueChars fieldName, uint32_t funcIndex);
explicit Export(UniqueChars fieldName, uint32_t index, DefinitionKind kind);
explicit Export(UniqueChars fieldName, DefinitionKind kind);
const char* fieldName() const { return fieldName_.get(); }
DefinitionKind kind() const { return pod.kind_; }
uint32_t funcIndex() const;
uint32_t globalIndex() const;
WASM_DECLARE_SERIALIZABLE(Export)
};
@ -149,11 +162,11 @@ typedef Vector<DataSegment, 0, SystemAllocPolicy> DataSegmentVector;
struct ElemSegment
{
uint32_t tableIndex;
uint32_t offset;
InitExpr offset;
Uint32Vector elems;
ElemSegment() = default;
ElemSegment(uint32_t tableIndex, uint32_t offset, Uint32Vector&& elems)
ElemSegment(uint32_t tableIndex, InitExpr offset, Uint32Vector&& elems)
: tableIndex(tableIndex), offset(offset), elems(Move(elems))
{}
@ -189,7 +202,7 @@ class Module : public RefCounted<Module>
bool instantiateTable(JSContext* cx, HandleWasmTableObject tableImport,
SharedTableVector* tables) const;
bool initElems(JSContext* cx, HandleWasmInstanceObject instanceObj,
HandleWasmTableObject tableObj) const;
const ValVector& globalImports, HandleWasmTableObject tableObj) const;
public:
Module(Bytes&& code,
@ -219,6 +232,7 @@ class Module : public RefCounted<Module>
Handle<FunctionVector> funcImports,
HandleWasmTableObject tableImport,
HandleWasmMemoryObject memoryImport,
const ValVector& globalImports,
HandleObject instanceProto,
MutableHandleWasmInstanceObject instanceObj) const;

View File

@ -86,8 +86,11 @@ class WasmToken
Export,
Float,
Func,
GetGlobal,
GetLocal,
Global,
If,
Immutable,
Import,
Index,
Memory,
@ -105,6 +108,7 @@ class WasmToken
Result,
Return,
Segment,
SetGlobal,
SetLocal,
SignedInteger,
Start,
@ -978,8 +982,12 @@ WasmTokenStream::next()
break;
case 'g':
if (consume(u"get_global"))
return WasmToken(WasmToken::GetGlobal, begin, cur_);
if (consume(u"get_local"))
return WasmToken(WasmToken::GetLocal, begin, cur_);
if (consume(u"global"))
return WasmToken(WasmToken::Global, begin, cur_);
break;
case 'i':
@ -1266,6 +1274,8 @@ WasmTokenStream::next()
}
break;
}
if (consume(u"immutable"))
return WasmToken(WasmToken::Immutable, begin, cur_);
if (consume(u"import"))
return WasmToken(WasmToken::Import, begin, cur_);
if (consume(u"infinity"))
@ -1317,6 +1327,8 @@ WasmTokenStream::next()
case 's':
if (consume(u"select"))
return WasmToken(WasmToken::TernaryOpcode, Expr::Select, begin, cur_);
if (consume(u"set_global"))
return WasmToken(WasmToken::SetGlobal, begin, cur_);
if (consume(u"set_local"))
return WasmToken(WasmToken::SetLocal, begin, cur_);
if (consume(u"segment"))
@ -1841,6 +1853,29 @@ ParseGetLocal(WasmParseContext& c)
return new(c.lifo) AstGetLocal(local);
}
static AstGetGlobal*
ParseGetGlobal(WasmParseContext& c)
{
AstRef local;
if (!c.ts.matchRef(&local, c.error))
return nullptr;
return new(c.lifo) AstGetGlobal(local);
}
static AstSetGlobal*
ParseSetGlobal(WasmParseContext& c)
{
AstRef global;
if (!c.ts.matchRef(&global, c.error))
return nullptr;
AstExpr* value = ParseExpr(c);
if (!value)
return nullptr;
return new(c.lifo) AstSetGlobal(global, *value);
}
static AstSetLocal*
ParseSetLocal(WasmParseContext& c)
{
@ -2176,6 +2211,8 @@ ParseExprInsideParens(WasmParseContext& c)
return ParseConversionOperator(c, token.expr());
case WasmToken::If:
return ParseIf(c);
case WasmToken::GetGlobal:
return ParseGetGlobal(c);
case WasmToken::GetLocal:
return ParseGetLocal(c);
case WasmToken::Load:
@ -2184,6 +2221,8 @@ ParseExprInsideParens(WasmParseContext& c)
return ParseBlock(c, Expr::Loop);
case WasmToken::Return:
return ParseReturn(c);
case WasmToken::SetGlobal:
return ParseSetGlobal(c);
case WasmToken::SetLocal:
return ParseSetLocal(c);
case WasmToken::Store:
@ -2423,6 +2462,20 @@ ParseStartFunc(WasmParseContext& c, WasmToken token, AstModule* module)
return true;
}
static bool
ParseGlobalType(WasmParseContext& c, WasmToken* typeToken, uint32_t* flags)
{
if (!c.ts.match(WasmToken::ValueType, typeToken, c.error))
return false;
// Mutable by default.
*flags = 0x1;
if (c.ts.getIf(WasmToken::Immutable))
*flags = 0x0;
return true;
}
static AstImport*
ParseImport(WasmParseContext& c, bool newFormat, AstModule* module)
{
@ -2458,6 +2511,16 @@ ParseImport(WasmParseContext& c, bool newFormat, AstModule* module)
return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
DefinitionKind::Table, table);
}
if (c.ts.getIf(WasmToken::Global)) {
WasmToken typeToken;
uint32_t flags = 0;
if (!ParseGlobalType(c, &typeToken, &flags))
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
AstGlobal(AstName(), typeToken.valueType(), flags));
}
}
if (c.ts.getIf(WasmToken::Type)) {
@ -2494,13 +2557,21 @@ ParseExport(WasmParseContext& c)
WasmToken exportee = c.ts.get();
switch (exportee.kind()) {
case WasmToken::Index:
return new(c.lifo) AstExport(name.text(), AstRef(AstName(), exportee.index()));
return new(c.lifo) AstExport(name.text(), DefinitionKind::Function,
AstRef(AstName(), exportee.index()));
case WasmToken::Name:
return new(c.lifo) AstExport(name.text(), AstRef(exportee.name(), AstNoIndex));
return new(c.lifo) AstExport(name.text(), DefinitionKind::Function,
AstRef(exportee.name(), AstNoIndex));
case WasmToken::Table:
return new(c.lifo) AstExport(name.text(), DefinitionKind::Table);
case WasmToken::Memory:
return new(c.lifo) AstExport(name.text(), DefinitionKind::Memory);
case WasmToken::Global: {
AstRef ref;
if (!c.ts.matchRef(&ref, c.error))
return nullptr;
return new(c.lifo) AstExport(name.text(), DefinitionKind::Global, ref);
}
default:
break;
}
@ -2541,15 +2612,19 @@ ParseTable(WasmParseContext& c, WasmToken token, AstModule* module)
return false;
}
AstElemSegment* segment = new(c.lifo) AstElemSegment(0, Move(elems));
auto* zero = new(c.lifo) AstConst(Val(uint32_t(0)));
if (!zero)
return false;
AstElemSegment* segment = new(c.lifo) AstElemSegment(zero, Move(elems));
return segment && module->append(segment);
}
static AstElemSegment*
ParseElemSegment(WasmParseContext& c)
{
WasmToken offset;
if (!c.ts.match(WasmToken::Index, &offset, c.error))
AstExpr* offset = ParseExpr(c);
if (!offset)
return nullptr;
AstRefVector elems(c.lifo);
@ -2560,7 +2635,24 @@ ParseElemSegment(WasmParseContext& c)
return nullptr;
}
return new(c.lifo) AstElemSegment(offset.index(), Move(elems));
return new(c.lifo) AstElemSegment(offset, Move(elems));
}
static AstGlobal*
ParseGlobal(WasmParseContext& c)
{
AstName name = c.ts.getIfName();
WasmToken typeToken;
uint32_t flags = 0;
if (!ParseGlobalType(c, &typeToken, &flags))
return nullptr;
AstExpr* init = ParseExpr(c);
if (!init)
return nullptr;
return new(c.lifo) AstGlobal(name, typeToken.valueType(), flags, Some(init));
}
static AstModule*
@ -2597,6 +2689,12 @@ ParseModule(const char16_t* text, bool newFormat, LifoAlloc& lifo, UniqueChars*
return nullptr;
break;
}
case WasmToken::Global: {
AstGlobal* global = ParseGlobal(c);
if (!global || !module->append(global))
return nullptr;
break;
}
case WasmToken::Data: {
AstDataSegment* segment = ParseDataSegment(c);
if (!segment || !module->append(segment))
@ -2658,6 +2756,7 @@ class Resolver
{
UniqueChars* error_;
AstNameMap varMap_;
AstNameMap globalMap_;
AstNameMap sigMap_;
AstNameMap funcMap_;
AstNameMap importMap_;
@ -2703,13 +2802,18 @@ class Resolver
explicit Resolver(LifoAlloc& lifo, UniqueChars* error)
: error_(error),
varMap_(lifo),
globalMap_(lifo),
sigMap_(lifo),
funcMap_(lifo),
importMap_(lifo),
targetStack_(lifo)
{}
bool init() {
return sigMap_.init() && funcMap_.init() && importMap_.init() && varMap_.init();
return sigMap_.init() &&
funcMap_.init() &&
importMap_.init() &&
varMap_.init() &&
globalMap_.init();
}
void beginFunc() {
varMap_.clear();
@ -2727,6 +2831,9 @@ class Resolver
bool registerVarName(AstName name, size_t index) {
return name.empty() || registerName(varMap_, name, index);
}
bool registerGlobalName(AstName name, size_t index) {
return name.empty() || registerName(globalMap_, name, index);
}
bool pushTarget(AstName name) {
return targetStack_.append(name);
}
@ -2755,6 +2862,11 @@ class Resolver
return failResolveLabel("local", ref.name());
return true;
}
bool resolveGlobal(AstRef& ref) {
if (!ref.name().empty() && !resolveRef(globalMap_, ref))
return failResolveLabel("global", ref.name());
return true;
}
bool resolveBranchTarget(AstRef& ref) {
if (ref.name().empty())
return true;
@ -2887,6 +2999,24 @@ ResolveSetLocal(Resolver& r, AstSetLocal& sl)
return true;
}
static bool
ResolveGetGlobal(Resolver& r, AstGetGlobal& gl)
{
return r.resolveGlobal(gl.global());
}
static bool
ResolveSetGlobal(Resolver& r, AstSetGlobal& sl)
{
if (!ResolveExpr(r, sl.value()))
return false;
if (!r.resolveGlobal(sl.global()))
return false;
return true;
}
static bool
ResolveUnaryOperator(Resolver& r, AstUnaryOperator& b)
{
@ -3006,6 +3136,8 @@ ResolveExpr(Resolver& r, AstExpr& expr)
return true;
case AstExprKind::ConversionOperator:
return ResolveConversionOperator(r, expr.as<AstConversionOperator>());
case AstExprKind::GetGlobal:
return ResolveGetGlobal(r, expr.as<AstGetGlobal>());
case AstExprKind::GetLocal:
return ResolveGetLocal(r, expr.as<AstGetLocal>());
case AstExprKind::If:
@ -3014,6 +3146,8 @@ ResolveExpr(Resolver& r, AstExpr& expr)
return ResolveLoad(r, expr.as<AstLoad>());
case AstExprKind::Return:
return ResolveReturn(r, expr.as<AstReturn>());
case AstExprKind::SetGlobal:
return ResolveSetGlobal(r, expr.as<AstSetGlobal>());
case AstExprKind::SetLocal:
return ResolveSetLocal(r, expr.as<AstSetLocal>());
case AstExprKind::Store:
@ -3033,8 +3167,7 @@ ResolveFunc(Resolver& r, AstFunc& func)
{
r.beginFunc();
size_t numVars = func.locals().length();
for (size_t i = 0; i < numVars; i++) {
for (size_t i = 0; i < func.locals().length(); i++) {
if (!r.registerVarName(func.locals()[i], i))
return r.fail("duplicate var");
}
@ -3078,29 +3211,50 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
}
size_t numImports = module->imports().length();
size_t lastGlobalIndex = 0;
for (size_t i = 0; i < numImports; i++) {
AstImport* imp = module->imports()[i];
if (!r.registerImportName(imp->name(), i))
return r.fail("duplicate import");
switch (imp->kind()) {
case DefinitionKind::Function:
if (!r.registerImportName(imp->name(), i))
return r.fail("duplicate import");
if (!r.resolveSignature(imp->funcSig()))
return false;
break;
case DefinitionKind::Global:
if (!r.registerGlobalName(imp->name(), lastGlobalIndex++))
return r.fail("duplicate import");
break;
case DefinitionKind::Memory:
case DefinitionKind::Table:
break;
}
}
for (AstExport* export_ : module->exports()) {
if (export_->kind() != DefinitionKind::Function)
continue;
if (!r.resolveFunction(export_->func()))
const AstGlobalVector& globals = module->globals();
for (const AstGlobal* global : globals) {
if (!r.registerGlobalName(global->name(), lastGlobalIndex++))
return r.fail("duplicate import");
if (global->hasInit() && !ResolveExpr(r, global->init()))
return false;
}
for (AstExport* export_ : module->exports()) {
switch (export_->kind()) {
case DefinitionKind::Function:
if (!r.resolveFunction(export_->ref()))
return false;
break;
case DefinitionKind::Global:
if (!r.resolveGlobal(export_->ref()))
return false;
break;
case DefinitionKind::Table:
case DefinitionKind::Memory:
break;
}
}
for (AstFunc* func : module->funcs()) {
if (!ResolveFunc(r, *func))
return false;
@ -3111,6 +3265,11 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
return false;
}
for (AstElemSegment* segment : module->elemSegments()) {
if (!ResolveExpr(r, *segment->offset()))
return false;
}
return true;
}
@ -3261,6 +3420,21 @@ EncodeSetLocal(Encoder& e, AstSetLocal& sl)
e.writeVarU32(sl.local().index());
}
static bool
EncodeGetGlobal(Encoder& e, AstGetGlobal& gg)
{
return e.writeExpr(Expr::GetGlobal) &&
e.writeVarU32(gg.global().index());
}
static bool
EncodeSetGlobal(Encoder& e, AstSetGlobal& sg)
{
return EncodeExpr(e, sg.value()) &&
e.writeExpr(Expr::SetGlobal) &&
e.writeVarU32(sg.global().index());
}
static bool
EncodeUnaryOperator(Encoder& e, AstUnaryOperator& b)
{
@ -3427,6 +3601,8 @@ EncodeExpr(Encoder& e, AstExpr& expr)
return EncodeConversionOperator(e, expr.as<AstConversionOperator>());
case AstExprKind::GetLocal:
return EncodeGetLocal(e, expr.as<AstGetLocal>());
case AstExprKind::GetGlobal:
return EncodeGetGlobal(e, expr.as<AstGetGlobal>());
case AstExprKind::If:
return EncodeIf(e, expr.as<AstIf>());
case AstExprKind::Load:
@ -3435,6 +3611,8 @@ EncodeExpr(Encoder& e, AstExpr& expr)
return EncodeReturn(e, expr.as<AstReturn>());
case AstExprKind::SetLocal:
return EncodeSetLocal(e, expr.as<AstSetLocal>());
case AstExprKind::SetGlobal:
return EncodeSetGlobal(e, expr.as<AstSetGlobal>());
case AstExprKind::Store:
return EncodeStore(e, expr.as<AstStore>());
case AstExprKind::BranchTable:
@ -3569,6 +3747,13 @@ EncodeImport(Encoder& e, bool newFormat, AstImport& imp)
if (!e.writeVarU32(imp.funcSig().index()))
return false;
break;
case DefinitionKind::Global:
MOZ_ASSERT(!imp.global().hasInit());
if (!e.writeValType(imp.global().type()))
return false;
if (!e.writeVarU32(imp.global().flags()))
return false;
break;
case DefinitionKind::Table:
case DefinitionKind::Memory:
if (!EncodeResizable(e, imp.resizable()))
@ -3640,6 +3825,34 @@ EncodeMemorySection(Encoder& e, bool newFormat, AstModule& module)
return true;
}
static bool
EncodeGlobalSection(Encoder& e, AstModule& module)
{
size_t offset;
if (!e.startSection(GlobalSectionId, &offset))
return false;
const AstGlobalVector& globals = module.globals();
if (!e.writeVarU32(globals.length()))
return false;
for (const AstGlobal* global : globals) {
MOZ_ASSERT(global->hasInit());
if (!e.writeValType(global->type()))
return false;
if (!e.writeVarU32(global->flags()))
return false;
if (!EncodeExpr(e, global->init()))
return false;
if (!e.writeExpr(Expr::End))
return false;
}
e.finishSection(offset);
return true;
}
static bool
EncodeExport(Encoder& e, bool newFormat, AstExport& exp)
{
@ -3647,7 +3860,7 @@ EncodeExport(Encoder& e, bool newFormat, AstExport& exp)
if (exp.kind() != DefinitionKind::Function)
return true;
if (!e.writeVarU32(exp.func().index()))
if (!e.writeVarU32(exp.ref().index()))
return false;
if (!EncodeBytes(e, exp.name()))
@ -3664,7 +3877,8 @@ EncodeExport(Encoder& e, bool newFormat, AstExport& exp)
switch (exp.kind()) {
case DefinitionKind::Function:
if (!e.writeVarU32(exp.func().index()))
case DefinitionKind::Global:
if (!e.writeVarU32(exp.ref().index()))
return false;
break;
case DefinitionKind::Table:
@ -3868,9 +4082,9 @@ EncodeElemSegment(Encoder& e, AstElemSegment& segment)
if (!e.writeVarU32(0)) // table index
return false;
if (!e.writeExpr(Expr::I32Const))
if (!EncodeExpr(e, *segment.offset()))
return false;
if (!e.writeVarU32(segment.offset()))
if (!e.writeExpr(Expr::End))
return false;
if (!e.writeVarU32(segment.elems().length()))
@ -3932,6 +4146,9 @@ EncodeModule(AstModule& module, bool newFormat, Bytes* bytes)
if (!EncodeMemorySection(e, newFormat, module))
return false;
if (!EncodeGlobalSection(e, module))
return false;
if (!EncodeExportSection(e, newFormat, module))
return false;

View File

@ -37,7 +37,7 @@ using namespace js::jit;
using namespace js::wasm;
void
Val::writePayload(uint8_t* dst)
Val::writePayload(uint8_t* dst) const
{
switch (type_) {
case ValType::I32:

View File

@ -361,9 +361,11 @@ class Val
return u.f32x4_;
}
void writePayload(uint8_t* dst);
void writePayload(uint8_t* dst) const;
};
typedef Vector<Val, 0, SystemAllocPolicy> ValVector;
// The Sig class represents a WebAssembly function signature which takes a list
// of value types and returns an expression type. The engine uses two in-memory
// representations of the argument Vector's memory (when elements do not fit
@ -413,6 +415,142 @@ struct SigHashPolicy
static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; }
};
// An InitExpr describes a deferred initializer expression, used to initialize
// a global or a table element offset. Such expressions are created during
// decoding and actually executed on module instantiation.
class InitExpr
{
public:
enum class Kind {
Constant,
GetGlobal
};
private:
Kind kind_;
union {
Val val_;
struct {
uint32_t index_;
ValType type_;
} global;
} u;
public:
InitExpr() = default;
explicit InitExpr(Val val) : kind_(Kind::Constant) {
u.val_ = val;
}
explicit InitExpr(uint32_t globalIndex, ValType type) : kind_(Kind::GetGlobal) {
u.global.index_ = globalIndex;
u.global.type_ = type;
}
Kind kind() const { return kind_; }
bool isVal() const { return kind() == Kind::Constant; }
Val val() const { MOZ_ASSERT(isVal()); return u.val_; }
uint32_t globalIndex() const { MOZ_ASSERT(kind() == Kind::GetGlobal); return u.global.index_; }
ValType type() const {
switch (kind()) {
case Kind::Constant: return u.val_.type();
case Kind::GetGlobal: return u.global.type_;
}
MOZ_CRASH("unexpected initExpr type");
}
};
// A GlobalDesc describes a single global variable. Currently, asm.js and wasm
// exposes mutable and immutable private globals, but can't import nor export
// mutable globals.
enum class GlobalKind
{
Import,
Constant,
Variable
};
class GlobalDesc
{
union {
struct {
union {
InitExpr initial_;
struct {
ValType type_;
uint32_t index_;
} import;
} val;
unsigned offset_;
bool isMutable_;
} var;
Val cst_;
} u;
GlobalKind kind_;
public:
GlobalDesc() = default;
explicit GlobalDesc(InitExpr initial, bool isMutable)
: kind_((isMutable || !initial.isVal()) ? GlobalKind::Variable : GlobalKind::Constant)
{
if (isVariable()) {
u.var.val.initial_ = initial;
u.var.isMutable_ = isMutable;
u.var.offset_ = UINT32_MAX;
} else {
u.cst_ = initial.val();
}
}
explicit GlobalDesc(ValType type, bool isMutable, uint32_t importIndex)
: kind_(GlobalKind::Import)
{
u.var.val.import.type_ = type;
u.var.val.import.index_ = importIndex;
u.var.isMutable_ = isMutable;
u.var.offset_ = UINT32_MAX;
}
void setOffset(unsigned offset) {
MOZ_ASSERT(!isConstant());
MOZ_ASSERT(u.var.offset_ == UINT32_MAX);
u.var.offset_ = offset;
}
unsigned offset() const {
MOZ_ASSERT(!isConstant());
MOZ_ASSERT(u.var.offset_ != UINT32_MAX);
return u.var.offset_;
}
GlobalKind kind() const { return kind_; }
bool isVariable() const { return kind_ == GlobalKind::Variable; }
bool isConstant() const { return kind_ == GlobalKind::Constant; }
bool isImport() const { return kind_ == GlobalKind::Import; }
bool isMutable() const { return !isConstant() && u.var.isMutable_; }
Val constantValue() const { MOZ_ASSERT(isConstant()); return u.cst_; }
const InitExpr& initExpr() const { MOZ_ASSERT(isVariable()); return u.var.val.initial_; }
uint32_t importIndex() const { MOZ_ASSERT(isImport()); return u.var.val.import.index_; }
ValType type() const {
switch (kind_) {
case GlobalKind::Import: return u.var.val.import.type_;
case GlobalKind::Variable: return u.var.val.initial_.type();
case GlobalKind::Constant: return u.cst_.type();
}
MOZ_CRASH("unexpected global kind");
}
};
typedef Vector<GlobalDesc, 0, SystemAllocPolicy> GlobalDescVector;
// SigIdDesc describes a signature id that can be used by call_indirect and
// table-entry prologues to structurally compare whether the caller and callee's
// signatures *structurally* match. To handle the general case, a Sig is
@ -468,21 +606,6 @@ struct SigWithId : Sig
typedef Vector<SigWithId, 0, SystemAllocPolicy> SigWithIdVector;
typedef Vector<const SigWithId*, 0, SystemAllocPolicy> SigWithIdPtrVector;
// A GlobalDesc describes a single global variable. Currently, globals are only
// exposed through asm.js.
struct GlobalDesc
{
ValType type;
unsigned globalDataOffset;
bool isConst;
GlobalDesc(ValType type, unsigned offset, bool isConst)
: type(type), globalDataOffset(offset), isConst(isConst)
{}
};
typedef Vector<GlobalDesc, 0, SystemAllocPolicy> GlobalDescVector;
// The (,Profiling,Func)Offsets classes are used to record the offsets of
// different key points in a CodeRange during compilation.
@ -940,6 +1063,7 @@ static const unsigned InitialGlobalDataBytes = NaN32GlobalDataOffset + sizeo
static const unsigned MaxSigs = 4 * 1024;
static const unsigned MaxFuncs = 512 * 1024;
static const unsigned MaxGlobals = 4 * 1024;
static const unsigned MaxLocals = 64 * 1024;
static const unsigned MaxImports = 64 * 1024;
static const unsigned MaxExports = 64 * 1024;

View File

@ -36,8 +36,9 @@ function jsify(wasmVal) {
// - if the expected value is in the int32 range, it can be just a number.
// - otherwise, an object with the properties "high" and "low".
function assertEqI64(observed, expect) {
assertEq(typeof observed, 'object');
assertEq(typeof expect === 'object' || typeof expect === 'number', true);
assertEq(typeof observed, 'object', "observed must be an i64 object");
assertEq(typeof expect === 'object' || typeof expect === 'number', true,
"expect must be an i64 object or number");
let {low, high} = observed;
if (typeof expect === 'number') {

View File

@ -0,0 +1,209 @@
// |jit-test| test-also-wasm-baseline
load(libdir + "wasm.js");
const { Instance, Module } = WebAssembly;
const evalText = (txt, imports = {}) => new Instance(new Module(wasmTextToBinary(txt, 'new-format')), imports).exports;
// Locally-defined globals
assertErrorMessage(() => evalText(`(module (global))`), SyntaxError, /parsing/);
assertErrorMessage(() => evalText(`(module (global i32))`), SyntaxError, /parsing/);
assertErrorMessage(() => evalText(`(module (global i32 immutable))`), SyntaxError, /parsing/);
// Initializer expressions.
assertErrorMessage(() => evalText(`(module (global i32 (f32.const 13.37)))`), TypeError, /type mismatch/);
assertErrorMessage(() => evalText(`(module (global f64 (f32.const 13.37)))`), TypeError, /type mismatch/);
assertErrorMessage(() => evalText(`(module (global i32 (i32.add (i32.const 13) (i32.const 37))))`), TypeError, /failed to read end/);
assertErrorMessage(() => evalText(`(module (global i32 (get_global 0)))`), TypeError, /out of range/);
assertErrorMessage(() => evalText(`(module (global i32 (get_global 1)) (global i32 immutable (i32.const 1)))`), TypeError, /out of range/);
// Test a well-defined global section.
function testInner(type, initialValue, nextValue, coercion, assertFunc = assertEq)
{
var module = evalText(`(module
(global ${type} (${type}.const ${initialValue}))
(global ${type} immutable (${type}.const ${initialValue}))
(func $get (result ${type}) (get_global 0))
(func $set (param ${type}) (set_global 0 (get_local 0)))
(func $get_cst (result ${type}) (get_global 1))
(export "get" $get)
(export "get_cst" $get_cst)
(export "set" $set)
)`);
assertFunc(module.get(), coercion(initialValue));
assertEq(module.set(coercion(nextValue)), undefined);
assertFunc(module.get(), coercion(nextValue));
assertFunc(module.get_cst(), coercion(initialValue));
}
testInner('i32', 13, 37, x => x|0);
testInner('f32', 13.37, 0.1989, Math.fround);
testInner('f64', 13.37, 0.1989, x => +x);
// Semantic errors.
assertErrorMessage(() => evalText(`(module (global i32 (i32.const 1337)) (func (set_global 1 (i32.const 0))))`), TypeError, /out of range/);
assertErrorMessage(() => evalText(`(module (global i32 immutable (i32.const 1337)) (func (set_global 0 (i32.const 0))))`), TypeError, /can't write an immutable global/);
// Big module with many variables: test that setting one doesn't overwrite the
// other ones.
function get_set(i, type) { return `
(func $get_${i} (result ${type}) (get_global ${i}))
(func $set_${i} (param ${type}) (set_global ${i} (get_local 0)))
`
}
var module = evalText(`(module
(global i32 (i32.const 42))
(global i32 (i32.const 10))
(global f32 (f32.const 13.37))
(global f64 (f64.const 13.37))
(global i32 (i32.const -18))
${get_set(0, 'i32')}
${get_set(1, 'i32')}
${get_set(2, 'f32')}
${get_set(3, 'f64')}
${get_set(4, 'i32')}
(export "get0" $get_0) (export "set0" $set_0)
(export "get1" $get_1) (export "set1" $set_1)
(export "get2" $get_2) (export "set2" $set_2)
(export "get3" $get_3) (export "set3" $set_3)
(export "get4" $get_4) (export "set4" $set_4)
)`);
let values = [42, 10, Math.fround(13.37), 13.37, -18];
let nextValues = [13, 37, Math.fround(-17.89), 9.3, -13];
for (let i = 0; i < 5; i++) {
assertEq(module[`get${i}`](), values[i]);
assertEq(module[`set${i}`](nextValues[i]), undefined);
assertEq(module[`get${i}`](), nextValues[i]);
for (let j = 0; j < 5; j++) {
if (i === j)
continue;
assertEq(module[`get${j}`](), values[j]);
}
assertEq(module[`set${i}`](values[i]), undefined);
assertEq(module[`get${i}`](), values[i]);
}
// Initializer expressions can also be used in elem section initializers.
assertErrorMessage(() => evalText(`(module (import "globals" "a" (global f32 immutable)) (table (resizable 4)) (elem (get_global 0) $f) (func $f))`), TypeError, /type mismatch/);
module = evalText(`(module
(import "globals" "a" (global i32 immutable))
(table (resizable 4))
(elem (get_global 0) $f)
(func $f)
(export "f" $f)
(export "tbl" table)
)`, {
globals: {
a: 1
}
});
assertEq(module.f, module.tbl.get(1));
// Import/export rules.
assertErrorMessage(() => evalText(`(module (import "globals" "x" (global i32)))`), TypeError, /can't import.* mutable globals in the MVP/);
assertErrorMessage(() => evalText(`(module (global i32 (i32.const 42)) (export "" global 0))`), TypeError, /can't .*export mutable globals in the MVP/);
// Import/export semantics.
module = evalText(`(module
(import $g "globals" "x" (global i32 immutable))
(func $get (result i32) (get_global $g))
(export "getter" $get)
(export "value" global 0)
)`, { globals: {x: 42} });
assertEq(module.getter(), 42);
assertEq(module.value, 42);
// Imported globals and locally defined globals use the same index space.
module = evalText(`(module
(import "globals" "x" (global i32 immutable))
(global i32 immutable (i32.const 1337))
(export "imported" global 0)
(export "defined" global 1)
)`, { globals: {x: 42} });
assertEq(module.imported, 42);
assertEq(module.defined, 1337);
// Initializer expressions can reference an imported immutable global.
assertErrorMessage(() => evalText(`(module (global f32 immutable (f32.const 13.37)) (global i32 (get_global 0)))`), TypeError, /must reference a global immutable import/);
assertErrorMessage(() => evalText(`(module (global f32 (f32.const 13.37)) (global i32 (get_global 0)))`), TypeError, /must reference a global immutable import/);
assertErrorMessage(() => evalText(`(module (global i32 (i32.const 0)) (global i32 (get_global 0)))`), TypeError, /must reference a global immutable import/);
assertErrorMessage(() => evalText(`(module (import "globals" "a" (global f32 immutable)) (global i32 (get_global 0)))`), TypeError, /type mismatch/);
function testInitExpr(type, initialValue, nextValue, coercion, assertFunc = assertEq) {
var module = evalText(`(module
(import "globals" "a" (global ${type} immutable))
(global ${type} (get_global 0))
(global ${type} immutable (get_global 0))
(func $get0 (result ${type}) (get_global 0))
(func $get1 (result ${type}) (get_global 1))
(func $set1 (param ${type}) (set_global 1 (get_local 0)))
(func $get_cst (result ${type}) (get_global 2))
(export "get0" $get0)
(export "get1" $get1)
(export "get_cst" $get_cst)
(export "set1" $set1)
)`, {
globals: {
a: coercion(initialValue)
}
});
assertFunc(module.get0(), coercion(initialValue));
assertFunc(module.get1(), coercion(initialValue));
assertEq(module.set1(coercion(nextValue)), undefined);
assertFunc(module.get1(), coercion(nextValue));
assertFunc(module.get0(), coercion(initialValue));
assertFunc(module.get_cst(), coercion(initialValue));
}
testInitExpr('i32', 13, 37, x => x|0);
testInitExpr('f32', 13.37, 0.1989, Math.fround);
testInitExpr('f64', 13.37, 0.1989, x => +x);
// Int64.
if (hasI64()) {
assertErrorMessage(() => evalText(`(module (import "globals" "x" (global i64 immutable)))`), TypeError, /can't import.* an Int64 global/);
assertErrorMessage(() => evalText(`(module (global i64 immutable (i64.const 42)) (export "" global 0))`), TypeError, /can't .*export an Int64 global/);
setJitCompilerOption('wasm.test-mode', 1);
testInner('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
testInitExpr('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
module = evalText(`(module
(import "globals" "x" (global i64 immutable))
(global i64 immutable (i64.const 0xFAFADADABABA))
(export "imported" global 0)
(export "defined" global 1)
)`, { globals: {x: createI64('0x1234567887654321')} });
assertEqI64(module.imported, createI64('0x1234567887654321'));
assertEqI64(module.defined, createI64('0xFAFADADABABA'));
setJitCompilerOption('wasm.test-mode', 0);
} else {
assertErrorMessage(() => evalText(`(module (global i64 (i64.const 0)))`), TypeError, /NYI/);
assertErrorMessage(() => evalText(`(module (import "globals" "x" (global i64 immutable)))`), TypeError, /NYI/);
}

View File

@ -220,8 +220,8 @@ var code = textToBinary(`(module
(func $g (result i32) (i32.const 2))
(func $h (result i32) (i32.const 3))
(table (resizable 4))
(elem 0 $f)
(elem 2 $g)
(elem (i32.const 0) $f)
(elem (i32.const 2) $g)
(export "f1" $f)
(export "tbl1" table)
(export "f2" $f)
@ -267,6 +267,7 @@ assertEq(tbl, e.bar);
// Non-existent export errors
assertErrorMessage(() => new Module(textToBinary('(module (export "a" 0))')), TypeError, /exported function index out of bounds/);
assertErrorMessage(() => new Module(textToBinary('(module (export "a" global 0))')), TypeError, /exported global index out of bounds/);
assertErrorMessage(() => new Module(textToBinary('(module (export "a" memory))')), TypeError, /exported memory index out of bounds/);
assertErrorMessage(() => new Module(textToBinary('(module (export "a" table))')), TypeError, /exported table index out of bounds/);
@ -309,8 +310,8 @@ assertEq(i8[102], 0x0);
var m = new Module(textToBinary(`
(module
(import "a" "b" (table 10))
(elem 0 $one $two)
(elem 3 $three $four)
(elem (i32.const 0) $one $two)
(elem (i32.const 3) $three $four)
(func $one (result i32) (i32.const 1))
(func $two (result i32) (i32.const 2))
(func $three (result i32) (i32.const 3))

View File

@ -21,7 +21,7 @@ var callee = i => `(func $f${i} (type $v2i) (result i32) (i32.const ${i}))`;
// should not hold their originating table alive. Live exported functions should
// hold instances alive. Nothing should hold the export object alive.
resetFinalizeCount();
var i = evalText(`(module (table (resizable 2)) (export "tbl" table) (elem 0 $f0) ${callee(0)} ${caller})`);
var i = evalText(`(module (table (resizable 2)) (export "tbl" table) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`);
var e = i.exports;
var t = e.tbl;
var f = t.get(0);
@ -59,7 +59,7 @@ assertEq(finalizeCount(), 5);
// A table should hold the instance of any of its elements alive.
resetFinalizeCount();
var i = evalText(`(module (table (resizable 1)) (export "tbl" table) (elem 0 $f0) ${callee(0)} ${caller})`);
var i = evalText(`(module (table (resizable 1)) (export "tbl" table) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`);
var e = i.exports;
var t = e.tbl;
var f = t.get(0);

View File

@ -14,13 +14,28 @@ const evalText = (str, imports) => new Instance(new Module(textToBinary(str)), i
var callee = i => `(func $f${i} (result i32) (i32.const ${i}))`;
assertErrorMessage(() => new Module(textToBinary(`(module (elem 0 $f0) ${callee(0)})`)), TypeError, /table index out of range/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem 0 0))`)), TypeError, /table element out of range/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (func) (elem 0 0 1))`)), TypeError, /table element out of range/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem 10 $f0) ${callee(0)})`)), TypeError, /element segment does not fit/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem 8 $f0 $f0 $f0) ${callee(0)})`)), TypeError, /element segment does not fit/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem 1 $f0 $f0) (elem 0 $f0) ${callee(0)})`)), TypeError, /must be.*ordered/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem 1 $f0 $f0) (elem 2 $f0) ${callee(0)})`)), TypeError, /must be.*disjoint/);
assertErrorMessage(() => new Module(textToBinary(`(module (elem (i32.const 0) $f0) ${callee(0)})`)), TypeError, /table index out of range/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 0) 0))`)), TypeError, /table element out of range/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (func) (elem (i32.const 0) 0 1))`)), TypeError, /table element out of range/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (func) (elem (f32.const 0) 0) ${callee(0)})`)), TypeError, /type mismatch/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 10) $f0) ${callee(0)})`)), TypeError, /element segment does not fit/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`)), TypeError, /element segment does not fit/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)), TypeError, /must be.*ordered/);
assertErrorMessage(() => new Module(textToBinary(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)), TypeError, /must be.*disjoint/);
assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:10}}), TypeError, /element segment does not fit/);
assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), TypeError, /element segment does not fit/);
assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (i32.const 1) $f0 $f0) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:0}}), TypeError, /must be.*ordered/);
assertErrorMessage(() => evalText(`(module (table (resizable 10)) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`, {globals:{a:1}}), TypeError, /must be.*disjoint/);
var tbl = new Table({initial:50});
assertErrorMessage(() => evalText(`(module
(import "globals" "table" (table 10 100))
(import "globals" "a" (global i32 immutable))
(elem (get_global 0) $f0 $f0)
${callee(0)})
`, {globals:{a:20, table:tbl}}), Error, /element segment does not fit/);
var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect $v2i (get_local $i))) (export "call" $call)`
var callee = i => `(func $f${i} (type $v2i) (result i32) (i32.const ${i}))`;
@ -29,17 +44,17 @@ var call = evalText(`(module (table (resizable 10)) ${callee(0)} ${caller})`).ex
assertErrorMessage(() => call(0), Error, /bad wasm indirect call/);
assertErrorMessage(() => call(10), Error, /out-of-range/);
var call = evalText(`(module (table (resizable 10)) (elem 0) ${callee(0)} ${caller})`).exports.call;
var call = evalText(`(module (table (resizable 10)) (elem (i32.const 0)) ${callee(0)} ${caller})`).exports.call;
assertErrorMessage(() => call(0), Error, /bad wasm indirect call/);
assertErrorMessage(() => call(10), Error, /out-of-range/);
var call = evalText(`(module (table (resizable 10)) (elem 0 $f0) ${callee(0)} ${caller})`).exports.call;
var call = evalText(`(module (table (resizable 10)) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`).exports.call;
assertEq(call(0), 0);
assertErrorMessage(() => call(1), Error, /bad wasm indirect call/);
assertErrorMessage(() => call(2), Error, /bad wasm indirect call/);
assertErrorMessage(() => call(10), Error, /out-of-range/);
var call = evalText(`(module (table (resizable 10)) (elem 1 $f0 $f1) (elem 4 $f0 $f2) ${callee(0)} ${callee(1)} ${callee(2)} ${caller})`).exports.call;
var call = evalText(`(module (table (resizable 10)) (elem (i32.const 1) $f0 $f1) (elem (i32.const 4) $f0 $f2) ${callee(0)} ${callee(1)} ${callee(2)} ${caller})`).exports.call;
assertErrorMessage(() => call(0), Error, /bad wasm indirect call/);
assertEq(call(1), 0);
assertEq(call(2), 1);
@ -50,7 +65,7 @@ assertErrorMessage(() => call(6), Error, /bad wasm indirect call/);
assertErrorMessage(() => call(10), Error, /out-of-range/);
var tbl = new Table({initial:3});
var call = evalText(`(module (import "a" "b" (table 2)) (export "tbl" table) (elem 0 $f0 $f1) ${callee(0)} ${callee(1)} ${caller})`, {a:{b:tbl}}).exports.call;
var call = evalText(`(module (import "a" "b" (table 2)) (export "tbl" table) (elem (i32.const 0) $f0 $f1) ${callee(0)} ${callee(1)} ${caller})`, {a:{b:tbl}}).exports.call;
assertEq(call(0), 0);
assertEq(call(1), 1);
assertEq(tbl.get(0)(), 0);

View File

@ -2139,6 +2139,8 @@ jit::MakeMRegExpHoistable(MIRGraph& graph)
// faster than a not movable regexp.
RegExpObject* source = regexp->source();
if (source->sticky() || source->global()) {
if (!graph.alloc().ensureBallast())
return false;
MConstant* zero = MConstant::New(graph.alloc(), Int32Value(0));
regexp->block()->insertAfter(regexp, zero);

View File

@ -4083,13 +4083,20 @@ LIRGenerator::visitHasClass(MHasClass* ins)
void
LIRGenerator::visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins)
{
define(new(alloc()) LWasmLoadGlobalVar, ins);
if (ins->type() == MIRType::Int64)
defineInt64(new(alloc()) LWasmLoadGlobalVarI64, ins);
else
define(new(alloc()) LWasmLoadGlobalVar, ins);
}
void
LIRGenerator::visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins)
{
add(new(alloc()) LWasmStoreGlobalVar(useRegisterAtStart(ins->value())), ins);
MDefinition* value = ins->value();
if (value->type() == MIRType::Int64)
add(new(alloc()) LWasmStoreGlobalVarI64(useInt64RegisterAtStart(value)), ins);
else
add(new(alloc()) LWasmStoreGlobalVar(useRegisterAtStart(value)), ins);
}
void

View File

@ -8062,6 +8062,15 @@ class LWasmLoadGlobalVar : public LInstructionHelper<1, 0, 0>
}
};
class LWasmLoadGlobalVarI64 : public LInstructionHelper<INT64_PIECES, 0, 0>
{
public:
LIR_HEADER(WasmLoadGlobalVarI64);
MWasmLoadGlobalVar* mir() const {
return mir_->toWasmLoadGlobalVar();
}
};
class LWasmStoreGlobalVar : public LInstructionHelper<0, 1, 0>
{
public:
@ -8077,6 +8086,19 @@ class LWasmStoreGlobalVar : public LInstructionHelper<0, 1, 0>
}
};
class LWasmStoreGlobalVarI64 : public LInstructionHelper<0, INT64_PIECES, 0>
{
public:
LIR_HEADER(WasmStoreGlobalVarI64);
explicit LWasmStoreGlobalVarI64(const LInt64Allocation& value) {
setInt64Operand(0, value);
}
MWasmStoreGlobalVar* mir() const {
return mir_->toWasmStoreGlobalVar();
}
static const uint32_t InputIndex = 0;
};
class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 0>
{
public:

View File

@ -390,7 +390,9 @@
_(WasmStore) \
_(WasmBoundsCheck) \
_(WasmLoadGlobalVar) \
_(WasmLoadGlobalVarI64) \
_(WasmStoreGlobalVar) \
_(WasmStoreGlobalVarI64) \
_(AsmJSLoadHeap) \
_(AsmJSStoreHeap) \
_(AsmJSLoadFuncPtr) \

View File

@ -1211,6 +1211,15 @@ CodeGeneratorX64::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
MWasmLoadGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->type() == MIRType::Int64);
CodeOffset label = masm.loadRipRelativeInt64(ToRegister(ins->output()));
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
@ -1246,6 +1255,16 @@ CodeGeneratorX64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->value()->type() == MIRType::Int64);
Register value = ToRegister(ins->getOperand(LWasmStoreGlobalVarI64::InputIndex));
CodeOffset label = masm.storeRipRelativeInt64(value);
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitTruncateDToInt32(LTruncateDToInt32* ins)
{

View File

@ -77,6 +77,8 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared
void visitWasmStore(LWasmStore* ins);
void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins);
void visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins);
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
void visitAsmSelectI64(LAsmSelectI64* ins);
void visitAsmJSCall(LAsmJSCall* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);

View File

@ -5554,7 +5554,7 @@ static void DebugPaintItem(DrawTarget& aDrawTarget,
aPresContext->AppUnitsPerDevPixel());
RefPtr<DrawTarget> tempDT =
aDrawTarget.CreateSimilarDrawTarget(IntSize(bounds.width, bounds.height),
aDrawTarget.CreateSimilarDrawTarget(IntSize::Truncate(bounds.width, bounds.height),
SurfaceFormat::B8G8R8A8);
RefPtr<gfxContext> context = gfxContext::CreateOrNull(tempDT);
if (!context) {

View File

@ -1351,6 +1351,7 @@ public:
, mScrollClip(nullptr)
, mReferenceFrame(nullptr)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif

View File

@ -6541,7 +6541,7 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
// XXX(seth): May be buggy; see bug 1151016.
CSSIntSize svgViewportSize = currentMatrix.IsIdentity()
? CSSIntSize(intImageSize.width, intImageSize.height)
: CSSIntSize(devPixelDest.width, devPixelDest.height);
: CSSIntSize::Truncate(devPixelDest.width, devPixelDest.height);
// Compute the set of pixels that would be sampled by an ideal rendering
gfxPoint subimageTopLeft =

View File

@ -307,8 +307,8 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
return;
}
dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width),
ceil(destRect.height)),
dt = destDT->CreateSimilarDrawTarget(IntSize::Ceil(destRect.width,
destRect.height),
SurfaceFormat::B8G8R8A8);
if (dt && dt->IsValid()) {
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);

View File

@ -403,7 +403,7 @@ nsSVGImageFrame::PaintSVG(gfxContext& aContext,
// come from width/height *attributes* in SVG). They influence the region
// of the SVG image's internal document that is visible, in combination
// with preserveAspectRatio and viewBox.
SVGImageContext context(CSSIntSize(width, height),
SVGImageContext context(CSSIntSize::Truncate(width, height),
Some(imgElem->mPreserveAspectRatio.GetAnimValue()),
1.0, true);

View File

@ -587,7 +587,7 @@ CacheFileChunk::UpdateDataSize(uint32_t aOffset, uint32_t aLen)
mIsDirty = true;
int64_t fileSize = kChunkSize * mIndex + aOffset + aLen;
int64_t fileSize = static_cast<int64_t>(kChunkSize) * mIndex + aOffset + aLen;
bool notify = false;
if (fileSize > mFile->mDataSize) {

View File

@ -60,11 +60,6 @@ function contentHandler(metadata, response)
function run_test()
{
if (!newCacheBackEndUsed()) {
do_check_true(true, "This test doesn't run when the old cache back end is used since the behavior is different");
return;
}
// Static check
do_check_true(responseBody.length > 1024);

View File

@ -65,6 +65,11 @@ function run_test()
do_get_profile();
if (!newCacheBackEndUsed()) {
do_check_true(true, "This test doesn't run when the old cache back end is used since the behavior is different");
return;
}
Services.prefs.setIntPref("browser.cache.disk.max_entry_size", 1);
httpServer = new HttpServer();

View File

@ -55,16 +55,16 @@ function contentHandler(metadata, response)
function run_test()
{
if (!newCacheBackEndUsed()) {
do_check_true(true, "This test doesn't run when the old cache back end is used since the behavior is different");
return;
}
// Static check
do_check_true(responseBody.length > 1024);
do_get_profile();
if (!newCacheBackEndUsed()) {
do_check_true(true, "This test doesn't run when the old cache back end is used since the behavior is different");
return;
}
Services.prefs.setIntPref("browser.cache.disk.max_entry_size", 1);
httpServer = new HttpServer();

View File

@ -282,6 +282,7 @@ SandboxInfo::SubmitTelemetry()
sandboxInfo.Test(SandboxInfo::kEnabledForMedia));
}
#ifdef MOZ_CRASHREPORTER
void
SandboxInfo::AnnotateCrashReport() const
{
@ -291,5 +292,6 @@ SandboxInfo::AnnotateCrashReport() const
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString);
}
#endif
} // namespace mozilla

View File

@ -57,7 +57,9 @@ public:
return !Test(kEnabledForMedia) || Test(kHasSeccompBPF);
}
#ifdef MOZ_CRASHREPORTER
MOZ_EXPORT void AnnotateCrashReport() const;
#endif
static void SubmitTelemetry();

View File

@ -17,6 +17,7 @@ echo "running as" $(id)
: NEED_WINDOW_MANAGER ${NEED_WINDOW_MANAGER:=false}
: NEED_PULSEAUDIO ${NEED_PULSEAUDIO:=false}
: START_VNC ${START_VNC:=false}
: TASKCLUSTER_INTERACTIVE ${TASKCLUSTER_INTERACTIVE:=false}
: WORKSPACE ${WORKSPACE:=/home/worker/workspace}
: mozharness args "${@}"
@ -42,10 +43,12 @@ cleanup() {
# To share X issues
cp /home/worker/.xsession-errors ~/artifacts/public/xsession-errors.log
fi
# When you call this script with START_VNC we make sure we
# don't kill xvfb so you don't lose your VNC connection
if [ -n "$xvfb_pid" ] && [ $START_VNC == false ] ; then
# When you call this script with START_VNC or TASKCLUSTER_INTERACTIVE
# we make sure we don't kill xvfb so you don't lose your connection
xvfb_pid=`pidof Xvfb`
if [ -n "$xvfb_pid" ] && [ $START_VNC == false ] && [ $TASKCLUSTER_INTERACTIVE == false ] ; then
kill $xvfb_pid || true
screen -XS xvfb quit || true
fi
exit $rv
}
@ -70,12 +73,11 @@ if $NEED_PULSEAUDIO; then
pactl load-module module-null-sink
fi
# run XVfb in the background, if necessary
# run Xvfb in the background, if necessary
if $NEED_XVFB; then
Xvfb :0 -nolisten tcp -screen 0 1600x1200x24 \
> ~/artifacts/public/xvfb.log 2>&1 &
screen -dmS xvfb Xvfb :0 -nolisten tcp -screen 0 1600x1200x24 \
> ~/artifacts/public/xvfb.log 2>&1
export DISPLAY=:0
xvfb_pid=$!
# Only error code 255 matters, because it signifies that no
# display could be opened. As long as we can open the display
# tests should work. We'll retry a few times with a sleep before
@ -146,7 +148,7 @@ exec \${cmd}" > ${mozharness_bin}
chmod +x ${mozharness_bin}
# In interactive mode, the user will be prompted with options for what to do.
if [ "$TASKCLUSTER_INTERACTIVE" != "true" ]; then
if ! $TASKCLUSTER_INTERACTIVE; then
# run the given mozharness script and configs, but pass the rest of the
# arguments in from our own invocation
${mozharness_bin};

View File

@ -19,6 +19,9 @@ from taskgraph.util.time import (
logger = logging.getLogger(__name__)
# the maximum number of parallel createTask calls to make
CONCURRENCY = 50
def create_tasks(taskgraph, label_to_taskid):
# TODO: use the taskGroupId of the decision task
@ -29,7 +32,7 @@ def create_tasks(taskgraph, label_to_taskid):
decision_task_id = os.environ.get('TASK_ID')
with futures.ThreadPoolExecutor(requests.adapters.DEFAULT_POOLSIZE) as e:
with futures.ThreadPoolExecutor(CONCURRENCY) as e:
fs = {}
# We can't submit a task until its dependencies have been submitted.

View File

@ -21,8 +21,8 @@ already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch() const
MOZ_ASSERT(NS_IsMainThread(),
"Can only create dom::Touch instances on main thread");
RefPtr<Touch> touch = new Touch(mIdentifier,
LayoutDeviceIntPoint(mScreenPoint.x, mScreenPoint.y),
LayoutDeviceIntPoint(mRadius.width, mRadius.height),
LayoutDeviceIntPoint::Truncate(mScreenPoint.x, mScreenPoint.y),
LayoutDeviceIntPoint::Truncate(mRadius.width, mRadius.height),
mRotationAngle,
mForce);
return touch.forget();

View File

@ -507,10 +507,10 @@ AndroidGeckoEvent::MakeTouchEvent(nsIWidget* widget)
// and the Points() array has points in CSS pixels, which we need
// to convert.
CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
LayoutDeviceIntPoint pt(
auto pt = LayoutDeviceIntPoint::Truncate(
(Points()[i].x * scale.scale) - offset.x,
(Points()[i].y * scale.scale) - offset.y);
LayoutDeviceIntPoint radius(
auto radius = LayoutDeviceIntPoint::Truncate(
PointRadii()[i].x * scale.scale,
PointRadii()[i].y * scale.scale);
RefPtr<Touch> t = new Touch(PointIndicies()[i],
@ -625,8 +625,8 @@ AndroidGeckoEvent::MakeMouseEvent(nsIWidget* widget)
const LayoutDeviceIntPoint& offset = widget->WidgetToScreenOffset();
CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
event.mRefPoint =
LayoutDeviceIntPoint((Points()[0].x * scale.scale) - offset.x,
(Points()[0].y * scale.scale) - offset.y);
LayoutDeviceIntPoint::Truncate((Points()[0].x * scale.scale) - offset.x,
(Points()[0].y * scale.scale) - offset.y);
return event;
}

View File

@ -1620,8 +1620,9 @@ nsWindow::Resize(double aX,
mBounds.width = NSToIntRound(aWidth);
mBounds.height = NSToIntRound(aHeight);
if (needSizeDispatch)
OnSizeChanged(gfx::IntSize(aWidth, aHeight));
if (needSizeDispatch) {
OnSizeChanged(gfx::IntSize::Truncate(aWidth, aHeight));
}
// Should we skip honoring aRepaint here?
if (aRepaint && FindTopLevel() == nsWindow::TopWindow())

View File

@ -3746,7 +3746,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
NSSize viewSize = [self bounds].size;
nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale);
gfx::IntSize backingSize = gfx::IntSize::Truncate(viewSize.width * scale, viewSize.height * scale);
LayoutDeviceIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect];
bool painted = mGeckoChild->PaintWindowInContext(aContext, region, backingSize);
@ -4126,7 +4126,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
if ([theEvent type] == NSLeftMouseDown) {
NSPoint point = [NSEvent mouseLocation];
FlipCocoaScreenCoordinate(point);
nsIntPoint pos(point.x, point.y);
gfx::IntPoint pos = gfx::IntPoint::Truncate(point.x, point.y);
consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, true, &pos, nullptr);
}
else {
@ -5770,7 +5770,7 @@ PanGestureTypeForEvent(NSEvent* aEvent)
nsDragService* dragService = static_cast<nsDragService *>(mDragService);
NSPoint pnt = [NSEvent mouseLocation];
FlipCocoaScreenCoordinate(pnt);
dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y)));
dragService->SetDragEndPoint(gfx::IntPoint::Round(pnt.x, pnt.y));
// XXX: dropEffect should be updated per |operation|.
// As things stand though, |operation| isn't well handled within "our"

View File

@ -477,7 +477,7 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer *aImage, ui
// Render a vector image at the correct resolution on a retina display
if (aImage->GetType() == imgIContainer::TYPE_VECTOR && scaleFactor != 1.0f) {
IntSize scaledSize(ceil(width * scaleFactor), ceil(height * scaleFactor));
IntSize scaledSize = IntSize::Ceil(width * scaleFactor, height * scaleFactor);
RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(scaledSize, SurfaceFormat::B8G8R8A8);

View File

@ -146,7 +146,7 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget()
GetPaperRect(&top, &left, &bottom, &right);
const double width = right - left;
const double height = bottom - top;
IntSize size(floor(width), floor(height));
IntSize size = IntSize::Floor(width, height);
CGContextRef context;
::PMSessionGetCGGraphicsContext(mPrintSession, &context);

View File

@ -161,7 +161,7 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecGTK::MakePrintTarget()
}
}
IntSize size(width, height);
IntSize size = IntSize::Truncate(width, height);
if (format == nsIPrintSettings::kOutputFormatPDF) {
return PrintTargetPDF::CreateOrNull(stream, size);

Some files were not shown because too many files have changed in this diff Show More