This commit is contained in:
Wes Kocher 2015-06-09 18:41:02 -07:00
Родитель f73f980797 8a712e9b3d
Коммит 2cf14d30b8
71 изменённых файлов: 1878 добавлений и 353 удалений

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

@ -599,6 +599,33 @@ AST_MATCHER(QualType, isRefCounted) {
return isClassRefCounted(Node);
}
#if CLANG_VERSION_FULL < 304
/// The 'equalsBoundeNode' matcher was added in clang 3.4.
/// Since infra runs clang 3.3, we polyfill it here.
AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
std::string, ID) {
BoundNodesTree bindings = Builder->build();
bool haveMatchingResult = false;
struct Visitor : public BoundNodesTree::Visitor {
const NodeType &Node;
std::string ID;
bool &haveMatchingResult;
Visitor(const NodeType &Node, const std::string &ID, bool &haveMatchingResult)
: Node(Node), ID(ID), haveMatchingResult(haveMatchingResult) {}
void visitMatch(const BoundNodes &BoundNodesView) override {
if (BoundNodesView.getNodeAs<NodeType>(ID) == &Node) {
haveMatchingResult = true;
}
}
};
Visitor visitor(Node, ID, haveMatchingResult);
bindings.visitMatches(&visitor);
return haveMatchingResult;
}
#endif
}
}
@ -704,8 +731,14 @@ DiagnosticsMatcher::DiagnosticsMatcher()
).bind("node"),
&noAddRefReleaseOnReturnChecker);
// Match declrefs with type "pointer to object of ref-counted type" inside a
// lambda, where the declaration they reference is not inside the lambda.
// This excludes arguments and local variables, leaving only captured
// variables.
astMatcher.addMatcher(lambdaExpr(
hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted())))).bind("node"))
hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted()))),
to(decl().bind("decl"))).bind("declref")),
unless(hasDescendant(decl(equalsBoundNode("decl"))))
),
&refCountedInsideLambdaChecker);
@ -917,14 +950,14 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
const MatchFinder::MatchResult &Result) {
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be used inside a lambda");
DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be captured by a lambda");
unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Note, "Please consider using a smart pointer");
const DeclRefExpr *node = Result.Nodes.getNodeAs<DeclRefExpr>("node");
const DeclRefExpr *declref = Result.Nodes.getNodeAs<DeclRefExpr>("declref");
Diag.Report(node->getLocStart(), errorID) << node->getFoundDecl() <<
node->getType()->getPointeeType();
Diag.Report(node->getLocStart(), noteID);
Diag.Report(declref->getLocStart(), errorID) << declref->getFoundDecl() <<
declref->getType()->getPointeeType();
Diag.Report(declref->getLocStart(), noteID);
}
void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run(

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

@ -19,40 +19,76 @@ void take(...);
void foo() {
R* ptr;
SmartPtr<R> sp;
take([&]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([&](R* argptr) {
R* localptr;
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
argptr->method();
localptr->method();
});
take([&]() {
take([&](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
sp->method();
argsp->method();
localsp->method();
});
take([&]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([&](R* argptr) {
R* localptr;
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
take(argptr);
take(localptr);
});
take([&]() {
take([&](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
take(sp);
take(argsp);
take(localsp);
});
take([=]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([=](R* argptr) {
R* localptr;
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
argptr->method();
localptr->method();
});
take([=]() {
take([=](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
sp->method();
argsp->method();
localsp->method();
});
take([=]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([=](R* argptr) {
R* localptr;
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
take(argptr);
take(localptr);
});
take([=]() {
take([=](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
take(sp);
take(argsp);
take(localsp);
});
take([ptr]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([ptr](R* argptr) {
R* localptr;
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
argptr->method();
localptr->method();
});
take([sp]() {
take([sp](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
sp->method();
argsp->method();
localsp->method();
});
take([ptr]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
take([ptr](R* argptr) {
R* localptr;
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
take(argptr);
take(localptr);
});
take([sp]() {
take([sp](SmartPtr<R> argsp) {
SmartPtr<R> localsp;
take(sp);
take(argsp);
take(localsp);
});
}

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

@ -460,17 +460,20 @@ IsOnFullDomainWhitelist(nsIURI* aURI)
NS_LITERAL_CSTRING("m.video.baidu.com"),
NS_LITERAL_CSTRING("m.video.baidu.com"),
NS_LITERAL_CSTRING("imgcache.gtimg.cn"), // for m.v.qq.com
NS_LITERAL_CSTRING("s.tabelog.jp"),
NS_LITERAL_CSTRING("s.yimg.jp"), // for s.tabelog.jp
NS_LITERAL_CSTRING("i.yimg.jp"), // for *.yahoo.co.jp
NS_LITERAL_CSTRING("ai.yimg.jp"), // for *.yahoo.co.jp
NS_LITERAL_CSTRING("m.finance.yahoo.co.jp"),
NS_LITERAL_CSTRING("daily.c.yimg.jp"), // for sp.daily.co.jp
NS_LITERAL_CSTRING("stat100.ameba.jp"), // for ameblo.jp
NS_LITERAL_CSTRING("user.ameba.jp"), // for ameblo.jp
NS_LITERAL_CSTRING("www.goo.ne.jp"),
NS_LITERAL_CSTRING("s.tabelog.jp"),
NS_LITERAL_CSTRING("x.gnst.jp"), // for mobile.gnavi.co.jp
NS_LITERAL_CSTRING("c.x.gnst.jp"), // for mobile.gnavi.co.jp
NS_LITERAL_CSTRING("www.smbc-card.com"),
NS_LITERAL_CSTRING("static.card.jp.rakuten-static.com"), // for rakuten-card.co.jp
NS_LITERAL_CSTRING("img.travel.rakuten.co.jp"), // for travel.rakuten.co.jp
NS_LITERAL_CSTRING("img.mixi.net"), // for mixi.jp
NS_LITERAL_CSTRING("girlschannel.net"),
NS_LITERAL_CSTRING("www.fancl.co.jp"),
@ -488,13 +491,14 @@ IsOnFullDomainWhitelist(nsIURI* aURI)
NS_LITERAL_CSTRING("www.tokyo-sports.co.jp"),
NS_LITERAL_CSTRING("www.bellemaison.jp"),
NS_LITERAL_CSTRING("www.kuronekoyamato.co.jp"),
NS_LITERAL_CSTRING("s.tsite.jp"),
NS_LITERAL_CSTRING("formassist.jp"), // for orico.jp
NS_LITERAL_CSTRING("sp.m.reuters.co.jp"),
NS_LITERAL_CSTRING("www.atre.co.jp"),
NS_LITERAL_CSTRING("www.jtb.co.jp"),
NS_LITERAL_CSTRING("www.sharp.co.jp"),
NS_LITERAL_CSTRING("www.biccamera.com"),
NS_LITERAL_CSTRING("weathernews.jp"),
NS_LITERAL_CSTRING("cache.ymail.jp"), // for www.yamada-denkiweb.com
};
static const size_t sNumFullDomainsOnWhitelist =
MOZ_ARRAY_LENGTH(sFullDomainsOnWhitelist);
@ -524,6 +528,7 @@ IsOnBaseDomainWhitelist(nsIURI* aURI)
NS_LITERAL_CSTRING("dpfile.com"), // for m.dianping.com
NS_LITERAL_CSTRING("hao123img.com"), // for hao123.com
NS_LITERAL_CSTRING("tabelog.k-img.com"), // for s.tabelog.com
NS_LITERAL_CSTRING("tsite.jp"), // for *.tsite.jp
};
static const size_t sNumBaseDomainsOnWhitelist =
MOZ_ARRAY_LENGTH(sBaseDomainsOnWhitelist);

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

@ -13867,7 +13867,9 @@ nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
return NS_OK;
}
*aOut = false;
// If we don't have a presShell, fall back to the default platform value of
// whether or not APZ is enabled.
*aOut = gfxPlatform::AsyncPanZoomEnabled();
return NS_OK;
}

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

@ -49,7 +49,8 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/EncodingUtils.h"
#include "nsComputedDOMStyle.h"
#include "nsContainerFrame.h"
#include "nsBlockFrame.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -324,7 +325,45 @@ nsDocumentEncoder::IncludeInContext(nsINode *aNode)
static
bool
IsInvisibleBreak(nsINode *aNode) {
LineHasNonEmptyContentWorker(nsIFrame* aFrame)
{
// Look for non-empty frames, but ignore inline and br frames.
// For inline frames, descend into the children, if any.
if (aFrame->GetType() == nsGkAtoms::inlineFrame) {
nsIFrame* child = aFrame->GetFirstPrincipalChild();
while (child) {
if (LineHasNonEmptyContentWorker(child)) {
return true;
}
child = child->GetNextSibling();
}
} else {
if (aFrame->GetType() != nsGkAtoms::brFrame &&
!aFrame->IsEmpty()) {
return true;
}
}
return false;
}
static
bool
LineHasNonEmptyContent(nsLineBox* aLine)
{
int32_t count = aLine->GetChildCount();
for (nsIFrame* frame = aLine->mFirstChild; count > 0;
--count, frame = frame->GetNextSibling()) {
if (LineHasNonEmptyContentWorker(frame)) {
return true;
}
}
return false;
}
static
bool
IsInvisibleBreak(nsINode *aNode)
{
if (!aNode->IsElement() || !aNode->IsEditable()) {
return false;
}
@ -333,14 +372,36 @@ IsInvisibleBreak(nsINode *aNode) {
return false;
}
// If the BRFrame has caused a visible line break, it should have a next
// sibling, or otherwise no siblings (or immediately after a br) and a
// non-zero height.
bool visible = frame->GetNextSibling() ||
((!frame->GetPrevSibling() ||
frame->GetPrevSibling()->GetType() == nsGkAtoms::brFrame) &&
frame->GetRect().Height() != 0);
return !visible;
nsContainerFrame* f = frame->GetParent();
while (f && f->IsFrameOfType(nsBox::eLineParticipant)) {
f = f->GetParent();
}
nsBlockFrame* blockAncestor = do_QueryFrame(f);
if (!blockAncestor) {
// The container frame doesn't support line breaking.
return false;
}
bool valid = false;
nsBlockInFlowLineIterator iter(blockAncestor, frame, &valid);
if (!valid) {
return false;
}
bool lineNonEmpty = LineHasNonEmptyContent(iter.GetLine());
while (iter.Next()) {
auto currentLine = iter.GetLine();
// Completely skip empty lines.
if (!currentLine->IsEmpty()) {
// If we come across an inline line, the BR has caused a visible line break.
if (currentLine->IsInline()) {
return false;
}
}
}
return lineNonEmpty;
}
nsresult

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

@ -28,6 +28,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=116083
<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-line" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
<div data-result="foo&#10;bar&#10;baz&#10;qux"><div>foo<br></div><span>bar<br>baz<br>qux</span></div>
<div data-result="foo&#10;bar&#10;baz&#10;qux" contenteditable><div>foo<br></div><span>bar<br>baz<br>qux</span></div>
<div data-result="foo&#10;&#10;"><div>foo</div><span><br></span></div>
<div data-result="foo&#10;&#10;" contenteditable><div>foo</div><span><br></span></div>
<div data-result="foo&#10;&#10;bar"><div>foo</div><span><br></span><div>bar</div></div>
<div data-result="foo&#10;&#10;bar" contenteditable><div>foo</div><span><br></span><div>bar</div></div>
<div data-result="foo&#10;bar&#10;"><div>foo</div><span>bar<br></span></div>
<div data-result="foo&#10;bar" contenteditable><div>foo</div><span>bar<br></span></div>
<div data-result="foo&#10;bar&#10;baz"><div>foo</div><span>bar<br></span><div>baz</div></div>
<div data-result="foo&#10;bar&#10;baz" contenteditable><div>foo</div><span>bar<br></span><div>baz</div></div>
<div data-result="&#10;&#10;foo"><div><br><br><div>foo</div></div></div>
<div data-result="&#10;&#10;foo" contenteditable><div><br><br><div>foo</div></div></div>
<div data-result="foo&#10;bar"><div>foo<br>bar</div></div>
<div data-result="foo&#10;bar" contenteditable><div>foo<br>bar</div></div>
<div data-result="foo&#10;bar&#10;"><div>foo<br>bar<br></div></div>
<div data-result="foo&#10;bar" contenteditable><div>foo<br>bar<br></div></div>
<div data-result="&#10;foo bar&#10;">foo bar</div>
</div>
<script type="application/javascript">

2
dom/cache/test/mochitest/empty.html поставляемый Normal file
Просмотреть файл

@ -0,0 +1,2 @@
<!DOCTYPE html>
<!-- This is only used to give us access to the caches global after setting the pref. -->

1
dom/cache/test/mochitest/mochitest.ini поставляемый
Просмотреть файл

@ -22,6 +22,7 @@ support-files =
test_cache_put_reorder.js
test_cache_https.js
large_url_list.js
empty.html
[test_cache.html]
[test_cache_add.html]

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

@ -9,6 +9,18 @@
</head>
<body>
<script class="testbody" type="text/javascript">
function setupTestIframe() {
return new Promise(function(resolve) {
var iframe = document.createElement("iframe");
iframe.src = "empty.html";
iframe.onload = function() {
window.caches = iframe.contentWindow.caches;
resolve();
};
document.body.appendChild(iframe);
});
}
function resetStorage() {
return new Promise(function(resolve, reject) {
var principal = SpecialPowers.wrap(document).nodePrincipal;
@ -32,7 +44,9 @@ SpecialPowers.pushPrefEnv({
var name = 'foo';
var url = './test_cache_add.js';
var cache;
caches.open(name).then(function(c) {
setupTestIframe().then(function() {
return caches.open(name);
}).then(function(c) {
cache = c;
return cache.add(url);
}).then(function() {

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

@ -10,6 +10,18 @@
</head>
<body>
<script class="testbody" type="text/javascript">
function setupTestIframe() {
return new Promise(function(resolve) {
var iframe = document.createElement("iframe");
iframe.src = "empty.html";
iframe.onload = function() {
window.caches = iframe.contentWindow.caches;
resolve();
};
document.body.appendChild(iframe);
});
}
function clearStorage() {
return new Promise(function(resolve, reject) {
var principal = SpecialPowers.wrap(document).nodePrincipal;
@ -73,7 +85,9 @@ SpecialPowers.pushPrefEnv({
var endUsage = 0;
// start from a fresh origin directory so other tests do not influence our
// results
clearStorage().then(function() {
setupTestIframe().then(function() {
return clearStorage();
}).then(function() {
return storageUsage();
}).then(function(usage) {
is(0, usage, 'disk usage should be zero to start');

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

@ -3640,9 +3640,11 @@ SetDefaultPragmas(mozIStorageConnection* aConnection)
#ifndef IDB_MOBILE
if (kSQLiteGrowthIncrement) {
// This is just an optimization so ignore the failure if the disk is
// currently too full.
rv = aConnection->SetGrowthIncrement(kSQLiteGrowthIncrement,
EmptyCString());
if (NS_WARN_IF(NS_FAILED(rv))) {
if (rv != NS_ERROR_FILE_TOO_BIG && NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}

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

@ -10,10 +10,13 @@ EXTRA_COMPONENTS += [
]
EXTRA_PP_JS_MODULES += [
'PushServiceWebSocket.jsm',
]
EXTRA_JS_MODULES += [
'PushDB.jsm',
'PushService.jsm',
'PushServiceHttp2.jsm',
'PushServiceWebSocket.jsm',
]
MOCHITEST_MANIFESTS += [

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

@ -2546,6 +2546,11 @@ ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal,
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aURI);
//XXXnsm Temporary fix until Bug 1171432 is fixed.
if (NS_WARN_IF(BasePrincipal::Cast(aPrincipal)->AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID)) {
return nullptr;
}
nsAutoCString originAttributesSuffix;
nsresult rv = PrincipalToScopeKey(aPrincipal, originAttributesSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {

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

@ -1695,6 +1695,7 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
mX.EndTouch(aEvent.mTime);
mY.EndTouch(aEvent.mTime);
SetState(NOTHING);
RequestContentRepaint();
return nsEventStatus_eConsumeNoDefault;

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

@ -607,6 +607,8 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
*aRenderBoundsOut = rect;
}
mRenderBoundsOut = rect;
GLint width = rect.width;
GLint height = rect.height;
@ -950,6 +952,19 @@ CompositorOGL::DrawQuad(const Rect& aRect,
DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
return;
}
// XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
// quads. Fix me.
Rect destRect = aTransform.TransformBounds(aRect);
mPixelsFilled += destRect.width * destRect.height;
// Do a simple culling if this rect is out of target buffer.
// Inflate a small size to avoid some numerical imprecision issue.
destRect.Inflate(1, 1);
if (!mRenderBoundsOut.Intersects(destRect)) {
return;
}
LayerScope::DrawBegin();
Rect clipRect = aClipRect;
@ -999,13 +1014,6 @@ CompositorOGL::DrawQuad(const Rect& aRect,
maskType = MaskType::MaskNone;
}
{
// XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
// quads. Fix me.
const Rect destRect = aTransform.TransformBounds(aRect);
mPixelsFilled += destRect.width * destRect.height;
}
// Determine the color if this is a color shader and fold the opacity into
// the color since color shaders don't have an opacity uniform.
Color color;

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

@ -457,6 +457,8 @@ private:
FenceHandle mReleaseFenceHandle;
ShaderProgramOGL *mCurrentProgram;
gfx::Rect mRenderBoundsOut;
CompositorOGLVRObjects mVR;
};

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

@ -10,8 +10,6 @@
#include <servers/bootstrap.h>
#include <sys/types.h>
#include <CoreServices/CoreServices.h>
#include "base/basictypes.h"
//==============================================================================
@ -145,16 +143,12 @@ class MachMessage {
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
}
u_int32_t GetDataLength() {
return EndianU32_LtoN(GetDataPacket()->data_length);
}
u_int32_t GetDataLength();
// The message ID may be used as a code identifying the type of message
void SetMessageID(int32_t message_id) {
GetDataPacket()->id = EndianU32_NtoL(message_id);
}
void SetMessageID(int32_t message_id);
int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
int32_t GetMessageID();
// Adds a descriptor (typically a mach port) to be translated
// returns true if successful, otherwise not enough space
@ -280,6 +274,9 @@ class ReceivePort {
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
mach_msg_timeout_t timeout);
kern_return_t SendMessageToSelf(MachSendMessage& msg,
mach_msg_timeout_t timeout);
// The underlying mach port that we wrap
mach_port_t GetPort() const { return port_; }

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

@ -59,6 +59,21 @@ MachMessage::~MachMessage() {
}
}
u_int32_t MachMessage::GetDataLength() {
return EndianU32_LtoN(GetDataPacket()->data_length);
}
// The message ID may be used as a code identifying the type of message
void MachMessage::SetMessageID(int32_t message_id) {
GetDataPacket()->id = EndianU32_NtoL(message_id);
}
int32_t MachMessage::GetMessageID() {
return EndianU32_LtoN(GetDataPacket()->id);
}
//==============================================================================
// returns true if successful
bool MachMessage::SetData(const void* data,
@ -251,7 +266,7 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
out_message->Head()->msgh_id = 0;
kern_return_t result = mach_msg(out_message->Head(),
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
MACH_RCV_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_RCV_TIMEOUT),
0,
out_message->MaxSize(),
port_,
@ -261,6 +276,34 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
return result;
}
//==============================================================================
// send a message to this port
kern_return_t ReceivePort::SendMessageToSelf(MachSendMessage& message, mach_msg_timeout_t timeout) {
if (message.Head()->msgh_size == 0) {
NOTREACHED();
return KERN_INVALID_VALUE; // just for safety -- never should occur
};
if (init_result_ != KERN_SUCCESS)
return init_result_;
message.Head()->msgh_remote_port = port_;
message.Head()->msgh_bits
= MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND,
MACH_MSG_TYPE_MAKE_SEND_ONCE);
kern_return_t result = mach_msg(message.Head(),
MACH_SEND_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_SEND_TIMEOUT),
message.Head()->msgh_size,
0,
MACH_PORT_NULL,
timeout, // timeout in ms
MACH_PORT_NULL);
return result;
}
#pragma mark -
//==============================================================================
@ -297,7 +340,7 @@ kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
message.Head()->msgh_remote_port = send_port_;
kern_return_t result = mach_msg(message.Head(),
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
MACH_SEND_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_SEND_TIMEOUT),
message.Head()->msgh_size,
0,
MACH_PORT_NULL,

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

@ -14,6 +14,7 @@
#include "chrome/common/mach_ipc_mac.h"
#include "base/rand_util.h"
#include "nsILocalFileMac.h"
#include "SharedMemoryBasic.h"
#endif
#include "MainThreadUtils.h"
@ -119,12 +120,16 @@ GeckoChildProcessHost::~GeckoChildProcessHost()
MOZ_COUNT_DTOR(GeckoChildProcessHost);
if (mChildProcessHandle > 0)
if (mChildProcessHandle > 0) {
#if defined(MOZ_WIDGET_COCOA)
SharedMemoryBasic::CleanupForPid(mChildProcessHandle);
#endif
ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
#if defined(NS_BUILD_REFCNT_LOGGING)
, false // don't "force"
#endif
);
}
#if defined(MOZ_WIDGET_COCOA)
if (mChildTask != MACH_PORT_NULL)
@ -783,18 +788,44 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
}
MachPortSender parent_sender(child_message.GetTranslatedPort(1));
if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
}
MachPortSender* parent_recv_port_memory_ack = new MachPortSender(child_message.GetTranslatedPort(2));
if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
}
MachPortSender* parent_send_port_memory = new MachPortSender(child_message.GetTranslatedPort(3));
MachSendMessage parent_message(/* id= */0);
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
return false;
}
ReceivePort* parent_recv_port_memory = new ReceivePort();
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_recv_port_memory->GetPort() << ") failed.";
return false;
}
ReceivePort* parent_send_port_memory_ack = new ReceivePort();
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_send_port_memory_ack->GetPort() << ") failed.";
return false;
}
err = parent_sender.SendMessage(parent_message, kTimeoutMs);
if (err != KERN_SUCCESS) {
std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
return false;
}
SharedMemoryBasic::SetupMachMemory(process, parent_recv_port_memory, parent_recv_port_memory_ack,
parent_send_port_memory, parent_send_port_memory_ack, false);
#endif
//--------------------------------------------------

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

@ -10,6 +10,8 @@
#ifdef ANDROID
# include "mozilla/ipc/SharedMemoryBasic_android.h"
#elif defined(XP_MACOSX)
# include "mozilla/ipc/SharedMemoryBasic_mach.h"
#else
# include "mozilla/ipc/SharedMemoryBasic_chromium.h"
#endif

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

@ -0,0 +1,692 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <map>
#include <mach/vm_map.h>
#include <mach/mach_port.h>
#include <mach/mach_vm.h>
#include "SharedMemoryBasic.h"
#include "chrome/common/mach_ipc_mac.h"
#include "mozilla/Services.h"
#include "mozilla/StaticMutex.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
#include "nsXPCOMPrivate.h"
#ifdef DEBUG
#define LOG_ERROR(str, args...) \
PR_BEGIN_MACRO \
char *msg = PR_smprintf(str, ## args); \
NS_WARNING(msg); \
PR_smprintf_free(msg); \
PR_END_MACRO
#else
#define LOG_ERROR(str, args...) do { /* nothing */ } while(0)
#endif
#define CHECK_MACH_ERROR(kr, msg) \
PR_BEGIN_MACRO \
if (kr != KERN_SUCCESS) { \
LOG_ERROR("%s %s (%x)\n", msg, mach_error_string(kr), kr); \
return false; \
} \
PR_END_MACRO
/*
* This code is responsible for sharing memory between processes. Memory can be
* shared between parent and child or between two children. Each memory region is
* referenced via a Mach port. Mach ports are also used for messaging when
* sharing a memory region.
*
* When the parent starts a child, it starts a thread whose only purpose is to
* communicate with the child about shared memory. Once the child has started,
* it starts a similar thread for communicating with the parent. Each side can
* communicate with the thread on the other side via Mach ports. When either
* side wants to share memory with the other, it sends a Mach message to the
* other side. Attached to the message is the port that references the shared
* memory region. When the other side receives the message, it automatically
* gets access to the region. It sends a reply (also via a Mach port) so that
* the originating side can continue.
*
* The two sides communicate using four ports. Two ports are used when the
* parent shares memory with the child. The other two are used when the child
* shares memory with the parent. One of these two ports is used for sending the
* "share" message and the other is used for the reply.
*
* If a child wants to share memory with another child, it sends a "GetPorts"
* message to the parent. The parent forwards this GetPorts message to the
* target child. The message includes some ports so that the children can talk
* directly. Both children start up a thread to communicate with the other child,
* similar to the way parent and child communicate. In the future, when these
* two children want to communicate, they re-use the channels that were created.
*
* When a child shuts down, the parent notifies all other children. Those
* children then have the opportunity to shut down any threads they might have
* been using to communicate directly with that child.
*/
namespace mozilla {
namespace ipc {
struct MemoryPorts {
MachPortSender* mSender;
ReceivePort* mReceiver;
MemoryPorts() {}
MemoryPorts(MachPortSender* sender, ReceivePort* receiver)
: mSender(sender), mReceiver(receiver) {}
};
// Protects gMemoryCommPorts and gThreads.
static StaticMutex gMutex;
static std::map<pid_t, MemoryPorts> gMemoryCommPorts;
enum {
kGetPortsMsg = 1,
kSharePortsMsg,
kReturnIdMsg,
kReturnPortsMsg,
kShutdownMsg,
kCleanupMsg,
};
const int kTimeout = 1000;
pid_t gParentPid = 0;
struct PIDPair {
pid_t mRequester;
pid_t mRequested;
PIDPair(pid_t requester, pid_t requested)
: mRequester(requester), mRequested(requested) {}
};
struct ListeningThread {
pthread_t mThread;
MemoryPorts* mPorts;
ListeningThread() {}
ListeningThread(pthread_t thread, MemoryPorts* ports)
: mThread(thread), mPorts(ports) {}
};
std::map<pid_t, ListeningThread> gThreads;
static void *
PortServerThread(void *argument);
namespace {
class ShutdownObserver final : public nsIObserver
{
~ShutdownObserver() {}
static bool sInitialized;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
void InitializeOnMainThread()
{
if (sInitialized) {
return;
}
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (!observerService) {
return;
}
nsCOMPtr<nsIObserver> obs = new ShutdownObserver();
observerService->AddObserver(obs, "xpcom-shutdown-threads", false);
sInitialized = true;
}
static void Initialize(bool onMainThread)
{
if (sInitialized) {
return;
}
nsRefPtr<ShutdownObserver> obs = new ShutdownObserver();
if (onMainThread) {
obs->InitializeOnMainThread();
} else {
NS_DispatchToMainThread(NS_NewRunnableMethod(obs, &ShutdownObserver::InitializeOnMainThread));
}
}
};
bool ShutdownObserver::sInitialized = false;
} // namespace
NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
NS_IMETHODIMP
ShutdownObserver::Observe(nsISupports* subject,
const char* topic,
const char16_t* data)
{
MOZ_ASSERT(strcmp(topic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID) == 0);
StaticMutexAutoLock smal(gMutex);
for (auto it = gThreads.begin(); it != gThreads.end(); ++it) {
MachSendMessage shutdownMsg(kShutdownMsg);
it->second.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
pthread_join(it->second.mThread, nullptr);
}
gThreads.clear();
for (auto it = gMemoryCommPorts.begin(); it != gMemoryCommPorts.end(); ++it) {
delete it->second.mSender;
delete it->second.mReceiver;
}
gMemoryCommPorts.clear();
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "xpcom-shutdown-threads");
}
return NS_OK;
}
static void
SetupMachMemory(pid_t pid,
ReceivePort* listen_port,
MachPortSender* listen_port_ack,
MachPortSender* send_port,
ReceivePort* send_port_ack,
bool pidIsParent)
{
if (pidIsParent) {
gParentPid = pid;
}
MemoryPorts* listen_ports = new MemoryPorts(listen_port_ack, listen_port);
pthread_t thread;
int err = pthread_create(&thread, nullptr, PortServerThread, listen_ports);
if (err) {
LOG_ERROR("pthread_create failed with %x\n", err);
return;
}
gMutex.AssertCurrentThreadOwns();
gThreads[pid] = ListeningThread(thread, listen_ports);
gMemoryCommPorts[pid] = MemoryPorts(send_port, send_port_ack);
}
// Send two communication ports to another process along with the pid of the process that is
// listening on them.
bool
SendPortsMessage(MachPortSender* sender,
mach_port_t ports_in_receiver,
mach_port_t ports_out_receiver,
PIDPair pid_pair)
{
MachSendMessage getPortsMsg(kGetPortsMsg);
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver))) {
LOG_ERROR("Adding descriptor to message failed");
return false;
}
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver))) {
LOG_ERROR("Adding descriptor to message failed");
return false;
}
getPortsMsg.SetData(&pid_pair, sizeof(PIDPair));
kern_return_t err = sender->SendMessage(getPortsMsg, kTimeout);
if (KERN_SUCCESS != err) {
LOG_ERROR("Error sending get ports message %s (%x)\n", mach_error_string(err), err);
return false;
}
return true;
}
// Receive two communication ports from another process
bool
RecvPortsMessage(ReceivePort* receiver, mach_port_t* ports_in_sender, mach_port_t* ports_out_sender)
{
MachReceiveMessage rcvPortsMsg;
kern_return_t err = receiver->WaitForMessage(&rcvPortsMsg, kTimeout);
if (KERN_SUCCESS != err) {
LOG_ERROR("Error receiving get ports message %s (%x)\n", mach_error_string(err), err);
}
if (rcvPortsMsg.GetTranslatedPort(0) == MACH_PORT_NULL) {
LOG_ERROR("GetTranslatedPort(0) failed");
return false;
}
*ports_in_sender = rcvPortsMsg.GetTranslatedPort(0);
if (rcvPortsMsg.GetTranslatedPort(1) == MACH_PORT_NULL) {
LOG_ERROR("GetTranslatedPort(1) failed");
return false;
}
*ports_out_sender = rcvPortsMsg.GetTranslatedPort(1);
return true;
}
// Send two communication ports to another process and receive two back
bool
RequestPorts(const MemoryPorts& request_ports,
mach_port_t ports_in_receiver,
mach_port_t* ports_in_sender,
mach_port_t* ports_out_sender,
mach_port_t ports_out_receiver,
PIDPair pid_pair)
{
if (!SendPortsMessage(request_ports.mSender, ports_in_receiver, ports_out_receiver, pid_pair)) {
return false;
}
return RecvPortsMessage(request_ports.mReceiver, ports_in_sender, ports_out_sender);
}
MemoryPorts*
GetMemoryPortsForPid(pid_t pid)
{
gMutex.AssertCurrentThreadOwns();
if (gMemoryCommPorts.find(pid) == gMemoryCommPorts.end()) {
// We don't have the ports open to communicate with that pid, so we're going to
// ask our parent process over IPC to set them up for us.
if (gParentPid == 0) {
// If we're the top level parent process, we have no parent to ask.
LOG_ERROR("request for ports for pid %d, but we're the chrome process\n", pid);
return nullptr;
}
const MemoryPorts& parent = gMemoryCommPorts[gParentPid];
// Create two receiving ports in this process to send to the parent. One will be used for
// for listening for incoming memory to be shared, the other for getting the Handle of
// memory we share to the other process.
ReceivePort* ports_in_receiver = new ReceivePort();
ReceivePort* ports_out_receiver = new ReceivePort();
mach_port_t raw_ports_in_sender, raw_ports_out_sender;
if (!RequestPorts(parent,
ports_in_receiver->GetPort(),
&raw_ports_in_sender,
&raw_ports_out_sender,
ports_out_receiver->GetPort(),
PIDPair(getpid(), pid))) {
LOG_ERROR("failed to request ports\n");
return nullptr;
}
// Our parent process sent us two ports, one is for sending new memory to, the other
// is for replying with the Handle when we receive new memory.
MachPortSender* ports_in_sender = new MachPortSender(raw_ports_in_sender);
MachPortSender* ports_out_sender = new MachPortSender(raw_ports_out_sender);
SetupMachMemory(pid,
ports_in_receiver,
ports_in_sender,
ports_out_sender,
ports_out_receiver,
false);
MOZ_ASSERT(gMemoryCommPorts.find(pid) != gMemoryCommPorts.end());
}
return &gMemoryCommPorts.at(pid);
}
// We just received a port representing a region of shared memory, reply to
// the process that set it with the mach_port_t that represents it in this process.
// That will be the Handle to be shared over normal IPC
void
HandleSharePortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports)
{
mach_port_t port = rmsg->GetTranslatedPort(0);
MachSendMessage msg(kReturnIdMsg);
msg.SetData(&port, sizeof(port));
kern_return_t err = ports->mSender->SendMessage(msg, kTimeout);
if (KERN_SUCCESS != err) {
LOG_ERROR("SendMessage failed 0x%x %s\n", err, mach_error_string(err));
}
}
// We were asked by another process to get communications ports to some process. Return
// those ports via an IPC message.
bool
SendReturnPortsMsg(MachPortSender* sender,
mach_port_t raw_ports_in_sender,
mach_port_t raw_ports_out_sender)
{
MachSendMessage getPortsMsg(kReturnPortsMsg);
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(raw_ports_in_sender))) {
LOG_ERROR("Adding descriptor to message failed");
return false;
}
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(raw_ports_out_sender))) {
LOG_ERROR("Adding descriptor to message failed");
return false;
}
kern_return_t err = sender->SendMessage(getPortsMsg, kTimeout);
if (KERN_SUCCESS != err) {
LOG_ERROR("Error sending get ports message %s (%x)\n", mach_error_string(err), err);
return false;
}
return true;
}
// We were asked for communcations ports to a process that isn't us. Assuming that process
// is one of our children, forward that request on.
void
ForwardGetPortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports, PIDPair* pid_pair)
{
if (rmsg->GetTranslatedPort(0) == MACH_PORT_NULL) {
LOG_ERROR("GetTranslatedPort(0) failed");
return;
}
if (rmsg->GetTranslatedPort(1) == MACH_PORT_NULL) {
LOG_ERROR("GetTranslatedPort(1) failed");
return;
}
mach_port_t raw_ports_in_sender, raw_ports_out_sender;
MemoryPorts* requestedPorts = GetMemoryPortsForPid(pid_pair->mRequested);
if (!requestedPorts) {
LOG_ERROR("failed to find port for process\n");
return;
}
if (!RequestPorts(*requestedPorts, rmsg->GetTranslatedPort(0), &raw_ports_in_sender,
&raw_ports_out_sender, rmsg->GetTranslatedPort(1), *pid_pair)) {
LOG_ERROR("failed to request ports\n");
return;
}
SendReturnPortsMsg(ports->mSender, raw_ports_in_sender, raw_ports_out_sender);
}
// We receieved a message asking us to get communications ports for another process
void
HandleGetPortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports)
{
PIDPair* pid_pair;
if (rmsg->GetDataLength() != sizeof(PIDPair)) {
LOG_ERROR("Improperly formatted message\n");
return;
}
pid_pair = reinterpret_cast<PIDPair*>(rmsg->GetData());
if (pid_pair->mRequested != getpid()) {
// This request is for ports to a process that isn't us, forward it to that process
ForwardGetPortsMessage(rmsg, ports, pid_pair);
} else {
if (rmsg->GetTranslatedPort(0) == MACH_PORT_NULL) {
LOG_ERROR("GetTranslatedPort(0) failed");
return;
}
if (rmsg->GetTranslatedPort(1) == MACH_PORT_NULL) {
LOG_ERROR("GetTranslatedPort(1) failed");
return;
}
MachPortSender* ports_in_sender = new MachPortSender(rmsg->GetTranslatedPort(0));
MachPortSender* ports_out_sender = new MachPortSender(rmsg->GetTranslatedPort(1));
ReceivePort* ports_in_receiver = new ReceivePort();
ReceivePort* ports_out_receiver = new ReceivePort();
if (SendReturnPortsMsg(ports->mSender, ports_in_receiver->GetPort(), ports_out_receiver->GetPort())) {
SetupMachMemory(pid_pair->mRequester,
ports_out_receiver,
ports_out_sender,
ports_in_sender,
ports_in_receiver,
false);
}
}
}
static void *
PortServerThread(void *argument)
{
MemoryPorts* ports = static_cast<MemoryPorts*>(argument);
MachReceiveMessage child_message;
while (true) {
MachReceiveMessage rmsg;
kern_return_t err = ports->mReceiver->WaitForMessage(&rmsg, MACH_MSG_TIMEOUT_NONE);
if (err != KERN_SUCCESS) {
LOG_ERROR("Wait for message failed 0x%x %s\n", err, mach_error_string(err));
continue;
}
StaticMutexAutoLock smal(gMutex);
switch (rmsg.GetMessageID()) {
case kSharePortsMsg:
HandleSharePortsMessage(&rmsg, ports);
break;
case kGetPortsMsg:
HandleGetPortsMessage(&rmsg, ports);
break;
case kShutdownMsg:
delete ports->mSender;
delete ports->mReceiver;
delete ports;
return nullptr;
case kCleanupMsg:
if (gParentPid == 0) {
LOG_ERROR("Cleanup message not valid for parent process");
continue;
}
pid_t* pid;
if (rmsg.GetDataLength() != sizeof(pid_t)) {
LOG_ERROR("Improperly formatted message\n");
continue;
}
pid = reinterpret_cast<pid_t*>(rmsg.GetData());
SharedMemoryBasic::CleanupForPid(*pid);
break;
default:
LOG_ERROR("Unknown message\n");
}
}
}
void
SharedMemoryBasic::SetupMachMemory(pid_t pid,
ReceivePort* listen_port,
MachPortSender* listen_port_ack,
MachPortSender* send_port,
ReceivePort* send_port_ack,
bool pidIsParent)
{
StaticMutexAutoLock smal(gMutex);
mozilla::ipc::SetupMachMemory(pid, listen_port, listen_port_ack, send_port, send_port_ack, pidIsParent);
ShutdownObserver::Initialize(pidIsParent);
}
void
SharedMemoryBasic::CleanupForPid(pid_t pid)
{
if (gThreads.find(pid) == gThreads.end()) {
return;
}
const ListeningThread& listeningThread = gThreads[pid];
MachSendMessage shutdownMsg(kShutdownMsg);
kern_return_t ret = listeningThread.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
if (ret != KERN_SUCCESS) {
LOG_ERROR("sending shutdown msg failed %s %x\n", mach_error_string(ret), ret);
}
gThreads.erase(pid);
if (gParentPid == 0) {
// We're the parent. Broadcast the cleanup message to everyone else.
for (auto it = gMemoryCommPorts.begin(); it != gMemoryCommPorts.end(); ++it) {
MachSendMessage msg(kCleanupMsg);
msg.SetData(&pid, sizeof(pid));
// We don't really care if this fails, we could be trying to send to an already shut down proc
it->second.mSender->SendMessage(msg, kTimeout);
}
}
MemoryPorts& ports = gMemoryCommPorts[pid];
delete ports.mSender;
delete ports.mReceiver;
gMemoryCommPorts.erase(pid);
}
SharedMemoryBasic::SharedMemoryBasic()
: mPort(MACH_PORT_NULL)
, mMemory(nullptr)
{
}
SharedMemoryBasic::SharedMemoryBasic(Handle aHandle)
: mPort(MACH_PORT_NULL)
, mMemory(nullptr)
{
mPort = aHandle;
}
SharedMemoryBasic::~SharedMemoryBasic()
{
Unmap();
Destroy();
}
static inline void*
toPointer(mach_vm_address_t address)
{
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
}
static inline mach_vm_address_t
toVMAddress(void* pointer)
{
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
}
bool
SharedMemoryBasic::Create(size_t size)
{
mach_vm_address_t address;
kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, round_page(size), VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to allocate mach_vm_allocate shared memory (%zu bytes). %s (%x)\n",
size, mach_error_string(kr), kr);
return false;
}
memory_object_size_t memoryObjectSize = round_page(size);
kr = mach_make_memory_entry_64(mach_task_self(),
&memoryObjectSize,
address,
VM_PROT_DEFAULT,
&mPort,
MACH_PORT_NULL);
if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n",
size, mach_error_string(kr), kr);
return false;
}
mMemory = toPointer(address);
Mapped(size);
return true;
}
bool
SharedMemoryBasic::Map(size_t size)
{
if (mMemory) {
return true;
}
if (MACH_PORT_NULL == mPort) {
return false;
}
kern_return_t kr;
mach_vm_address_t address = 0;
vm_prot_t vmProtection = VM_PROT_READ | VM_PROT_WRITE;
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0, VM_FLAGS_ANYWHERE,
mPort, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
size, mach_task_self(), mPort, mach_error_string(kr), kr);
return false;
}
mMemory = toPointer(address);
Mapped(size);
return true;
}
bool
SharedMemoryBasic::ShareToProcess(base::ProcessId pid,
Handle* aNewHandle)
{
StaticMutexAutoLock smal(gMutex);
MemoryPorts* ports = GetMemoryPortsForPid(pid);
if (!ports) {
LOG_ERROR("Unable to get ports for process.\n");
return false;
}
MachSendMessage smsg(kSharePortsMsg);
smsg.AddDescriptor(MachMsgPortDescriptor(mPort, MACH_MSG_TYPE_COPY_SEND));
kern_return_t err = ports->mSender->SendMessage(smsg, kTimeout);
if (err != KERN_SUCCESS) {
LOG_ERROR("sending port failed %s %x\n", mach_error_string(err), err);
return false;
}
MachReceiveMessage msg;
err = ports->mReceiver->WaitForMessage(&msg, kTimeout);
if (err != KERN_SUCCESS) {
LOG_ERROR("didn't get an id %s %x\n", mach_error_string(err), err);
return false;
}
if (msg.GetDataLength() != sizeof(mach_port_t)) {
LOG_ERROR("Improperly formatted reply\n");
return false;
}
mach_port_t *id = reinterpret_cast<mach_port_t*>(msg.GetData());
*aNewHandle = *id;
return true;
}
void
SharedMemoryBasic::Unmap()
{
if (!mMemory) {
return;
}
vm_address_t address = toVMAddress(mMemory);
kern_return_t kr = vm_deallocate(mach_task_self(), address, vm_page_size);
if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n", mach_error_string(kr), kr);
return;
}
mMemory = nullptr;
}
void
SharedMemoryBasic::Destroy()
{
mach_port_deallocate(mach_task_self(), mPort);
}
bool
SharedMemoryBasic::IsHandleValid(const Handle& aHandle)
{
return aHandle > 0;
}
} // namespace ipc
} // namespace mozilla

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

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_SharedMemoryBasic_mach_h
#define mozilla_ipc_SharedMemoryBasic_mach_h
#include "base/file_descriptor_posix.h"
#include "base/process.h"
#include "SharedMemory.h"
#include <mach/port.h>
//
// This is a low-level wrapper around platform shared memory. Don't
// use it directly; use Shmem allocated through IPDL interfaces.
//
class MachPortSender;
class ReceivePort;
namespace mozilla {
namespace ipc {
class SharedMemoryBasic final : public SharedMemory
{
public:
typedef mach_port_t Handle;
static void SetupMachMemory(pid_t pid,
ReceivePort* listen_port,
MachPortSender* listen_port_ack,
MachPortSender* send_port,
ReceivePort* send_port_ack,
bool pidIsParent);
static void CleanupForPid(pid_t pid);
SharedMemoryBasic();
explicit SharedMemoryBasic(Handle aHandle);
virtual bool Create(size_t aNbytes) override;
virtual bool Map(size_t nBytes) override;
virtual void* memory() const override
{
return mMemory;
}
virtual SharedMemoryType Type() const override
{
return TYPE_BASIC;
}
static Handle NULLHandle()
{
return Handle();
}
static bool IsHandleValid(const Handle &aHandle);
bool ShareToProcess(base::ProcessId aProcessId,
Handle* aNewHandle);
private:
~SharedMemoryBasic();
void Unmap();
void Destroy();
mach_port_t mPort;
// Pointer to mapped region, null if unmapped.
void *mMemory;
};
} // namespace ipc
} // namespace mozilla
#endif // ifndef mozilla_ipc_SharedMemoryBasic_mach_h

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

@ -76,6 +76,11 @@ if CONFIG['OS_TARGET'] == 'Android':
UNIFIED_SOURCES += [
'SharedMemoryBasic_android.cpp',
]
elif CONFIG['OS_ARCH'] == 'Darwin':
EXPORTS.mozilla.ipc += ['SharedMemoryBasic_mach.h']
SOURCES += [
'SharedMemoryBasic_mach.cpp',
]
else:
EXPORTS.mozilla.ipc += ['SharedMemoryBasic_chromium.h']

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

@ -1902,182 +1902,430 @@ BytecodeEmitter::bindNameToSlot(ParseNode* pn)
bool
BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
{
if (!pn || *answer)
JS_CHECK_RECURSION(cx, return false);
switch (pn->getKind()) {
// Trivial cases with no side effects.
case PNK_NEWTARGET:
case PNK_NOP:
case PNK_STRING:
case PNK_TEMPLATE_STRING:
case PNK_REGEXP:
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_THIS:
case PNK_ELISION:
case PNK_GENERATOR:
case PNK_NUMBER:
case PNK_OBJECT_PROPERTY_NAME:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
*answer = false;
return true;
switch (pn->getArity()) {
case PN_CODE:
case PNK_BREAK:
case PNK_CONTINUE:
case PNK_DEBUGGER:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
*answer = true;
return true;
// Watch out for getters!
case PNK_SUPERPROP:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
*answer = true;
return true;
// Again, getters.
case PNK_DOT:
MOZ_ASSERT(pn->isArity(PN_NAME));
*answer = true;
return true;
// Unary cases with side effects only if the child has them.
case PNK_TYPEOFEXPR:
case PNK_VOID:
case PNK_NOT:
case PNK_COMPUTED_NAME:
MOZ_ASSERT(pn->isArity(PN_UNARY));
return checkSideEffects(pn->pn_kid, answer);
// Looking up or evaluating the associated name could throw.
case PNK_TYPEOFNAME:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// These unary cases have side effects on the enclosing object/array,
// sure. But that's not the question this function answers: it's
// whether the operation may have a side effect on something *other* than
// the result of the overall operation in which it's embedded. The
// answer to that is no, for an object literal having a mutated prototype
// and an array comprehension containing no other effectful operations
// only produce a value, without affecting anything else.
case PNK_MUTATEPROTO:
case PNK_ARRAYPUSH:
MOZ_ASSERT(pn->isArity(PN_UNARY));
return checkSideEffects(pn->pn_kid, answer);
// Unary cases with obvious side effects.
case PNK_PREINCREMENT:
case PNK_POSTINCREMENT:
case PNK_PREDECREMENT:
case PNK_POSTDECREMENT:
case PNK_THROW:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// These might invoke valueOf/toString, even with a subexpression without
// side effects! Consider |+{ valueOf: null, toString: null }|.
case PNK_BITNOT:
case PNK_POS:
case PNK_NEG:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// This invokes the (user-controllable) iterator protocol.
case PNK_SPREAD:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
case PNK_YIELD_STAR:
case PNK_YIELD:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
// Deletion generally has side effects, even if isolated cases have none.
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// Deletion of a non-Reference expression has side effects only through
// evaluating the expression.
case PNK_DELETEEXPR: {
MOZ_ASSERT(pn->isArity(PN_UNARY));
ParseNode* expr = pn->pn_kid;
return checkSideEffects(expr, answer);
}
case PNK_SEMI:
MOZ_ASSERT(pn->isArity(PN_UNARY));
if (ParseNode* expr = pn->pn_kid)
return checkSideEffects(expr, answer);
*answer = false;
return true;
// Binary cases with obvious side effects.
case PNK_ASSIGN:
case PNK_ADDASSIGN:
case PNK_SUBASSIGN:
case PNK_BITORASSIGN:
case PNK_BITXORASSIGN:
case PNK_BITANDASSIGN:
case PNK_LSHASSIGN:
case PNK_RSHASSIGN:
case PNK_URSHASSIGN:
case PNK_MULASSIGN:
case PNK_DIVASSIGN:
case PNK_MODASSIGN:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
case PNK_STATEMENTLIST:
case PNK_CATCHLIST:
// Strict equality operations and logical operators are well-behaved and
// perform no conversions.
case PNK_OR:
case PNK_AND:
case PNK_STRICTEQ:
case PNK_STRICTNE:
// Any subexpression of a comma expression could be effectful.
case PNK_COMMA:
MOZ_ASSERT(pn->pn_count > 0);
// Subcomponents of a literal may be effectful.
case PNK_ARRAY:
case PNK_OBJECT:
MOZ_ASSERT(pn->isArity(PN_LIST));
for (ParseNode* item = pn->pn_head; item; item = item->pn_next) {
if (!checkSideEffects(item, answer))
return false;
if (*answer)
return true;
}
return true;
// Most other binary operations (parsed as lists in SpiderMonkey) may
// perform conversions triggering side effects. Math operations perform
// ToNumber and may fail invoking invalid user-defined toString/valueOf:
// |5 < { toString: null }|. |instanceof| throws if provided a
// non-object constructor: |null instanceof null|. |in| throws if given
// a non-object RHS: |5 in null|.
case PNK_BITOR:
case PNK_BITXOR:
case PNK_BITAND:
case PNK_EQ:
case PNK_NE:
case PNK_LT:
case PNK_LE:
case PNK_GT:
case PNK_GE:
case PNK_INSTANCEOF:
case PNK_IN:
case PNK_LSH:
case PNK_RSH:
case PNK_URSH:
case PNK_ADD:
case PNK_SUB:
case PNK_STAR:
case PNK_DIV:
case PNK_MOD:
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count >= 2);
*answer = true;
return true;
case PNK_DEFAULT:
case PNK_COLON:
case PNK_CASE:
MOZ_ASSERT(pn->isArity(PN_BINARY));
if (!checkSideEffects(pn->pn_left, answer))
return false;
if (*answer)
return true;
return checkSideEffects(pn->pn_right, answer);
// More getters.
case PNK_ELEM:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
// Again, getters.
case PNK_SUPERELEM:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// These affect visible names in this code, or in other code.
case PNK_IMPORT:
case PNK_EXPORT_FROM:
case PNK_EXPORT_DEFAULT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
// Likewise.
case PNK_EXPORT:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// Every part of a loop might be effect-free, but looping infinitely *is*
// an effect. (Language lawyer trivia: C++ says threads can be assumed
// to exit or have side effects, C++14 [intro.multithread]p27, so a C++
// implementation's equivalent of the below could set |*answer = false;|
// if all loop sub-nodes set |*answer = false|!)
case PNK_DOWHILE:
case PNK_WHILE:
case PNK_FOR:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
// Declarations affect the name set of the relevant scope.
case PNK_VAR:
case PNK_CONST:
case PNK_LET:
case PNK_GLOBALCONST:
MOZ_ASSERT(pn->isArity(PN_LIST));
*answer = true;
return true;
case PNK_CONDITIONAL:
MOZ_ASSERT(pn->isArity(PN_TERNARY));
if (!checkSideEffects(pn->pn_kid1, answer))
return false;
if (*answer)
return true;
if (!checkSideEffects(pn->pn_kid2, answer))
return false;
if (*answer)
return true;
return checkSideEffects(pn->pn_kid3, answer);
case PNK_IF:
MOZ_ASSERT(pn->isArity(PN_TERNARY));
if (!checkSideEffects(pn->pn_kid1, answer))
return false;
if (*answer)
return true;
if (!checkSideEffects(pn->pn_kid2, answer))
return false;
if (*answer)
return true;
if (ParseNode* elseNode = pn->pn_kid3) {
if (!checkSideEffects(elseNode, answer))
return false;
}
return true;
// Function calls can invoke non-local code.
case PNK_NEW:
case PNK_CALL:
case PNK_TAGGED_TEMPLATE:
MOZ_ASSERT(pn->isArity(PN_LIST));
*answer = true;
return true;
// Classes typically introduce names. Even if no name is introduced,
// the heritage and/or class body (through computed property names)
// usually have effects.
case PNK_CLASS:
MOZ_ASSERT(pn->isArity(PN_TERNARY));
*answer = true;
return true;
// |with| calls |ToObject| on its expression and so throws if that value
// is null/undefined.
case PNK_WITH:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
case PNK_RETURN:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
case PNK_NAME:
MOZ_ASSERT(pn->isArity(PN_NAME));
*answer = true;
return true;
// Shorthands could trigger getters: the |x| in the object literal in
// |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
// one. (Of course, it isn't necessary to use |with| for a shorthand to
// trigger a getter.)
case PNK_SHORTHAND:
MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
case PNK_FUNCTION:
MOZ_ASSERT(pn->isArity(PN_CODE));
/*
* A named function, contrary to ES3, is no longer useful, because we
* bind its name lexically (using JSOP_CALLEE) instead of creating an
* Object instance and binding a readonly, permanent property in it
* A named function, contrary to ES3, is no longer effectful, because
* we bind its name lexically (using JSOP_CALLEE) instead of creating
* an Object instance and binding a readonly, permanent property in it
* (the object and binding can be detected and hijacked or captured).
* This is a bug fix to ES3; it is fixed in ES3.1 drafts.
*/
MOZ_ASSERT(*answer == false);
*answer = false;
return true;
case PN_LIST:
if (pn->isOp(JSOP_NOP) || pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) ||
pn->isOp(JSOP_STRICTEQ) || pn->isOp(JSOP_STRICTNE)) {
/*
* Non-operators along with ||, &&, ===, and !== never invoke
* toString or valueOf.
*/
bool ok = true;
for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
ok &= checkSideEffects(pn2, answer);
return ok;
}
// Generator expressions have no side effects on their own.
case PNK_GENEXP:
MOZ_ASSERT(pn->isArity(PN_LIST));
*answer = false;
return true;
if (pn->isKind(PNK_GENEXP)) {
/* Generator-expressions are harmless if the result is ignored. */
MOZ_ASSERT(*answer == false);
case PNK_TRY:
MOZ_ASSERT(pn->isArity(PN_TERNARY));
if (!checkSideEffects(pn->pn_kid1, answer))
return false;
if (*answer)
return true;
if (ParseNode* catchList = pn->pn_kid2) {
MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
if (!checkSideEffects(catchList, answer))
return false;
if (*answer)
return true;
}
if (ParseNode* finallyBlock = pn->pn_kid3) {
if (!checkSideEffects(finallyBlock, answer))
return false;
}
return true;
/*
* All invocation operations (construct: PNK_NEW, call: PNK_CALL)
* are presumed to be useful, because they may have side effects
* even if their main effect (their return value) is discarded.
*
* PNK_ELEM binary trees of 3+ nodes are flattened into lists to
* avoid too much recursion. All such lists must be presumed to be
* useful because each index operation could invoke a getter.
*
* Likewise, array and object initialisers may call prototype
* setters (the __defineSetter__ built-in, and writable __proto__
* on Array.prototype create this hazard). Initialiser list nodes
* have JSOP_NEWINIT in their pn_op.
*/
case PNK_CATCH:
MOZ_ASSERT(pn->isArity(PN_TERNARY));
if (!checkSideEffects(pn->pn_kid1, answer))
return false;
if (*answer)
return true;
if (ParseNode* cond = pn->pn_kid2) {
if (!checkSideEffects(cond, answer))
return false;
if (*answer)
return true;
}
return checkSideEffects(pn->pn_kid3, answer);
case PNK_SWITCH:
case PNK_LETBLOCK:
MOZ_ASSERT(pn->isArity(PN_BINARY));
if (!checkSideEffects(pn->pn_left, answer))
return false;
return *answer || checkSideEffects(pn->pn_right, answer);
case PNK_LABEL:
case PNK_LEXICALSCOPE:
MOZ_ASSERT(pn->isArity(PN_NAME));
return checkSideEffects(pn->expr(), answer);
// We could methodically check every interpolated expression, but it's
// probably not worth the trouble. Treat template strings as effect-free
// only if they don't contain any substitutions.
case PNK_TEMPLATE_STRING_LIST:
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count > 0);
MOZ_ASSERT((pn->pn_count % 2) == 1,
"template strings must alternate template and substitution "
"parts");
*answer = pn->pn_count > 1;
return true;
case PNK_ARRAYCOMP:
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count == 1);
return checkSideEffects(pn->pn_head, answer);
case PNK_ARGSBODY:
*answer = true;
return true;
case PN_TERNARY:
return checkSideEffects(pn->pn_kid1, answer) &&
checkSideEffects(pn->pn_kid2, answer) &&
checkSideEffects(pn->pn_kid3, answer);
case PNK_FORIN: // by PNK_FOR
case PNK_FOROF: // by PNK_FOR
case PNK_FORHEAD: // by PNK_FOR
case PNK_FRESHENBLOCK: // by PNK_FOR
case PNK_CLASSMETHOD: // by PNK_CLASS
case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_CLASSMETHODLIST: // by PNK_CLASS
case PNK_IMPORT_SPEC_LIST: // by PNK_IMPORT
case PNK_IMPORT_SPEC: // by PNK_IMPORT
case PNK_EXPORT_BATCH_SPEC:// by PNK_EXPORT
case PNK_EXPORT_SPEC_LIST: // by PNK_EXPORT
case PNK_EXPORT_SPEC: // by PNK_EXPORT
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
MOZ_CRASH("handled by parent nodes");
case PN_BINARY:
case PN_BINARY_OBJ:
if (pn->isAssignment()) {
/*
* Assignment is presumed to be useful, even if the next operation
* is another assignment overwriting this one's ostensible effect,
* because the left operand may be a property with a setter that
* has side effects.
*
* The only exception is assignment of a useless value to a const
* declared in the function currently being compiled.
*/
ParseNode* pn2 = pn->pn_left;
if (!pn2->isKind(PNK_NAME)) {
*answer = true;
} else {
if (!bindNameToSlot(pn2))
return false;
if (!checkSideEffects(pn->pn_right, answer))
return false;
if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst()))
*answer = true;
}
return true;
}
MOZ_ASSERT(!pn->isOp(JSOP_OR), "|| produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_AND), "&& produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_STRICTEQ), "=== produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_STRICTNE), "!== produces a list now");
/*
* We can't easily prove that neither operand ever denotes an
* object with a toString or valueOf method.
*/
*answer = true;
return true;
case PN_UNARY:
switch (pn->getKind()) {
case PNK_DELETENAME: {
ParseNode* nameExpr = pn->pn_kid;
MOZ_ASSERT(nameExpr->isKind(PNK_NAME));
if (!bindNameToSlot(nameExpr))
return false;
*answer = !nameExpr->isConst();
return true;
}
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
// All these delete addressing modes have effects, too.
*answer = true;
return true;
case PNK_DELETEEXPR:
return checkSideEffects(pn->pn_kid, answer);
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
case PNK_VOID:
case PNK_NOT:
case PNK_BITNOT:
if (pn->isOp(JSOP_NOT)) {
/* ! does not convert its operand via toString or valueOf. */
return checkSideEffects(pn->pn_kid, answer);
}
/* FALL THROUGH */
default:
/*
* All of PNK_INC, PNK_DEC and PNK_THROW have direct effects. Of
* the remaining unary-arity node types, we can't easily prove that
* the operand never denotes an object with a toString or valueOf
* method.
*/
*answer = true;
return true;
}
MOZ_CRASH("We have a returning default case");
case PN_NAME:
/*
* Take care to avoid trying to bind a label name (labels, both for
* statements and property values in object initialisers, have pn_op
* defaulted to JSOP_NOP).
*/
if (pn->isKind(PNK_NAME) && !pn->isOp(JSOP_NOP)) {
if (!bindNameToSlot(pn))
return false;
if (!pn->isOp(JSOP_CALLEE) && pn->pn_cookie.isFree()) {
/*
* Not a use of an unshadowed named function expression's given
* name, so this expression could invoke a getter that has side
* effects.
*/
*answer = true;
}
}
if (pn->isHoistedLexicalUse()) {
// Hoisted uses of lexical bindings throw on access.
*answer = true;
}
if (pn->isKind(PNK_DOT)) {
/* Dotted property references in general can call getters. */
*answer = true;
}
return checkSideEffects(pn->maybeExpr(), answer);
case PN_NULLARY:
if (pn->isKind(PNK_DEBUGGER) ||
pn->isKind(PNK_SUPERPROP))
*answer = true;
return true;
case PNK_LIMIT: // invalid sentinel value
MOZ_CRASH("invalid node kind");
}
return true;
MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
"BytecodeEmitter::checkSideEffects");
}
bool

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

