This commit is contained in:
Ryan VanderMeulen 2014-11-11 16:53:12 -05:00
Родитель 9556bac074 12b79ce664
Коммит 40ef701a45
145 изменённых файлов: 1584 добавлений и 700 удалений

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

@ -199,8 +199,12 @@ NS_IMETHODIMP
xpcAccessible::GetState(uint32_t* aState, uint32_t* aExtraState)
{
NS_ENSURE_ARG_POINTER(aState);
if (!Intl())
nsAccUtils::To32States(states::DEFUNCT, aState, aExtraState);
else
nsAccUtils::To32States(Intl()->State(), aState, aExtraState);
nsAccUtils::To32States(Intl()->State(), aState, aExtraState);
return NS_OK;
}

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ed238f7f8824973ea16e69aef08c6a1d58c7165f"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ed238f7f8824973ea16e69aef08c6a1d58c7165f"/>

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

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "a7c053f5e582c15255c49645b07a19d72e4e5cb2",
"revision": "7ca06f787f88fc9571667cbc68ba07319229cd0b",
"repo_path": "integration/gaia-central"
}

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

@ -17,9 +17,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ed238f7f8824973ea16e69aef08c6a1d58c7165f"/>

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

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ed238f7f8824973ea16e69aef08c6a1d58c7165f"/>

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

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6af3a8a833eb8bb651e8b188cb3f3c3a43bb4184"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5ae28ff11b982e2bd7d1aa097cda131536952bdc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -421,6 +421,10 @@ add_task(function* openFxASettings() {
yield new Promise((resolve, reject) => {
let progressListener = {
onLocationChange: function onLocationChange(aBrowser) {
if (aBrowser.currentURI.spec == BASE_URL) {
// Ignore the changes from the addTab above.
return;
}
gBrowser.removeTabsProgressListener(progressListener);
let contentURI = Services.io.newURI(params.content_uri, null, null);
is(aBrowser.currentURI.spec, Services.io.newURI("/settings", null, contentURI).spec,

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

@ -17,6 +17,7 @@
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIClassInfoImpl.h"
#include "nsIProtocolHandler.h"
#include "nsError.h"
#include "nsIContentSecurityPolicy.h"
#include "jswrapper.h"
@ -490,6 +491,18 @@ nsPrincipal::GetBaseDomain(nsACString& aBaseDomain)
}
}
bool hasNoRelativeFlag;
nsresult rv = NS_URIChainHasFlags(mCodebase,
nsIProtocolHandler::URI_NORELATIVE,
&hasNoRelativeFlag);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (hasNoRelativeFlag) {
return mCodebase->GetSpec(aBaseDomain);
}
// For everything else, we ask the TLD service via
// the ThirdPartyUtil.
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =

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

@ -646,21 +646,26 @@ nsCSPParser::sourceExpression()
// mCurValue = ""
resetCurValue();
// If mCurToken does not provide a scheme, we apply the scheme from selfURI
// If mCurToken does not provide a scheme (scheme-less source), we apply the scheme
// from selfURI but we also need to remember if the protected resource is http, in
// which case we should allow https loads, see:
// http://www.w3.org/TR/CSP2/#match-source-expression
bool allowHttps = false;
if (parsedScheme.IsEmpty()) {
// Resetting internal helpers, because we might already have parsed some of the host
// when trying to parse a scheme.
resetCurChar(mCurToken);
nsAutoCString scheme;
mSelfURI->GetScheme(scheme);
parsedScheme.AssignASCII(scheme.get());
nsAutoCString selfScheme;
mSelfURI->GetScheme(selfScheme);
parsedScheme.AssignASCII(selfScheme.get());
allowHttps = selfScheme.EqualsASCII("http");
}
// At this point we are expecting a host to be parsed.
// Trying to create a new nsCSPHost.
if (nsCSPHostSrc *cspHost = hostSource()) {
// Do not forget to set the parsed scheme.
cspHost->setScheme(parsedScheme);
cspHost->setScheme(parsedScheme, allowHttps);
return cspHost;
}
// Error was reported in hostSource()

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

@ -279,6 +279,7 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const
nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
: mHost(aHost)
, mAllowHttps(false)
{
ToLowerCase(mHost);
}
@ -307,7 +308,16 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
NS_ENSURE_SUCCESS(rv, false);
if (!mScheme.IsEmpty() &&
!mScheme.EqualsASCII(scheme.get())) {
return false;
// We should not return false for scheme-less sources where the protected resource
// is http and the load is https, see:
// http://www.w3.org/TR/CSP2/#match-source-expression
bool isHttpsScheme =
(NS_SUCCEEDED(aUri->SchemeIs("https", &isHttpsScheme)) && isHttpsScheme);
if (!(isHttpsScheme && mAllowHttps)) {
return false;
}
}
// The host in nsCSpHostSrc should never be empty. In case we are enforcing
@ -386,7 +396,13 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
if (mPort.IsEmpty()) {
int32_t port = NS_GetDefaultPort(NS_ConvertUTF16toUTF8(mScheme).get());
if (port != uriPort) {
return false;
// We should not return false for scheme-less sources where the protected resource
// is http and the load is https, see: http://www.w3.org/TR/CSP2/#match-source-expression
// BUT, we only allow scheme-less sources to be upgraded from http to https if CSP
// does not explicitly define a port.
if (!(uriPort == NS_GetDefaultPort("https") && mAllowHttps)) {
return false;
}
}
}
// 4.7) Port matching: Compare the ports.
@ -431,10 +447,11 @@ nsCSPHostSrc::toString(nsAString& outStr) const
}
void
nsCSPHostSrc::setScheme(const nsAString& aScheme)
nsCSPHostSrc::setScheme(const nsAString& aScheme, bool aAllowHttps)
{
mScheme = aScheme;
ToLowerCase(mScheme);
mAllowHttps = aAllowHttps;
}
void

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

@ -220,7 +220,7 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
void toString(nsAString& outStr) const;
void setScheme(const nsAString& aScheme);
void setScheme(const nsAString& aScheme, bool aAllowHttps = false);
void setPort(const nsAString& aPort);
void appendPath(const nsAString &aPath);
@ -229,6 +229,7 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
nsString mHost;
nsString mPort;
nsString mPath;
bool mAllowHttps;
};
/* =============== nsCSPKeywordSrc ============ */

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

@ -427,46 +427,61 @@ private:
bool IsDeniedCrossSiteRequest();
public:
void Send(ErrorResult& aRv)
void Send(JSContext* /*aCx*/, ErrorResult& aRv)
{
aRv = Send(Nullable<RequestBody>());
}
void Send(const mozilla::dom::ArrayBuffer& aArrayBuffer, ErrorResult& aRv)
void Send(JSContext* /*aCx*/,
const mozilla::dom::ArrayBuffer& aArrayBuffer,
ErrorResult& aRv)
{
aRv = Send(RequestBody(&aArrayBuffer));
}
void Send(const mozilla::dom::ArrayBufferView& aArrayBufferView,
void Send(JSContext* /*aCx*/,
const mozilla::dom::ArrayBufferView& aArrayBufferView,
ErrorResult& aRv)
{
aRv = Send(RequestBody(&aArrayBufferView));
}
void Send(mozilla::dom::File& aBlob, ErrorResult& aRv)
void Send(JSContext* /*aCx*/, mozilla::dom::File& aBlob, ErrorResult& aRv)
{
aRv = Send(RequestBody(aBlob));
}
void Send(nsIDocument& aDoc, ErrorResult& aRv)
void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv)
{
aRv = Send(RequestBody(&aDoc));
}
void Send(const nsAString& aString, ErrorResult& aRv)
void Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv)
{
if (DOMStringIsNull(aString)) {
Send(aRv);
Send(aCx, aRv);
}
else {
aRv = Send(RequestBody(aString));
}
}
void Send(nsFormData& aFormData, ErrorResult& aRv)
void Send(JSContext* /*aCx*/, nsFormData& aFormData, ErrorResult& aRv)
{
aRv = Send(RequestBody(aFormData));
}
void Send(nsIInputStream* aStream, ErrorResult& aRv)
void Send(JSContext* aCx, nsIInputStream* aStream, ErrorResult& aRv)
{
NS_ASSERTION(aStream, "Null should go to string version");
nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aStream);
if (wjs) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
JSObject* data = wjs->GetJSObject();
if (!data) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
JS::Rooted<JS::Value> dataAsValue(aCx, JS::ObjectValue(*data));
nsAutoString dataAsString;
if (ConvertJSValueToString(aCx, dataAsValue, mozilla::dom::eNull,
mozilla::dom::eNull, dataAsString)) {
Send(aCx, dataAsString, aRv);
} else {
aRv.Throw(NS_ERROR_FAILURE);
}
return;
}
aRv = Send(RequestBody(aStream));

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

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 826805 - CSP: Allow http and https for scheme-less sources</title>
</head>
<body>
<div id="testdiv">blocked</div>
<!--
We resue file_csp_path_matching.js which just updates the contents of 'testdiv' to contain allowed.
Note, that we are loading the file_csp_path_matchting.js using a scheme of 'https'.
-->
<script src="https://example.com/tests/dom/base/test/csp/file_csp_path_matching.js#foo"></script>
</body>
</html>

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

@ -4,6 +4,7 @@ support-files =
file_connect-src.html
file_CSP.css
file_CSP.sjs
file_csp_allow_https_schemes.html
file_CSP_bug663567.xsl
file_CSP_bug663567_allows.xml
file_CSP_bug663567_allows.xml^headers^
@ -103,6 +104,8 @@ support-files =
[test_base-uri.html]
[test_connect-src.html]
[test_CSP.html]
[test_csp_allow_https_schemes.html]
skip-if = buildapp == 'b2g' #no ssl support
[test_CSP_bug663567.html]
[test_CSP_bug802872.html]
[test_CSP_bug885433.html]

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

@ -91,6 +91,7 @@ function loadNextTest() {
if (counter == tests.length) {
window.ConnectSrcExaminer.remove();
SimpleTest.finish();
return;
}
var src = "file_csp_testserver.sjs";

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

@ -0,0 +1,71 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 826805 - Allow http and https for scheme-less sources</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>
<p id="display"></p>
<div id="content" style="visibility: hidden">
<iframe style="width:100%;" id="testframe"></iframe>
</div>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
/* Description of the test:
* We are loading the following url (including a fragment portion):
* https://example.com/tests/dom/base/test/csp/file_csp_path_matching.js#foo
* using different policies that lack specification of a scheme.
*
* Since the file is served over http:, the upgrade to https should be
* permitted by CSP in case no port is specified.
*/
var policies = [
["allowed", "example.com"],
["allowed", "example.com:443"],
["blocked", "example.com:80"]
]
var counter = 0;
var policy;
function loadNextTest() {
if (counter == policies.length) {
SimpleTest.finish();
}
else {
policy = policies[counter++];
var src = "file_csp_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/base/test/csp/file_csp_allow_https_schemes.html");
// append the CSP that should be used to serve the file
src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);
document.getElementById("testframe").addEventListener("load", test, false);
document.getElementById("testframe").src = src;
}
}
function test() {
try {
document.getElementById("testframe").removeEventListener('load', test, false);
var testframe = document.getElementById("testframe");
var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
is(divcontent, policy[0], "should be " + policy[0] + " in test " + (counter - 1) + "!");
}
catch (e) {
ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
}
loadNextTest();
}
loadNextTest();
</script>
</body>
</html>

21
dom/base/test/echo.sjs Normal file
Просмотреть файл

@ -0,0 +1,21 @@
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
function handleRequest(request, response)
{
response.setHeader("Content-Type", "text/plain");
if (request.method == "GET") {
response.write(request.queryString);
return;
}
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var body = "";
var bodyAvail;
while ((bodyAvail = bodyStream.available()) > 0)
body += String.fromCharCode.apply(null, bodyStream.readByteArray(bodyAvail));
response.write(body);
}

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

