This commit is contained in:
Ryan VanderMeulen 2014-11-11 16:29:57 -05:00
Родитель 5f2440425d dfa6d6b02a
Коммит b621e08282
117 изменённых файлов: 1244 добавлений и 485 удалений

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

@ -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;
}

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

@ -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();

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

@ -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,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

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

@ -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);

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

@ -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;

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

@ -1565,19 +1565,19 @@
* interpretation.
* Category: Statements
* Type: Generator
* Operands:
* Operands: uint24_t yieldIndex
* Stack: generator =>
*/ \
macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \
/*
* Pops the generator and the return value 'rval1', stops interpretation and
* returns 'rval1'. Pushes sent value from 'send()' onto the stack.
* Category: Statements
* Type: Generator
* Operands:
* Operands: uint24_t yieldIndex
* Stack: rval1, gen => rval2
*/ \
macro(JSOP_YIELD, 203,"yield", NULL, 1, 2, 1, JOF_BYTE) \
macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \
/*
* Pops the generator and suspends and closes it. Yields the value in the
* frame's return value slot.

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

@ -621,8 +621,14 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
// in the bytecode interpreter, which can execute while tolerating
// future interrupts. Otherwise, if we keep getting interrupted we
// will never finish executing the regexp.
if (cx->runtime()->hasPendingInterrupt()) {
if (!cx->runtime()->handleInterrupt(cx))
bool interrupted;
{
JSRuntime::AutoLockForInterrupt lock(cx->runtime());
interrupted = cx->runtime()->interrupt;
}
if (interrupted) {
if (!InvokeInterruptCallback(cx))
return RegExpRunStatus_Error;
break;
}

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

@ -36,7 +36,6 @@
#include "jit/PcScriptCache.h"
#include "js/MemoryMetrics.h"
#include "js/SliceBudget.h"
#include "vm/Debugger.h"
#include "jscntxtinlines.h"
#include "jsgcinlines.h"
@ -74,7 +73,7 @@ PerThreadData::PerThreadData(JSRuntime *runtime)
runtime_(runtime),
jitTop(nullptr),
jitJSContext(nullptr),
jitStackLimit_(0xbad),
jitStackLimit(0),
#ifdef JS_TRACE_LOGGING
traceLogger(nullptr),
#endif
@ -136,8 +135,8 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
),
mainThread(this),
parentRuntime(parentRuntime),
interrupt_(false),
interruptPar_(false),
interrupt(false),
interruptPar(false),
handlingSignal(false),
interruptCallback(nullptr),
interruptLock(nullptr),
@ -156,7 +155,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
execAlloc_(nullptr),
jitRuntime_(nullptr),
selfHostingGlobal_(nullptr),
nativeStackBase(GetNativeStackBase()),
nativeStackBase(0),
cxCallback(nullptr),
destroyCompartmentCallback(nullptr),
destroyZoneCallback(nullptr),
@ -322,6 +321,8 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
return false;
#endif
nativeStackBase = GetNativeStackBase();
jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint();
jitSupportsSimd = js::jit::JitSupportsSimd();
@ -463,6 +464,17 @@ NewObjectCache::clearNurseryObjects(JSRuntime *rt)
#endif
}
void
JSRuntime::resetJitStackLimit()
{
AutoLockForInterrupt lock(this);
mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
mainThread.setJitStackLimit(js::jit::Simulator::StackLimit());
#endif
}
void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
{
@ -517,120 +529,33 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
#endif
}
static bool
InvokeInterruptCallback(JSContext *cx)
{
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
cx->gcIfNeeded();
// 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;
}
void
PerThreadData::resetJitStackLimit()
{
// 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 defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
jitStackLimit_ = jit::Simulator::StackLimit();
#else
jitStackLimit_ = nativeStackLimit[StackForUntrustedScript];
#endif
}
void
PerThreadData::initJitStackLimit()
{
resetJitStackLimit();
}
void
PerThreadData::initJitStackLimitPar(uintptr_t limit)
{
jitStackLimit_ = limit;
}
void
JSRuntime::requestInterrupt(InterruptMode mode)
{
interrupt_ = true;
interruptPar_ = true;
mainThread.jitStackLimit_ = UINTPTR_MAX;
AutoLockForInterrupt lock(this);
/*
* Invalidate ionTop to trigger its over-recursion check. Note this must be
* set before interrupt, to avoid racing with js::InvokeInterruptCallback,
* into a weird state where interrupt is stuck at 0 but jitStackLimit is
* MAXADDR.
*/
mainThread.setJitStackLimit(-1);
interrupt = true;
RequestInterruptForForkJoin(this, mode);
/*
* asm.js and normal Ion code optionally use memory protection and signal
* handlers to halt running code.
*/
if (canUseSignalHandlers()) {
AutoLockForInterrupt lock(this);
RequestInterruptForAsmJSCode(this, mode);
jit::RequestInterruptForIonCode(this, mode);
}
}
bool
JSRuntime::handleInterrupt(JSContext *cx)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
if (interrupt_ || mainThread.jitStackLimit_ == UINTPTR_MAX) {
interrupt_ = false;
interruptPar_ = false;
mainThread.resetJitStackLimit();
return InvokeInterruptCallback(cx);
}
return true;
}
jit::ExecutableAllocator *
JSRuntime::createExecutableAllocator(JSContext *cx)
{

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

@ -519,20 +519,13 @@ class PerThreadData : public PerThreadDataFriendFields
*/
JSContext *jitJSContext;
/* See comment for JSRuntime::interrupt_. */
private:
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
void resetJitStackLimit();
friend struct ::JSRuntime;
public:
void initJitStackLimit();
void initJitStackLimitPar(uintptr_t limit);
/*
* The stack limit checked by JIT code. This stack limit may be temporarily
* set to null to force JIT code to exit (e.g., for the operation callback).
*/
uintptr_t jitStackLimit;
uintptr_t jitStackLimit() const { return jitStackLimit_; }
// For read-only JIT use:
void *addressOfJitStackLimit() { return &jitStackLimit_; }
static size_t offsetOfJitStackLimit() { return offsetof(PerThreadData, jitStackLimit_); }
inline void setJitStackLimit(uintptr_t limit);
// Information about the heap allocated backtrack stack used by RegExp JIT code.
irregexp::RegExpStack regexpStack;
@ -685,6 +678,8 @@ class PerThreadData : public PerThreadDataFriendFields
class AutoLockForExclusiveAccess;
void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
} // namespace js
struct JSRuntime : public JS::shadow::Runtime,
@ -708,56 +703,18 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
JSRuntime *parentRuntime;
private:
mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptPar_;
public:
/*
* If true, we've been asked to call the interrupt callback as soon as
* possible.
*/
mozilla::Atomic<bool, mozilla::Relaxed> interrupt;
enum InterruptMode {
RequestInterruptMainThread,
RequestInterruptAnyThread,
RequestInterruptAnyThreadDontStopIon,
RequestInterruptAnyThreadForkJoin
};
// Any thread can call requestInterrupt() to request that the main JS thread
// stop running and call the interrupt callback (allowing the interrupt
// callback to halt execution). To stop the main JS thread, requestInterrupt
// sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to
// UINTPTR_MAX). The JS engine must continually poll one of these fields
// and call handleInterrupt if either field has the interrupt value. (The
// point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already
// needs to guard on jitStackLimit_ in every function prologue to avoid
// stack overflow, so we avoid a second branch on interrupt_ by setting
// jitStackLimit_ to a value that is guaranteed to fail the guard.)
//
// Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed
// Atomic so, while the writes are guaranteed to eventually be visible to
// the main thread, it can happen in any order. handleInterrupt calls the
// interrupt callback if either is set, so it really doesn't matter as long
// as the JS engine is continually polling at least one field. In corner
// cases, this relaxed ordering could lead to an interrupt handler being
// called twice in succession after a single requestInterrupt call, but
// that's fine.
void requestInterrupt(InterruptMode mode);
bool handleInterrupt(JSContext *cx);
MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const {
return interrupt_;
}
MOZ_ALWAYS_INLINE bool hasPendingInterruptPar() const {
return interruptPar_;
}
// For read-only JIT use:
void *addressOfInterruptUint32() {
static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers");
return &interrupt_;
}
void *addressOfInterruptParUint32() {
static_assert(sizeof(interruptPar_) == sizeof(uint32_t), "Assumed by JIT callers");
return &interruptPar_;
}
/*
* If non-zero, ForkJoin should service an interrupt. This is a separate
* flag from |interrupt| because we cannot use the mprotect trick with PJS
* code and ignore the TriggerCallbackAnyThreadDontStopIon trigger.
*/
mozilla::Atomic<bool, mozilla::Relaxed> interruptPar;
/* Set when handling a signal for a thread associated with this runtime. */
bool handlingSignal;
@ -943,7 +900,7 @@ struct JSRuntime : public JS::shadow::Runtime,
void setDefaultVersion(JSVersion v) { defaultVersion_ = v; }
/* Base address of the native stack for the current thread. */
const uintptr_t nativeStackBase;
uintptr_t nativeStackBase;
/* The native stack size limit that runtime should not exceed. */
size_t nativeStackQuota[js::StackKindCount];
@ -1309,6 +1266,10 @@ struct JSRuntime : public JS::shadow::Runtime,
bool jitSupportsFloatingPoint;
bool jitSupportsSimd;
// Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1)
// has been noticed by Ion/Baseline.
void resetJitStackLimit();
// Cache for jit::GetPcScript().
js::jit::PcScriptCache *ionPcScriptCache;
@ -1369,6 +1330,17 @@ struct JSRuntime : public JS::shadow::Runtime,
/* onOutOfMemory but can call the largeAllocationFailureCallback. */
JS_FRIEND_API(void *) onOutOfMemoryCanGC(void *p, size_t bytes);
// Ways in which the interrupt callback on the runtime can be triggered,
// varying based on which thread is triggering the callback.
enum InterruptMode {
RequestInterruptMainThread,
RequestInterruptAnyThread,
RequestInterruptAnyThreadDontStopIon,
RequestInterruptAnyThreadForkJoin
};
void requestInterrupt(InterruptMode mode);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *runtime);
private:
@ -1592,6 +1564,13 @@ class MOZ_STACK_CLASS AutoKeepAtoms
}
};
inline void
PerThreadData::setJitStackLimit(uintptr_t limit)
{
MOZ_ASSERT(runtime_->currentThreadOwnsInterruptLock());
jitStackLimit = limit;
}
inline JSRuntime *
PerThreadData::runtimeFromMainThread()
{

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

@ -605,7 +605,7 @@ const Class DynamicWithObject::class_ = {
with_SetGenericAttributes,
with_DeleteGeneric,
nullptr, nullptr, /* watch/unwatch */
nullptr, /* slice */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
with_ThisObject,
}
@ -1045,7 +1045,7 @@ const Class UninitializedLexicalObject::class_ = {
uninitialized_SetGenericAttributes,
uninitialized_DeleteGeneric,
nullptr, nullptr, /* watch/unwatch */
nullptr, /* slice */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
nullptr, /* this */
}

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

@ -34,7 +34,7 @@ namespace js {
* Nightly) and without (all others). FIXME: Bug 1066322 - Enable ES6 symbols
* in all builds.
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 194;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 196;
static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above");
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND

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

@ -697,7 +697,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = {
nullptr, // setGenericAttributes
nullptr, // deleteGeneric
nullptr, nullptr, // watch/unwatch
nullptr, // slice
nullptr, // getElements
XPC_WN_JSOp_Enumerate,
XPC_WN_JSOp_ThisObject,
}

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

@ -974,7 +974,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
nullptr, /* setGenericAttributes */ \
nullptr, /* deleteGeneric */ \
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* slice */ \
nullptr, /* getElements */ \
XPC_WN_JSOp_Enumerate, \
XPC_WN_JSOp_ThisObject, \
}
@ -997,7 +997,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
nullptr, /* setGenericAttributes */ \
nullptr, /* deleteGeneric */ \
nullptr, nullptr, /* watch/unwatch */ \
nullptr, /* slice */ \
nullptr, /* getElements */ \
XPC_WN_JSOp_Enumerate, \
XPC_WN_JSOp_ThisObject, \
}

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