@ -175,7 +175,9 @@ class NameResolver
* assign to the function's displayAtom field
*/
bool resolveFun(ParseNode* pn, HandleAtom prefix, MutableHandleAtom retAtom) {
MOZ_ASSERT(pn != nullptr && pn->isKind(PNK_FUNCTION));
MOZ_ASSERT(pn != nullptr);
MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
MOZ_ASSERT(pn->isArity(PN_CODE));
RootedFunction fun(cx, pn->pn_funbox->function());
StringBuffer buf(cx);
@ -335,7 +337,8 @@ class NameResolver
if (cur == nullptr)
return true;
if (cur->isKind(PNK_FUNCTION) && cur->isArity(PN_CODE)) {
MOZ_ASSERT(cur->isKind(PNK_FUNCTION) == cur->isArity(PN_CODE));
if (cur->isKind(PNK_FUNCTION)) {
RootedAtom prefix2(cx);
if (!resolveFun(cur, prefix, &prefix2))
return false;

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

@ -946,10 +946,6 @@ struct NullaryNode : public ParseNode
pn_atom = atom;
}
static bool test(const ParseNode& node) {
return node.isArity(PN_NULLARY);
}
#ifdef DEBUG
void dump();
#endif
@ -963,10 +959,6 @@ struct UnaryNode : public ParseNode
pn_kid = kid;
}
static bool test(const ParseNode& node) {
return node.isArity(PN_UNARY);
}
#ifdef DEBUG
void dump(int indent);
#endif
@ -988,10 +980,6 @@ struct BinaryNode : public ParseNode
pn_right = right;
}
static bool test(const ParseNode& node) {
return node.isArity(PN_BINARY);
}
#ifdef DEBUG
void dump(int indent);
#endif
@ -1008,10 +996,6 @@ struct BinaryObjNode : public ParseNode
pn_binary_obj = objbox;
}
static bool test(const ParseNode& node) {
return node.isArity(PN_BINARY_OBJ);
}
#ifdef DEBUG
void dump(int indent);
#endif
@ -1038,10 +1022,6 @@ struct TernaryNode : public ParseNode
pn_kid3 = kid3;
}
static bool test(const ParseNode& node) {
return node.isArity(PN_TERNARY);
}
#ifdef DEBUG
void dump(int indent);
#endif
@ -1087,10 +1067,6 @@ struct CodeNode : public ParseNode
pn_cookie.makeFree();
}
static bool test(const ParseNode& node) {
return node.isArity(PN_CODE);
}
#ifdef DEBUG
void dump(int indent);
#endif
@ -1110,10 +1086,6 @@ struct NameNode : public ParseNode
MOZ_ASSERT(pn_blockid == blockid); // check for bitfield overflow
}
static bool test(const ParseNode& node) {
return node.isArity(PN_NAME);
}
#ifdef DEBUG
void dump(int indent);
#endif

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