@ -56,6 +56,7 @@ support-files =
bug819051.sjs
copypaste.js
delayedServerEvents.sjs
echo.sjs
eventsource.resource
eventsource.resource^headers^
eventsource_redirect.resource
@ -384,7 +385,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || (os == 'linux' && debug &
[test_bug340571.html]
[test_bug343596.html]
[test_bug345339.html]
skip-if = e10s # Bug 1081453 - shutdown leaks with e10s and WebIDL dom::File
[test_bug346485.html]
[test_bug352728.html]
[test_bug352728.xhtml]
@ -739,6 +739,7 @@ skip-if = toolkit == 'android'
[test_xhr_forbidden_headers.html]
[test_xhr_progressevents.html]
skip-if = toolkit == 'android'
[test_xhr_send.html]
[test_xhr_send_readystate.html]
[test_xhr_withCredentials.html]
[test_file_from_blob.html]

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

@ -0,0 +1,83 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1096263
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1096263</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1096263 **/
SimpleTest.waitForExplicitFinish();
function simpleGetTest() {
var x = new XMLHttpRequest();
x.open("GET", "echo.sjs");
x.onload = function() {
ok(true, "Should have processed GET");
simplePostTest();
}
x.send({});
}
function simplePostTest() {
var x = new XMLHttpRequest();
x.open("POST", "echo.sjs");
x.onload = function() {
ise(x.responseText, "somedata", "Should have processed POST");
undefinedPostTest();
}
x.send({toString: function() { return "somedata"; }});
}
function undefinedPostTest() {
var x = new XMLHttpRequest();
x.open("POST", "echo.sjs");
x.onload = function() {
ise(x.responseText, "undefined", "Should have processed POST");
nullPostTest();
}
x.send({toString: function() { return undefined; }});
}
function nullPostTest() {
var x = new XMLHttpRequest();
x.open("POST", "echo.sjs");
x.onload = function() {
ise(x.responseText, "null", "Should have processed POST");
testExceptionInToString();
}
x.send({toString: function() { return null; }});
}
function testExceptionInToString() {
var x = new XMLHttpRequest();
x.open("GET", "echo.sjs");
x.onload = function() {
ok(false);
SimpleTest.finish();
}
try {
x.send({toString: function() { throw "dummy"; }});
} catch(ex) {
ise(ex, "dummy");
SimpleTest.finish();
}
}
</script>
</head>
<body onload="simpleGetTest()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1096263">Mozilla Bug 1096263</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
</pre>
</body>
</html>

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

@ -1551,7 +1551,7 @@ DOMInterfaces = {
'XMLHttpRequest': [
{
'nativeType': 'nsXMLHttpRequest',
'implicitJSContext': [ 'constructor', ],
'implicitJSContext': [ 'constructor', 'send'],
},
{
'workers': True,

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

@ -409,7 +409,7 @@ class CGDOMJSClass(CGThing):
nullptr, /* deleteGeneric */
nullptr, /* watch */
nullptr, /* unwatch */
nullptr, /* slice */
nullptr, /* getElements */
nullptr, /* enumerate */
JS_ObjectToOuterObject /* thisObject */
}
@ -10716,7 +10716,7 @@ class CGDOMJSProxyHandler_finalize(ClassMethod):
finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
class CGDOMJSProxyHandler_slice(ClassMethod):
class CGDOMJSProxyHandler_getElements(ClassMethod):
def __init__(self, descriptor):
assert descriptor.supportsIndexedProperties()
@ -10724,8 +10724,8 @@ class CGDOMJSProxyHandler_slice(ClassMethod):
Argument('JS::Handle<JSObject*>', 'proxy'),
Argument('uint32_t', 'begin'),
Argument('uint32_t', 'end'),
Argument('JS::Handle<JSObject*>', 'array')]
ClassMethod.__init__(self, "slice", "bool", args, virtual=True, override=True, const=True)
Argument('js::ElementAdder*', 'adder')]
ClassMethod.__init__(self, "getElements", "bool", args, virtual=True, override=True, const=True)
self.descriptor = descriptor
def getBody(self):
@ -10738,7 +10738,7 @@ class CGDOMJSProxyHandler_slice(ClassMethod):
'jsvalRef': 'temp',
'jsvalHandle': '&temp',
'obj': 'proxy',
'successCode': ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n"
'successCode': ("adder->append(cx, temp);\n"
"continue;\n")
}
get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define()
@ -10763,7 +10763,7 @@ class CGDOMJSProxyHandler_slice(ClassMethod):
if (!js::GetObjectProto(cx, proxy, &proto)) {
return false;
}
return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array);
return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder);
}
return true;
@ -10836,7 +10836,7 @@ class CGDOMJSProxyHandler(CGClass):
if descriptor.supportsIndexedProperties():
methods.append(CGDOMJSProxyHandler_slice(descriptor))
methods.append(CGDOMJSProxyHandler_getElements(descriptor))
if (descriptor.operations['IndexedSetter'] is not None or
(descriptor.operations['NamedSetter'] is not None and
descriptor.interface.getExtendedAttribute('OverrideBuiltins'))):

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

@ -236,13 +236,15 @@ class HTMLInputElementState MOZ_FINAL : public nsISupports
mValue = aValue;
}
const nsTArray<nsRefPtr<File>>& GetFiles() {
return mFiles;
const nsTArray<nsRefPtr<FileImpl>>& GetFileImpls() {
return mFileImpls;
}
void SetFiles(const nsTArray<nsRefPtr<File>>& aFiles) {
mFiles.Clear();
mFiles.AppendElements(aFiles);
void SetFileImpls(const nsTArray<nsRefPtr<File>>& aFile) {
mFileImpls.Clear();
for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) {
mFileImpls.AppendElement(aFile[i]->Impl());
}
}
HTMLInputElementState()
@ -255,7 +257,7 @@ class HTMLInputElementState MOZ_FINAL : public nsISupports
~HTMLInputElementState() {}
nsString mValue;
nsTArray<nsRefPtr<File>> mFiles;
nsTArray<nsRefPtr<FileImpl>> mFileImpls;
bool mChecked;
bool mCheckedSet;
};
@ -5697,7 +5699,7 @@ HTMLInputElement::SaveState()
case VALUE_MODE_FILENAME:
if (!mFiles.IsEmpty()) {
inputState = new HTMLInputElementState();
inputState->SetFiles(mFiles);
inputState->SetFileImpls(mFiles);
}
break;
case VALUE_MODE_VALUE:
@ -5900,7 +5902,17 @@ HTMLInputElement::RestoreState(nsPresState* aState)
break;
case VALUE_MODE_FILENAME:
{
const nsTArray<nsRefPtr<File>>& files = inputState->GetFiles();
const nsTArray<nsRefPtr<FileImpl>>& fileImpls = inputState->GetFileImpls();
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
MOZ_ASSERT(global);
nsTArray<nsRefPtr<File>> files;
for (uint32_t i = 0, len = fileImpls.Length(); i < len; ++i) {
nsRefPtr<File> file = new File(global, fileImpls[i]);
files.AppendElement(file);
}
SetFiles(files, true);
}
break;

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

@ -65,7 +65,7 @@ PRLogModuleInfo* gMediaStreamGraphLog;
/**
* The singleton graph instance.
*/
static MediaStreamGraphImpl* gGraph;
static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
MediaStreamGraphImpl::~MediaStreamGraphImpl()
{
@ -1636,9 +1636,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
NS_DispatchToMainThread(event);
LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
if (this == gGraph) {
MediaStreamGraphImpl* graph;
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
// null out gGraph if that's the graph being shut down
gGraph = nullptr;
gGraphs.Remove(mAudioChannel);
}
}
} else {
@ -1789,9 +1790,12 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage)
delete aMessage;
if (IsEmpty() &&
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
if (gGraph == this) {
gGraph = nullptr;
MediaStreamGraphImpl* graph;
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
gGraphs.Remove(mAudioChannel);
}
Destroy();
}
return;
@ -2741,6 +2745,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
#ifdef DEBUG
, mCanRunMessagesSynchronously(false)
#endif
, mAudioChannel(static_cast<uint32_t>(aChannel))
{
#ifdef PR_LOGGING
if (!gMediaStreamGraphLog) {
@ -2779,15 +2784,26 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
static bool gShutdownObserverRegistered = false;
namespace {
PLDHashOperator
ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */,
MediaStreamGraphImpl* aGraph,
void* /* aUnused */)
{
aGraph->ForceShutDown();
return PL_DHASH_NEXT;
}
} // anonymous namespace
NS_IMETHODIMP
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
if (gGraph) {
gGraph->ForceShutDown();
}
gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
nsContentUtils::UnregisterShutdownObserver(this);
gShutdownObserverRegistered = false;
}
@ -2799,7 +2815,10 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
{
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
if (!gGraph) {
uint32_t channel = static_cast<uint32_t>(aChannel);
MediaStreamGraphImpl* graph = nullptr;
if (!gGraphs.Get(channel, &graph)) {
if (!gShutdownObserverRegistered) {
gShutdownObserverRegistered = true;
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
@ -2807,12 +2826,13 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
CubebUtils::InitPreferredSampleRate();
gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
gGraphs.Put(channel, graph);
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph));
}
return gGraph;
return graph;
}
MediaStreamGraph*
@ -2995,7 +3015,10 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine,
bool
MediaStreamGraph::IsNonRealtime() const
{
return this != gGraph;
const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
MediaStreamGraphImpl* graph;
return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
}
void

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

@ -661,6 +661,8 @@ public:
nsRefPtr<AudioOutputObserver> mFarendObserverRef;
#endif
uint32_t AudioChannel() const { return mAudioChannel; }
private:
virtual ~MediaStreamGraphImpl();
@ -694,6 +696,9 @@ private:
bool mCanRunMessagesSynchronously;
#endif
// We use uint32_t instead AudioChannel because this is just used as key for
// the hashtable gGraphs.
uint32_t mAudioChannel;
};
}

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

@ -374,6 +374,7 @@ skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !de
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_fastSeek-forwards.html]
[test_imagecapture.html]
skip-if = toolkit == 'android' # bug 1071217 - crashes on 2.3
[test_info_leak.html]
[test_invalid_reject.html]
[test_invalid_reject_play.html]

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

@ -654,12 +654,6 @@ AudioContext::MozAudioChannelType() const
return mDestination->MozAudioChannelType();
}
void
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
{
mDestination->SetMozAudioChannelType(aValue, aRv);
}
AudioChannel
AudioContext::TestAudioChannelInAudioNodeStream()
{

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

@ -222,7 +222,6 @@ public:
JSObject* GetGlobalJSObject() const;
AudioChannel MozAudioChannelType() const;
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
AudioChannel TestAudioChannelInAudioNodeStream();

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

@ -18,27 +18,23 @@ function test_basic() {
// Default
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
// random wrong channel
ac.mozAudioChannelType = "foo";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
// Unpermitted channels
ac.mozAudioChannelType = "content";
ac = new AudioContext("content");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "notification";
ac = new AudioContext("notification");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "alarm";
ac = new AudioContext("alarm");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "telephony";
ac = new AudioContext("telephony");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "ringer";
ac = new AudioContext("ringer");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "publicnotification";
ac = new AudioContext("publicnotification");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
runTest();
@ -56,7 +52,7 @@ function test_permission(aChannel) {
SpecialPowers.pushPermissions(
[{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
function() {
ac.mozAudioChannelType = aChannel;
var ac = new AudioContext(aChannel);
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();

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

@ -14,13 +14,14 @@ skip-if = toolkit == "gonk"
[test_tcpsocket_enabled_with_perm.html]
skip-if = toolkit == "gonk" || e10s
[test_networkstats_alarms.html]
skip-if = toolkit != "gonk"
skip-if = true # Bug 958689
[test_networkstats_basics.html]
skip-if = toolkit != "gonk" || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Will be fixed in bug 858005) b2g-desktop(Will be fixed in bug 858005)
skip-if = true # Bug 958689, bug 858005
[test_networkstats_disabled.html]
skip-if = toolkit != "gonk"
[test_networkstats_enabled_no_perm.html]
skip-if = toolkit != "gonk"
skip-if = true # Bug 958689
[test_networkstats_enabled_perm.html]
skip-if = toolkit != "gonk"
[test_udpsocket.html]
skip-if = toolkit != "gonk" || (toolkit == 'gonk' && debug) # Bug 1061174 for B2G debug

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

@ -99,15 +99,10 @@ SpeakerManagerService::TuruOnSpeaker(bool aOn)
{
nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
NS_ENSURE_TRUE_VOID(audioManager);
int32_t phoneState;
audioManager->GetPhoneState(&phoneState);
int32_t forceuse = (phoneState == nsIAudioManager::PHONE_STATE_IN_CALL ||
phoneState == nsIAudioManager::PHONE_STATE_IN_COMMUNICATION)
? nsIAudioManager::USE_COMMUNICATION : nsIAudioManager::USE_MEDIA;
if (aOn) {
audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_SPEAKER);
audioManager->SetForceForUse(nsIAudioManager::USE_MEDIA, nsIAudioManager::FORCE_SPEAKER);
} else {
audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_NONE);
audioManager->SetForceForUse(nsIAudioManager::USE_MEDIA, nsIAudioManager::FORCE_NONE);
}
}

78
dom/telephony/MMICall.cpp Normal file
Просмотреть файл

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/MMICall.h"
#include "mozilla/dom/MMICallBinding.h"
#include "nsIGlobalObject.h"
using namespace mozilla::dom;
using mozilla::ErrorResult;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MMICall, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MMICall)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MMICall)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MMICall)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
MMICall::MMICall(nsPIDOMWindow* aWindow, const nsAString& aServiceCode)
: mWindow(aWindow), mServiceCode(aServiceCode)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
if (!global) {
return;
}
ErrorResult rv;
nsRefPtr<Promise> promise = Promise::Create(global, rv);
if (rv.Failed()) {
return;
}
mPromise = promise;
}
MMICall::~MMICall()
{
}
nsPIDOMWindow*
MMICall::GetParentObject() const
{
return mWindow;
}
JSObject*
MMICall::WrapObject(JSContext* aCx)
{
return MMICallBinding::Wrap(aCx, this);
}
void
MMICall::NotifyResult(JS::Handle<JS::Value> aResult)
{
if (!mPromise) {
return;
}
mPromise->MaybeResolve(aResult);
}
// WebIDL
already_AddRefed<Promise>
MMICall::GetResult(ErrorResult& aRv)
{
if (!mPromise) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = mPromise;
return promise.forget();
}

60
dom/telephony/MMICall.h Normal file
Просмотреть файл

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_MMICall_h
#define mozilla_dom_MMICall_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsJSUtils.h"
#include "nsWrapperCache.h"
struct JSContext;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class MMICall MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MMICall)
MMICall(nsPIDOMWindow* aWindow, const nsAString& aServiceCode);
nsPIDOMWindow*
GetParentObject() const;
virtual JSObject*
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
void
NotifyResult(JS::Handle<JS::Value> aResult);
// WebIDL
already_AddRefed<Promise>
GetResult(ErrorResult& aRv);
private:
~MMICall();
nsCOMPtr<nsPIDOMWindow> mWindow;
nsString mServiceCode;
nsRefPtr<Promise> mPromise;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MMICall_h

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