@ -8832,7 +8832,7 @@ PresShell::IsVisible()
// inner view of subdoc frame
view = view->GetParent();
if (!view)
return true;
return mIsActive;
// subdoc view
view = view->GetParent();

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

@ -318,7 +318,7 @@ nsFieldSetFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
LogicalSize result =
nsContainerFrame::ComputeSize(aRenderingContext, aWM,

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

@ -29,7 +29,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE;
/**

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

@ -641,7 +641,7 @@ FloatMarginISize(const nsHTMLReflowState& aCBReflowState,
aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) -
aFloatOffsetState.ComputedLogicalPadding().Size(wm),
aFloatOffsetState.ComputedLogicalPadding().Size(wm),
true);
nsIFrame::ComputeSizeFlags::eShrinkWrap);
return floatSize.ISize(wm) +
aFloatOffsetState.ComputedLogicalMargin().IStartEnd(wm) +

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

@ -147,7 +147,7 @@ nsFirstLetterFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
if (GetPrevInFlow()) {
// We're wrapping the text *after* the first letter, so behave like an

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

@ -58,7 +58,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
virtual void Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,

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

@ -4074,12 +4074,12 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
aCBSize, aAvailableISize,
aMargin, aBorder, aPadding,
aFlags & eShrinkWrap);
aFlags & ComputeSizeFlags::eShrinkWrap);
LogicalSize boxSizingAdjust(aWM);
const nsStylePosition *stylePos = StylePosition();
@ -8399,7 +8399,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
reflowState.ComputedLogicalBorderPadding().Size(wm) -
reflowState.ComputedLogicalPadding().Size(wm),
reflowState.ComputedLogicalPadding().Size(wm),
false).Height(wm));
ComputeSizeFlags::eDefault).Height(wm));
}
}

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

@ -257,7 +257,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
// Compute tight bounds assuming this frame honours its border, background
// and outline, its children's tight bounds, and nothing else.

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

@ -161,7 +161,7 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
nsIntSize size = GetCanvasSize();

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

@ -68,7 +68,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
virtual void Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,

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

@ -1461,9 +1461,11 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext,
bool widthIsAuto = eStyleUnit_Auto == mStylePosition->mWidth.GetUnit();
bool heightIsAuto = eStyleUnit_Auto == mStylePosition->mHeight.GetUnit();
uint32_t computeSizeFlags = 0;
typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags;
ComputeSizeFlags computeSizeFlags = ComputeSizeFlags::eDefault;
if (leftIsAuto || rightIsAuto) {
computeSizeFlags |= nsIFrame::eShrinkWrap;
computeSizeFlags =
ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
}
{
@ -2117,7 +2119,9 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
AutoMaybeDisableFontInflation an(frame);
bool isBlock = NS_CSS_FRAME_TYPE_BLOCK == NS_FRAME_GET_TYPE(mFrameType);
uint32_t computeSizeFlags = isBlock ? 0 : nsIFrame::eShrinkWrap;
typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags;
ComputeSizeFlags computeSizeFlags =
isBlock ? ComputeSizeFlags::eDefault : ComputeSizeFlags::eShrinkWrap;
// Make sure legend frames with display:block and width:auto still
// shrink-wrap.
@ -2126,17 +2130,20 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
frame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::scrolledContent) ||
(aFrameType == nsGkAtoms::scrollFrame &&
frame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame))) {
computeSizeFlags |= nsIFrame::eShrinkWrap;
computeSizeFlags =
ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
}
const nsFlexContainerFrame* flexContainerFrame = GetFlexContainer(frame);
if (flexContainerFrame) {
computeSizeFlags |= nsIFrame::eShrinkWrap;
computeSizeFlags =
ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
// If we're inside of a flex container that needs to measure our
// auto height, pass that information along to ComputeSize().
if (mFlags.mIsFlexContainerMeasuringHeight) {
computeSizeFlags |= nsIFrame::eUseAutoHeight;
computeSizeFlags =
ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoHeight);
}
} else {
MOZ_ASSERT(!mFlags.mIsFlexContainerMeasuringHeight,

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

@ -1634,7 +1634,8 @@ public:
/**
* Bit-flags to pass to ComputeSize in |aFlags| parameter.
*/
enum {
enum ComputeSizeFlags {
eDefault = 0,
/* Set if the frame is in a context where non-replaced blocks should
* shrink-wrap (e.g., it's floating, absolutely positioned, or
* inline-block). */
@ -1693,7 +1694,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) = 0;
ComputeSizeFlags aFlags) = 0;
/**
* Compute a tight bounding rectangle for the frame. This is a rectangle

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

@ -106,16 +106,17 @@ static bool HaveFixedSize(const nsStylePosition* aStylePosition)
return aStylePosition->mWidth.IsCoordPercentCalcUnit() &&
aStylePosition->mHeight.IsCoordPercentCalcUnit();
}
// use the data in the reflow state to decide if the image has a constrained size
// (i.e. width and height that are based on the containing block size and not the image size)
// (i.e. width and height that are based on the containing block size and not the image size)
// so we can avoid animated GIF related reflows
inline bool HaveFixedSize(const nsHTMLReflowState& aReflowState)
{
{
NS_ASSERTION(aReflowState.mStylePosition, "crappy reflowState - null stylePosition");
// when an image has percent css style height or width, but ComputedHeight()
// or ComputedWidth() of reflow state is NS_UNCONSTRAINEDSIZE
// when an image has percent css style height or width, but ComputedHeight()
// or ComputedWidth() of reflow state is NS_UNCONSTRAINEDSIZE
// it needs to return false to cause an incremental reflow later
// if an image is inside table like bug 156731 simple testcase III,
// if an image is inside table like bug 156731 simple testcase III,
// during pass 1 reflow, ComputedWidth() is NS_UNCONSTRAINEDSIZE
// in pass 2 reflow, ComputedWidth() is 0, it also needs to return false
// see bug 156731
@ -127,7 +128,7 @@ inline bool HaveFixedSize(const nsHTMLReflowState& aReflowState)
(NS_UNCONSTRAINEDSIZE == aReflowState.ComputedWidth() ||
0 == aReflowState.ComputedWidth())))
? false
: HaveFixedSize(aReflowState.mStylePosition);
: HaveFixedSize(aReflowState.mStylePosition);
}
nsIFrame*
@ -773,7 +774,7 @@ nsImageFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
EnsureIntrinsicSizeAndRatio();

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

@ -184,7 +184,7 @@ protected:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
bool IsServerImageMap();

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

@ -233,7 +233,7 @@ nsInlineFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
// Inlines and text don't compute size before reflow.
return LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);

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

@ -78,7 +78,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE;
virtual void Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,

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

@ -712,7 +712,7 @@ nsSubDocumentFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
if (subDocRoot) {

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

@ -69,7 +69,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
virtual void Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,

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

@ -7553,7 +7553,7 @@ nsTextFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
uint32_t aFlags)
ComputeSizeFlags aFlags)
{
// Inlines and text don't compute size before reflow.
return LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);

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

@ -218,7 +218,7 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
ComputeSizeFlags aFlags) MOZ_OVERRIDE;
virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE;
virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext,
nscoord* aX,

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