@ -1,12 +1,29 @@
// |jit-test| error: InternalError
// This test case creates an array, with no third element. When we iterate over
// the third element of the array (GetElement) see that it is "undefined" and
// start looking for __noSuchMethod__. Iterating over the protoype chain end on
// the Proxy defined as the __proto__ of Array.
//
// When looking for the __noSuchMethod__ property (BaseProxyHandler::get) on the
// proxy, the function getPropertyDescriptor is called which cause an error.
//
// Unfortunately, IonMonkey GetElementIC do not have supports for
// __noSuchMethod__ (Bug 964574) at the moment, which cause a differential
// behaviour.
//
// As we hope to remote __noSuchMethod__ soon (Bug 683218), we disable the mode
// which force the selection of IonMonkey ICs.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
Array.prototype.__proto__ = Proxy.create({
getPropertyDescriptor: function(name) {
return (560566);
},
}, null);
function f() {}
function g() { }
function g() {}
var x = [f,f,f,undefined,g];
for (var i = 0; i < 5; ++i)
y = x[i]("x");

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

@ -0,0 +1,3 @@
setJitCompilerOption("ion.warmup.trigger", 50);
for (var i = 0; i < 150; i++)
Infinity;

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

@ -4,6 +4,12 @@
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 100)
setJitCompilerOption("ion.warmup.trigger", 100);
// This test checks that we are able to remove the getelem & setelem with scalar
// replacement, so we should not force inline caches, as this would skip the
// generation of getelem & setelem instructions.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
// This function is used to force a bailout when it is inlined, and to recover
// the frame which is inlining this function.
var resumeHere = function (i) { if (i >= 99) bailout(); };

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