@ -4,11 +4,9 @@
#include "TelephonyDialCallback.h"
#include "mozilla/dom/DOMMMIError.h"
#include "mozilla/dom/MozMobileConnectionBinding.h"
#include "nsIMobileCallForwardingOptions.h"
#include "nsIMobileConnectionService.h"
#include "nsServiceManagerUtils.h"
using namespace mozilla::dom;
using namespace mozilla::dom::telephony;
@ -26,15 +24,6 @@ TelephonyDialCallback::TelephonyDialCallback(nsPIDOMWindow* aWindow,
MOZ_ASSERT(mTelephony);
}
nsresult
TelephonyDialCallback::NotifyDialMMISuccess(JS::Handle<JS::Value> aResult)
{
nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return rs->FireSuccessAsync(mMMIRequest, aResult);
}
nsresult
TelephonyDialCallback::NotifyDialMMISuccess(JSContext* aCx,
const MozMMIResult& aResult)
@ -46,7 +35,8 @@ TelephonyDialCallback::NotifyDialMMISuccess(JSContext* aCx,
return NS_ERROR_TYPE_ERR;
}
return NotifyDialMMISuccess(jsResult);
mMMICall->NotifyResult(jsResult);
return NS_OK;
}
// nsITelephonyDialCallback
@ -54,10 +44,10 @@ TelephonyDialCallback::NotifyDialMMISuccess(JSContext* aCx,
NS_IMETHODIMP
TelephonyDialCallback::NotifyDialMMI(const nsAString& aServiceCode)
{
mMMIRequest = new DOMRequest(mWindow);
mServiceCode.Assign(aServiceCode);
mPromise->MaybeResolve(mMMIRequest);
mMMICall = new MMICall(mWindow, aServiceCode);
mPromise->MaybeResolve(mMMICall);
return NS_OK;
}
@ -85,6 +75,7 @@ TelephonyDialCallback::NotifyDialMMISuccess(const nsAString& aStatusMessage)
JSContext* cx = jsapi.cx();
MozMMIResult result;
result.mSuccess = true;
result.mServiceCode.Assign(mServiceCode);
result.mStatusMessage.Assign(aStatusMessage);
@ -103,6 +94,7 @@ TelephonyDialCallback::NotifyDialMMISuccessWithInteger(const nsAString& aStatusM
JSContext* cx = jsapi.cx();
MozMMIResult result;
result.mSuccess = true;
result.mServiceCode.Assign(mServiceCode);
result.mStatusMessage.Assign(aStatusMessage);
result.mAdditionalInformation.Construct().SetAsUnsignedShort() = aAdditionalInformation;
@ -123,6 +115,7 @@ TelephonyDialCallback::NotifyDialMMISuccessWithStrings(const nsAString& aStatusM
JSContext* cx = jsapi.cx();
RootedDictionary<MozMMIResult> result(cx);
result.mSuccess = true;
result.mServiceCode.Assign(mServiceCode);
result.mStatusMessage.Assign(aStatusMessage);
@ -156,6 +149,7 @@ TelephonyDialCallback::NotifyDialMMISuccessWithCallForwardingOptions(const nsASt
JSContext* cx = jsapi.cx();
RootedDictionary<MozMMIResult> result(cx);
result.mSuccess = true;
result.mServiceCode.Assign(mServiceCode);
result.mStatusMessage.Assign(aStatusMessage);
@ -213,28 +207,37 @@ TelephonyDialCallback::NotifyDialMMISuccessWithCallForwardingOptions(const nsASt
NS_IMETHODIMP
TelephonyDialCallback::NotifyDialMMIError(const nsAString& aError)
{
Nullable<int16_t> info;
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
return NS_ERROR_FAILURE;
}
nsRefPtr<DOMError> error =
new DOMMMIError(mWindow, aError, EmptyString(), mServiceCode, info);
JSContext* cx = jsapi.cx();
nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
MozMMIResult result;
result.mSuccess = false;
result.mServiceCode.Assign(mServiceCode);
result.mStatusMessage.Assign(aError);
return rs->FireDetailedError(mMMIRequest, error);
return NotifyDialMMISuccess(cx, result);
}
NS_IMETHODIMP
TelephonyDialCallback::NotifyDialMMIErrorWithInfo(const nsAString& aError,
uint16_t aInfo)
{
Nullable<int16_t> info(aInfo);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
return NS_ERROR_FAILURE;
}
nsRefPtr<DOMError> error =
new DOMMMIError(mWindow, aError, EmptyString(), mServiceCode, info);
JSContext* cx = jsapi.cx();
nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
MozMMIResult result;
result.mSuccess = false;
result.mServiceCode.Assign(mServiceCode);
result.mStatusMessage.Assign(aError);
result.mAdditionalInformation.Construct().SetAsUnsignedShort() = aInfo;
return rs->FireDetailedError(mMMIRequest, error);
return NotifyDialMMISuccess(cx, result);
}

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

@ -6,7 +6,7 @@
#define mozilla_dom_TelephonyDialCallback_h
#include "Telephony.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/MMICall.h"
#include "mozilla/dom/MozMobileConnectionBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ToJSValue.h"
@ -38,9 +38,6 @@ public:
private:
~TelephonyDialCallback() {}
nsresult
NotifyDialMMISuccess(JS::Handle<JS::Value> aResult);
nsresult
NotifyDialMMISuccess(JSContext* aCx, const MozMMIResult& aResult);
@ -49,8 +46,8 @@ private:
nsRefPtr<Telephony> mTelephony;
uint32_t mServiceId;
nsRefPtr<DOMRequest> mMMIRequest;
nsString mServiceCode;
nsRefPtr<MMICall> mMMICall;
};
} // namespace telephony

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

@ -12,6 +12,7 @@ XPIDL_MODULE = 'dom_telephony'
EXPORTS.mozilla.dom += [
'CallsList.h',
'MMICall.h',
'Telephony.h',
'TelephonyCall.h',
'TelephonyCallGroup.h',
@ -32,6 +33,7 @@ UNIFIED_SOURCES += [
'ipc/TelephonyChild.cpp',
'ipc/TelephonyIPCService.cpp',
'ipc/TelephonyParent.cpp',
'MMICall.cpp',
'Telephony.cpp',
'TelephonyCall.cpp',
'TelephonyCallback.cpp',

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

@ -1267,6 +1267,21 @@ let emulator = (function() {
return promise;
}
/**
* Send out the MMI code.
*
* @param mmi
* String of MMI code
* @return Promise<MozMMIResult>
*/
function sendMMI(mmi) {
return telephony.dial(mmi).then(mmiCall => {
ok(mmiCall instanceof MMICall, "mmiCall is instance of MMICall");
ok(mmiCall.result instanceof Promise, "result is Promise");
return mmiCall.result;
});
}
/**
* Public members.
*/
@ -1278,6 +1293,7 @@ let emulator = (function() {
this.gInCallStrPool = inCallStrPool;
this.gCheckState = checkState;
this.gCheckAll = checkAll;
this.gSendMMI = sendMMI;
this.gDial = dial;
this.gDialEmergency = dialEmergency;
this.gAnswer = answer;
@ -1393,16 +1409,3 @@ function startDSDSTest(test) {
finish();
}
}
function sendMMI(aMmi) {
let deferred = Promise.defer();
telephony.dial(aMmi)
.then(result => {
deferred.resolve(result);
}, cause => {
deferred.reject(cause);
});
return deferred.promise;
}

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

@ -7,24 +7,22 @@ MARIONETTE_HEAD_JS = "head.js";
function testGettingIMEI() {
log("Test *#06# ...");
let MMI_CODE = "*#06#";
return sendMMI(MMI_CODE)
.then(function resolve(aResult) {
ok(true, MMI_CODE + " success");
is(aResult.serviceCode, "scImei", "Service code IMEI");
// IMEI is hardcoded as "000000000000000".
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c
// (The result of +CGSN).
is(aResult.statusMessage, "000000000000000", "Emulator IMEI");
is(aResult.additionalInformation, undefined, "No additional information");
}, function reject() {
ok(false, MMI_CODE + " should not fail");
});
return gSendMMI("*#06#").then(aResult => {
ok(aResult.success, "success");
is(aResult.serviceCode, "scImei", "Service code IMEI");
// IMEI is hardcoded as "000000000000000".
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c
// (The aResult of +CGSN).
is(aResult.statusMessage, "000000000000000", "Emulator IMEI");
is(aResult.additionalInformation, undefined, "No additional information");
});
}
// Start test
startTest(function() {
Promise.resolve()
.then(() => testGettingIMEI())
testGettingIMEI()
.then(null, cause => {
ok(false, 'promise rejects during test: ' + cause);
})
.then(finish);
});

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

@ -112,15 +112,14 @@ function testSetCallForwarding(aData) {
is(aEvent.timeSeconds, aData.timeSeconds, "check timeSeconds");
is(aEvent.serviceClass, aData.serviceClass, "check serviceClass");
}));
// Check DOMRequest's result.
promises.push(sendMMI(MMI_CODE)
.then(function resolve(aResult) {
is(aResult.serviceCode, "scCallForwarding", "Check service code");
is(aResult.statusMessage, "smServiceRegistered", "Check status message");
is(aResult.additionalInformation, undefined, "Check additional information");
}, function reject(aError) {
ok(false, "got '" + aError.name + "' error");
}));
// Check MMI result.
promises.push(gSendMMI(MMI_CODE).then(aResult => {
ok(aResult.success, "success");
is(aResult.serviceCode, "scCallForwarding", "Check service code");
is(aResult.statusMessage, "smServiceRegistered", "Check status message");
is(aResult.additionalInformation, undefined, "Check additional information");
}));
return Promise.all(promises);
}
@ -130,30 +129,28 @@ function testGetCallForwarding(aExpectedData) {
let MMI_CODE = "*#" + CF_REASON_TO_MMI[aExpectedData.reason] + "#";
log("Test " + MMI_CODE);
return sendMMI(MMI_CODE)
.then(function resolve(aResult) {
is(aResult.serviceCode, "scCallForwarding", "Check service code");
is(aResult.statusMessage, "smServiceInterrogated", "Check status message");
is(Array.isArray(aResult.additionalInformation), true,
"additionalInformation should be an array");
return gSendMMI(MMI_CODE).then(aResult => {
ok(aResult.success, "success");
is(aResult.serviceCode, "scCallForwarding", "Check service code");
is(aResult.statusMessage, "smServiceInterrogated", "Check status message");
ok(Array.isArray(aResult.additionalInformation),
"additionalInformation should be an array");
for (let i = 0; i < aResult.additionalInformation.length; i++) {
let result = aResult.additionalInformation[i];
for (let i = 0; i < aResult.additionalInformation.length; i++) {
let result = aResult.additionalInformation[i];
// Only need to check the result containing the serviceClass that we are
// interested in.
if (!(result.serviceClass & aExpectedData.serviceClass)) {
continue;
}
// Only need to check the result containing the serviceClass that we are
// interested in.
if (!(result.serviceClass & aExpectedData.serviceClass)) {
continue;
}
is(result.active, true, "check active");
is(result.reason, aExpectedData.reason, "check reason");
is(result.number, aExpectedData.number, "check number");
is(result.timeSeconds, aExpectedData.timeSeconds, "check timeSeconds");
}
}, function reject(aError) {
ok(false, MMI_CODE + " got error: " + aError.name);
});
is(result.active, true, "check active");
is(result.reason, aExpectedData.reason, "check reason");
is(result.number, aExpectedData.number, "check number");
is(result.timeSeconds, aExpectedData.timeSeconds, "check timeSeconds");
}
});
}
function clearAllCallForwardingSettings() {
@ -185,8 +182,11 @@ startTestWithPermissions(['mobileconnection'], function() {
promise = promise.then(() => testSetCallForwarding(data))
.then(() => testGetCallForwarding(data));
}
// reset call forwarding settings.
return promise.then(null, () => { ok(false, "promise reject during test"); })
.then(() => clearAllCallForwardingSettings())
return promise.then(() => clearAllCallForwardingSettings())
.then(null, cause => {
ok(false, 'promise rejects during test: ' + cause);
})
.then(finish);
});

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

@ -81,20 +81,19 @@ function testChangePin(aPin, aNewPin, aNewPinAgain, aExpectedError) {
let MMI_CODE = "**04*" + aPin + "*" + aNewPin + "*" + aNewPinAgain + "#";
log("Test " + MMI_CODE);
return sendMMI(MMI_CODE)
.then(function resolve(aResult) {
ok(!aExpectedError, MMI_CODE + " success");
is(aResult.serviceCode, "scPin", "Check service code");
return gSendMMI(MMI_CODE).then(aResult => {
is(aResult.success, !aExpectedError, "check success");
is(aResult.serviceCode, "scPin", "Check service code");
if (aResult.success) {
is(aResult.statusMessage, "smPinChanged", "Check status message");
is(aResult.additionalInformation, undefined, "Check additional information");
}, function reject(aError) {
ok(aExpectedError, MMI_CODE + " fail");
is(aError.name, aExpectedError.name, "Check name");
is(aError.message, "", "Check message");
is(aError.serviceCode, "scPin", "Check service code");
is(aError.additionalInformation, aExpectedError.additionalInformation,
} else {
is(aResult.statusMessage, aExpectedError.name, "Check name");
is(aResult.additionalInformation, aExpectedError.additionalInformation,
"Check additional information");
});
}
});
}
// Start test
@ -107,5 +106,10 @@ startTest(function() {
data.newPinAgain,
data.expectedError));
}
return promise.then(finish);
return promise
.then(null, cause => {
ok(false, 'promise rejects during test: ' + cause);
})
.then(finish);
});

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

@ -78,8 +78,8 @@ interface AudioContext : EventTarget {
// Mozilla extensions
partial interface AudioContext {
// Read AudioChannel.webidl for more information about this attribute.
[Pref="media.useAudioChannelService", SetterThrows]
attribute AudioChannel mozAudioChannelType;
[Pref="media.useAudioChannelService"]
readonly attribute AudioChannel mozAudioChannelType;
// These 2 events are dispatched when the AudioContext object is muted by
// the AudioChannelService. It's call 'interrupt' because when this event is

13
dom/webidl/MMICall.webidl Normal file
Просмотреть файл

@ -0,0 +1,13 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Pref="dom.telephony.enabled",
CheckPermissions="telephony",
AvailableIn="CertifiedApps"]
interface MMICall {
[Throws]
readonly attribute Promise<MozMMIResult> result;
};

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

@ -660,6 +660,11 @@ dictionary MozCallBarringOptions
dictionary MozMMIResult
{
/**
* Indicate whether the result is successful or not.
*/
boolean success = true;
/**
* String key that identifies the service associated with the MMI code
* request. The UI is supposed to handle the localization of the strings
@ -668,7 +673,9 @@ dictionary MozMMIResult
DOMString serviceCode = "";
/**
* String key containing the status message of the associated MMI request.
* String key containing the status message of the associated MMI request or
* the error message when the request fails.
* The UI is supposed to handle the localization of the strings associated
* with this string key.
*/

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

@ -20,10 +20,10 @@ interface Telephony : EventTarget {
* Make a phone call or send the mmi code depending on the number provided.
*
* TelephonyCall - for call setup
* DOMRequest - for MMI code
* MMICall - for MMI code
*/
[Throws]
Promise<(TelephonyCall or DOMRequest)> dial(DOMString number, optional unsigned long serviceId);
Promise<(TelephonyCall or MMICall)> dial(DOMString number, optional unsigned long serviceId);
[Throws]
Promise<TelephonyCall> dialEmergency(DOMString number, optional unsigned long serviceId);

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

@ -276,6 +276,7 @@ WEBIDL_FILES = [
'MessagePortList.webidl',
'MimeType.webidl',
'MimeTypeArray.webidl',
'MMICall.webidl',
'MouseEvent.webidl',
'MouseScrollEvent.webidl',
'MozActivity.webidl',

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

@ -655,6 +655,9 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
{
tmp = selNode;
selNode = GetNodeLocation(tmp, &selOffset);
// selNode might be null in case a mutation listener removed
// the stuff we just inserted from the DOM.
NS_ENSURE_STATE(selNode);
++selOffset; // want to be *after* last leaf node in paste
}

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

@ -1270,7 +1270,7 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pa
extents = ComputeGlyphsExtents(bboxes, &positions.front(), aBuffer.mNumGlyphs, 1.0f);
ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(),
&positions.front(), aBuffer.mNumGlyphs, cg);
delete bboxes;
delete[] bboxes;
} else {
CGRect *bboxes = new CGRect[aBuffer.mNumGlyphs];
CGFontGetGlyphBBoxes(macFont->mFont, &glyphs.front(), aBuffer.mNumGlyphs, bboxes);
@ -1280,7 +1280,7 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pa
CGContextSetFontSize(cg, macFont->mSize);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(),
aBuffer.mNumGlyphs);
delete bboxes;
delete[] bboxes;
}
CGContextScaleCTM(cg, 1, -1);
DrawGradient(mColorSpace, cg, aPattern, extents);

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

@ -150,6 +150,28 @@ TransformClipRect(Layer* aLayer,
}
}
/**
* Set the given transform as the shadow transform on the layer, assuming
* that the given transform already has the pre- and post-scales applied.
* That is, this function cancels out the pre- and post-scales from aTransform
* before setting it as the shadow transform on the layer, so that when
* the layer's effective transform is computed, the pre- and post-scales will
* only be applied once.
*/
static void
SetShadowTransform(Layer* aLayer, Matrix4x4 aTransform)
{
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
aTransform.PreScale(1.0f / c->GetPreXScale(),
1.0f / c->GetPreYScale(),
1);
}
aTransform.PostScale(1.0f / aLayer->GetPostXScale(),
1.0f / aLayer->GetPostYScale(),
1);
aLayer->AsLayerComposite()->SetShadowTransform(aTransform);
}
static void
TranslateShadowLayer2D(Layer* aLayer,
const gfxPoint& aTranslation,
@ -157,9 +179,10 @@ TranslateShadowLayer2D(Layer* aLayer,
{
// This layer might also be a scrollable layer and have an async transform.
// To make sure we don't clobber that, we start with the shadow transform.
// Any adjustments to the shadow transform made in this function in previous
// frames have been cleared in ClearAsyncTransforms(), so such adjustments
// will not compound over successive frames.
// (i.e. GetLocalTransform() instead of GetTransform()).
// Note that the shadow transform is reset on every frame of composition so
// we don't have to worry about the adjustments compounding over successive
// frames.
Matrix layerTransform;
if (!aLayer->GetLocalTransform().Is2D(&layerTransform)) {
return;
@ -169,22 +192,8 @@ TranslateShadowLayer2D(Layer* aLayer,
layerTransform._31 += aTranslation.x;
layerTransform._32 += aTranslation.y;
// The transform already takes the resolution scale into account. Since we
// will apply the resolution scale again when computing the effective
// transform, we must apply the inverse resolution scale here.
Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
layerTransform3D.PreScale(1.0f/c->GetPreXScale(),
1.0f/c->GetPreYScale(),
1);
}
layerTransform3D.PostScale(1.0f/aLayer->GetPostXScale(),
1.0f/aLayer->GetPostYScale(),
1);
LayerComposite* layerComposite = aLayer->AsLayerComposite();
layerComposite->SetShadowTransform(layerTransform3D);
layerComposite->SetShadowTransformSetByAnimation(false);
SetShadowTransform(aLayer, Matrix4x4::From2D(layerTransform));
aLayer->AsLayerComposite()->SetShadowTransformSetByAnimation(false);
if (aAdjustClipRect) {
TransformClipRect(aLayer, Matrix4x4::Translation(aTranslation.x, aTranslation.y, 0));
@ -535,7 +544,7 @@ SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime)
}
Matrix4x4
AdjustAndCombineWithCSSTransform(const Matrix4x4& asyncTransform, Layer* aLayer)
AdjustForClip(const Matrix4x4& asyncTransform, Layer* aLayer)
{
Matrix4x4 result = asyncTransform;
@ -550,9 +559,6 @@ AdjustAndCombineWithCSSTransform(const Matrix4x4& asyncTransform, Layer* aLayer)
result.ChangeBasis(shadowClipRect->x, shadowClipRect->y, 0);
}
}
// Combine the async transform with the layer's CSS transform.
result = aLayer->GetTransform() * result;
return result;
}
@ -566,7 +572,6 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
ApplyAsyncContentTransformToTree(child);
}
LayerComposite* layerComposite = aLayer->AsLayerComposite();
Matrix4x4 oldTransform = aLayer->GetTransform();
Matrix4x4 combinedAsyncTransformWithoutOverscroll;
@ -614,22 +619,12 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
}
if (hasAsyncTransform) {
Matrix4x4 transform = AdjustAndCombineWithCSSTransform(combinedAsyncTransform, aLayer);
// GetTransform already takes the pre- and post-scale into account. Since we
// will apply the pre- and post-scale again when computing the effective
// transform, we must apply the inverses here.
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
transform.PreScale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
}
transform.PostScale(1.0f/aLayer->GetPostXScale(),
1.0f/aLayer->GetPostYScale(),
1);
layerComposite->SetShadowTransform(transform);
NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
"overwriting animated transform!");
// Apply the APZ transform on top of GetLocalTransform() here (rather than
// GetTransform()) in case the OMTA code in SampleAnimations already set a
// shadow transform; in that case we want to apply ours on top of that one
// rather than clobber it.
SetShadowTransform(aLayer,
aLayer->GetLocalTransform() * AdjustForClip(combinedAsyncTransform, aLayer));
const FrameMetrics& bottom = LayerMetricsWrapper::BottommostScrollableMetrics(aLayer);
MOZ_ASSERT(bottom.IsScrollable()); // must be true because hasAsyncTransform is true
@ -642,15 +637,18 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
oldTransform.PreScale(resolution.scale, resolution.scale, 1);
// For the purpose of aligning fixed and sticky layers, we disregard
// the overscroll transform when computing the 'aCurrentTransformForRoot'
// parameter. This ensures that the overscroll transform is not unapplied,
// and therefore that the visual effect applies to fixed and sticky layers.
Matrix4x4 transformWithoutOverscroll = AdjustAndCombineWithCSSTransform(
combinedAsyncTransformWithoutOverscroll, aLayer);
// the overscroll transform as well as any OMTA transform when computing the
// 'aCurrentTransformForRoot' parameter. This ensures that the overscroll
// and OMTA transforms are not unapplied, and therefore that the visual
// effects apply to fixed and sticky layers. We do this by using
// GetTransform() as the base transform rather than GetLocalTransform(),
// which would include those factors.
Matrix4x4 transformWithoutOverscrollOrOmta = aLayer->GetTransform() *
AdjustForClip(combinedAsyncTransformWithoutOverscroll, aLayer);
// Since fixed/sticky layers are relative to their nearest scrolling ancestor,
// we use the ViewID from the bottommost scrollable metrics here.
AlignFixedAndStickyLayers(aLayer, aLayer, bottom.GetScrollId(), oldTransform,
transformWithoutOverscroll, fixedLayerMargins);
transformWithoutOverscrollOrOmta, fixedLayerMargins);
appliedTransform = true;
}
@ -763,18 +761,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
}
}
// GetTransform already takes the pre- and post-scale into account. Since we
// will apply the pre- and post-scale again when computing the effective
// transform, we must apply the inverses here.
if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
transform.PreScale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
}
transform.PostScale(1.0f/aScrollbar->GetPostXScale(),
1.0f/aScrollbar->GetPostYScale(),
1);
aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
SetShadowTransform(aScrollbar, transform);
}
static LayerMetricsWrapper
@ -835,8 +822,6 @@ AsyncCompositionManager::ApplyAsyncTransformToScrollbar(Layer* aLayer)
void
AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
{
LayerComposite* layerComposite = aLayer->AsLayerComposite();
FrameMetrics metrics = LayerMetricsWrapper::TopmostScrollableMetrics(aLayer);
if (!metrics.IsScrollable()) {
// On Fennec it's possible that the there is no scrollable layer in the
@ -909,20 +894,8 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
ScreenPoint translation = userScroll - geckoScroll;
Matrix4x4 treeTransform = ViewTransform(scale, -translation);
// The transform already takes the resolution scale into account. Since we
// will apply the resolution scale again when computing the effective
// transform, we must apply the inverse resolution scale here.
Matrix4x4 computedTransform = oldTransform * treeTransform;
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
computedTransform.PreScale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
}
computedTransform.PostScale(1.0f/aLayer->GetPostXScale(),
1.0f/aLayer->GetPostYScale(),
1);
layerComposite->SetShadowTransform(computedTransform);
NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
SetShadowTransform(aLayer, oldTransform * treeTransform);
NS_ASSERTION(!aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation(),
"overwriting animated transform!");
// Apply resolution scaling to the old transform - the layer tree as it is
@ -969,18 +942,6 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
aLayer->GetLocalTransform(), fixedLayerMargins);
}
void
ClearAsyncTransforms(Layer* aLayer)
{
if (!aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation()) {
aLayer->AsLayerComposite()->SetShadowTransform(aLayer->GetBaseTransform());
}
for (Layer* child = aLayer->GetFirstChild();
child; child = child->GetNextSibling()) {
ClearAsyncTransforms(child);
}
}
bool
AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
{
@ -992,17 +953,11 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
return false;
}
// First, compute and set the shadow transforms from OMT animations.
// NB: we must sample animations *before* sampling pan/zoom
// transforms.
bool wantNextFrame = SampleAnimations(root, aCurrentFrame);
// Clear any async transforms (not due to animations) set in previous frames.
// This is necessary because some things called by
// ApplyAsyncContentTransformToTree (in particular, TranslateShadowLayer2D),
// add to the shadow transform rather than overwriting it.
ClearAsyncTransforms(root);
// FIXME/bug 775437: unify this interface with the ~native-fennec
// derived code
//

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