@ -4,6 +4,12 @@
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 90)
setJitCompilerOption("ion.warmup.trigger", 90);
// This test checks that we are able to remove the getprop & setprop with scalar
// replacement, so we should not force inline caches, as this would skip the
// generation of getprop & setprop instructions.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
var uceFault = function (i) {
if (i > 98)
uceFault = function (i) { return true; };

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

@ -1,3 +1,9 @@
// This test checks that we are able to optimize float32 inputs. As
// GetElementIC (float32 array accesses) output is not specialized with Float32
// output types, we should not force inline caches.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
// Fuzz tests
(function(){
//

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

@ -7460,6 +7460,8 @@ bool
IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded,
MDefinition* lexicalCheck)
{
MOZ_ASSERT(*psucceeded == false);
jsid id = NameToId(name);
MOZ_ASSERT(staticObject->is<GlobalObject>() || staticObject->is<CallObject>());
@ -7541,8 +7543,13 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc
if (barrier != BarrierKind::NoBarrier)
rvalType = MIRType_Value;
return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
rvalType, barrier, types);
if (!loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
rvalType, barrier, types)) {
*psucceeded = false;
return false;
}
return true;
}
// Whether a write of the given value may need a post-write barrier for GC purposes.
@ -7606,19 +7613,21 @@ bool
IonBuilder::jsop_getgname(PropertyName* name)
{
JSObject* obj = &script()->global();
bool succeeded;
if (!getStaticName(obj, name, &succeeded))
return false;
if (succeeded)
return true;
bool emitted = false;
if (!getStaticName(obj, name, &emitted) || emitted)
return emitted;
TemporaryTypeSet* types = bytecodeTypes(pc);
MDefinition* globalObj = constant(ObjectValue(*obj));
if (!getPropTryCommonGetter(&succeeded, globalObj, name, types))
return false;
if (succeeded)
return true;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
{
TemporaryTypeSet* types = bytecodeTypes(pc);
MDefinition* globalObj = constant(ObjectValue(*obj));
if (!getPropTryCommonGetter(&emitted, globalObj, name, types) || emitted)
return emitted;
}
do_InlineCache:
return jsop_getname(name);
}
@ -7742,6 +7751,8 @@ IonBuilder::jsop_getelem()
obj = maybeUnboxForPropertyAccess(obj);
bool emitted = false;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedObject);
if (!getElemTryTypedObject(&emitted, obj, index) || emitted)
@ -7771,6 +7782,7 @@ IonBuilder::jsop_getelem()
if (!getElemTryArgumentsInlined(&emitted, obj, index) || emitted)
return emitted;
do_InlineCache:
if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_MagicOptimizedArguments))
return abort("Type is not definitely lazy arguments.");
@ -8798,6 +8810,9 @@ IonBuilder::jsop_setelem()
return resumeAfter(ins);
}
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedObject);
if (!setElemTryTypedObject(&emitted, object, index, value) || emitted)
return emitted;
@ -8818,6 +8833,7 @@ IonBuilder::jsop_setelem()
if (!setElemTryArguments(&emitted, object, index, value) || emitted)
return emitted;
do_InlineCache:
if (script()->argumentsHasVarBinding() &&
object->mightBeType(MIRType_MagicOptimizedArguments) &&
info().analysisMode() != Analysis_ArgumentsUsage)
@ -10144,6 +10160,9 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!getPropTryInnerize(&emitted, obj, name, types) || emitted)
return emitted;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
// Try to hardcode known constants.
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
@ -10179,6 +10198,7 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!getPropTryInlineAccess(&emitted, obj, name, barrier, types) || emitted)
return emitted;
do_InlineCache:
// Try to emit a polymorphic cache.
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineCache);
if (!getPropTryCache(&emitted, obj, name, barrier, types) || emitted)
@ -11168,6 +11188,9 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
if (inner == obj)
return true;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
// Note: the Baseline ICs don't know about this optimization, so it's
// possible the global property's HeapTypeSet has not been initialized
// yet. In this case we'll fall back to getPropTryCache for now.
@ -11189,6 +11212,7 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
if (!getPropTryCommonGetter(emitted, inner, name, types) || *emitted)
return *emitted;
do_InlineCache:
// Passing the inner object to GetProperty IC is safe, see the
// needsOuterizedThisObject check in IsCacheableGetPropCallNative.
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
@ -11222,6 +11246,9 @@ IonBuilder::jsop_setprop(PropertyName* name)
return resumeAfter(ins);
}
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache_step1;
// Try to inline a common property setter, or make a call.
trackOptimizationAttempt(TrackedStrategy::SetProp_CommonSetter);
if (!setPropTryCommonSetter(&emitted, obj, name, value) || emitted)
@ -11232,20 +11259,28 @@ IonBuilder::jsop_setprop(PropertyName* name)
if (!setPropTryTypedObject(&emitted, obj, name, value) || emitted)
return emitted;
do_InlineCache_step1:
TemporaryTypeSet* objTypes = obj->resultTypeSet();
bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value,
/* canModify = */ true);
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache_step2;
// Try to emit stores to unboxed objects.
trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
return emitted;
do_InlineCache_step2:
// Add post barrier if needed. The instructions above manage any post
// barriers they need directly.
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache_step3;
// Try to emit store from definite slots.
trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
@ -11256,6 +11291,7 @@ IonBuilder::jsop_setprop(PropertyName* name)
if (!setPropTryInlineAccess(&emitted, obj, name, value, barrier, objTypes) || emitted)
return emitted;
do_InlineCache_step3:
// Emit a polymorphic cache.
trackOptimizationAttempt(TrackedStrategy::SetProp_InlineCache);
return setPropTryCache(&emitted, obj, name, value, barrier, objTypes);
@ -12288,11 +12324,9 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
JSObject* call = nullptr;
if (hasStaticScopeObject(sc, &call) && call) {
PropertyName* name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc);
bool succeeded;
if (!getStaticName(call, name, &succeeded, takeLexicalCheck()))
return false;
if (succeeded)
return true;
bool emitted = false;
if (!getStaticName(call, name, &emitted, takeLexicalCheck()) || emitted)
return emitted;
}
// See jsop_checkaliasedlet.

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