@ -46,7 +46,7 @@ HeaderIncludes = (
'prtime.h',
'IPCMessageStart.h',
'ipc/IPCMessageUtils.h',
'nsAutoPtr.h',
'nsRefPtr.h',
'nsStringGlue.h',
'nsTArray.h',
'mozilla/ipc/ProtocolUtils.h',

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

@ -9,6 +9,7 @@
#ifndef js_Class_h
#define js_Class_h
#include "mozilla/DebugOnly.h"
#include "mozilla/NullPtr.h"
#include "jstypes.h"
@ -226,9 +227,44 @@ typedef bool
typedef bool
(* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
class JS_FRIEND_API(ElementAdder)
{
public:
enum GetBehavior {
// Check if the element exists before performing the Get and preserve
// holes.
CheckHasElemPreserveHoles,
// Perform a Get operation, like obj[index] in JS.
GetElement
};
private:
// Only one of these is used.
JS::RootedObject resObj_;
JS::Value *vp_;
uint32_t index_;
mozilla::DebugOnly<uint32_t> length_;
GetBehavior getBehavior_;
public:
ElementAdder(JSContext *cx, JSObject *obj, uint32_t length, GetBehavior behavior)
: resObj_(cx, obj), vp_(nullptr), index_(0), length_(length), getBehavior_(behavior)
{}
ElementAdder(JSContext *cx, JS::Value *vp, uint32_t length, GetBehavior behavior)
: resObj_(cx), vp_(vp), index_(0), length_(length), getBehavior_(behavior)
{}
GetBehavior getBehavior() const { return getBehavior_; }
void append(JSContext *cx, JS::HandleValue v);
void appendHole();
};
typedef bool
(* SliceOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end,
JS::HandleObject result); // result is actually preallocted.
(* GetElementsOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end,
ElementAdder *adder);
// A generic type for functions mapping an object to another object, or null
// if an error or exception was thrown on cx.
@ -364,7 +400,7 @@ struct ObjectOps
DeleteGenericOp deleteGeneric;
WatchOp watch;
UnwatchOp unwatch;
SliceOp slice; // Optimized slice, can be null.
GetElementsOp getElements;
JSNewEnumerateOp enumerate;
ObjectOp thisObject;
};

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

@ -500,7 +500,7 @@ AsmJSHandleExecutionInterrupt()
{
AsmJSActivation *act = PerThreadData::innermostAsmJSActivation();
act->module().setInterrupted(true);
bool ret = CheckForInterrupt(act->cx());
bool ret = HandleExecutionInterrupt(act->cx());
act->module().setInterrupted(false);
return ret;
}
@ -673,8 +673,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
switch (kind) {
case AsmJSImm_Runtime:
return cx->runtimeAddressForJit();
case AsmJSImm_RuntimeInterruptUint32:
return cx->runtimeAddressOfInterruptUint32();
case AsmJSImm_RuntimeInterrupt:
return cx->runtimeAddressOfInterrupt();
case AsmJSImm_StackLimit:
return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
case AsmJSImm_ReportOverRecursed:

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

@ -2404,7 +2404,7 @@ LazyArrayBufferTable::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
TypedObject::obj_setGenericAttributes, \
TypedObject::obj_deleteGeneric, \
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* slice */ \
nullptr, /* getElements */ \
TypedObject::obj_enumerate, \
nullptr, /* thisObject */ \
} \

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

@ -133,6 +133,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
firstLine(lineNum),
localsToFrameSlots_(sc->context),
stackDepth(0), maxStackDepth(0),
yieldIndex(0),
arrayCompDepth(0),
emitLevel(0),
constList(sc->context),
@ -2999,6 +3000,28 @@ BytecodeEmitter::isRunOnceLambda()
!funbox->function()->name();
}
static bool
EmitYieldOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
{
if (op == JSOP_FINALYIELDRVAL)
return Emit1(cx, bce, JSOP_FINALYIELDRVAL) >= 0;
MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD);
ptrdiff_t off = EmitN(cx, bce, op, 3);
if (off < 0)
return false;
if (bce->yieldIndex >= JS_BIT(24)) {
bce->reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
return false;
}
SET_UINT24(bce->code(off), bce->yieldIndex);
bce->yieldIndex++;
return true;
}
bool
frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body)
{
@ -3074,7 +3097,7 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
return false;
// No need to check for finally blocks, etc as in EmitReturn.
if (Emit1(cx, bce, JSOP_FINALYIELDRVAL) < 0)
if (!EmitYieldOp(cx, bce, JSOP_FINALYIELDRVAL))
return false;
}
@ -5559,7 +5582,7 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc));
if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce))
return false;
if (Emit1(cx, bce, JSOP_FINALYIELDRVAL) < 0)
if (!EmitYieldOp(cx, bce, JSOP_FINALYIELDRVAL))
return false;
} else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != bce->offset()) {
bce->code()[top] = JSOP_SETRVAL;
@ -5598,7 +5621,7 @@ EmitYield(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!EmitTree(cx, bce, pn->pn_right))
return false;
if (Emit1(cx, bce, pn->getOp()) < 0)
if (!EmitYieldOp(cx, bce, pn->getOp()))
return false;
if (pn->getOp() == JSOP_INITIALYIELD && Emit1(cx, bce, JSOP_POP) < 0)
@ -5643,7 +5666,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
return false;
// Yield RESULT as-is, without re-boxing.
if (Emit1(cx, bce, JSOP_YIELD) < 0) // ITER RECEIVED
if (!EmitYieldOp(cx, bce, JSOP_YIELD)) // ITER RECEIVED
return false;
// Try epilogue.

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

@ -126,6 +126,8 @@ struct BytecodeEmitter
int32_t stackDepth; /* current stack depth in script frame */
uint32_t maxStackDepth; /* maximum stack depth so far */
uint32_t yieldIndex; /* index stored as operand of yield ops */
uint32_t arrayCompDepth; /* stack depth of array in comprehension */
unsigned emitLevel; /* js::frontend::EmitTree recursion level */

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

@ -152,7 +152,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx, bool match_only)
// Check if we have space on the stack.
Label stack_ok;
void *stack_limit = runtime->mainThread.addressOfJitStackLimit();
void *stack_limit = &runtime->mainThread.jitStackLimit;
masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok);
// Exit with an exception. There is not enough space on the stack
@ -502,7 +502,7 @@ NativeRegExpMacroAssembler::Backtrack()
// Check for an interrupt.
Label noInterrupt;
masm.branch32(Assembler::Equal,
AbsoluteAddress(runtime->addressOfInterruptUint32()), Imm32(0),
AbsoluteAddress(&runtime->interrupt), Imm32(0),
&noInterrupt);
masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
masm.jump(&exit_label_);

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

@ -0,0 +1,4 @@
// |jit-test| ion-eager;
for (var j = 0; j < 2; j++) {
(false).__proto__ = 0
}

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

@ -0,0 +1,26 @@
// fun.apply(null, proxy) should not invoke the proxy's Has trap.
var proxy = new Proxy({}, {
get: function (target, name, proxy) {
switch (name) {
case "length":
return 2;
case "0":
return 15;
case "1":
return undefined;
default:
assertEq(false, true);
}
},
has: function (target, name) {
assertEq(false, true);
}
});
function foo() {
assertEq(arguments.length, 2);
assertEq(arguments[0], 15);
assertEq(1 in arguments, true);
assertEq(arguments[1], undefined);
}
foo.apply(null, proxy);

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

@ -30,6 +30,7 @@ using namespace js::jit;
BaselineCompiler::BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script)
: BaselineCompilerSpecific(cx, alloc, script),
yieldOffsets_(cx),
modifiesArguments_(false)
{
}
@ -186,7 +187,8 @@ BaselineCompiler::compile()
icEntries_.length(),
pcMappingIndexEntries.length(),
pcEntries.length(),
bytecodeTypeMapEntries);
bytecodeTypeMapEntries,
yieldOffsets_.length());
if (!baselineScript)
return Method_Error;
@ -243,6 +245,8 @@ BaselineCompiler::compile()
// searches for the sought entry when queries are in linear order.
bytecodeMap[script->nTypeSets()] = 0;
baselineScript->copyYieldEntries(script, yieldOffsets_);
if (script->compartment()->debugMode())
baselineScript->setDebugMode();
@ -496,7 +500,7 @@ bool
BaselineCompiler::emitStackCheck(bool earlyCheck)
{
Label skipCall;
void *limitAddr = cx->runtime()->mainThread.addressOfJitStackLimit();
uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit;
uint32_t slotsSize = script->nslots() * sizeof(Value);
uint32_t tolerance = earlyCheck ? slotsSize : 0;
@ -646,7 +650,7 @@ BaselineCompiler::emitInterruptCheck()
frame.syncStack(0);
Label done;
void *interrupt = cx->runtimeAddressOfInterruptUint32();
void *interrupt = (void *)&cx->runtime()->interrupt;
masm.branch32(Assembler::Equal, AbsoluteAddress(interrupt), Imm32(0), &done);
prepareVMCall();
@ -3235,3 +3239,118 @@ BaselineCompiler::emit_JSOP_REST()
frame.push(R0);
return true;
}
typedef JSObject *(*CreateGeneratorFn)(JSContext *, BaselineFrame *);
static const VMFunction CreateGeneratorInfo = FunctionInfo<CreateGeneratorFn>(jit::CreateGenerator);
bool
BaselineCompiler::emit_JSOP_GENERATOR()
{
MOZ_ASSERT(frame.stackDepth() == 0);
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
prepareVMCall();
pushArg(R0.scratchReg());
if (!callVM(CreateGeneratorInfo))
return false;
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
frame.push(R0);
return true;
}
bool
BaselineCompiler::addYieldOffset()
{
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
uint32_t yieldIndex = GET_UINT24(pc);
while (yieldIndex >= yieldOffsets_.length()) {
if (!yieldOffsets_.append(0))
return false;
}
static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH,
"code below assumes INITIALYIELD and YIELD have same length");
yieldOffsets_[yieldIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
return true;
}
typedef bool (*InitialSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *);
static const VMFunction InitialSuspendInfo = FunctionInfo<InitialSuspendFn>(jit::InitialSuspend);
bool
BaselineCompiler::emit_JSOP_INITIALYIELD()
{
if (!addYieldOffset())
return false;
frame.syncStack(0);
// Store generator in R0, BaselineFrame pointer in R1.
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
prepareVMCall();
pushArg(ImmPtr(pc));
pushArg(R1.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(InitialSuspendInfo))
return false;
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand);
return emitReturn();
}
typedef bool (*NormalSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *, uint32_t);
static const VMFunction NormalSuspendInfo = FunctionInfo<NormalSuspendFn>(jit::NormalSuspend);
bool
BaselineCompiler::emit_JSOP_YIELD()
{
if (!addYieldOffset())
return false;
// Store generator in R0, BaselineFrame pointer in R1.
frame.popRegsAndSync(1);
masm.unboxObject(R0, R0.scratchReg());
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
prepareVMCall();
pushArg(Imm32(frame.stackDepth()));
pushArg(ImmPtr(pc));
pushArg(R1.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(NormalSuspendInfo))
return false;
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand);
return emitReturn();
}
typedef bool (*FinalSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *);
static const VMFunction FinalSuspendInfo = FunctionInfo<FinalSuspendFn>(jit::FinalSuspend);
bool
BaselineCompiler::emit_JSOP_FINALYIELDRVAL()
{
// Store generator in R0, BaselineFrame pointer in R1.
frame.popRegsAndSync(1);
masm.unboxObject(R0, R0.scratchReg());
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
prepareVMCall();
pushArg(ImmPtr(pc));
pushArg(R1.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(FinalSuspendInfo))
return false;
masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
return emitReturn();
}

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

@ -173,6 +173,10 @@ namespace jit {
_(JSOP_MOREITER) \
_(JSOP_ISNOITER) \
_(JSOP_ENDITER) \
_(JSOP_GENERATOR) \
_(JSOP_INITIALYIELD) \
_(JSOP_YIELD) \
_(JSOP_FINALYIELDRVAL) \
_(JSOP_CALLEE) \
_(JSOP_SETRVAL) \
_(JSOP_RETRVAL) \
@ -197,6 +201,10 @@ class BaselineCompiler : public BaselineCompilerSpecific
// equivalent positions when debug mode is off.
CodeOffsetLabel postDebugPrologueOffset_;
// For each INITIALYIELD or YIELD op, this Vector maps the yield index
// to the bytecode offset of the next op.
Vector<uint32_t> yieldOffsets_;
// Whether any on stack arguments are modified.
bool modifiesArguments_;
@ -278,6 +286,8 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool addPCMappingEntry(bool addIndexEntry);
bool addYieldOffset();
void getScopeCoordinateObject(Register reg);
Address getScopeCoordinateAddressFromObject(Register objReg, Register reg);
Address getScopeCoordinateAddress(Register reg);

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

@ -7921,6 +7921,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
// end up attaching a stub for the exact same access later.
bool isTemporarilyUnoptimizable = false;
if (stub->numOptimizedStubs() < ICSetProp_Fallback::MAX_OPTIMIZED_STUBS &&
lhs.isObject() &&
!TryAttachSetAccessorPropStub(cx, script, pc, stub, obj, oldShape, name, id,
rhs, &attached, &isTemporarilyUnoptimizable))
{
@ -7963,6 +7964,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
}
if (!attached &&
lhs.isObject() &&
!TryAttachSetValuePropStub(cx, script, pc, stub, obj, oldShape,
oldType, oldSlots, name, id, rhs, &attached))
{

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

@ -60,11 +60,6 @@ static const unsigned BASELINE_MAX_ARGS_LENGTH = 20000;
static bool
CheckFrame(InterpreterFrame *fp)
{
if (fp->script()->isGenerator()) {
JitSpew(JitSpew_BaselineAbort, "generator frame");
return false;
}
if (fp->isDebuggerFrame()) {
// Debugger eval-in-frame. These are likely short-running scripts so
// don't bother compiling them for now.
@ -339,23 +334,26 @@ BaselineScript *
BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset,
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset,
size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize,
size_t bytecodeTypeMapEntries)
size_t bytecodeTypeMapEntries, size_t yieldEntries)
{
static const unsigned DataAlignment = sizeof(uintptr_t);
size_t icEntriesSize = icEntries * sizeof(ICEntry);
size_t pcMappingIndexEntriesSize = pcMappingIndexEntries * sizeof(PCMappingIndexEntry);
size_t bytecodeTypeMapSize = bytecodeTypeMapEntries * sizeof(uint32_t);
size_t yieldEntriesSize = yieldEntries * sizeof(uintptr_t);
size_t paddedICEntriesSize = AlignBytes(icEntriesSize, DataAlignment);
size_t paddedPCMappingIndexEntriesSize = AlignBytes(pcMappingIndexEntriesSize, DataAlignment);
size_t paddedPCMappingSize = AlignBytes(pcMappingSize, DataAlignment);
size_t paddedBytecodeTypesMapSize = AlignBytes(bytecodeTypeMapSize, DataAlignment);
size_t paddedYieldEntriesSize = AlignBytes(yieldEntriesSize, DataAlignment);
size_t allocBytes = paddedICEntriesSize +
paddedPCMappingIndexEntriesSize +
paddedPCMappingSize +
paddedBytecodeTypesMapSize;
paddedBytecodeTypesMapSize +
paddedYieldEntriesSize;
BaselineScript *script = jsscript->zone()->pod_malloc_with_extra<BaselineScript, uint8_t>(allocBytes);
if (!script)
@ -379,7 +377,12 @@ BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilog
offsetCursor += paddedPCMappingSize;
script->bytecodeTypeMapOffset_ = bytecodeTypeMapEntries ? offsetCursor : 0;
offsetCursor += paddedBytecodeTypesMapSize;
script->yieldEntriesOffset_ = yieldEntries ? offsetCursor : 0;
offsetCursor += paddedYieldEntriesSize;
MOZ_ASSERT(offsetCursor == sizeof(BaselineScript) + allocBytes);
return script;
}
@ -570,6 +573,17 @@ BaselineScript::icEntryFromReturnAddress(uint8_t *returnAddr)
return icEntryFromReturnOffset(offset);
}
void
BaselineScript::copyYieldEntries(JSScript *script, Vector<uint32_t> &yieldOffsets)
{
uint8_t **entries = yieldEntryList();
for (size_t i = 0; i < yieldOffsets.length(); i++) {
uint32_t offset = yieldOffsets[i];
entries[i] = nativeCodeForPC(script, script->offsetToPC(offset));
}
}
void
BaselineScript::copyICEntries(JSScript *script, const ICEntry *entries, MacroAssembler &masm)
{

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

@ -178,6 +178,10 @@ struct BaselineScript
// they correspond to, for use by TypeScript::BytecodeTypes.
uint32_t bytecodeTypeMapOffset_;
// For generator scripts, we store the native code address for each yield
// instruction.
uint32_t yieldEntriesOffset_;
public:
// Do not call directly, use BaselineScript::New. This is public for cx->new_.
BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
@ -187,7 +191,8 @@ struct BaselineScript
uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
uint32_t spsPushToggleOffset, size_t icEntries,
size_t pcMappingIndexEntries, size_t pcMappingSize,
size_t bytecodeTypeMapEntries);
size_t bytecodeTypeMapEntries, size_t yieldEntries);
static void Trace(JSTracer *trc, BaselineScript *script);
static void Destroy(FreeOp *fop, BaselineScript *script);
@ -268,6 +273,9 @@ struct BaselineScript
ICEntry *icEntryList() {
return (ICEntry *)(reinterpret_cast<uint8_t *>(this) + icEntriesOffset_);
}
uint8_t **yieldEntryList() {
return (uint8_t **)(reinterpret_cast<uint8_t *>(this) + yieldEntriesOffset_);
}
PCMappingIndexEntry *pcMappingIndexEntryList() {
return (PCMappingIndexEntry *)(reinterpret_cast<uint8_t *>(this) + pcMappingIndexOffset_);
}
@ -319,6 +327,8 @@ struct BaselineScript
void copyICEntries(JSScript *script, const ICEntry *entries, MacroAssembler &masm);
void adoptFallbackStubs(FallbackICStubSpace *stubSpace);
void copyYieldEntries(JSScript *script, Vector<uint32_t> &yieldOffsets);
PCMappingIndexEntry &pcMappingIndexEntry(size_t index);
CompactBufferReader pcMappingReader(size_t indexEntry);
@ -354,6 +364,9 @@ struct BaselineScript
static size_t offsetOfFlags() {
return offsetof(BaselineScript, flags_);
}
static size_t offsetOfYieldEntriesOffset() {
return offsetof(BaselineScript, yieldEntriesOffset_);
}
static void writeBarrierPre(Zone *zone, BaselineScript *script);

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

@ -3772,7 +3772,7 @@ CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
Register tempReg = ToRegister(lir->getTempReg());
masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
masm.loadPtr(Address(tempReg, PerThreadData::offsetOfJitStackLimit()), tempReg);
masm.loadPtr(Address(tempReg, offsetof(PerThreadData, jitStackLimit)), tempReg);
// Conditional forward (unlikely) branch to failure.
CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
@ -9950,7 +9950,7 @@ CodeGenerator::visitInterruptCheck(LInterruptCheck *lir)
if (!ool)
return false;
AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterruptUint32());
AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterrupt());
masm.branch32(Assembler::NotEqual, interruptAddr, Imm32(0), ool->entry());
masm.bind(ool->rejoin());
return true;
@ -9960,8 +9960,8 @@ bool
CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir)
{
Register scratch = ToRegister(lir->scratch());
masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterruptUint32), scratch);
masm.load32(Address(scratch, 0), scratch);
masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterrupt), scratch);
masm.load8ZeroExtend(Address(scratch, 0), scratch);
Label rejoin;
masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin);
{

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

@ -43,7 +43,7 @@ CompileRuntime::addressOfJitTop()
const void *
CompileRuntime::addressOfJitStackLimit()
{
return runtime()->mainThread.addressOfJitStackLimit();
return &runtime()->mainThread.jitStackLimit;
}
const void *
@ -73,15 +73,15 @@ CompileRuntime::addressOfGCZeal()
#endif
const void *
CompileRuntime::addressOfInterruptUint32()
CompileRuntime::addressOfInterrupt()
{
return runtime()->addressOfInterruptUint32();
return &runtime()->interrupt;
}
const void *
CompileRuntime::addressOfInterruptParUint32()
CompileRuntime::addressOfInterruptPar()
{
return runtime()->addressOfInterruptParUint32();
return &runtime()->interruptPar;
}
const void *

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

@ -50,8 +50,8 @@ class CompileRuntime
const void *addressOfGCZeal();
#endif
const void *addressOfInterruptUint32();
const void *addressOfInterruptParUint32();
const void *addressOfInterrupt();
const void *addressOfInterruptPar();
const void *addressOfThreadPool();

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

@ -428,7 +428,7 @@ JitRuntime::ensureIonCodeAccessible(JSRuntime *rt)
ionCodeProtected_ = false;
}
if (rt->hasPendingInterrupt()) {
if (rt->interrupt) {
// The interrupt handler needs to be invoked by this thread, but we may
// be inside a signal handler and have no idea what is above us on the
// stack (probably we are executing Ion code at an arbitrary point, but
@ -1162,7 +1162,7 @@ IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code,
// whether an interrupt is currently desired, matching the targets
// established by ensureIonCodeAccessible() above. We don't handle the
// interrupt immediately as the interrupt lock is held here.
if (cx->runtime()->hasPendingInterrupt())
if (cx->runtime()->interrupt)
PatchBackedge(backedge, interruptCheck, JitRuntime::BackedgeInterruptCheck);
else
PatchBackedge(backedge, loopHeader, JitRuntime::BackedgeLoopHeader);
@ -2720,6 +2720,7 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool
JitSpew(JitSpew_IonInvalidate, "#%d rectifier frame @ %p", frameno, it.fp());
break;
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
case JitFrame_Unwound_BaselineStub:
MOZ_CRASH("invalid");
case JitFrame_Unwound_Rectifier:

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

@ -54,6 +54,7 @@ JitFrameIterator::isFakeExitFrame() const
{
bool res = (prevType() == JitFrame_Unwound_Rectifier ||
prevType() == JitFrame_Unwound_IonJS ||
prevType() == JitFrame_Unwound_BaselineJS ||
prevType() == JitFrame_Unwound_BaselineStub ||
(prevType() == JitFrame_Entry && type() == JitFrame_Exit));
MOZ_ASSERT_IF(res, type() == JitFrame_Exit || type() == JitFrame_BaselineJS);

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

@ -280,6 +280,7 @@ SizeOfFramePrefix(FrameType type)
case JitFrame_BaselineJS:
case JitFrame_IonJS:
case JitFrame_Bailout:
case JitFrame_Unwound_BaselineJS:
case JitFrame_Unwound_IonJS:
return IonJSFrameLayout::Size();
case JitFrame_BaselineStub:
@ -332,6 +333,8 @@ JitFrameIterator::operator++()
type_ = current()->prevType();
if (type_ == JitFrame_Unwound_IonJS)
type_ = JitFrame_IonJS;
else if (type_ == JitFrame_Unwound_BaselineJS)
type_ = JitFrame_BaselineJS;
else if (type_ == JitFrame_Unwound_BaselineStub)
type_ = JitFrame_BaselineStub;
returnAddressToFp_ = current()->returnAddress();
@ -808,6 +811,7 @@ void
EnsureExitFrame(IonCommonFrameLayout *frame)
{
if (frame->prevType() == JitFrame_Unwound_IonJS ||
frame->prevType() == JitFrame_Unwound_BaselineJS ||
frame->prevType() == JitFrame_Unwound_BaselineStub ||
frame->prevType() == JitFrame_Unwound_Rectifier)
{
@ -835,6 +839,12 @@ EnsureExitFrame(IonCommonFrameLayout *frame)
return;
}
if (frame->prevType() == JitFrame_BaselineJS) {
frame->changePrevType(JitFrame_Unwound_BaselineJS);
return;
}
MOZ_ASSERT(frame->prevType() == JitFrame_IonJS);
frame->changePrevType(JitFrame_Unwound_IonJS);
}
@ -1357,6 +1367,7 @@ MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
MarkBailoutFrame(trc, frames);
break;
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
MOZ_CRASH("invalid");
case JitFrame_Rectifier:
MarkRectifierFrame(trc, frames);
@ -2506,6 +2517,7 @@ JitFrameIterator::dump() const
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
break;
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
break;
case JitFrame_Exit:

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

@ -1238,7 +1238,7 @@ MacroAssembler::loadStringChar(Register str, Register index, Register output)
void
MacroAssembler::checkInterruptFlagPar(Register tempReg, Label *fail)
{
movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptParUint32()), tempReg);
movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptPar()), tempReg);
branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail);
}

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

@ -45,6 +45,7 @@ enum FrameType
// An unwound JS frame is a JS frame signalling that its callee frame has been
// turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and
// Baseline exception unwinding.
JitFrame_Unwound_BaselineJS,
JitFrame_Unwound_IonJS,
// Like Unwound_IonJS, but the caller is a baseline stub frame.

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

@ -147,7 +147,7 @@ jit::CheckOverRecursedPar(ForkJoinContext *cx)
}
#endif
if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit(), &stackDummy_)) {
if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit, &stackDummy_)) {
cx->bailoutRecord->joinCause(ParallelBailoutOverRecursed);
return false;
}

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

@ -113,17 +113,28 @@ NewGCObject(JSContext *cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap)
bool
CheckOverRecursed(JSContext *cx)
{
// We just failed the jitStackLimit check. There are two possible reasons:
// - jitStackLimit was the real stack limit and we're over-recursed
// - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
// and we need to call JSRuntime::handleInterrupt.
// IonMonkey's stackLimit is equal to nativeStackLimit by default. When we
// request an interrupt, we set the jitStackLimit to nullptr, which causes
// the stack limit check to fail.
//
// There are two states we're concerned about here:
// (1) The interrupt bit is set, and we need to fire the interrupt callback.
// (2) The stack limit has been exceeded, and we need to throw an error.
//
// Note that we can reach here if jitStackLimit is MAXADDR, but interrupt
// has not yet been set to 1. That's okay; it will be set to 1 very shortly,
// and in the interim we might just fire a few useless calls to
// CheckOverRecursed.
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
#else
JS_CHECK_RECURSION(cx, return false);
#endif
gc::MaybeVerifyBarriers(cx);
return cx->runtime()->handleInterrupt(cx);
if (cx->runtime()->interrupt)
return InterruptCheck(cx);
return true;
}
// This function can get called in two contexts. In the usual context, it's
@ -167,8 +178,10 @@ CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
#endif
gc::MaybeVerifyBarriers(cx);
return cx->runtime()->handleInterrupt(cx);
if (cx->runtime()->interrupt)
return InterruptCheck(cx);
return true;
}
bool
@ -829,6 +842,57 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
return ok;
}
JSObject *
CreateGenerator(JSContext *cx, BaselineFrame *frame)
{
return GeneratorObject::create(cx, frame);
}
bool
InitialSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc)
{
MOZ_ASSERT(*pc == JSOP_INITIALYIELD);
return GeneratorObject::initialSuspend(cx, obj, frame, pc);
}
bool
NormalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc,
uint32_t stackDepth)
{
MOZ_ASSERT(*pc == JSOP_YIELD);
// Return value is still on the stack.
MOZ_ASSERT(stackDepth >= 1);
// The expression stack slots are stored on the stack in reverse order, so
// we copy them to a Vector and pass a pointer to that instead. We use
// stackDepth - 1 because we don't want to include the return value.
AutoValueVector exprStack(cx);
if (!exprStack.reserve(stackDepth - 1))
return false;
size_t firstSlot = frame->numValueSlots() - stackDepth;
for (size_t i = 0; i < stackDepth - 1; i++)
exprStack.infallibleAppend(*frame->valueSlot(firstSlot + i));
MOZ_ASSERT(exprStack.length() == stackDepth - 1);
return GeneratorObject::normalSuspend(cx, obj, frame, pc, exprStack.begin(), stackDepth - 1);
}
bool
FinalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc)
{
MOZ_ASSERT(*pc == JSOP_FINALYIELDRVAL);
if (!GeneratorObject::finalSuspend(cx, obj)) {
// Leave this frame and propagate the exception to the caller.
return DebugEpilogue(cx, frame, pc, /* ok = */ false);
}
return true;
}
bool
StrictEvalPrologue(JSContext *cx, BaselineFrame *frame)
{

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

@ -706,6 +706,12 @@ bool DebugPrologue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mu
bool DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok);
bool DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *pc);
JSObject *CreateGenerator(JSContext *cx, BaselineFrame *frame);
bool InitialSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc);
bool NormalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc,
uint32_t stackDepth);
bool FinalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc);
bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame);
bool HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame);

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