@ -113,6 +113,9 @@ JitOptions::JitOptions()
// Whether functions are compiled immediately.
SET_DEFAULT(eagerCompilation, false);
// Whether IonBuilder should prefer IC generation above specialized MIR.
SET_DEFAULT(forceInlineCaches, false);
// Force how many invocation or loop iterations are needed before compiling
// a function with the highest ionmonkey optimization level.
// (i.e. OptimizationLevel_Normal)

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

@ -56,6 +56,7 @@ struct JitOptions
bool disableEaa;
bool disableAma;
bool eagerCompilation;
bool forceInlineCaches;
mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
bool limitScriptSize;

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

@ -5699,6 +5699,15 @@ JS_SetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt, uint32_t v
JitSpew(js::jit::JitSpew_IonScripts, "Enable ion's GVN");
}
break;
case JSJITCOMPILER_ION_FORCE_IC:
if (value == 0) {
jit::js_JitOptions.forceInlineCaches = false;
JitSpew(js::jit::JitSpew_IonScripts, "IonBuilder: Enable non-IC optimizations.");
} else {
jit::js_JitOptions.forceInlineCaches = true;
JitSpew(js::jit::JitSpew_IonScripts, "IonBuilder: Disable non-IC optimizations.");
}
break;
case JSJITCOMPILER_ION_ENABLE:
if (value == 1) {
JS::RuntimeOptionsRef(rt).setIon(true);
@ -5753,6 +5762,8 @@ JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt)
return jit::js_JitOptions.forcedDefaultIonWarmUpThreshold.isSome()
? jit::js_JitOptions.forcedDefaultIonWarmUpThreshold.ref()
: jit::OptimizationInfo::CompilerWarmupThreshold;
case JSJITCOMPILER_ION_FORCE_IC:
return jit::js_JitOptions.forceInlineCaches;
case JSJITCOMPILER_ION_ENABLE:
return JS::RuntimeOptionsRef(rt).ion();
case JSJITCOMPILER_BASELINE_ENABLE:

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

@ -4927,6 +4927,7 @@ JS_SetOffthreadIonCompilationEnabled(JSRuntime* rt, bool enabled);
Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \

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

@ -7350,7 +7350,7 @@ NewMemoryInfoObject(JSContext* cx)
RootedObject obj(cx, JS_NewObject(cx, nullptr));
using namespace MemInfo;
struct {
struct NamedGetter {
const char* name;
JSNative getter;
} getters[] = {
@ -7364,13 +7364,13 @@ NewMemoryInfoObject(JSContext* cx)
{ "minorGCCount", MinorGCCountGetter }
};
for (size_t i = 0; i < mozilla::ArrayLength(getters); i++) {
#ifdef JS_MORE_DETERMINISTIC
for (auto pair : getters) {
#ifdef JS_MORE_DETERMINISTIC
JSNative getter = DummyGetter;
#else
JSNative getter = getters[i].getter;
JSNative getter = pair.getter;
#endif
if (!JS_DefineProperty(cx, obj, getters[i].name, UndefinedHandleValue,
if (!JS_DefineProperty(cx, obj, pair.name, UndefinedHandleValue,
JSPROP_ENUMERATE | JSPROP_SHARED,
getter, nullptr))
{
@ -7385,7 +7385,7 @@ NewMemoryInfoObject(JSContext* cx)
if (!JS_DefineProperty(cx, obj, "zone", zoneObj, JSPROP_ENUMERATE))
return nullptr;
struct {
struct NamedZoneGetter {
const char* name;
JSNative getter;
} zoneGetters[] = {
@ -7399,13 +7399,13 @@ NewMemoryInfoObject(JSContext* cx)
{ "gcNumber", ZoneGCNumberGetter }
};
for (size_t i = 0; i < mozilla::ArrayLength(zoneGetters); i++) {
for (auto pair : zoneGetters) {
#ifdef JS_MORE_DETERMINISTIC
JSNative getter = DummyGetter;
#else
JSNative getter = zoneGetters[i].getter;
JSNative getter = pair.getter;
#endif
if (!JS_DefineProperty(cx, zoneObj, zoneGetters[i].name, UndefinedHandleValue,
if (!JS_DefineProperty(cx, zoneObj, pair.name, UndefinedHandleValue,
JSPROP_ENUMERATE | JSPROP_SHARED,
getter, nullptr))
{

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

@ -3125,14 +3125,9 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
}
if (!aFrame->GetParent()) {
MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::viewportFrame);
nsSubDocumentFrame* subdoc = static_cast<nsSubDocumentFrame*>(
nsLayoutUtils::GetCrossDocParentFrame(aFrame));
if (subdoc && subdoc->PassPointerEventsToChildren()) {
// If this viewport frame is for a subdocument with
// mozpasspointerevents, then we don't want to add the viewport itself
// to the event regions. Instead we want to add only subframes.
return;
}
// Viewport frames are never event targets, other frames, like canvas frames,
// are the event targets for any regions viewport frames may cover.
return;
}
uint8_t pointerEvents = aFrame->StyleVisibility()->GetEffectivePointerEvents(aFrame);
if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {

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

@ -260,6 +260,6 @@ support-files = bug1080361_inner.html
[test_bug1093686.html]
support-files = bug1093686_inner.html
[test_bug1120705.html]
skip-if = buildapp == 'android' || buildapp == 'b2g' || buildapp == 'b2g-debug' || os == 'mac' # android and b2g do not have clickable scrollbars, mac does not have scrollbar down and up buttons
skip-if = buildapp == 'android' || buildapp == 'b2g' || buildapp == 'b2g-debug' || os == 'mac' || toolkit == 'gtk2' || toolkit == 'gtk3' # android and b2g do not have clickable scrollbars, mac does not have scrollbar down and up buttons, gtk may or may not have scrollbar buttons depending on theme
[test_bug1153130.html]
support-files = bug1153130_inner.html

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

@ -136,7 +136,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "0",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -148,7 +148,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "500",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -160,7 +160,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "0",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -172,7 +172,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "500",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -184,7 +184,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "0",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -196,7 +196,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "500",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -208,7 +208,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "0",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},
{
@ -220,7 +220,7 @@ var testCases = [
"mouseOffset" : { "x" : 0, "y" : 0 },
"duration" : "500",
"runMac" : false, // OSX does not have have line-scroll buttons
"runGtk" : true,
"runGtk" : false, // Some GTK themes may not have scroll buttons
"runWin" : true
},

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

@ -5359,6 +5359,7 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
if (line->Contains(child)) {
*aFoundValidLine = true;
mLine = line;
aFrame->SetLineCursor(line.get());
return;
}
++line;
@ -5367,6 +5368,7 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
if (rline->Contains(child)) {
*aFoundValidLine = true;
mLine = rline;
aFrame->SetLineCursor(rline.get());
return;
}
++rline;
@ -6524,9 +6526,8 @@ void nsBlockFrame::SetupLineCursor()
|| mLines.empty()) {
return;
}
Properties().Set(LineCursorProperty(), mLines.front());
AddStateBits(NS_BLOCK_HAS_LINE_CURSOR);
SetLineCursor(mLines.front());
}
nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y)
@ -6554,7 +6555,7 @@ nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y)
}
if (cursor.get() != property) {
props.Set(LineCursorProperty(), cursor.get());
SetLineCursor(cursor.get());
}
return cursor.get();

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

@ -377,6 +377,10 @@ protected:
return (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR) ?
static_cast<nsLineBox*>(Properties().Get(LineCursorProperty())) : nullptr;
}
void SetLineCursor(nsLineBox* aCursor) {
Properties().Set(LineCursorProperty(), aCursor);
AddStateBits(NS_BLOCK_HAS_LINE_CURSOR);
}
nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock);

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

@ -237,6 +237,7 @@ public:
RefPtr(const RefPtr& aOther) : mPtr(ref(aOther.mPtr)) {}
MOZ_IMPLICIT RefPtr(const TemporaryRef<T>& aOther) : mPtr(aOther.take()) {}
MOZ_IMPLICIT RefPtr(already_AddRefed<T>& aOther) : mPtr(aOther.take()) {}
MOZ_IMPLICIT RefPtr(already_AddRefed<T>&& aOther) : mPtr(aOther.take()) {}
MOZ_IMPLICIT RefPtr(T* aVal) : mPtr(ref(aVal)) {}
template<typename U>
@ -259,6 +260,11 @@ public:
assign(aOther.take());
return *this;
}
RefPtr& operator=(already_AddRefed<T>&& aOther)
{
assign(aOther.take());
return *this;
}
RefPtr& operator=(T* aVal)
{
assign(ref(aVal));

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

@ -474,6 +474,9 @@ pref("security.mixed_content.block_active_content", true);
// Enable pinning
pref("security.cert_pinning.enforcement_level", 1);
// Only fetch OCSP for EV certificates
pref("security.OCSP.enabled", 2);
// Override some named colors to avoid inverse OS themes
pref("ui.-moz-dialog", "#efebe7");
pref("ui.-moz-dialogtext", "#101010");

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

@ -571,9 +571,8 @@ pref("apz.test.logging_enabled", false);
pref("gfx.hidpi.enabled", 2);
#endif
#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
// Containerless scrolling for root frames does not yet pass tests on Android
// or B2G.
#if !defined(MOZ_WIDGET_ANDROID)
// Containerless scrolling for root frames does not yet pass tests on Android.
pref("layout.scroll.root-frame-containers", false);
#endif

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

@ -175,6 +175,9 @@ static DllBlockInfo sWindowsDllBlocklist[] = {
// Old version of WebcamMax crashes WebRTC, bug 1130061
{ "vwcsource.ax", MAKE_VERSION(1, 5, 0, 0) },
// NetOp School, discontinued product, bug 763395
{ "nlsp.dll", MAKE_VERSION(6, 23, 2012, 19) },
{ nullptr, 0 }
};

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

@ -5001,12 +5001,17 @@ nsHttpChannel::BeginConnect()
mLoadFlags |= LOAD_FROM_CACHE;
mLoadFlags &= ~VALIDATE_ALWAYS;
nsCOMPtr<nsIPackagedAppService> pas =
do_GetService("@mozilla.org/network/packaged-app-service;1", &rv);
do_GetService("@mozilla.org/network/packaged-app-service;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
AsyncAbort(rv);
return rv;
}
return pas->RequestURI(mURI, GetLoadContextInfo(this), this);
rv = pas->RequestURI(mURI, GetLoadContextInfo(this), this);
if (NS_FAILED(rv)) {
AsyncAbort(rv);
}
return rv;
}
// when proxying only use the pipeline bit if ProxyPipelining() allows it.

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

@ -34,7 +34,7 @@ CertVerifier::CertVerifier(OcspDownloadConfig odc,
OcspGetConfig ogc,
uint32_t certShortLifetimeInDays,
PinningMode pinningMode)
: mOCSPDownloadEnabled(odc == ocspOn)
: mOCSPDownloadConfig(odc)
, mOCSPStrict(osc == ocspStrict)
, mOCSPGETEnabled(ogc == ocspGetEnabled)
, mCertShortLifetimeInDays(certShortLifetimeInDays)
@ -168,8 +168,11 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
return SECFailure;
}
NSSCertDBTrustDomain::OCSPFetching ocspFetching
= !mOCSPDownloadEnabled ||
// We configure the OCSP fetching modes separately for EV and non-EV
// verifications.
NSSCertDBTrustDomain::OCSPFetching defaultOCSPFetching
= (mOCSPDownloadConfig == ocspOff) ||
(mOCSPDownloadConfig == ocspEVOnly) ||
(flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP
: !mOCSPStrict ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
: NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
@ -194,7 +197,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
case certificateUsageSSLClient: {
// XXX: We don't really have a trust bit for SSL client authentication so
// just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching, mOCSPCache,
pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled,
@ -214,15 +217,17 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
#ifndef MOZ_NO_EV_CERTS
// Try to validate for EV first.
NSSCertDBTrustDomain::OCSPFetching evOCSPFetching
= (mOCSPDownloadConfig == ocspOff) ||
(flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
: NSSCertDBTrustDomain::FetchOCSPForEV;
CertPolicyId evPolicy;
SECOidTag evPolicyOidTag;
SECStatus srv = GetFirstEVPolicy(cert, evPolicy, evPolicyOidTag);
if (srv == SECSuccess) {
NSSCertDBTrustDomain
trustDomain(trustSSL,
ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP
? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
: NSSCertDBTrustDomain::FetchOCSPForEV,
trustDomain(trustSSL, evOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS,
hostname, builtChain);
@ -248,8 +253,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
}
// Now try non-EV.
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays, mPinningMode,
MIN_RSA_BITS, hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
@ -268,8 +273,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
}
// If that failed, try again with a smaller minimum key size.
NSSCertDBTrustDomain trustDomainWeak(trustSSL, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain trustDomainWeak(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
mPinningMode, MIN_RSA_BITS_WEAK,
hostname, builtChain);
@ -293,8 +298,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
}
case certificateUsageSSLCA: {
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
nullptr, builtChain);
@ -306,8 +311,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
}
case certificateUsageEmailSigner: {
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
nullptr, builtChain);
@ -330,8 +335,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
// TODO: The higher level S/MIME processing should pass in which key
// usage it is trying to verify for, and base its algorithm choices
// based on the result of the verification(s).
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
nullptr, builtChain);
@ -351,7 +356,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
}
case certificateUsageObjectSigner: {
NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
NSSCertDBTrustDomain trustDomain(trustObjectSigning, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
@ -382,16 +387,16 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
eku = KeyPurposeId::id_kp_OCSPSigning;
}
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache, pinArg,
ocspGETConfig, mCertShortLifetimeInDays,
NSSCertDBTrustDomain sslTrust(trustSSL, defaultOCSPFetching, mOCSPCache,
pinArg, ocspGETConfig, mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
nullptr, builtChain);
rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse);
if (rv == Result::ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain emailTrust(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
nullptr, builtChain);
@ -400,7 +405,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
stapledOCSPResponse);
if (rv == Result::ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
ocspFetching, mOCSPCache,
defaultOCSPFetching, mOCSPCache,
pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled,

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

@ -75,12 +75,14 @@ public:
pinningEnforceTestMode = 3
};
enum OcspDownloadConfig { ocspOff = 0, ocspOn };
enum OcspDownloadConfig {
ocspOff = 0,
ocspOn = 1,
ocspEVOnly = 2
};
enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
enum OcspGetConfig { ocspGetDisabled = 0, ocspGetEnabled = 1 };
bool IsOCSPDownloadEnabled() const { return mOCSPDownloadEnabled; }
CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
OcspGetConfig ogc, uint32_t certShortLifetimeInDays,
PinningMode pinningMode);
@ -88,7 +90,7 @@ public:
void ClearOCSPCache() { mOCSPCache.Clear(); }
const bool mOCSPDownloadEnabled;
const OcspDownloadConfig mOCSPDownloadConfig;
const bool mOCSPStrict;
const bool mOCSPGETEnabled;
const uint32_t mCertShortLifetimeInDays;

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

@ -193,10 +193,15 @@ GetRevocationBehaviorFromPrefs(/*out*/ CertVerifier::OcspDownloadConfig* odc,
MOZ_ASSERT(ogc);
MOZ_ASSERT(certShortLifetimeInDays);
// 0 = disabled, otherwise enabled
*odc = Preferences::GetInt("security.OCSP.enabled", 1)
? CertVerifier::ocspOn
: CertVerifier::ocspOff;
// 0 = disabled
// 1 = enabled for everything (default)
// 2 = enabled for EV certificates only
int32_t ocspLevel = Preferences::GetInt("security.OCSP.enabled", 1);
switch (ocspLevel) {
case 0: *odc = CertVerifier::ocspOff; break;
case 2: *odc = CertVerifier::ocspEVOnly; break;
default: *odc = CertVerifier::ocspOn; break;
}
*osc = Preferences::GetBool("security.OCSP.require", false)
? CertVerifier::ocspStrict
@ -266,6 +271,8 @@ nsNSSComponent::createBackgroundThreads()
nsNSSComponent::~nsNSSComponent()
{
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::dtor\n"));
NS_ASSERTION(!mCertVerificationThread,
"Cert verification thread should have been cleaned up.");
deleteBackgroundThreads();
@ -1326,6 +1333,8 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic,
bec->DontForward();
}
}
deleteBackgroundThreads();
}
else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
nsNSSShutDownPreventionLock locker;

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