@ -783,7 +783,7 @@ enum AsmJSImmKind
AsmJSImm_PowD = AsmJSExit::Builtin_PowD,
AsmJSImm_ATan2D = AsmJSExit::Builtin_ATan2D,
AsmJSImm_Runtime,
AsmJSImm_RuntimeInterruptUint32,
AsmJSImm_RuntimeInterrupt,
AsmJSImm_StackLimit,
AsmJSImm_ReportOverRecursed,
AsmJSImm_OnDetached,

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

@ -303,6 +303,7 @@ MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor
MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 0, JSEXN_SYNTAXERR, "more than one switch default")
MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 0, JSEXN_SYNTAXERR, "too many function arguments")
MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local variables")
MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions")
MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")

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

@ -2031,48 +2031,68 @@ JS_GetExternalStringFinalizer(JSString *str)
}
static void
SetNativeStackQuotaAndLimit(JSRuntime *rt, StackKind kind, size_t stackSize)
SetNativeStackQuota(JSRuntime *rt, StackKind kind, size_t stackSize)
{
rt->nativeStackQuota[kind] = stackSize;
if (rt->nativeStackBase)
RecomputeStackLimit(rt, kind);
}
void
js::RecomputeStackLimit(JSRuntime *rt, StackKind kind)
{
size_t stackSize = rt->nativeStackQuota[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
if (stackSize == 0) {
rt->mainThread.nativeStackLimit[kind] = UINTPTR_MAX;
} else {
MOZ_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize);
rt->mainThread.nativeStackLimit[kind] = rt->nativeStackBase + stackSize - 1;
rt->mainThread.nativeStackLimit[kind] =
rt->nativeStackBase + stackSize - 1;
}
#else
if (stackSize == 0) {
rt->mainThread.nativeStackLimit[kind] = 0;
} else {
MOZ_ASSERT(rt->nativeStackBase >= stackSize);
rt->mainThread.nativeStackLimit[kind] = rt->nativeStackBase - (stackSize - 1);
rt->mainThread.nativeStackLimit[kind] =
rt->nativeStackBase - (stackSize - 1);
}
#endif
// If there's no pending interrupt request set on the runtime's main thread's
// jitStackLimit, then update it so that it reflects the new nativeStacklimit.
//
// Note that, for now, we use the untrusted limit for ion. This is fine,
// because it's the most conservative limit, and if we hit it, we'll bail
// out of ion into the interpeter, which will do a proper recursion check.
if (kind == StackForUntrustedScript) {
JSRuntime::AutoLockForInterrupt lock(rt);
if (rt->mainThread.jitStackLimit != uintptr_t(-1)) {
rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind];
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
rt->mainThread.jitStackLimit = jit::Simulator::StackLimit();
#endif
}
}
}
JS_PUBLIC_API(void)
JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize, size_t trustedScriptStackSize,
JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize,
size_t trustedScriptStackSize,
size_t untrustedScriptStackSize)
{
MOZ_ASSERT(rt->requestDepth == 0);
MOZ_ASSERT_IF(trustedScriptStackSize,
trustedScriptStackSize < systemCodeStackSize);
if (!trustedScriptStackSize)
trustedScriptStackSize = systemCodeStackSize;
else
MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize);
MOZ_ASSERT_IF(untrustedScriptStackSize,
untrustedScriptStackSize < trustedScriptStackSize);
if (!untrustedScriptStackSize)
untrustedScriptStackSize = trustedScriptStackSize;
else
MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
SetNativeStackQuotaAndLimit(rt, StackForSystemCode, systemCodeStackSize);
SetNativeStackQuotaAndLimit(rt, StackForTrustedScript, trustedScriptStackSize);
SetNativeStackQuotaAndLimit(rt, StackForUntrustedScript, untrustedScriptStackSize);
rt->mainThread.initJitStackLimit();
SetNativeStackQuota(rt, StackForSystemCode, systemCodeStackSize);
SetNativeStackQuota(rt, StackForTrustedScript, trustedScriptStackSize);
SetNativeStackQuota(rt, StackForUntrustedScript, untrustedScriptStackSize);
}
/************************************************************************/

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

@ -2272,9 +2272,6 @@ JS_GetExternalStringFinalizer(JSString *str);
* The stack quotas for each kind of code should be monotonically descending,
* and may be specified with this function. If 0 is passed for a given kind
* of code, it defaults to the value of the next-highest-priority kind.
*
* This function may only be called immediately after the runtime is initialized
* and before any code is executed and/or interrupts requested.
*/
extern JS_PUBLIC_API(void)
JS_SetNativeStackQuota(JSRuntime *cx, size_t systemCodeStackSize,

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

@ -237,12 +237,51 @@ GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, Mutable
return GetElement(cx, obj, obj, index, hole, vp);
}
static bool
GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
void
ElementAdder::append(JSContext *cx, HandleValue v)
{
for (uint32_t i = 0; i < length; i++) {
if (!JSObject::getElement(cx, aobj, aobj, i, MutableHandleValue::fromMarkedLocation(&vp[i])))
return false;
MOZ_ASSERT(index_ < length_);
if (resObj_)
resObj_->as<NativeObject>().setDenseElementWithType(cx, index_++, v);
else
vp_[index_++] = v;
}
void
ElementAdder::appendHole()
{
MOZ_ASSERT(getBehavior_ == ElementAdder::CheckHasElemPreserveHoles);
MOZ_ASSERT(index_ < length_);
if (resObj_) {
MOZ_ASSERT(resObj_->as<NativeObject>().getDenseElement(index_).isMagic(JS_ELEMENTS_HOLE));
index_++;
} else {
vp_[index_++].setMagic(JS_ELEMENTS_HOLE);
}
}
bool
js::GetElementsWithAdder(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t begin, uint32_t end, ElementAdder *adder)
{
MOZ_ASSERT(begin <= end);
RootedValue val(cx);
for (uint32_t i = begin; i < end; i++) {
if (adder->getBehavior() == ElementAdder::CheckHasElemPreserveHoles) {
bool hole;
if (!GetElement(cx, obj, receiver, i, &hole, &val))
return false;
if (hole) {
adder->appendHole();
continue;
}
} else {
MOZ_ASSERT(adder->getBehavior() == ElementAdder::GetElement);
if (!JSObject::getElement(cx, obj, receiver, i, &val))
return false;
}
adder->append(cx, val);
}
return true;
@ -272,7 +311,17 @@ js::GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
}
}
return GetElementsSlow(cx, aobj, length, vp);
if (js::GetElementsOp op = aobj->getOps()->getElements) {
ElementAdder adder(cx, vp, length, ElementAdder::GetElement);
return op(cx, aobj, 0, length, &adder);
}
for (uint32_t i = 0; i < length; i++) {
if (!JSObject::getElement(cx, aobj, aobj, i, MutableHandleValue::fromMarkedLocation(&vp[i])))
return false;
}
return true;
}
/*
@ -2815,6 +2864,24 @@ GetIndexedPropertiesInRange(JSContext *cx, HandleObject obj, uint32_t begin, uin
return true;
}
static bool
SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver,
uint32_t begin, uint32_t end, HandleObject result)
{
RootedValue value(cx);
for (uint32_t slot = begin; slot < end; slot++) {
bool hole;
if (!CheckForInterrupt(cx) ||
!GetElement(cx, obj, receiver, slot, &hole, &value))
{
return false;
}
if (!hole && !JSObject::defineElement(cx, result, slot - begin, value))
return false;
}
return true;
}
static bool
SliceSparse(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end, HandleObject result)
{
@ -2913,14 +2980,16 @@ js::array_slice(JSContext *cx, unsigned argc, Value *vp)
return false;
TryReuseArrayType(obj, narr);
if (js::SliceOp op = obj->getOps()->slice) {
// Ensure that we have dense elements, so that DOM can use js::UnsafeDefineElement.
if (js::GetElementsOp op = obj->getOps()->getElements) {
// Ensure that we have dense elements, so that ElementAdder::append can
// use setDenseElementWithType.
NativeObject::EnsureDenseResult result = narr->ensureDenseElements(cx, 0, end - begin);
if (result == NativeObject::ED_FAILED)
return false;
if (result == NativeObject::ED_OK) {
if (!op(cx, obj, begin, end, narr))
ElementAdder adder(cx, narr, end - begin, ElementAdder::CheckHasElemPreserveHoles);
if (!op(cx, obj, begin, end, &adder))
return false;
args.rval().setObject(*narr);
@ -2943,24 +3012,6 @@ js::array_slice(JSContext *cx, unsigned argc, Value *vp)
return true;
}
JS_FRIEND_API(bool)
js::SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver,
uint32_t begin, uint32_t end, HandleObject result)
{
RootedValue value(cx);
for (uint32_t slot = begin; slot < end; slot++) {
bool hole;
if (!CheckForInterrupt(cx) ||
!GetElement(cx, obj, receiver, slot, &hole, &value))
{
return false;
}
if (!hole && !JSObject::defineElement(cx, result, slot - begin, value))
return false;
}
return true;
}
/* ES5 15.4.4.20. */
static bool
array_filter(JSContext *cx, unsigned argc, Value *vp)

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

@ -41,6 +41,7 @@
#include "gc/Marking.h"
#include "jit/Ion.h"
#include "js/CharacterEncoding.h"
#include "vm/Debugger.h"
#include "vm/HelperThreads.h"
#include "vm/Shape.h"
@ -970,6 +971,90 @@ js_GetErrorMessage(void *userRef, const unsigned errorNumber)
return nullptr;
}
bool
js::InvokeInterruptCallback(JSContext *cx)
{
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
JSRuntime *rt = cx->runtime();
MOZ_ASSERT(rt->interrupt);
// Reset the callback counter first, then run GC and yield. If another
// thread is racing us here we will accumulate another callback request
// which will be serviced at the next opportunity.
rt->interrupt = false;
// IonMonkey sets its stack limit to UINTPTR_MAX to trigger interrupt
// callbacks.
rt->resetJitStackLimit();
cx->gcIfNeeded();
rt->interruptPar = false;
// A worker thread may have requested an interrupt after finishing an Ion
// compilation.
jit::AttachFinishedCompilations(cx);
// Important: Additional callbacks can occur inside the callback handler
// if it re-enters the JS engine. The embedding must ensure that the
// callback is disconnected before attempting such re-entry.
JSInterruptCallback cb = cx->runtime()->interruptCallback;
if (!cb)
return true;
if (cb(cx)) {
// Debugger treats invoking the interrupt callback as a "step", so
// invoke the onStep handler.
if (cx->compartment()->debugMode()) {
ScriptFrameIter iter(cx);
if (iter.script()->stepModeEnabled()) {
RootedValue rval(cx);
switch (Debugger::onSingleStep(cx, &rval)) {
case JSTRAP_ERROR:
return false;
case JSTRAP_CONTINUE:
return true;
case JSTRAP_RETURN:
// See note in Debugger::propagateForcedReturn.
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
return false;
case JSTRAP_THROW:
cx->setPendingException(rval);
return false;
default:;
}
}
}
return true;
}
// No need to set aside any pending exception here: ComputeStackString
// already does that.
JSString *stack = ComputeStackString(cx);
JSFlatString *flat = stack ? stack->ensureFlat(cx) : nullptr;
const char16_t *chars;
AutoStableStringChars stableChars(cx);
if (flat && stableChars.initTwoByte(cx, flat))
chars = stableChars.twoByteRange().start().get();
else
chars = MOZ_UTF16("(stack not available)");
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
JSMSG_TERMINATED, chars);
return false;
}
bool
js::HandleExecutionInterrupt(JSContext *cx)
{
if (cx->runtime()->interrupt)
return InvokeInterruptCallback(cx);
return true;
}
ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
: ContextFriendFields(rt),
contextKind_(kind),

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