@ -81,6 +81,7 @@ function check_telemetry() {
}
function run_test() {
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_tls_server_setup("BadCertServer");
let fakeOCSPResponder = new HttpServer();

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

@ -68,6 +68,7 @@ function run_test() {
// setup and start ocsp responder
Services.prefs.setCharPref("network.dns.localDomains",
'www.example.com, crl.example.com');
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_test(function () {
clearOCSPCache();

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

@ -132,6 +132,7 @@ function checkRSAChains(inadequateKeySize, adequateKeySize) {
function run_test() {
Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
Services.prefs.setIntPref("security.OCSP.enabled", 1);
checkRSAChains(2040, 2048);

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

@ -16,6 +16,7 @@ function generateGoodOCSPResponse() {
function run_test() {
do_get_profile();
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_tls_server_setup("OCSPStaplingServer");
let ocspResponder = new HttpServer();

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

@ -37,6 +37,7 @@ function run_test() {
Services.prefs.setCharPref("network.dns.localDomains",
"www.example.com");
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_test(function() {
clearOCSPCache();

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

@ -14,6 +14,7 @@ let gOCSPRequestCount = 0;
function run_test() {
do_get_profile();
Services.prefs.setBoolPref("security.OCSP.require", true);
Services.prefs.setIntPref("security.OCSP.enabled", 1);
// We don't actually make use of stapling in this test. This is just how we
// get a TLS connection.

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

@ -27,6 +27,7 @@ function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe) {
do_get_profile();
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
Services.prefs.setIntPref("security.OCSP.enabled", 1);
let args = [["good", "localhostAndExampleCom", "unused"],
["expiredresponse", "localhostAndExampleCom", "unused"],
["oldvalidperiod", "localhostAndExampleCom", "unused"],

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

@ -26,6 +26,7 @@ let gSocketListener = {
function run_test() {
do_get_profile();
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_tls_server_setup("OCSPStaplingServer");

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

@ -39,6 +39,7 @@ function run_test() {
Services.prefs.setCharPref("network.dns.localDomains",
"www.example.com");
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_test(function() {
clearOCSPCache();

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

@ -22,6 +22,7 @@ import mozdebug
import mozinfo
import mozprocess
import mozrunner
import numbers
import re
import shutil
import signal
@ -2551,8 +2552,9 @@ class Mochitest(MochitestUtilsMixin):
"MOZ_HIDE_RESULTS_TABLE"] == "1":
options.hideResultsTable = True
d = dict((k, v) for k, v in options.__dict__.items() if (not k.startswith(
'log_') or not any([k.endswith(fmt) for fmt in commandline.log_formatters.keys()])))
# strip certain unnecessary items to avoid serialization errors in json.dumps()
d = dict((k, v) for k, v in options.__dict__.items() if (v is None) or
isinstance(v,(basestring,numbers.Number)))
d['testRoot'] = self.testRoot
content = json.dumps(d)

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

@ -0,0 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BreakpadLogging.h"
#include <ostream>
namespace mozilla {
// An output stream that acts like /dev/null and drops all output directed to it
// Passing 0 here causes the ostream to enter an error state, and so it silently
// drops all output directed to it.
std::ostream gNullStream(0);
} // namespace mozilla

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

@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BreakpadLogging_h
#define BreakpadLogging_h
#include <ostream>
namespace mozilla {
// An output stream that acts like /dev/null and drops all output directed to it
extern std::ostream gNullStream;
} // namespace mozilla
// Override the breakpad info stream to disable INFO logs
#define BPLOG_INFO_STREAM mozilla::gNullStream
#endif // BreakpadLogging_h

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

@ -0,0 +1,18 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
'BreakpadLogging.cpp',
]
Library('breakpad_logging')
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True
with Files('**'):
BUG_COMPONENT = ('Toolkit', 'Breakpad Integration')

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

@ -42,6 +42,7 @@ elif CONFIG['OS_ARCH'] == 'Darwin':
OS_LIBS += ['-framework Cocoa']
USE_LIBS += [
'breakpad_common_s',
'breakpad_logging',
'breakpad_mac_common_s',
]
elif CONFIG['OS_ARCH'] == 'SunOS':

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

@ -86,9 +86,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
if CONFIG['OS_TARGET'] == 'Android':
DEFINES['NO_STABS_SUPPORT'] = True
DEFINES['BP_LOGGING_INCLUDE'] = '"BreakpadLogging.h"'
include('/toolkit/crashreporter/crashreporter.mozbuild')
LOCAL_INCLUDES += [
'..',
'../../../breakpad-logging',
]

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

@ -23,9 +23,12 @@ UNIFIED_SOURCES += [
FINAL_LIBRARY = 'xul'
DEFINES['BP_LOGGING_INCLUDE'] = '"BreakpadLogging.h"'
LOCAL_INCLUDES += [
'..',
'../..',
'../../../breakpad-logging',
]
include('/toolkit/crashreporter/crashreporter.mozbuild')

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

@ -48,7 +48,10 @@ elif CONFIG['OS_ARCH'] == 'SunOS':
'google-breakpad/src/tools/solaris/dump_syms',
]
DIRS += ['client']
DIRS += [
'breakpad-logging',
'client',
]
if CONFIG['MOZ_CRASHREPORTER_INJECTOR']:
DIRS += ['injector']

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

@ -56,6 +56,7 @@ elif CONFIG['MOZ_ENABLE_PROFILER_SPS']:
# Profiler requires some crashreporter code,
# so build it even if crashreporter is disabled.
DIRS += [
'crashreporter/breakpad-logging',
'crashreporter/google-breakpad/src/common',
'crashreporter/google-breakpad/src/processor',
]

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

@ -375,6 +375,18 @@ XRE_InitChildProcess(int aArgc,
return NS_ERROR_FAILURE;
}
ReceivePort* ports_out_receiver = new ReceivePort();
if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver->GetPort()))) {
NS_WARNING("Adding descriptor to message failed");
return NS_ERROR_FAILURE;
}
ReceivePort* ports_in_receiver = new ReceivePort();
if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver->GetPort()))) {
NS_WARNING("Adding descriptor to message failed");
return NS_ERROR_FAILURE;
}
MachPortSender child_sender(mach_port_name);
kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
if (err != KERN_SUCCESS) {
@ -393,12 +405,27 @@ XRE_InitChildProcess(int aArgc,
NS_WARNING("child GetTranslatedPort(0) failed");
return NS_ERROR_FAILURE;
}
err = task_set_bootstrap_port(mach_task_self(),
parent_message.GetTranslatedPort(0));
if (parent_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
NS_WARNING("child GetTranslatedPort(1) failed");
return NS_ERROR_FAILURE;
}
MachPortSender* ports_out_sender = new MachPortSender(parent_message.GetTranslatedPort(1));
if (parent_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
NS_WARNING("child GetTranslatedPort(2) failed");
return NS_ERROR_FAILURE;
}
MachPortSender* ports_in_sender = new MachPortSender(parent_message.GetTranslatedPort(2));
if (err != KERN_SUCCESS) {
NS_WARNING("child task_set_bootstrap_port() failed");
return NS_ERROR_FAILURE;
}
#endif
SetupErrorHandling(aArgv[0]);
@ -467,6 +494,11 @@ XRE_InitChildProcess(int aArgc,
base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
MOZ_ASSERT(!*end, "invalid parent PID");
#ifdef XP_MACOSX
mozilla::ipc::SharedMemoryBasic::SetupMachMemory(parentPID, ports_in_receiver, ports_in_sender,
ports_out_sender, ports_out_receiver, true);
#endif
#if defined(XP_WIN)
// On Win7+, register the application user model id passed in by
// parent. This insures windows created by the container properly

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

@ -220,8 +220,33 @@ JSObject* TableTicker::ToJSObject(JSContext *aCx, float aSinceTime)
{
UniquePtr<char[]> buf = ToJSON(aSinceTime);
NS_ConvertUTF8toUTF16 js_string(nsDependentCString(buf.get()));
MOZ_ALWAYS_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()),
js_string.Length(), &val));
bool rv = JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()),
js_string.Length(), &val);
if (!rv) {
#ifdef NIGHTLY_BUILD
// XXXshu: Temporary code to help debug malformed JSON. See bug 1172157.
nsCOMPtr<nsIFile> path;
nsresult rv = NS_GetSpecialDirectory("TmpD", getter_AddRefs(path));
if (!NS_FAILED(rv)) {
rv = path->Append(NS_LITERAL_STRING("bad-profile.json"));
if (!NS_FAILED(rv)) {
nsCString cpath;
rv = path->GetNativePath(cpath);
if (!NS_FAILED(rv)) {
std::ofstream stream;
stream.open(cpath.get());
if (stream.is_open()) {
stream << buf.get();
stream.close();
printf_stderr("Malformed profiler JSON dumped to %s! "
"Please upload to https://bugzil.la/1172157\n",
cpath.get());
}
}
}
}
#endif
}
}
return &val.toObject();
}

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

@ -1304,14 +1304,13 @@ void nsWindow::ConfigureAPZCTreeManager()
// have code that can deal with them properly. If APZ is not enabled, this
// function doesn't get called, and |mGesture| will take care of touch-based
// scrolling. Note that RegisterTouchWindow may still do nothing depending
// on touch/pointer events prefs, and so it is possible to enable APZ without
// on touch events prefs, and so it is possible to enable APZ without
// also enabling touch support.
RegisterTouchWindow();
}
void nsWindow::RegisterTouchWindow() {
if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
gIsPointerEventsEnabled) {
if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0)) {
mTouchWindow = true;
mGesture.RegisterTouchWindow(mWnd);
::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
@ -5321,10 +5320,6 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
// A GestureNotify event is dispatched to decide which single-finger panning
// direction should be active (including none) and if pan feedback should
// be displayed. Java and plugin windows can make their own calls.
if (gIsPointerEventsEnabled) {
result = false;
break;
}
GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
nsPointWin touchPoint;
@ -6274,10 +6269,6 @@ static int32_t RoundDown(double aDouble)
// Gesture event processing. Handles WM_GESTURE events.
bool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
{
if (gIsPointerEventsEnabled) {
return false;
}
// Treatment for pan events which translate into scroll events:
if (mGesture.IsPanEvent(lParam)) {
if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) )