@ -289,7 +289,7 @@ struct ThreadSafeContext : ContextFriendFields,
PropertyName *emptyString() { return runtime_->emptyString; }
FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
void *runtimeAddressForJit() { return runtime_; }
void *runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
void *runtimeAddressOfInterrupt() { return &runtime_->interrupt; }
void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
void *stackLimitAddressForJitCode(StackKind kind);
size_t gcSystemPageSize() { return gc::SystemPageSize(); }
@ -782,15 +782,33 @@ extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
namespace js {
/*
* Invoke the interrupt callback and return false if the current execution
* is to be terminated.
*/
bool
InvokeInterruptCallback(JSContext *cx);
bool
HandleExecutionInterrupt(JSContext *cx);
/*
* Process any pending interrupt requests. Long-running inner loops in C++ must
* call this periodically to make sure they are interruptible --- that is, to
* make sure they do not prevent the slow script dialog from appearing.
*
* This can run a full GC or call the interrupt callback, which could do
* anything. In the browser, it displays the slow script dialog.
*
* If this returns true, the caller can continue; if false, the caller must
* break out of its loop. This happens if, for example, the user clicks "Stop
* script" on the slow script dialog; treat it as an uncatchable error.
*/
MOZ_ALWAYS_INLINE bool
CheckForInterrupt(JSContext *cx)
{
// Add an inline fast-path since we have to check for interrupts in some hot
// C++ loops of library builtins.
JSRuntime *rt = cx->runtime();
if (rt->hasPendingInterrupt())
return rt->handleInterrupt(cx);
return true;
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
return !cx->runtime()->interrupt || InvokeInterruptCallback(cx);
}
/************************************************************************/

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

@ -1386,14 +1386,6 @@ js::GetObjectMetadata(JSObject *obj)
return obj->getMetadata();
}
JS_FRIEND_API(void)
js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value)
{
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(index < obj->as<NativeObject>().getDenseInitializedLength());
obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
}
JS_FRIEND_API(bool)
js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
JS::Handle<js::PropertyDescriptor> descriptor, bool *bp)

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

@ -323,7 +323,7 @@ namespace js {
js::proxy_SetGenericAttributes, \
js::proxy_DeleteGeneric, \
js::proxy_Watch, js::proxy_Unwatch, \
js::proxy_Slice, \
js::proxy_GetElements, \
nullptr, /* enumerate */ \
nullptr, /* thisObject */ \
} \
@ -411,8 +411,8 @@ proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObje
extern JS_FRIEND_API(bool)
proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
extern JS_FRIEND_API(bool)
proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
JS::HandleObject result);
proxy_GetElements(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder *adder);
/*
* A class of objects that return source code on demand.
@ -2578,12 +2578,9 @@ SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata
JS_FRIEND_API(JSObject *)
GetObjectMetadata(JSObject *obj);
JS_FRIEND_API(void)
UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value);
JS_FRIEND_API(bool)
SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver,
uint32_t begin, uint32_t end, JS::HandleObject result);
GetElementsWithAdder(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
uint32_t begin, uint32_t end, js::ElementAdder *adder);
JS_FRIEND_API(bool)
ForwardToNative(JSContext *cx, JSNative native, const JS::CallArgs &args);

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

@ -526,7 +526,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
rt->gc.runDebugGC();
#endif
if (rt->hasPendingInterrupt()) {
if (rt->interrupt) {
// Invoking the interrupt callback can fail and we can't usefully
// handle that here. Just check in case we need to collect instead.
ncx->gcIfNeeded();

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

@ -18,7 +18,6 @@ inline uintptr_t
GetNativeStackBase()
{
uintptr_t stackBase = reinterpret_cast<uintptr_t>(GetNativeStackBaseImpl());
MOZ_ASSERT(stackBase != 0);
MOZ_ASSERT(stackBase % sizeof(void *) == 0);
return stackBase;
}

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

@ -1067,8 +1067,7 @@ js_Disassemble1(JSContext *cx, HandleScript script, jsbytecode *pc,
goto print_int;
case JOF_UINT24:
MOZ_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY || op == JSOP_INITELEM_ARRAY ||
op == JSOP_DUPAT);
MOZ_ASSERT(len == 4);
i = (int)GET_UINT24(pc);
goto print_int;

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

@ -332,8 +332,8 @@ class JS_FRIEND_API(BaseProxyHandler)
JS::HandleObject callable) const;
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) const;
virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result) const;
virtual bool getElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder *adder) const;
/* See comment for weakmapKeyDelegateOp in js/Class.h. */
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const;

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

@ -341,12 +341,12 @@ BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id) const
}
bool
BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result) const
BaseProxyHandler::getElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder *adder) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder);
}
bool

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

@ -550,8 +550,8 @@ Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id)
}
/* static */ bool
Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
Proxy::getElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder *adder)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
@ -560,11 +560,11 @@ Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
if (!policy.allowed()) {
if (policy.returnValue()) {
MOZ_ASSERT(!cx->isExceptionPending());
return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder);
}
return false;
}
return handler->slice(cx, proxy, begin, end, result);
return handler->getElements(cx, proxy, begin, end, adder);
}
JSObject *
@ -835,10 +835,10 @@ js::proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id)
}
bool
js::proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
js::proxy_GetElements(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder *adder)
{
return Proxy::slice(cx, proxy, begin, end, result);
return Proxy::getElements(cx, proxy, begin, end, adder);
}
const Class js::ProxyObject::class_ =

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

@ -69,8 +69,8 @@ class Proxy
static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
HandleObject result);
static bool getElements(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
ElementAdder *adder);
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,

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

@ -1440,7 +1440,7 @@ ForkJoinShared::execute()
// Sometimes a GC request occurs *just before* we enter into the
// parallel section. Rather than enter into the parallel section
// and then abort, we just check here and abort early.
if (cx_->runtime()->hasPendingInterruptPar())
if (cx_->runtime()->interruptPar)
return TP_RETRY_SEQUENTIALLY;
AutoLockMonitor lock(*this);
@ -1518,7 +1518,7 @@ ForkJoinShared::executeFromWorker(ThreadPoolWorker *worker, uintptr_t stackLimit
// Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the
// lock has not been initialized in these cases.
thisThread.initJitStackLimitPar(stackLimit);
thisThread.jitStackLimit = stackLimit;
executePortion(&thisThread, worker);
TlsPerThreadData.set(nullptr);
@ -1551,7 +1551,7 @@ ForkJoinShared::executeFromMainThread(ThreadPoolWorker *worker)
//
// Thus, use GetNativeStackLimit instead of just propagating the
// main thread's.
thisThread.initJitStackLimitPar(GetNativeStackLimit(cx_));
thisThread.jitStackLimit = GetNativeStackLimit(cx_);
executePortion(&thisThread, worker);
TlsPerThreadData.set(oldData);
@ -1647,7 +1647,7 @@ ForkJoinShared::executePortion(PerThreadData *perThread, ThreadPoolWorker *worke
void
ForkJoinShared::setAbortFlagDueToInterrupt(ForkJoinContext &cx)
{
MOZ_ASSERT(cx_->runtime()->hasPendingInterruptPar());
MOZ_ASSERT(cx_->runtime()->interruptPar);
// The GC Needed flag should not be set during parallel
// execution. Instead, one of the requestGC() or
// requestZoneGC() methods should be invoked.
@ -1826,7 +1826,7 @@ ForkJoinContext::hasAcquiredJSContext() const
bool
ForkJoinContext::check()
{
if (runtime()->hasPendingInterruptPar()) {
if (runtime()->interruptPar) {
shared_->setAbortFlagDueToInterrupt(*this);
return false;
}
@ -2273,6 +2273,13 @@ js::ParallelTestsShouldPass(JSContext *cx)
cx->runtime()->gcZeal() == 0;
}
void
js::RequestInterruptForForkJoin(JSRuntime *rt, JSRuntime::InterruptMode mode)
{
if (mode != JSRuntime::RequestInterruptAnyThreadDontStopIon)
rt->interruptPar = true;
}
bool
js::intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp)
{

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

@ -546,6 +546,8 @@ bool InExclusiveParallelSection();
bool ParallelTestsShouldPass(JSContext *cx);
void RequestInterruptForForkJoin(JSRuntime *rt, JSRuntime::InterruptMode mode);
bool intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp);
extern const JSJitInfo intrinsic_SetForkJoinTargetRegionInfo;

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

@ -60,19 +60,28 @@ GeneratorObject::create(JSContext *cx, AbstractFramePtr frame)
bool
GeneratorObject::suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc,
Value *vp, unsigned nvalues, GeneratorObject::SuspendKind suspendKind)
Value *vp, unsigned nvalues)
{
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
MOZ_ASSERT(!genObj->hasExpressionStack());
if (suspendKind == NORMAL && genObj->isClosing()) {
if (*pc == JSOP_YIELD && genObj->isClosing()) {
MOZ_ASSERT(genObj->is<LegacyGeneratorObject>());
RootedValue val(cx, ObjectValue(*frame.callee()));
js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, NullPtr());
return false;
}
genObj->setSuspendedBytecodeOffset(pc - frame.script()->code(), suspendKind == INITIAL);
uint32_t yieldIndex = GET_UINT24(pc);
MOZ_ASSERT((*pc == JSOP_INITIALYIELD) == (yieldIndex == 0));
static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH,
"code below assumes INITIALYIELD and YIELD have same length");
pc += JSOP_YIELD_LENGTH;
genObj->setSuspendedBytecodeOffset(frame.script()->pcToOffset(pc), yieldIndex);
genObj->setScopeChain(*frame.scopeChain());
if (nvalues) {
@ -128,6 +137,15 @@ GeneratorObject::resume(JSContext *cx, InterpreterActivation &activation,
activation.regs().pc = callee->nonLazyScript()->code() + genObj->suspendedBytecodeOffset();
#ifdef DEBUG
// Verify the YIELD_INDEX slot holds the right value.
static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH,
"code below assumes INITIALYIELD and YIELD have same length");
jsbytecode *yieldpc = activation.regs().pc - JSOP_YIELD_LENGTH;
MOZ_ASSERT(*yieldpc == JSOP_INITIALYIELD || *yieldpc == JSOP_YIELD);
MOZ_ASSERT(GET_UINT24(yieldpc) == genObj->suspendedYieldIndex());
#endif
// Always push on a value, even if we are raising an exception. In the
// exception case, the stack needs to have something on it so that exception
// handling doesn't skip the catch blocks. See TryNoteIter::settle.

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

@ -28,12 +28,17 @@ class GeneratorObject : public NativeObject
ARGS_OBJ_SLOT,
EXPRESSION_STACK_SLOT,
BYTECODE_OFFSET_SLOT,
YIELD_INDEX_SLOT,
RESERVED_SLOTS
};
enum SuspendKind { INITIAL, NORMAL, FINAL };
enum ResumeKind { NEXT, THROW, CLOSE };
private:
static bool suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc,
Value *vp, unsigned nvalues);
public:
static inline ResumeKind getResumeKind(jsbytecode *pc) {
MOZ_ASSERT(*pc == JSOP_RESUME);
unsigned arg = GET_UINT16(pc);
@ -52,19 +57,16 @@ class GeneratorObject : public NativeObject
static JSObject *create(JSContext *cx, AbstractFramePtr frame);
static bool suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc,
Value *vp, unsigned nvalues, SuspendKind kind);
static bool resume(JSContext *cx, InterpreterActivation &activation,
HandleObject obj, HandleValue arg, ResumeKind resumeKind);
static bool initialSuspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc) {
return suspend(cx, obj, frame, pc, nullptr, 0, INITIAL);
return suspend(cx, obj, frame, pc, nullptr, 0);
}
static bool normalSuspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc,
Value *vp, unsigned nvalues) {
return suspend(cx, obj, frame, pc, vp, nvalues, NORMAL);
return suspend(cx, obj, frame, pc, vp, nvalues);
}
static bool finalSuspend(JSContext *cx, HandleObject obj);
@ -149,11 +151,23 @@ class GeneratorObject : public NativeObject
MOZ_ASSERT(isSuspended());
return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() >> 1;
}
void setSuspendedBytecodeOffset(ptrdiff_t offset, bool newborn) {
void setSuspendedBytecodeOffset(ptrdiff_t offset, uint32_t yieldIndex) {
bool newborn = (yieldIndex == 0);
MOZ_ASSERT(newborn ? getFixedSlot(BYTECODE_OFFSET_SLOT).isUndefined() : isRunning());
MOZ_ASSERT(offset > 0 && offset < MAX_BYTECODE_OFFSET);
setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value((offset << 1) | (newborn ? 0x1 : 0)));
MOZ_ASSERT(isSuspended());
MOZ_ASSERT(yieldIndex <= INT32_MAX);
setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex));
}
// When the generator is suspended, the yield index slot contains the yield
// index (see JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction
// that suspended the generator. This is only used by JIT code to lookup the
// native code address when resuming.
uint32_t suspendedYieldIndex() const {
MOZ_ASSERT(isSuspended());
return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
}
bool isClosed() const {
return getFixedSlot(CALLEE_SLOT).isNull();
@ -165,6 +179,7 @@ class GeneratorObject : public NativeObject
setFixedSlot(ARGS_OBJ_SLOT, NullValue());
setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
setFixedSlot(BYTECODE_OFFSET_SLOT, NullValue());
setFixedSlot(YIELD_INDEX_SLOT, NullValue());
}
static size_t offsetOfCalleeSlot() {
@ -182,6 +197,9 @@ class GeneratorObject : public NativeObject
static size_t offsetOfBytecodeOffsetSlot() {
return getFixedSlotOffset(BYTECODE_OFFSET_SLOT);
}
static size_t offsetOfYieldIndexSlot() {
return getFixedSlotOffset(YIELD_INDEX_SLOT);
}
static size_t offsetOfExpressionStackSlot() {
return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
}

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

@ -3362,7 +3362,7 @@ CASE(JSOP_INITIALYIELD)
obj = &REGS.sp[-1].toObject();
POP_RETURN_VALUE();
MOZ_ASSERT(REGS.stackDepth() == 0);
if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_INITIALYIELD_LENGTH))
if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc))
goto error;
goto successful_return_continuation;
}
@ -3373,7 +3373,7 @@ CASE(JSOP_YIELD)
MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
RootedObject &obj = rootObject0;
obj = &REGS.sp[-1].toObject();
if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_YIELD_LENGTH,
if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc,
REGS.spForStackDepth(0), REGS.stackDepth() - 2))
{
goto error;

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