Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2014-02-05 16:14:03 -05:00
commit 84cac0677c
131 changed files with 1573 additions and 1373 deletions

View File

@ -10,6 +10,7 @@
#include "nsAccessibilityService.h"
#include "nsIAccessibleTypes.h"
#include "DocAccessible.h"
#include "HTMLListAccessible.h"
#include "Role.h"
#include "States.h"
#include "TextAttrs.h"
@ -238,7 +239,7 @@ HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
if (!aNode)
return 0;
uint32_t addTextOffset = 0;
uint32_t offset = 0;
nsINode* findNode = nullptr;
if (aNodeOffset == -1) {
@ -251,7 +252,7 @@ HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
NS_ENSURE_TRUE(frame, 0);
nsresult rv = ContentToRenderedOffset(frame, aNodeOffset, &addTextOffset);
nsresult rv = ContentToRenderedOffset(frame, aNodeOffset, &offset);
NS_ENSURE_SUCCESS(rv, 0);
// Get the child node and
findNode = aNode;
@ -304,14 +305,20 @@ HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
descendant = GetFirstAvailableAccessible(findNode);
}
// From the descendant, go up and get the immediate child of this hypertext
Accessible* childAtOffset = nullptr;
return TransformOffset(descendant, offset, aIsEndOffset);
}
int32_t
HyperTextAccessible::TransformOffset(Accessible* aDescendant,
int32_t aOffset, bool aIsEndOffset) const
{
// From the descendant, go up and get the immediate child of this hypertext.
int32_t offset = aOffset;
Accessible* descendant = aDescendant;
while (descendant) {
Accessible* parent = descendant->Parent();
if (parent == this) {
childAtOffset = descendant;
break;
}
if (parent == this)
return GetChildOffset(descendant) + offset;
// This offset no longer applies because the passed-in text object is not
// a child of the hypertext. This happens when there are nested hypertexts,
@ -321,17 +328,16 @@ HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
// is not at 0 offset then the returned offset should be after an embedded
// character the original point belongs to.
if (aIsEndOffset)
addTextOffset = (addTextOffset > 0 || descendant->IndexInParent() > 0) ? 1 : 0;
offset = (offset > 0 || descendant->IndexInParent() > 0) ? 1 : 0;
else
addTextOffset = 0;
offset = 0;
descendant = parent;
}
// If the given DOM point cannot be mapped into offset relative this hypertext
// If the given a11y point cannot be mapped into offset relative this hypertext
// offset then return length as fallback value.
return childAtOffset ?
GetChildOffset(childAtOffset) + addTextOffset : CharacterCount();
return CharacterCount();
}
bool
@ -420,6 +426,31 @@ HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
return -1;
child = text->GetChildAt(childIdx);
// HTML list items may need special processing because PeekOffset doesn't
// work with list bullets.
if (text->IsHTMLListItem()) {
HTMLLIAccessible* li = text->AsHTMLListItem();
if (child == li->Bullet()) {
// It works only when the bullet is one single char.
if (aDirection == eDirPrevious)
return text != this ? TransformOffset(text, 0, false) : 0;
if (aAmount == eSelectEndLine || aAmount == eSelectLine) {
if (text != this)
return TransformOffset(text, 1, true);
// Ask a text leaf next (if not empty) to the bullet for an offset
// since list item may be multiline.
return aOffset + 1 < CharacterCount() ?
FindOffset(aOffset + 1, aDirection, aAmount, aWordMovementType) : 1;
}
// Case of word and char boundaries.
return text != this ? TransformOffset(text, 1, true) : 1;
}
}
innerOffset -= text->GetChildOffset(childIdx);
text = child->AsHyperText();
@ -463,10 +494,16 @@ HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
pos.mContentOffset,
aDirection == eDirNext);
// If we reached the end during search, this means we didn't find the DOM point
// and we're actually at the start of the paragraph
if (hyperTextOffset == CharacterCount() && aDirection == eDirPrevious)
return 0;
if (aDirection == eDirPrevious) {
// If we reached the end during search, this means we didn't find the DOM point
// and we're actually at the start of the paragraph
if (hyperTextOffset == CharacterCount())
return 0;
// PeekOffset stops right before bullet so return 0 to workaround it.
if (IsHTMLListItem() && aAmount == eSelectBeginLine && hyperTextOffset == 1)
return 0;
}
return hyperTextOffset;
}

View File

@ -120,6 +120,12 @@ public:
int32_t DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
bool aIsEndOffset = false) const;
/**
* Transform the given a11y point into the offset relative this hypertext.
*/
int32_t TransformOffset(Accessible* aDescendant, int32_t aOffset,
bool aIsEndOffset) const;
/**
* Convert start and end hypertext offsets into DOM range.
*
@ -435,9 +441,9 @@ protected:
* Return an offset corresponding to the given direction and selection amount
* relative the given offset. A helper used to find word or line boundaries.
*/
virtual int32_t FindOffset(int32_t aOffset, nsDirection aDirection,
nsSelectionAmount aAmount,
EWordMovementType aWordMovementType = eDefaultBehavior);
int32_t FindOffset(int32_t aOffset, nsDirection aDirection,
nsSelectionAmount aAmount,
EWordMovementType aWordMovementType = eDefaultBehavior);
/**
* Return the boundaries of the substring in case of textual frame or

View File

@ -98,33 +98,6 @@ HTMLLIAccessible::GetBounds(int32_t* aX, int32_t* aY,
return NS_OK;
}
int32_t
HTMLLIAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
nsSelectionAmount aAmount,
EWordMovementType aWordMovementType)
{
Accessible* child = GetChildAtOffset(aOffset);
if (!child)
return -1;
if (child != mBullet) {
if (aDirection == eDirPrevious &&
(aAmount == eSelectBeginLine || aAmount == eSelectLine))
return 0;
return HyperTextAccessible::FindOffset(aOffset, aDirection,
aAmount, aWordMovementType);
}
if (aDirection == eDirPrevious)
return 0;
if (aAmount == eSelectEndLine || aAmount == eSelectLine)
return CharacterCount();
return nsAccUtils::TextLength(child);
}
////////////////////////////////////////////////////////////////////////////////
// HTMLLIAccessible: public

View File

@ -55,12 +55,8 @@ public:
virtual a11y::role NativeRole();
virtual uint64_t NativeState();
// HyperTextAccessible
virtual int32_t FindOffset(int32_t aOffset, nsDirection aDirection,
nsSelectionAmount aAmount,
EWordMovementType aWordMovementType) MOZ_OVERRIDE;
// HTMLLIAccessible
HTMLListBulletAccessible* Bullet() const { return mBullet; }
void UpdateBullet(bool aHasBullet);
protected:

View File

@ -119,6 +119,18 @@
testTextAtOffset([ "li1" ], BOUNDARY_LINE_START,
[ [ 0, 5, kDiscBulletChar + "Item", 0, 5 ] ]);
testTextAtOffset([ "li2" ], BOUNDARY_LINE_START,
[ [ 0, 1, kDiscBulletChar, 0, 1 ] ]);
testTextAtOffset([ "li3" ], BOUNDARY_LINE_START,
[ [ 0, 7, kDiscBulletChar + "a long ", 0, 8 ],
[ 8, 11, "and ", 8, 12 ] ]);
testTextAtOffset([ "li4" ], BOUNDARY_LINE_START,
[ [ 0, 6, kDiscBulletChar + "a " + kEmbedChar + " c", 0, 6 ] ]);
testTextAtOffset([ "ul1" ], BOUNDARY_LINE_START,
[ [ 0, 0, kEmbedChar, 0, 1 ],
[ 1, 1, kEmbedChar, 1, 2 ],
[ 2, 2, kEmbedChar, 2, 3 ],
[ 3, 4, kEmbedChar, 3, 4 ] ]);
//////////////////////////////////////////////////////////////////////////
// Nested hypertexts
@ -193,8 +205,11 @@ two words
<p id="ht_4">Hello world
</p>
<ul>
<ul id="ul1">
<li id="li1">Item</li>
<li id="li2"></li>
<li id="li3" style="width:10ex; font-family:monospace; font-size:10pt;">a long and winding road that lead me to your door</li>
<li id="li4">a <a href=''>b</a> c</li>
</ul>
<div id="ht_5">
@ -203,5 +218,6 @@ two words
<p>seciofarus</p>
</div>
</div>
</body>
</html>

View File

@ -12,8 +12,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>

View File

@ -11,8 +11,8 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>

View File

@ -12,8 +12,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>

View File

@ -1,4 +1,4 @@
{
"revision": "cea79abbb7a97c0bd67051087bcdf40d25611930",
"revision": "0fd4065b6621e3b7409cf90ac30d4e174e7317a6",
"repo_path": "/integration/gaia-central"
}

View File

@ -11,8 +11,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>

View File

@ -10,8 +10,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>

View File

@ -12,8 +12,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>

View File

@ -11,8 +11,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>

View File

@ -11,8 +11,8 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>

View File

@ -11,8 +11,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ce212ba54f36284db84068f82af0c790ceb2c3ff"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ac8a273809b5b160554e616bc5ef2d6fa026ce0e"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>

View File

@ -564,7 +564,6 @@
@BINPATH@/components/Payment.js
@BINPATH@/components/PaymentFlowInfo.js
@BINPATH@/components/PaymentRequestInfo.js
@BINPATH@/components/Payment.manifest
@BINPATH@/components/DownloadsAPI.js

View File

@ -288,6 +288,7 @@ run-if = crashreporter
[browser_popupNotification.js]
skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
[browser_popupUI.js]
[browser_printpreview.js]
[browser_private_browsing_window.js]
[browser_private_no_prompt.js]
[browser_relatedTabs.js]

View File

@ -0,0 +1,65 @@
function test() {
waitForExplicitFinish();
ok(!gInPrintPreviewMode,
"Should NOT be in print preview mode at starting this tests");
// Skip access key test on platforms which don't support access key.
if (!/Win|Linux/.test(navigator.platform)) {
openPrintPreview(testClosePrintPreviewWithEscKey);
} else {
openPrintPreview(testClosePrintPreviewWithAccessKey);
}
}
function testClosePrintPreviewWithAccessKey() {
EventUtils.synthesizeKey("c", { altKey: true });
checkPrintPreviewClosed(function (aSucceeded) {
ok(aSucceeded,
"print preview mode should be finished by access key");
openPrintPreview(testClosePrintPreviewWithEscKey);
});
}
function testClosePrintPreviewWithEscKey() {
EventUtils.synthesizeKey("VK_ESCAPE", {});
checkPrintPreviewClosed(function (aSucceeded) {
ok(aSucceeded,
"print preview mode should be finished by Esc key press");
openPrintPreview(testClosePrintPreviewWithClosingWindowShortcutKey);
});
}
function testClosePrintPreviewWithClosingWindowShortcutKey() {
EventUtils.synthesizeKey("w", { accelKey: true });
checkPrintPreviewClosed(function (aSucceeded) {
ok(aSucceeded,
"print preview mode should be finished by closing window shortcut key");
finish();
});
}
function openPrintPreview(aCallback) {
document.getElementById("cmd_printPreview").doCommand();
executeSoon(function () {
if (gInPrintPreviewMode) {
executeSoon(aCallback);
return;
}
executeSoon(arguments.callee);
});
}
function checkPrintPreviewClosed(aCallback) {
let count = 0;
executeSoon(function () {
if (!gInPrintPreviewMode) {
executeSoon(function () { aCallback(count < 1000); });
return;
}
if (++count == 1000) {
// The test might fail.
PrintUtils.exitPrintPreview();
}
executeSoon(arguments.callee);
});
}

View File

@ -569,7 +569,6 @@
@BINPATH@/components/Payment.js
@BINPATH@/components/PaymentFlowInfo.js
@BINPATH@/components/PaymentRequestInfo.js
@BINPATH@/components/Payment.manifest
#ifdef MOZ_WEBRTC

View File

@ -512,11 +512,9 @@ def dumpScreen(utilityPath):
# Run the capture
try:
with mozfile.NamedTemporaryFile(suffix='.png',
prefix='mozilla-test-fail-screenshot_',
dir=parent_dir,
delete=False) as f:
returncode = subprocess.call(utility + [f.name])
tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail-screenshot_', suffix='.png', dir=parent_dir)
os.close(tmpfd)
returncode = subprocess.call(utility + [imgfilename])
except OSError, err:
log.info("Failed to start %s for screenshot: %s",
utility[0], err.strerror)

View File

@ -1460,7 +1460,7 @@ ifeq (,$(wildcard $(DIST)/bin/nsinstall$(HOST_BIN_SUFFIX)))
nsinstall_is_usable = $(if $(wildcard $(DIST)/bin/nsinstall$(HOST_BIN_SUFFIX)),yes)
define install_cmd_override
$(1): install_cmd = $$(if $$(nsinstall_is_usable),$$(INSTALL),$$(NSINSTALL_PY)) $$(1)
$(1): install_cmd = $$(if $$(nsinstall_is_usable),$$(INSTALL),$$(NSINSTALL_PY) -t) $$(1)
endef
endif
endif

View File

@ -1249,6 +1249,7 @@ GK_ATOM(feConvolveMatrix, "feConvolveMatrix")
GK_ATOM(feDiffuseLighting, "feDiffuseLighting")
GK_ATOM(feDisplacementMap, "feDisplacementMap")
GK_ATOM(feDistantLight,"feDistantLight")
GK_ATOM(feDropShadow, "feDropShadow")
GK_ATOM(feFlood, "feFlood")
GK_ATOM(feFuncA, "feFuncA")
GK_ATOM(feFuncB, "feFuncB")

View File

@ -306,6 +306,7 @@ nsIAtom** const kElementsSVG[] = {
&nsGkAtoms::feDiffuseLighting, // feDiffuseLighting
&nsGkAtoms::feDisplacementMap, // feDisplacementMap
&nsGkAtoms::feDistantLight, // feDistantLight
&nsGkAtoms::feDropShadow, // feDropShadow
&nsGkAtoms::feFlood, // feFlood
&nsGkAtoms::feFuncA, // feFuncA
&nsGkAtoms::feFuncB, // feFuncB

View File

@ -1,72 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "AudioCompactor.h"
#if defined(MOZ_MEMORY)
# include "mozmemory.h"
#endif
namespace mozilla {
static size_t
MallocGoodSize(size_t aSize)
{
# if defined(MOZ_MEMORY)
return malloc_good_size(aSize);
# else
return aSize;
# endif
}
static size_t
TooMuchSlop(size_t aSize, size_t aAllocSize, size_t aMaxSlop)
{
// If the allocated size is less then our target size, then we
// are chunking. This means it will be completely filled with
// zero slop.
size_t slop = (aAllocSize > aSize) ? (aAllocSize - aSize) : 0;
return slop > aMaxSlop;
}
uint32_t
AudioCompactor::GetChunkSamples(uint32_t aFrames, uint32_t aChannels,
size_t aMaxSlop)
{
size_t size = AudioDataSize(aFrames, aChannels);
size_t chunkSize = MallocGoodSize(size);
// Reduce the chunk size until we meet our slop goal or the chunk
// approaches an unreasonably small size.
while (chunkSize > 64 && TooMuchSlop(size, chunkSize, aMaxSlop)) {
chunkSize = MallocGoodSize(chunkSize / 2);
}
// Calculate the number of samples based on expected malloc size
// in order to allow as many frames as possible to be packed.
return chunkSize / sizeof(AudioDataValue);
}
uint32_t
AudioCompactor::NativeCopy::operator()(AudioDataValue *aBuffer, size_t aSamples)
{
NS_ASSERTION(aBuffer, "cannot copy to null buffer pointer");
NS_ASSERTION(aSamples, "cannot copy zero values");
size_t bufferBytes = aSamples * sizeof(AudioDataValue);
size_t maxBytes = std::min(bufferBytes, mSourceBytes - mNextByte);
uint32_t frames = maxBytes / BytesPerFrame(mChannels);
size_t bytes = frames * BytesPerFrame(mChannels);
NS_ASSERTION((mNextByte + bytes) <= mSourceBytes,
"tried to copy beyond source buffer");
NS_ASSERTION(bytes <= bufferBytes, "tried to copy beyond destination buffer");
memcpy(aBuffer, mSource + mNextByte, bytes);
mNextByte += bytes;
return frames;
}
} // namespace mozilla

View File

@ -1,121 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#if !defined(AudioCompactor_h)
#define AudioCompactor_h
#include "MediaQueue.h"
#include "MediaData.h"
#include "VideoUtils.h"
namespace mozilla {
class AudioCompactor
{
public:
AudioCompactor(MediaQueue<AudioData>& aQueue)
: mQueue(aQueue)
{ }
// Push audio data into the underlying queue with minimal heap allocation
// slop. This method is responsible for allocating AudioDataValue[] buffers.
// The caller must provide a functor to copy the data into the buffers. The
// functor must provide the following signature:
//
// uint32_t operator()(AudioDataValue *aBuffer, size_t aSamples);
//
// The functor must copy as many complete frames as possible to the provided
// buffer given its length (in AudioDataValue elements). The number of frames
// copied must be returned. This copy functor must support being called
// multiple times in order to copy the audio data fully. The copy functor
// must copy full frames as partial frames will be ignored.
template<typename CopyFunc>
bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate,
uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc)
{
// If we are losing more than a reasonable amount to padding, try to chunk
// the data.
size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR;
while (aFrames > 0) {
uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop);
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[samples]);
// Copy audio data to buffer using caller-provided functor.
uint32_t framesCopied = aCopyFunc(buffer, samples);
NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames");
CheckedInt64 duration = FramesToUsecs(framesCopied, aSampleRate);
if (!duration.isValid()) {
return false;
}
mQueue.Push(new AudioData(aOffset,
aTime,
duration.value(),
framesCopied,
buffer.forget(),
aChannels));
// Remove the frames we just pushed into the queue and loop if there is
// more to be done.
aTime += duration.value();
aFrames -= framesCopied;
// NOTE: No need to update aOffset as its only an approximation anyway.
}
return true;
}
// Copy functor suitable for copying audio samples already in the
// AudioDataValue format/layout expected by AudioStream on this platform.
class NativeCopy
{
public:
NativeCopy(const uint8_t* aSource, size_t aSourceBytes,
uint32_t aChannels)
: mSource(aSource)
, mSourceBytes(aSourceBytes)
, mChannels(aChannels)
, mNextByte(0)
{ }
uint32_t operator()(AudioDataValue *aBuffer, size_t aSamples);
private:
const uint8_t* const mSource;
const size_t mSourceBytes;
const uint32_t mChannels;
size_t mNextByte;
};
// Allow 12.5% slop before chunking kicks in. Public so that the gtest can
// access it.
static const size_t MAX_SLOP_DIVISOR = 8;
private:
// Compute the number of AudioDataValue samples that will be fit the most
// frames while keeping heap allocation slop less than the given threshold.
static uint32_t
GetChunkSamples(uint32_t aFrames, uint32_t aChannels, size_t aMaxSlop);
static size_t BytesPerFrame(uint32_t aChannels)
{
return sizeof(AudioDataValue) * aChannels;
}
static size_t AudioDataSize(uint32_t aFrames, uint32_t aChannels)
{
return aFrames * BytesPerFrame(aChannels);
}
MediaQueue<AudioData> &mQueue;
};
} // namespace mozilla
#endif // AudioCompactor_h

View File

@ -45,8 +45,7 @@ void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
}
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mAudioCompactor(mAudioQueue),
mDecoder(aDecoder),
: mDecoder(aDecoder),
mIgnoreAudioOutputFormat(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
@ -281,3 +280,4 @@ MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
}
} // namespace mozilla

View File

@ -10,7 +10,6 @@
#include "MediaInfo.h"
#include "MediaData.h"
#include "MediaQueue.h"
#include "AudioCompactor.h"
namespace mozilla {
@ -106,12 +105,6 @@ protected:
// the decoder, state machine, and main threads.
MediaQueue<VideoData> mVideoQueue;
// An adapter to the audio queue which first copies data to buffers with
// minimal allocation slop and then pushes them to the queue. This is
// useful for decoders working with formats that give awkward numbers of
// frames such as mp3.
AudioCompactor mAudioCompactor;
public:
// Populates aBuffered with the time ranges which are buffered. aStartTime
// must be the presentation time of the first frame in the media, e.g.

View File

@ -45,13 +45,6 @@ extern PRLogModuleInfo* gMediaDecoderLog;
#define DECODER_LOG(type, msg)
#endif
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
// implementation. With unified builds, putting this in headers is not enough.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
// Wait this number of seconds when buffering, then leave and play
// as best as we can if the required amount of data hasn't been
// retrieved.

View File

@ -92,13 +92,6 @@ namespace mozilla {
class AudioSegment;
class VideoSegment;
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
// implementation.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
/*
The state machine class. This manages the decoding and seeking in the
MediaDecoderReader on the decode thread, and A/V sync on the shared

View File

@ -72,6 +72,8 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
// on UpdateCurrentTime to notify our listeners once the stream end
// has been reached.
EnsureNextIteration();
SetStreamOrderDirty();
}
void
@ -80,6 +82,8 @@ MediaStreamGraphImpl::AddStream(MediaStream* aStream)
aStream->mBufferStartTime = mCurrentTime;
*mStreams.AppendElement() = already_AddRefed<MediaStream>(aStream);
STREAM_LOG(PR_LOG_DEBUG, ("Adding media stream %p to the graph", aStream));
SetStreamOrderDirty();
}
void
@ -97,6 +101,8 @@ MediaStreamGraphImpl::RemoveStream(MediaStream* aStream)
}
}
SetStreamOrderDirty();
// This unrefs the stream, probably destroying it
mStreams.RemoveElement(aStream);
@ -430,6 +436,7 @@ MediaStreamGraphImpl::UpdateCurrentTime()
stream->StreamTimeToGraphTime(stream->GetStreamBuffer().GetAllTracksEnd())) {
stream->mNotifiedFinished = true;
stream->mLastPlayedVideoFrame.SetNull();
SetStreamOrderDirty();
for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) {
MediaStreamListener* l = stream->mListeners[j];
l->NotifyFinished(this);
@ -1168,7 +1175,9 @@ MediaStreamGraphImpl::RunThread()
}
messageQueue.Clear();
UpdateStreamOrder();
if (mStreamOrderDirty) {
UpdateStreamOrder();
}
// Find the sampling rate that we need to use for non-realtime graphs.
TrackRate sampleRate = IdealAudioRate();
@ -2279,6 +2288,8 @@ MediaInputPort::Disconnect()
mSource = nullptr;
mDest->RemoveInput(this);
mDest = nullptr;
GraphImpl()->SetStreamOrderDirty();
}
MediaInputPort::InputInterval
@ -2357,6 +2368,7 @@ ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, uint32_t aFlags,
{
mPort->Init();
// The graph holds its reference implicitly
mPort->GraphImpl()->SetStreamOrderDirty();
mPort.forget();
}
virtual void RunDuringShutdown()
@ -2410,6 +2422,7 @@ ProcessedMediaStream::DestroyImpl()
mInputs[i]->Disconnect();
}
MediaStream::DestroyImpl();
GraphImpl()->SetStreamOrderDirty();
}
/**

View File

@ -204,7 +204,7 @@ public:
void Revoke() { mResource = nullptr; }
private:
nsRefPtr<RtspMediaResource> mResource;
RtspMediaResource* mResource;
};
friend class Listener;

View File

@ -12,12 +12,8 @@
#define AUDIO_READ_BYTES 4096
// Maximum number of audio frames we will accept from the audio decoder in one
// go. Carefully select this to work well with both the mp3 1152 max frames
// per block and power-of-2 allocation sizes. Since we must pre-allocate the
// buffer we cannot use AudioCompactor without paying for an additional
// allocation and copy. Therefore, choosing a value that divides exactly into
// 1152 is most memory efficient.
#define MAX_AUDIO_FRAMES 128
// go.
#define MAX_AUDIO_FRAMES 4096
namespace mozilla {
@ -205,8 +201,7 @@ AppleMP3Reader::AudioSampleCallback(UInt32 aNumBytes,
LOGD("got %u bytes, %u packets\n", aNumBytes, aNumPackets);
// 1 frame per packet * num channels * 32-bit float
uint32_t decodedSize = MAX_AUDIO_FRAMES * mAudioChannels *
sizeof(AudioDataValue);
uint32_t decodedSize = MAX_AUDIO_FRAMES * mAudioChannels * 4;
// descriptions for _decompressed_ audio packets. ignored.
nsAutoArrayPtr<AudioStreamPacketDescription>
@ -243,14 +238,6 @@ AppleMP3Reader::AudioSampleCallback(UInt32 aNumBytes,
break;
}
// If we decoded zero frames then AudiOConverterFillComplexBuffer is out
// of data to provide. We drained its internal buffer completely on the
// last pass.
if (numFrames == 0 && rv == kNeedMoreData) {
LOGD("FillComplexBuffer out of data exactly\n");
break;
}
int64_t time = FramesToUsecs(mCurrentAudioFrame, mAudioSampleRate).value();
int64_t duration = FramesToUsecs(numFrames, mAudioSampleRate).value();

View File

@ -1,5 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -248,48 +247,6 @@ DirectShowReader::Finish(HRESULT aStatus)
return false;
}
class DirectShowCopy
{
public:
DirectShowCopy(uint8_t *aSource, uint32_t aBytesPerSample,
uint32_t aSamples, uint32_t aChannels)
: mSource(aSource)
, mBytesPerSample(aBytesPerSample)
, mSamples(aSamples)
, mChannels(aChannels)
, mNextSample(0)
{ }
uint32_t operator()(AudioDataValue *aBuffer, size_t aSamples)
{
size_t maxSamples = std::min(aSamples, mSamples - mNextSample);
uint32_t frames = maxSamples / mChannels;
size_t byteOffset = mNextSample * mBytesPerSample;
if (mBytesPerSample == 1) {
for (uint32_t i = 0; i < maxSamples; ++i) {
uint8_t *sample = mSource + byteOffset;
aBuffer[i] = UnsignedByteToAudioSample(*sample);
byteOffset += mBytesPerSample;
}
} else if (mBytesPerSample == 2) {
for (uint32_t i = 0; i < maxSamples; ++i) {
int16_t *sample = reinterpret_cast<int16_t *>(mSource + byteOffset);
aBuffer[i] = AudioSampleToFloat(*sample);
byteOffset += mBytesPerSample;
}
}
mNextSample = maxSamples;
return frames;
}
private:
uint8_t * const mSource;
const uint32_t mBytesPerSample;
const uint32_t mSamples;
const uint32_t mChannels;
uint32_t mNextSample;
};
bool
DirectShowReader::DecodeAudioData()
{
@ -324,15 +281,26 @@ DirectShowReader::DecodeAudioData()
hr = sample->GetPointer(&data);
NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr));
mAudioCompactor.Push(mDecoder->GetResource()->Tell(),
RefTimeToUsecs(start),
mInfo.mAudio.mRate,
numFrames,
mNumChannels,
DirectShowCopy(reinterpret_cast<uint8_t *>(data),
mBytesPerSample,
numSamples,
mNumChannels));
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[numSamples]);
AudioDataValue* dst = buffer.get();
if (mBytesPerSample == 1) {
uint8_t* src = reinterpret_cast<uint8_t*>(data);
for (int32_t i = 0; i < numSamples; ++i) {
dst[i] = UnsignedByteToAudioSample(src[i]);
}
} else if (mBytesPerSample == 2) {
int16_t* src = reinterpret_cast<int16_t*>(data);
for (int32_t i = 0; i < numSamples; ++i) {
dst[i] = AudioSampleToFloat(src[i]);
}
}
mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
RefTimeToUsecs(start),
RefTimeToUsecs(end - start),
numFrames,
buffer.forget(),
mNumChannels));
return true;
}

View File

@ -532,20 +532,20 @@ bool GStreamerReader::DecodeAudioData()
timestamp = gst_segment_to_stream_time(&mAudioSegment,
GST_FORMAT_TIME, timestamp);
timestamp = GST_TIME_AS_USECONDS(timestamp);
int64_t duration = 0;
if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
int64_t offset = GST_BUFFER_OFFSET(buffer);
unsigned int size = GST_BUFFER_SIZE(buffer);
int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudio.mChannels;
ssize_t outSize = static_cast<size_t>(size / sizeof(AudioDataValue));
nsAutoArrayPtr<AudioDataValue> data(new AudioDataValue[outSize]);
memcpy(data, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
AudioData* audio = new AudioData(offset, timestamp, duration,
frames, data.forget(), mInfo.mAudio.mChannels);
typedef AudioCompactor::NativeCopy GstCopy;
mAudioCompactor.Push(offset,
timestamp,
mInfo.mAudio.mRate,
frames,
mInfo.mAudio.mChannels,
GstCopy(GST_BUFFER_DATA(buffer),
size,
mInfo.mAudio.mChannels));
mAudioQueue.Push(audio);
gst_buffer_unref(buffer);
return true;

View File

@ -1,131 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "gtest/gtest.h"
#include "AudioCompactor.h"
#include "MediaDecoderReader.h"
using mozilla::AudioCompactor;
using mozilla::AudioData;
using mozilla::AudioDataValue;
using mozilla::MediaDecoderReader;
using mozilla::MediaQueue;
class TestCopy
{
public:
TestCopy(uint32_t aFrames, uint32_t aChannels,
uint32_t &aCallCount, uint32_t &aFrameCount)
: mFrames(aFrames)
, mChannels(aChannels)
, mCallCount(aCallCount)
, mFrameCount(aFrameCount)
{ }
uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples)
{
mCallCount += 1;
uint32_t frames = std::min(mFrames - mFrameCount, aSamples / mChannels);
mFrameCount += frames;
return frames;
}
private:
const uint32_t mFrames;
const uint32_t mChannels;
uint32_t &mCallCount;
uint32_t &mFrameCount;
};
static void TestAudioCompactor(size_t aBytes)
{
MediaQueue<AudioData> queue;
AudioCompactor compactor(queue);
uint64_t offset = 0;
uint64_t time = 0;
uint32_t sampleRate = 44000;
uint32_t channels = 2;
uint32_t frames = aBytes / (channels * sizeof(AudioDataValue));
size_t maxSlop = aBytes / AudioCompactor::MAX_SLOP_DIVISOR;
uint32_t callCount = 0;
uint32_t frameCount = 0;
compactor.Push(offset, time, sampleRate, frames, channels,
TestCopy(frames, channels, callCount, frameCount));
EXPECT_GT(callCount, 0U) << "copy functor never called";
EXPECT_EQ(frames, frameCount) << "incorrect number of frames copied";
MediaDecoderReader::AudioQueueMemoryFunctor memoryFunc;
queue.LockedForEach(memoryFunc);
size_t allocSize = memoryFunc.mSize - (callCount * sizeof(AudioData));
size_t slop = allocSize - aBytes;
EXPECT_LE(slop, maxSlop) << "allowed too much allocation slop";
}
TEST(Media, AudioCompactor_4000)
{
TestAudioCompactor(4000);
}
TEST(Media, AudioCompactor_4096)
{
TestAudioCompactor(4096);
}
TEST(Media, AudioCompactor_5000)
{
TestAudioCompactor(5000);
}
TEST(Media, AudioCompactor_5256)
{
TestAudioCompactor(5256);
}
TEST(Media, AudioCompactor_NativeCopy)
{
const uint32_t channels = 2;
const size_t srcBytes = 32;
const uint32_t srcSamples = srcBytes / sizeof(AudioDataValue);
const uint32_t srcFrames = srcSamples / channels;
uint8_t src[srcBytes];
for (uint32_t i = 0; i < srcBytes; ++i) {
src[i] = i;
}
AudioCompactor::NativeCopy copy(src, srcBytes, channels);
const uint32_t dstSamples = srcSamples * 2;
AudioDataValue dst[dstSamples];
const AudioDataValue notCopied = 0xffff;
for (uint32_t i = 0; i < dstSamples; ++i) {
dst[i] = notCopied;
}
const uint32_t copyCount = 8;
uint32_t copiedFrames = 0;
uint32_t nextSample = 0;
for (uint32_t i = 0; i < copyCount; ++i) {
uint32_t copySamples = dstSamples / copyCount;
copiedFrames += copy(dst + nextSample, copySamples);
nextSample += copySamples;
}
EXPECT_EQ(srcFrames, copiedFrames) << "copy exact number of source frames";
// Verify that the only the correct bytes were copied.
for (uint32_t i = 0; i < dstSamples; ++i) {
if (i < srcSamples) {
EXPECT_NE(notCopied, dst[i]) << "should have copied over these bytes";
} else {
EXPECT_EQ(notCopied, dst[i]) << "should not have copied over these bytes";
}
}
}

View File

@ -7,7 +7,6 @@
LIBRARY_NAME = 'media_gtest'
UNIFIED_SOURCES += [
'TestAudioCompactor.cpp',
'TestTrackEncoder.cpp',
]

View File

@ -58,7 +58,6 @@ EXPORTS += [
'AbstractMediaDecoder.h',
'AudioAvailableEventManager.h',
'AudioChannelFormat.h',
'AudioCompactor.h',
'AudioEventTimeline.h',
'AudioNodeEngine.h',
'AudioNodeExternalInputStream.h',
@ -116,7 +115,6 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
'AudioAvailableEventManager.cpp',
'AudioChannelFormat.cpp',
'AudioCompactor.cpp',
'AudioNodeEngine.cpp',
'AudioNodeExternalInputStream.cpp',
'AudioNodeStream.cpp',

View File

@ -312,29 +312,33 @@ bool MediaOmxReader::DecodeAudioData()
int64_t pos = mDecoder->GetResource()->Tell();
// Read next frame
MPAPI::AudioFrame source;
if (!mOmxDecoder->ReadAudio(&source, mAudioSeekTimeUs)) {
MPAPI::AudioFrame frame;
if (!mOmxDecoder->ReadAudio(&frame, mAudioSeekTimeUs)) {
return false;
}
mAudioSeekTimeUs = -1;
// Ignore empty buffer which stagefright media read will sporadically return
if (source.mSize == 0) {
if (frame.mSize == 0) {
return true;
}
uint32_t frames = source.mSize / (source.mAudioChannels *
sizeof(AudioDataValue));
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frame.mSize/2] );
memcpy(buffer.get(), frame.mData, frame.mSize);
typedef AudioCompactor::NativeCopy OmxCopy;
return mAudioCompactor.Push(pos,
source.mTimeUs,
source.mAudioSampleRate,
frames,
source.mAudioChannels,
OmxCopy(static_cast<uint8_t *>(source.mData),
source.mSize,
source.mAudioChannels));
uint32_t frames = frame.mSize / (2 * frame.mAudioChannels);
CheckedInt64 duration = FramesToUsecs(frames, frame.mAudioSampleRate);
if (!duration.isValid()) {
return false;
}
mAudioQueue.Push(new AudioData(pos,
frame.mTimeUs,
duration.value(),
frames,
buffer.forget(),
frame.mAudioChannels));
return true;
}
nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)

View File

@ -1886,7 +1886,7 @@ InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(instance, true));
if (unwrapped && jsipc::JavaScriptParent::IsCPOW(unwrapped)) {
bool boolp = false;
if (!jsipc::JavaScriptParent::DOMInstanceOf(unwrapped, clasp->mPrototypeID,
if (!jsipc::JavaScriptParent::DOMInstanceOf(cx, unwrapped, clasp->mPrototypeID,
clasp->mDepth, &boolp)) {
return false;
}

View File

@ -1467,7 +1467,7 @@ BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
}
// Listen as a server if there's no more batch to process
if (!ProcessNextBatch()) {
if (!ProcessNextBatch() && !mIsServer) {
Listen();
}
}

View File

@ -11,7 +11,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944397
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=944397">Mozilla Bug 944397</a>
<input type="text" />
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
@ -26,6 +25,14 @@ function appFrameScript() {
input.oninput = function() {
sendAsyncMessage('test:InputMethod:oninput', {});
};
/*
* Bug 957213. Sometimes we need to refocus the input field to avoid
* intermittent test failure.
*/
content.setInterval(function() {
input.focus();
}, 500);
}
function runTest() {
@ -40,8 +47,12 @@ function runTest() {
let mm = SpecialPowers.getBrowserFrameMessageManager(app);
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
mm.addMessageListener("test:InputMethod:oninput", function() {
if (!timeoutId) {
return;
}
ok(true, 'Keyboard input was received.');
clearTimeout(timeoutId);
timeoutId = null;
inputmethod_cleanup();
});
});
@ -80,7 +91,7 @@ function runTest() {
timeoutId = setTimeout(function() {
inputmethod_cleanup();
ok(false, 'Failed to generate keyboard input.');
}, 60000);
}, 20000);
};
req.onerror = function() {
@ -89,6 +100,7 @@ function runTest() {
};
// Loads the input method app to the browser frame after a delay.
SpecialPowers.DOMWindowUtils.focus(app);
setTimeout(function() {
keyboard.src = imeUrl;
}, 100);

View File

@ -92,6 +92,10 @@
#define getpid _getpid
#endif
#ifdef MOZ_X11
#include "mozilla/X11Util.h"
#endif
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#endif
@ -352,6 +356,13 @@ ContentChild::Init(MessageLoop* aIOLoop,
Open(aChannel, aParentHandle, aIOLoop);
sSingleton = this;
#ifdef MOZ_X11
// Send the parent our X socket to act as a proxy reference for our X
// resources.
int xSocketFd = ConnectionNumber(DefaultXDisplay());
SendBackUpXResources(FileDescriptor(xSocketFd));
#endif
#ifdef MOZ_CRASHREPORTER
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
XRE_GetProcessType());

View File

@ -2012,7 +2012,7 @@ ContentParent::AllocPJavaScriptParent()
bool
ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
{
static_cast<mozilla::jsipc::JavaScriptParent *>(parent)->destroyFromContent();
static_cast<mozilla::jsipc::JavaScriptParent *>(parent)->decref();
return true;
}
@ -3258,6 +3258,22 @@ ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, const uint32_t&
return true;
}
bool
ContentParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
{
#ifndef MOZ_X11
NS_RUNTIMEABORT("This message only makes sense on X11 platforms");
#else
NS_ABORT_IF_FALSE(0 > mChildXSocketFdDup.get(),
"Already backed up X resources??");
mChildXSocketFdDup.forget();
if (aXSocketFd.IsValid()) {
mChildXSocketFdDup.reset(aXSocketFd.PlatformHandle());
}
#endif
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -11,6 +11,7 @@
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/Attributes.h"
#include "mozilla/FileUtils.h"
#include "mozilla/HalTypes.h"
#include "mozilla/LinkedList.h"
#include "mozilla/StaticPtr.h"
@ -534,6 +535,9 @@ private:
virtual bool RecvRemoveIdleObserver(const uint64_t& observerId,
const uint32_t& aIdleTimeInS) MOZ_OVERRIDE;
virtual bool
RecvBackUpXResources(const FileDescriptor& aXSocketFd) MOZ_OVERRIDE;
// If you add strong pointers to cycle collected objects here, be sure to
// release these objects in ShutDownProcess. See the comment there for more
// details.
@ -586,6 +590,12 @@ private:
nsConsoleService* GetConsoleService();
nsDataHashtable<nsUint64HashKey, nsCOMPtr<ParentIdleListener> > mIdleListeners;
#ifdef MOZ_X11
// Dup of child's X socket, used to scope its resources to this
// object instead of the child process's lifetime.
ScopedClose mChildXSocketFdDup;
#endif
};
} // namespace dom

View File

@ -519,6 +519,20 @@ parent:
AddIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
RemoveIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
/**
* This message is only used on X11 platforms.
*
* Send a dup of the plugin process's X socket to the parent
* process. In theory, this scheme keeps the plugin's X resources
* around until after both the plugin process shuts down *and* the
* parent process closes the dup fd. This is used to prevent the
* parent process from crashing on X errors if, e.g., the plugin
* crashes *just before* a repaint and the parent process tries to
* use the newly-invalid surface.
*/
BackUpXResources(FileDescriptor aXSocketFd);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal);

View File

@ -610,7 +610,7 @@ TabChild::HandlePossibleViewportChange()
// The page must have been refreshed in some way such as a new document or
// new CSS viewport, so we know that there's no velocity, acceleration, and
// we have no idea how long painting will take.
metrics, ScreenPoint(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
metrics, ScreenPoint(0.0f, 0.0f), 0.0);
metrics.mCumulativeResolution = metrics.mZoom / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.

View File

@ -29,6 +29,15 @@ const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
const NET_TYPE_MOBILE = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE;
// Networks have different status that NetworkStats API needs to be aware of.
// Network is present and ready, so NetworkManager provides the whole info.
const NETWORK_STATUS_READY = 0;
// Network is present but hasn't established a connection yet (e.g. SIM that has not
// enabled 3G since boot).
const NETWORK_STATUS_STANDBY = 1;
// Network is not present, but stored in database by the previous connections.
const NETWORK_STATUS_AWAY = 2;
// The maximum traffic amount can be saved in the |cachedStats|.
const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB
@ -89,7 +98,8 @@ this.NetworkStatsService = {
let netId = this.getNetworkId('0', NET_TYPE_WIFI);
this._networks[netId] = { network: { id: '0',
type: NET_TYPE_WIFI },
interfaceName: null };
interfaceName: null,
status: NETWORK_STATUS_STANDBY };
this.messages = ["NetworkStats:Get",
"NetworkStats:Clear",
@ -278,6 +288,7 @@ this.NetworkStatsService = {
type: aNetwork.type };
}
this._networks[netId].status = NETWORK_STATUS_READY;
this._networks[netId].interfaceName = aNetwork.name;
return netId;
},
@ -286,6 +297,46 @@ this.NetworkStatsService = {
return aIccId + '' + aNetworkType;
},
/* Function to ensure that one network is valid. The network is valid if its status is
* NETWORK_STATUS_READY, NETWORK_STATUS_STANDBY or NETWORK_STATUS_AWAY.
*
* The result is |netId| or null in case of a non-valid network
* aCallback is signatured as |function(netId)|.
*/
validateNetwork: function validateNetwork(aNetwork, aCallback) {
let netId = this.getNetworkId(aNetwork.id, aNetwork.type);
if (this._networks[netId]) {
aCallback(netId);
return;
}
// Check if network is valid (RIL entry) but has not established a connection yet.
// If so add to networks list with empty interfaceName.
let rilNetworks = this.getRilNetworks();
if (rilNetworks[netId]) {
this._networks[netId] = Object.create(null);
this._networks[netId].network = rilNetworks[netId];
this._networks[netId].status = NETWORK_STATUS_STANDBY;
this._currentAlarms[netId] = Object.create(null);
aCallback(netId);
return;
}
// Check if network is available in the DB.
this._db.isNetworkAvailable(aNetwork, function(aError, aResult) {
if (aResult) {
this._networks[netId] = Object.create(null);
this._networks[netId].network = aNetwork;
this._networks[netId].status = NETWORK_STATUS_AWAY;
this._currentAlarms[netId] = Object.create(null);
aCallback(netId);
}
aCallback(null);
});
},
getAvailableNetworks: function getAvailableNetworks(mm, msg) {
let self = this;
let rilNetworks = this.getRilNetworks();
@ -368,91 +419,55 @@ this.NetworkStatsService = {
let start = new Date(msg.start);
let end = new Date(msg.end);
// Check if the network is currently active. If yes, we need to update
// the cached stats first before retrieving stats from the DB.
if (this._networks[netId]) {
this.updateStats(netId, function onStatsUpdated(aResult, aMessage) {
debug("getstats for network " + network.id + " of type " + network.type);
debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
self.updateCachedStats(function onStatsUpdated(aResult, aMessage) {
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
});
return;
}
// Check if the network is available in the DB. If yes, we also
// retrieve the stats for it from the DB.
this._db.isNetworkAvailable(network, function(aError, aResult) {
let toFind = false;
if (aResult) {
toFind = true;
} else if (!aError) {
// Network is not found in the database without any errors.
// Check if network is valid but has not established a connection yet.
let rilNetworks = self.getRilNetworks();
if (rilNetworks[netId]) {
// find will not get data for network from the database but will format the
// result object in order to make NetworkStatsManager be able to construct a
// nsIDOMMozNetworkStats object.
toFind = true;
}
}
if (toFind) {
// If network is not active, there is no need to update stats before finding.
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: "Invalid connectionType", result: null });
return;
}
if (!aError) {
aError = "Invalid connectionType";
// If network is currently active we need to update the cached stats first before
// retrieving stats from the DB.
if (self._networks[aNetId].status == NETWORK_STATUS_READY) {
self.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) {
debug("getstats for network " + network.id + " of type " + network.type);
debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
self.updateCachedStats(function onStatsUpdated(aResult, aMessage) {
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
});
return;
}
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: null });
// Network not active, so no need to update
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
},
clearInterfaceStats: function clearInterfaceStats(mm, msg) {
let self = this;
let network = msg.network;
let netId = this.getNetworkId(network.id, network.type);
debug("clear stats for network " + network.id + " of type " + network.type);
if (!this._networks[netId]) {
// Check if network is valid but has not established a connection yet. If it is not
// found in RIL networks, it can be a SIM network used in the past having sample
// in the database.
let rilNetworks = this.getRilNetworks();
if (!rilNetworks[netId]) {
// Check if it is available in the DB.
this._db.isNetworkAvailable(network, function(aError, aResult) {
if (aResult) {
this._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: aError, result: aResult });
});
return;
}
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: "Invalid networkType", result: null });
});
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: "Invalid connectionType", result: null });
return;
}
}
this._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: aError, result: aResult });
self._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: aError, result: aResult });
});
});
},
@ -478,7 +493,7 @@ this.NetworkStatsService = {
this.updateCachedStats();
let elements = [];
let lastElement;
let lastElement = null;
// For each connectionType create an object containning the type
// and the 'queueIndex', the 'queueIndex' is an integer representing
@ -487,14 +502,27 @@ this.NetworkStatsService = {
// else it is pushed in 'elements' array, which later will be pushed to
// the queue array.
for (let netId in this._networks) {
if (this._networks[netId].status != NETWORK_STATUS_READY) {
continue;
}
lastElement = { netId: netId,
queueIndex: this.updateQueueIndex(netId)};
if (lastElement.queueIndex == -1) {
elements.push({netId: lastElement.netId, callbacks: []});
elements.push({ netId: lastElement.netId, callbacks: [] });
}
}
if (!lastElement) {
// No elements need to be updated, probably because status is different than
// NETWORK_STATUS_READY.
if (aCallback) {
aCallback(true, "OK");
}
return;
}
if (elements.length > 0) {
// If length of elements is greater than 0, callback is set to
// the last element.
@ -800,21 +828,29 @@ this.NetworkStatsService = {
},
getAlarms: function getAlarms(mm, msg) {
let self = this;
let network = msg.data.network;
let manifestURL = msg.data.manifestURL;
let netId = null;
if (network) {
netId = this.getNetworkId(network.id, network.type);
if (!this._networks[netId]) {
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
{ id: msg.id, error: "InvalidInterface", result: null });
return;
}
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
{ id: msg.id, error: "InvalidInterface", result: null });
return;
}
self._getAlarms(mm, msg, aNetId, manifestURL);
});
return;
}
this._getAlarms(mm, msg, null, manifestURL);
},
_getAlarms: function _getAlarms(mm, msg, aNetId, aManifestURL) {
let self = this;
this._db.getAlarms(netId, manifestURL, function onCompleted(error, result) {
this._db.getAlarms(aNetId, aManifestURL, function onCompleted(error, result) {
if (error) {
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
{ id: msg.id, error: error, result: result });
@ -884,48 +920,49 @@ this.NetworkStatsService = {
return;
}
let netId = this.getNetworkId(network.id, network.type);
if (!this._networks[netId]) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: "InvalidiConnectionType", result: null });
return;
}
let newAlarm = {
id: null,
networkId: netId,
threshold: threshold,
absoluteThreshold: null,
startTime: options.startTime,
data: options.data,
pageURL: options.pageURL,
manifestURL: options.manifestURL
};
let self = this;
this._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
if (error) {
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: null });
{ id: msg.id, error: "InvalidiConnectionType", result: null });
return;
}
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) {
let newAlarm = {
id: null,
networkId: aNetId,
threshold: threshold,
absoluteThreshold: null,
startTime: options.startTime,
data: options.data,
pageURL: options.pageURL,
manifestURL: options.manifestURL
};
self._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
if (error) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: null });
return;
}
newAlarm.id = newId;
self._setAlarm(newAlarm, function onSet(error, success) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: newId });
if (error == "InvalidStateError") {
self._fireAlarm(newAlarm);
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) {
if (error) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: null });
return;
}
newAlarm.id = newId;
self._setAlarm(newAlarm, function onSet(error, success) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: newId });
if (error == "InvalidStateError") {
self._fireAlarm(newAlarm);
}
});
});
});
});
@ -933,8 +970,9 @@ this.NetworkStatsService = {
_setAlarm: function _setAlarm(aAlarm, aCallback) {
let currentAlarm = this._currentAlarms[aAlarm.networkId];
if (Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) {
if ((Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) ||
this._networks[aAlarm.networkId].status != NETWORK_STATUS_READY) {
aCallback(null, true);
return;
}
@ -985,6 +1023,14 @@ this.NetworkStatsService = {
return;
}
if (!result) {
// There are no stats for the network of the alarm, set them to default 0 in
// order to be able to calculate the offset, systemThreshold and
// absoluteThreshold.
result = { rxTotalBytes: 0, txTotalBytes: 0,
rxSystemBytes: 0, txSystemBytes: 0 };
}
let offset = aAlarm.threshold - result.rxTotalBytes - result.txTotalBytes;
// Alarm set to a threshold lower than current rx/tx bytes.

View File

@ -3,6 +3,10 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const NETWORK_STATUS_READY = 0;
const NETWORK_STATUS_STANDBY = 1;
const NETWORK_STATUS_AWAY = 2;
function getNetworks(callback) {
NetworkStatsService._db.getAvailableNetworks(function onGetNetworks(aError, aResult) {
callback(aError, aResult);
@ -85,9 +89,18 @@ add_test(function test_updateQueueIndex() {
});
add_test(function test_updateAllStats() {
NetworkStatsService._networks[wifiId].status = NETWORK_STATUS_READY;
NetworkStatsService.updateAllStats(function(success, msg) {
do_check_eq(success, true);
run_next_test();
NetworkStatsService._networks[wifiId].status = NETWORK_STATUS_STANDBY;
NetworkStatsService.updateAllStats(function(success, msg) {
do_check_eq(success, true);
NetworkStatsService._networks[wifiId].status = NETWORK_STATUS_AWAY;
NetworkStatsService.updateAllStats(function(success, msg) {
do_check_eq(success, true);
run_next_test();
});
});
});
});
@ -189,6 +202,8 @@ add_test(function test_setAlarm_invalid_threshold() {
pageURL: testPageURL,
manifestURL: testManifestURL };
NetworkStatsService._networks[wifiId].status = NETWORK_STATUS_READY;
NetworkStatsService._setAlarm(alarm, function onSet(error, result) {
do_check_eq(error, "InvalidStateError");
run_next_test();

View File

@ -93,9 +93,6 @@ let PaymentManager = {
if (!pr) {
continue;
}
if (!(pr instanceof Ci.nsIDOMPaymentRequestInfo)) {
return;
}
// We consider jwt type repetition an error.
if (jwtTypes[pr.type]) {
this.paymentFailed(requestId,
@ -342,17 +339,7 @@ let PaymentManager = {
}
let pldRequest = payloadObject.request;
let request = Cc["@mozilla.org/payment/request-info;1"]
.createInstance(Ci.nsIDOMPaymentRequestInfo);
if (!request) {
this.paymentFailed(aRequestId,
"INTERNAL_ERROR_ERROR_CREATING_PAY_REQUEST");
return true;
}
request.wrappedJSObject.init(aJwt,
payloadObject.typ,
provider.name);
return request;
return { jwt: aJwt, type: payloadObject.typ, providerName: provider.name };
},
showPaymentFlow: function showPaymentFlow(aRequestId,

View File

@ -4,6 +4,3 @@ category JavaScript-navigator-property mozPay @mozilla.org/payment/content-helpe
component {b8bce4e7-fbf0-4719-a634-b1bf9018657c} PaymentFlowInfo.js
contract @mozilla.org/payment/flow-info;1 {b8bce4e7-fbf0-4719-a634-b1bf9018657c}
component {0a58c67d-f003-48da-81d1-bd8f605f4b1c} PaymentRequestInfo.js
contract @mozilla.org/payment/request-info;1 {0a58c67d-f003-48da-81d1-bd8f605f4b1c}

View File

@ -1,41 +0,0 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const PAYMENTREQUESTINFO_CID =
Components.ID("{0a58c67d-f003-48da-81d1-bd8f605f4b1c}");
// nsIDOMPaymentRequestInfo
function PaymentRequestInfo() {
this.wrappedJSObject = this;
};
PaymentRequestInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestInfo]),
classID: PAYMENTREQUESTINFO_CID,
classInfo: XPCOMUtils.generateCI({
classID: PAYMENTREQUESTINFO_CID,
contractID: "@mozilla.org/payment/request-info;1",
classDescription: "Payment request information",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMPaymentRequestInfo]
}),
jwt: null,
type: null,
providerName: null,
init: function init(aJwt, aType, aProviderName) {
this.jwt = aJwt;
this.type = aType;
this.providerName = aProviderName;
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentRequestInfo]);

View File

@ -5,7 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIDOMPaymentRequestInfo.idl',
'nsINavigatorPayment.idl',
'nsIPaymentFlowInfo.idl',
'nsIPaymentUIGlue.idl',

View File

@ -1,19 +0,0 @@
/* 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 "nsISupports.idl"
[scriptable, uuid(93462984-0e9a-4016-bdb4-a24a88c08a29)]
interface nsIDOMPaymentRequestInfo : nsISupports
{
// Base64 encoded and digitally signed payment request.
readonly attribute DOMString jwt;
// JWT type that identifies the payment provider owner of the payment request
// format.
readonly attribute DOMString type;
// Payment provider name.
readonly attribute DOMString providerName;
};

View File

@ -16,6 +16,5 @@ EXTRA_COMPONENTS += [
'Payment.js',
'Payment.manifest',
'PaymentFlowInfo.js',
'PaymentRequestInfo.js',
]

View File

@ -288,6 +288,11 @@ static bool gCrossSlideEnabled = false;
*/
static bool gUseProgressiveTilePainting = false;
/**
* Pref that allows or disallows checkerboarding
*/
static bool gAllowCheckerboarding = true;
/**
* Is aAngle within the given threshold of the horizontal axis?
* @param aAngle an angle in radians in the range [0, pi]
@ -412,6 +417,7 @@ AsyncPanZoomController::InitializeGlobalState()
Preferences::AddIntVarCache(&gAsyncScrollTimeout, "apz.asyncscroll.timeout", gAsyncScrollTimeout);
Preferences::AddBoolVarCache(&gCrossSlideEnabled, "apz.cross_slide.enabled", gCrossSlideEnabled);
Preferences::AddIntVarCache(&gAxisLockMode, "apz.axis_lock_mode", gAxisLockMode);
Preferences::AddBoolVarCache(&gAllowCheckerboarding, "apz.allow-checkerboarding", gAllowCheckerboarding);
gUseProgressiveTilePainting = gfxPlatform::UseProgressiveTilePainting();
gComputedTimingFunction = new ComputedTimingFunction();
@ -994,10 +1000,6 @@ const ScreenPoint AsyncPanZoomController::GetVelocityVector() {
return ScreenPoint(mX.GetVelocity(), mY.GetVelocity());
}
const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
return gfx::Point(mX.GetAccelerationFactor(), mY.GetAccelerationFactor());
}
void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle, TouchBehaviorFlags aBehavior) {
// Handling of cross sliding will need to be added in this method after touch-action released
// enabled by default.
@ -1309,7 +1311,6 @@ EnlargeDisplayPortAlongAxis(float* aOutOffset, float* aOutLength,
const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
const FrameMetrics& aFrameMetrics,
const ScreenPoint& aVelocity,
const gfx::Point& aAcceleration,
double aEstimatedPaintDuration)
{
// convert to milliseconds
@ -1343,10 +1344,9 @@ const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
displayPort = displayPort.ForceInside(scrollableRect) - scrollOffset;
APZC_LOG_FM(aFrameMetrics,
"Calculated displayport as (%f %f %f %f) from velocity (%f %f) acceleration (%f %f) paint time %f metrics",
"Calculated displayport as (%f %f %f %f) from velocity (%f %f) paint time %f metrics",
displayPort.x, displayPort.y, displayPort.width, displayPort.height,
aVelocity.x, aVelocity.y, aAcceleration.x, aAcceleration.y,
(float)estimatedPaintDurationMillis);
aVelocity.x, aVelocity.y, (float)estimatedPaintDurationMillis);
return displayPort;
}
@ -1365,7 +1365,6 @@ void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics)
aFrameMetrics.mDisplayPort =
CalculatePendingDisplayPort(aFrameMetrics,
GetVelocityVector(),
GetAccelerationVector(),
mPaintThrottler.AverageDuration().ToSeconds());
// If we're trying to paint what we already think is painted, discard this
@ -1537,7 +1536,28 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
if (mLastContentPaintMetrics.IsScrollable()) {
lastPaintScrollOffset = mLastContentPaintMetrics.mScrollOffset;
}
LayerPoint translation = (mFrameMetrics.mScrollOffset - lastPaintScrollOffset)
CSSPoint currentScrollOffset = mFrameMetrics.mScrollOffset;
// If checkerboarding has been disallowed, clamp the scroll position to stay
// within rendered content.
if (!gAllowCheckerboarding &&
!mLastContentPaintMetrics.mDisplayPort.IsEmpty()) {
CSSRect compositedRect = mLastContentPaintMetrics.CalculateCompositedRectInCssPixels();
CSSPoint maxScrollOffset = lastPaintScrollOffset +
CSSPoint(mLastContentPaintMetrics.mDisplayPort.XMost() - compositedRect.width,
mLastContentPaintMetrics.mDisplayPort.YMost() - compositedRect.height);
CSSPoint minScrollOffset = lastPaintScrollOffset + mLastContentPaintMetrics.mDisplayPort.TopLeft();
if (minScrollOffset.x < maxScrollOffset.x) {
currentScrollOffset.x = clamped(currentScrollOffset.x, minScrollOffset.x, maxScrollOffset.x);
}
if (minScrollOffset.y < maxScrollOffset.y) {
currentScrollOffset.y = clamped(currentScrollOffset.y, minScrollOffset.y, maxScrollOffset.y);
}
}
LayerPoint translation = (currentScrollOffset - lastPaintScrollOffset)
* mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
return ViewTransform(-translation,
@ -1720,7 +1740,6 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
endZoomToMetrics.mDisplayPort =
CalculatePendingDisplayPort(endZoomToMetrics,
ScreenPoint(0,0),
gfx::Point(0,0),
0);
StartAnimation(new ZoomAnimation(

View File

@ -240,7 +240,6 @@ public:
static const CSSRect CalculatePendingDisplayPort(
const FrameMetrics& aFrameMetrics,
const ScreenPoint& aVelocity,
const gfx::Point& aAcceleration,
double aEstimatedPaintDuration);
/**
@ -438,11 +437,6 @@ protected:
*/
const ScreenPoint GetVelocityVector();
/**
* Gets a vector of the acceleration factors of each axis.
*/
const gfx::Point GetAccelerationVector();
/**
* Gets a reference to the first touch point from a MultiTouchInput. This
* gets only the first one and assumes the rest are either missing or not

View File

@ -33,22 +33,6 @@ static float gMaxEventAcceleration = 999.0f;
*/
static float gFlingFriction = 0.002f;
/**
* Threshold for velocity beneath which we turn off any acceleration we had
* during repeated flings.
*/
static float gVelocityThreshold = 0.14f;
/**
* Amount of acceleration we multiply in each time the user flings in one
* direction. Every time they let go of the screen, we increase the acceleration
* by this amount raised to the power of the amount of times they have let go,
* times two (to make the curve steeper). This stops if the user lets go and we
* slow down enough, or if they put their finger down without moving it for a
* moment (or in the opposite direction).
*/
static float gAccelerationMultiplier = 1.125f;
/**
* When flinging, if the velocity goes below this number, we just stop the
* animation completely. This is to prevent asymptotically approaching 0
@ -67,8 +51,6 @@ static void ReadAxisPrefs()
{
Preferences::AddFloatVarCache(&gMaxEventAcceleration, "apz.max_event_acceleration", gMaxEventAcceleration);
Preferences::AddFloatVarCache(&gFlingFriction, "apz.fling_friction", gFlingFriction);
Preferences::AddFloatVarCache(&gVelocityThreshold, "apz.velocity_threshold", gVelocityThreshold);
Preferences::AddFloatVarCache(&gAccelerationMultiplier, "apz.acceleration_multiplier", gAccelerationMultiplier);
Preferences::AddFloatVarCache(&gFlingStoppedThreshold, "apz.fling_stopped_threshold", gFlingStoppedThreshold);
Preferences::AddUintVarCache(&gMaxVelocityQueueSize, "apz.max_velocity_queue_size", gMaxVelocityQueueSize);
}
@ -100,7 +82,6 @@ static void InitAxisPrefs()
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
: mPos(0),
mVelocity(0.0f),
mAcceleration(0),
mAxisLocked(false),
mAsyncPanZoomController(aAsyncPanZoomController)
{
@ -110,15 +91,6 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) {
float newVelocity = mAxisLocked ? 0 : (mPos - aPos) / aTimeDelta.ToMilliseconds();
bool curVelocityBelowThreshold = fabsf(newVelocity) < gVelocityThreshold;
bool directionChange = (mVelocity > 0) != (newVelocity > 0);
// If we've changed directions, or the current velocity threshold, stop any
// acceleration we've accumulated.
if (directionChange || curVelocityBelowThreshold) {
mAcceleration = 0;
}
mVelocity = newVelocity;
mPos = aPos;
@ -145,23 +117,17 @@ float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut,
if (aScrollingDisabled) {
// Scrolling is disabled on this axis, stop scrolling.
aOverscrollAmountOut = aDisplacement;
mAcceleration = 0;
return 0;
}
if (fabsf(mVelocity) < gVelocityThreshold) {
mAcceleration = 0;
}
float displacement = aDisplacement;
float accelerationFactor = GetAccelerationFactor();
float displacement = aDisplacement * accelerationFactor;
// If this displacement will cause an overscroll, throttle it. Can potentially
// bring it to 0 even if the velocity is high.
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
// No need to have a velocity along this axis anymore; it won't take us
// anywhere, so we're just spinning needlessly.
mVelocity = 0.0f;
mAcceleration = 0;
aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
displacement -= aOverscrollAmountOut;
}
@ -177,8 +143,6 @@ float Axis::PanDistance(float aPos) {
}
void Axis::EndTouch() {
mAcceleration++;
// Calculate the mean velocity and empty the queue.
int count = mVelocityQueue.Length();
if (count) {
@ -193,7 +157,6 @@ void Axis::EndTouch() {
void Axis::CancelTouch() {
mVelocity = 0.0f;
mAcceleration = 0;
while (!mVelocityQueue.IsEmpty()) {
mVelocityQueue.RemoveElementAt(0);
}
@ -302,10 +265,6 @@ float Axis::GetVelocity() {
return mAxisLocked ? 0 : mVelocity;
}
float Axis::GetAccelerationFactor() {
return powf(gAccelerationMultiplier, std::max(0, (mAcceleration - 4) * 3));
}
float Axis::GetCompositionEnd() {
return GetOrigin() + GetCompositionLength();
}

View File

@ -70,12 +70,11 @@ public:
void CancelTouch();
/**
* Takes a requested displacement to the position of this axis, and adjusts
* it to account for acceleration (which might increase the displacement),
* overscroll (which might decrease the displacement; this is to prevent the
* viewport from overscrolling the page rect), and axis locking (which might
* prevent any displacement from happening). If overscroll ocurred, its amount
* is written to |aOverscrollAmountOut|.
* Takes a requested displacement to the position of this axis, and adjusts it
* to account for overscroll (which might decrease the displacement; this is
* to prevent the viewport from overscrolling the page rect), and axis locking
* (which might prevent any displacement from happening). If overscroll
* ocurred, its amount is written to |aOverscrollAmountOut|.
* The adjusted displacement is returned.
*
* aScrollingDisabled is used to indicate that no scrolling should happen
@ -128,12 +127,6 @@ public:
*/
float GetExcess();
/**
* Gets the factor of acceleration applied to the velocity, based on the
* amount of flings that have been done successively.
*/
float GetAccelerationFactor();
/**
* Gets the raw velocity of this axis at this moment.
*/
@ -188,12 +181,6 @@ protected:
int32_t mPos;
int32_t mStartPos;
float mVelocity;
// Acceleration is represented by an int, which is the power we raise a
// constant to and then multiply the velocity by whenever it is sampled. We do
// this only when we detect that the user wants to do a fast fling; that is,
// they are flinging multiple times in a row very quickly, probably trying to
// reach one of the extremes of the page.
int32_t mAcceleration;
bool mAxisLocked; // Whether movement on this axis is locked.
AsyncPanZoomController* mAsyncPanZoomController;
nsTArray<float> mVelocityQueue;

View File

@ -581,7 +581,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
const std::map<uint32_t, OpenTypeTable>::const_iterator it
= table_map.find(Tag(table_parsers[i].tag));
ots::TableAction action = GetTableAction(it->first);
ots::TableAction action = GetTableAction(Tag(table_parsers[i].tag));
if (it == table_map.end()) {
if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);

View File

@ -22,6 +22,10 @@
#include "mozilla/ipc/MessageLink.h"
#include "mozilla/LinkedList.h"
#if defined(ANDROID) && defined(DEBUG)
#include <android/log.h>
#endif
// WARNING: this takes into account the private, special-message-type
// enum in ipc_channel.h. They need to be kept in sync.
namespace {

View File

@ -1825,11 +1825,13 @@ def _generateMessageClass(clsname, msgid, prettyName, compress):
# generate a logging function
# 'pfx' will be something like "[FooParent] sent"
pfxvar = ExprVar('__pfx')
outfvar = ExprVar('__outf')
otherprocess = ExprVar('__otherProcess')
receiving = ExprVar('__receiving')
logger = MethodDefn(MethodDecl(
'Log',
params=([ Decl(Type('std::string', const=1, ref=1), pfxvar.name),
Decl(Type('FILE', ptr=True), outfvar.name) ]),
Decl(Type('base::ProcessHandle'), otherprocess.name),
Decl(Type('bool'), receiving.name) ]),
const=1))
# TODO/cjones: allow selecting what information is printed to
# the log
@ -1843,9 +1845,12 @@ def _generateMessageClass(clsname, msgid, prettyName, compress):
StmtExpr(ExprCall(
ExprVar('StringAppendF'),
args=[ ExprAddrOf(msgvar),
ExprLiteral.String('[time:%" PRId64 "][%d]'),
ExprLiteral.String('[time:%" PRId64 "][%d%s%d]'),
ExprCall(ExprVar('PR_Now')),
ExprCall(ExprVar('base::GetCurrentProcId')) ])),
ExprCall(ExprVar('base::GetCurrentProcId')),
ExprConditional(receiving, ExprLiteral.String('<-'),
ExprLiteral.String('->')),
otherprocess ])),
appendToMsg(pfxvar),
appendToMsg(ExprLiteral.String(clsname +'(')),
Whitespace.NL
@ -1855,10 +1860,21 @@ def _generateMessageClass(clsname, msgid, prettyName, compress):
logger.addstmt(appendToMsg(ExprLiteral.String('[TODO])\\n')))
logger.addstmts([
CppDirective('ifdef', 'ANDROID'),
StmtExpr(ExprCall(
ExprVar('__android_log_write'),
args=[ ExprVar('ANDROID_LOG_INFO'),
ExprLiteral.String('GeckoIPC'),
ExprCall(ExprSelect(msgvar, '.', 'c_str')) ])),
CppDirective('endif')
])
# and actually print the log message
logger.addstmt(StmtExpr(ExprCall(
ExprVar('fputs'),
args=[ ExprCall(ExprSelect(msgvar, '.', 'c_str')), outfvar ])))
args=[ ExprCall(ExprSelect(msgvar, '.', 'c_str')),
ExprVar('stderr') ])))
cls.addstmt(logger)
@ -4929,7 +4945,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
+ sendstmts)
destmts = self.deserializeReply(
md, ExprAddrOf(replyvar), self.side, errfnSend)
md, ExprAddrOf(replyvar), self.side, errfnSend, actorvar)
ifsendok = StmtIf(ExprLiteral.FALSE)
ifsendok.addifstmts(destmts)
ifsendok.addifstmts([ Whitespace.NL,
@ -5165,7 +5181,8 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
'.', 'set_name'),
args=[ ExprLiteral.String(md.prettyMsgName(self.protocol.name
+'::')) ])),
self.logMessage(md, md.msgCast(msgexpr), 'Received '),
self.logMessage(md, md.msgCast(msgexpr), 'Received ',
receiving=True),
self.profilerLabel('Recv', md.decl.progname),
Whitespace.NL
])
@ -5200,10 +5217,10 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return stmts
def deserializeReply(self, md, replyexpr, side, errfn):
def deserializeReply(self, md, replyexpr, side, errfn, actor=None):
stmts = [ Whitespace.NL,
self.logMessage(md, md.replyCast(replyexpr),
'Received reply ') ]
'Received reply ', actor, receiving=True) ]
if 0 == len(md.returns):
return stmts
@ -5226,7 +5243,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return (
sendok,
([ Whitespace.NL,
self.logMessage(md, msgexpr, 'Sending '),
self.logMessage(md, msgexpr, 'Sending ', actor),
self.profilerLabel('AsyncSend', md.decl.progname) ]
+ self.transition(md, 'out', actor)
+ [ Whitespace.NL,
@ -5243,7 +5260,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return (
sendok,
([ Whitespace.NL,
self.logMessage(md, msgexpr, 'Sending '),
self.logMessage(md, msgexpr, 'Sending ', actor),
self.profilerLabel('Send', md.decl.progname) ]
+ self.transition(md, 'out', actor)
+ [ Whitespace.NL,
@ -5312,13 +5329,14 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
decl.ret = md.actorDecl().bareType(self.side)
return decl
def logMessage(self, md, msgptr, pfx):
def logMessage(self, md, msgptr, pfx, actor=None, receiving=False):
actorname = _actorName(self.protocol.name, self.side)
return _ifLogging([
StmtExpr(ExprCall(
ExprSelect(msgptr, '->', 'Log'),
args=[ ExprLiteral.String('['+ actorname +'] '+ pfx),
ExprVar('stderr') ])) ])
return _ifLogging([ StmtExpr(ExprCall(
ExprSelect(msgptr, '->', 'Log'),
args=[ ExprLiteral.String('['+ actorname +'] '+ pfx),
self.protocol.callOtherProcess(actor),
ExprLiteral.TRUE if receiving else ExprLiteral.FALSE ])) ])
def profilerLabel(self, tag, msgname):
return StmtExpr(ExprCall(ExprVar('PROFILER_LABEL'),

View File

@ -174,6 +174,9 @@ public:
RefPtr<UnixSocketConsumer> mConsumer;
private:
void FireSocketError();
/**
* libevent triggered functions that reads data from socket when available and
* guarenteed non-blocking. Only to be called on IO thread.
@ -487,29 +490,47 @@ void ShutdownSocketTask::Run()
}
void
UnixSocketImpl::Accept()
UnixSocketImpl::FireSocketError()
{
MOZ_ASSERT(!NS_IsMainThread());
if (!mConnector) {
NS_WARNING("No connector object available!");
return;
}
// Clean up watchers, statuses, fds
mReadWatcher.StopWatchingFileDescriptor();
mWriteWatcher.StopWatchingFileDescriptor();
mConnectionStatus = SOCKET_DISCONNECTED;
mFd.reset(-1);
// Tell the main thread we've errored
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
}
void
UnixSocketImpl::Accept()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mConnector);
// This will set things we don't particularly care about, but it will hand
// back the correct structure size which is what we do care about.
if (!mConnector->CreateAddr(true, mAddrSize, mAddr, nullptr)) {
NS_WARNING("Cannot create socket address!");
FireSocketError();
return;
}
if (mFd.get() < 0) {
mFd = mConnector->Create();
if (mFd.get() < 0) {
NS_WARNING("Cannot create socket fd!");
FireSocketError();
return;
}
if (!SetSocketFlags()) {
NS_WARNING("Cannot set socket flags!");
FireSocketError();
return;
}
@ -517,6 +538,7 @@ UnixSocketImpl::Accept()
#ifdef DEBUG
CHROMIUM_LOG("...bind(%d) gave errno %d", mFd.get(), errno);
#endif
FireSocketError();
return;
}
@ -524,15 +546,13 @@ UnixSocketImpl::Accept()
#ifdef DEBUG
CHROMIUM_LOG("...listen(%d) gave errno %d", mFd.get(), errno);
#endif
FireSocketError();
return;
}
if (!mConnector->SetUpListenSocket(mFd)) {
NS_WARNING("Could not set up listen socket!");
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
FireSocketError();
return;
}
@ -545,15 +565,13 @@ void
UnixSocketImpl::Connect()
{
MOZ_ASSERT(!NS_IsMainThread());
if (!mConnector) {
NS_WARNING("No connector object available!");
return;
}
MOZ_ASSERT(mConnector);
if (mFd.get() < 0) {
mFd = mConnector->Create();
if (mFd.get() < 0) {
NS_WARNING("Cannot create socket fd!");
FireSocketError();
return;
}
}
@ -562,15 +580,14 @@ UnixSocketImpl::Connect()
if (!mConnector->CreateAddr(false, mAddrSize, mAddr, mAddress.get())) {
NS_WARNING("Cannot create socket address!");
FireSocketError();
return;
}
// Select non-blocking IO.
if (-1 == fcntl(mFd.get(), F_SETFL, O_NONBLOCK)) {
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
NS_WARNING("Cannot set nonblock!");
FireSocketError();
return;
}
@ -583,20 +600,12 @@ UnixSocketImpl::Connect()
int current_opts = fcntl(mFd.get(), F_GETFL, 0);
if (-1 == current_opts) {
NS_WARNING("Cannot get socket opts!");
mFd.reset(-1);
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
FireSocketError();
return;
}
if (-1 == fcntl(mFd.get(), F_SETFL, current_opts & ~O_NONBLOCK)) {
NS_WARNING("Cannot set socket opts to blocking!");
mFd.reset(-1);
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
FireSocketError();
return;
}
@ -616,20 +625,19 @@ UnixSocketImpl::Connect()
#if DEBUG
CHROMIUM_LOG("Socket connect errno=%d\n", errno);
#endif
mFd.reset(-1);
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
FireSocketError();
return;
}
if (!SetSocketFlags()) {
NS_WARNING("Cannot set socket flags!");
FireSocketError();
return;
}
if (!mConnector->SetUp(mFd)) {
NS_WARNING("Could not set up socket!");
FireSocketError();
return;
}
@ -862,30 +870,19 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
if (ret || error) {
NS_WARNING("getsockopt failure on async socket connect!");
mFd.reset(-1);
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
FireSocketError();
return;
}
if (!SetSocketFlags()) {
mFd.reset(-1);
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
NS_WARNING("Cannot set socket flags!");
FireSocketError();
return;
}
if (!mConnector->SetUp(mFd)) {
NS_WARNING("Could not set up socket!");
mFd.reset(-1);
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
FireSocketError();
return;
}

View File

@ -95,10 +95,18 @@ class CPOWProxyHandler : public BaseProxyHandler
CPOWProxyHandler CPOWProxyHandler::singleton;
#define FORWARD(call, args) \
JavaScriptParent *parent = ParentOf(proxy); \
if (!parent->active()) { \
JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \
return false; \
} \
return parent->call args;
bool
CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
{
return ParentOf(proxy)->preventExtensions(cx, proxy);
FORWARD(preventExtensions, (cx, proxy));
}
bool
@ -117,7 +125,7 @@ bool
CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
{
return ParentOf(proxy)->getPropertyDescriptor(cx, proxy, id, desc, flags);
FORWARD(getPropertyDescriptor, (cx, proxy, id, desc, flags));
}
bool
@ -145,7 +153,7 @@ CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
HandleId id, MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
{
return ParentOf(proxy)->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc, flags));
}
bool
@ -172,7 +180,7 @@ bool
CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
return ParentOf(proxy)->defineProperty(cx, proxy, id, desc);
FORWARD(defineProperty, (cx, proxy, id, desc));
}
bool
@ -199,7 +207,7 @@ JavaScriptParent::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
bool
CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return ParentOf(proxy)->getOwnPropertyNames(cx, proxy, props);
FORWARD(getOwnPropertyNames, (cx, proxy, props));
}
bool
@ -211,7 +219,7 @@ JavaScriptParent::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdV
bool
CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
return ParentOf(proxy)->delete_(cx, proxy, id, bp);
FORWARD(delete_, (cx, proxy, id, bp));
}
bool
@ -233,7 +241,7 @@ JavaScriptParent::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *
bool
CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return ParentOf(proxy)->enumerate(cx, proxy, props);
FORWARD(enumerate, (cx, proxy, props));
}
bool
@ -245,7 +253,7 @@ JavaScriptParent::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &pro
bool
CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
return ParentOf(proxy)->has(cx, proxy, id, bp);
FORWARD(has, (cx, proxy, id, bp));
}
bool
@ -267,7 +275,7 @@ JavaScriptParent::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
bool
CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
return ParentOf(proxy)->hasOwn(cx, proxy, id, bp);
FORWARD(hasOwn, (cx, proxy, id, bp));
}
bool
@ -290,7 +298,7 @@ bool
CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
return ParentOf(proxy)->get(cx, proxy, receiver, id, vp);
FORWARD(get, (cx, proxy, receiver, id, vp));
}
bool
@ -319,7 +327,7 @@ bool
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
{
return ParentOf(proxy)->set(cx, proxy, receiver, id, strict, vp);
FORWARD(set, (cx, proxy, receiver, id, strict, vp));
}
bool
@ -351,7 +359,7 @@ JavaScriptParent::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject re
bool
CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return ParentOf(proxy)->keys(cx, proxy, props);
FORWARD(keys, (cx, proxy, props));
}
bool
@ -363,7 +371,7 @@ JavaScriptParent::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
bool
CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
{
return ParentOf(proxy)->isExtensible(cx, proxy, extensible);
FORWARD(isExtensible, (cx, proxy, extensible));
}
bool
@ -381,7 +389,7 @@ JavaScriptParent::isExtensible(JSContext *cx, HandleObject proxy, bool *extensib
bool
CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
return ParentOf(proxy)->call(cx, proxy, args);
FORWARD(call, (cx, proxy, args));
}
bool
@ -456,7 +464,7 @@ JavaScriptParent::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
bool
CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
{
return ParentOf(proxy)->objectClassIs(cx, proxy, classValue);
FORWARD(objectClassIs, (cx, proxy, classValue));
}
bool
@ -476,7 +484,10 @@ JavaScriptParent::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassVa
const char *
CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
{
return ParentOf(proxy)->className(cx, proxy);
JavaScriptParent *parent = ParentOf(proxy);
if (!parent->active())
return "<dead CPOW>";
return parent->className(cx, proxy);
}
const char *
@ -486,7 +497,7 @@ JavaScriptParent::className(JSContext *cx, HandleObject proxy)
nsString name;
if (!CallClassName(objId, &name))
return nullptr;
return "<error>";
return ToNewCString(name);
}
@ -634,10 +645,9 @@ JavaScriptParent::incref()
}
void
JavaScriptParent::destroyFromContent()
JavaScriptParent::ActorDestroy(ActorDestroyReason why)
{
inactive_ = true;
decref();
}
/* static */ bool
@ -647,9 +657,12 @@ JavaScriptParent::IsCPOW(JSObject *obj)
}
/* static */ nsresult
JavaScriptParent::InstanceOf(JSObject *obj, const nsID *id, bool *bp)
JavaScriptParent::InstanceOf(JSObject *proxy, const nsID *id, bool *bp)
{
return ParentOf(obj)->instanceOf(obj, id, bp);
JavaScriptParent *parent = ParentOf(proxy);
if (!parent->active())
return NS_ERROR_UNEXPECTED;
return parent->instanceOf(proxy, id, bp);
}
nsresult
@ -671,24 +684,21 @@ JavaScriptParent::instanceOf(JSObject *obj, const nsID *id, bool *bp)
}
/* static */ bool
JavaScriptParent::DOMInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp)
JavaScriptParent::DOMInstanceOf(JSContext *cx, JSObject *proxy, int prototypeID, int depth, bool *bp)
{
return ParentOf(obj)->domInstanceOf(obj, prototypeID, depth, bp);
FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
}
bool
JavaScriptParent::domInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp)
JavaScriptParent::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp)
{
ObjectId objId = idOf(obj);
ReturnStatus status;
if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
return false;
return ipcfail(cx);
if (status.type() != ReturnStatus::TReturnSuccess)
return false;
return true;
return ok(cx, status);
}
mozilla::ipc::IProtocol*

View File

@ -59,9 +59,12 @@ class JavaScriptParent
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
const char* className(JSContext *cx, JS::HandleObject proxy);
virtual void ActorDestroy(ActorDestroyReason why);
void decref();
void incref();
void destroyFromContent();
bool active() { return !inactive_; }
void drop(JSObject *obj);
@ -74,8 +77,8 @@ class JavaScriptParent
* Check that |obj| is a DOM wrapper whose prototype chain contains
* |prototypeID| at depth |depth|.
*/
static bool DOMInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp);
bool domInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp);
static bool DOMInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
mozilla::ipc::IProtocol*
CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;

View File

@ -497,7 +497,7 @@ class NonLocalExitScope {
StmtInfoBCE *stmt = bce->topStmt;
while (1) {
JS_ASSERT(stmt);
if (stmt->isBlockScope) {
if (stmt->isNestedScope) {
openScopeIndex = stmt->blockScopeIndex;
break;
}
@ -512,18 +512,12 @@ class NonLocalExitScope {
bce->stackDepth = savedDepth;
}
bool popScopeForNonLocalExit(StaticBlockObject &blockObj, uint32_t blockScopeIndex) {
bool popScopeForNonLocalExit(uint32_t blockScopeIndex) {
uint32_t scopeObjectIndex = bce->blockScopeList.findEnclosingScope(blockScopeIndex);
uint32_t parent = openScopeIndex;
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
return false;
if (blockObj.needsClone()) {
if (Emit1(cx, bce, JSOP_POPBLOCKSCOPE) < 0)
return false;
}
openScopeIndex = bce->blockScopeList.length() - 1;
return true;
}
@ -550,10 +544,11 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
break;
case STMT_WITH:
/* There's a With object on the stack that we need to pop. */
FLUSH_POPS();
if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
return false;
JS_ASSERT(stmt->isNestedScope);
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
return false;
break;
case STMT_FOR_OF_LOOP:
@ -578,9 +573,16 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
}
if (stmt->isBlockScope) {
JS_ASSERT(stmt->isNestedScope);
StaticBlockObject &blockObj = stmt->staticBlock();
if (!popScopeForNonLocalExit(blockObj, stmt->blockScopeIndex))
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
return false;
if (blockObj.needsClone()) {
if (Emit1(cx, bce, JSOP_POPBLOCKSCOPE) < 0)
return false;
}
npops += blockObj.slotCount();
}
}
@ -728,6 +730,55 @@ ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlo
static bool
EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmitter *bce);
static bool
EnterNestedScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
StmtType stmtType)
{
Rooted<NestedScopeObject *> scopeObj(cx, &objbox->object->as<NestedScopeObject>());
uint32_t scopeObjectIndex = bce->objectList.add(objbox);
switch (stmtType) {
case STMT_BLOCK: {
Rooted<StaticBlockObject *> blockObj(cx, &scopeObj->as<StaticBlockObject>());
if (!ComputeAliasedSlots(cx, bce, blockObj))
return false;
if (blockObj->needsClone()) {
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_PUSHBLOCKSCOPE, bce))
return false;
}
break;
}
case STMT_WITH:
JS_ASSERT(scopeObj->is<StaticWithObject>());
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_ENTERWITH, bce))
return false;
break;
default:
MOZ_ASSUME_UNREACHABLE();
}
uint32_t parent = BlockScopeNote::NoBlockScopeIndex;
if (bce->staticScope) {
StmtInfoBCE *stmt = bce->topScopeStmt;
for (; stmt->staticScope != bce->staticScope; stmt = stmt->down) {}
parent = stmt->blockScopeIndex;
}
stmt->blockScopeIndex = bce->blockScopeList.length();
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
return false;
PushStatementBCE(bce, stmt, stmtType, bce->offset());
scopeObj->initEnclosingNestedScope(EnclosingStaticScope(bce));
FinishPushNestedScope(bce, stmt, *scopeObj);
JS_ASSERT(stmt->isNestedScope);
stmt->isBlockScope = (stmtType == STMT_BLOCK);
return true;
}
// ~ Block Scopes ~
//
// A block scope is a region of a script with an additional set of named
@ -771,50 +822,26 @@ EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmit
// for-in loops.
//
// Summary: Enter block scopes with EnterBlockScope. It will emit
// PUSHBLOCKSCOPE if needed. Leave them with LeaveBlockScope, which will emit
// PUSHBLOCKSCOPE if needed. Leave them with LeaveNestedScope, which will emit
// DEBUGLEAVEBLOCK and may emit POPBLOCKSCOPE. Pass EnterBlockScope a fresh
// StmtInfoBCE object, and pass that same object to the corresponding
// LeaveBlockScope. Push locals before entering a scope, and pop them
// LeaveNestedScope. Push locals before entering a scope, and pop them
// afterwards. Brush your teeth, and clean behind your ears!
//
static bool
EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
unsigned extraSlots)
{
uint32_t parent = BlockScopeNote::NoBlockScopeIndex;
if (bce->staticScope) {
StmtInfoBCE *stmt = bce->topScopeStmt;
for (; stmt->staticScope != bce->staticScope; stmt = stmt->down) {}
parent = stmt->blockScopeIndex;
}
Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
uint32_t scopeObjectIndex = bce->objectList.add(objbox);
// FIXME: Once bug 962599 lands, we won't care about the stack depth, so we
// won't have extraSlots and thus invocations of EnterBlockScope can become
// invocations of EnterNestedScope.
int depth = bce->stackDepth - (blockObj->slotCount() + extraSlots);
JS_ASSERT(depth >= 0);
blockObj->setStackDepth(depth);
if (!ComputeAliasedSlots(cx, bce, blockObj))
return false;
if (blockObj->needsClone()) {
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_PUSHBLOCKSCOPE, bce))
return false;
}
stmt->blockScopeIndex = bce->blockScopeList.length();
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
return false;
PushStatementBCE(bce, stmt, STMT_BLOCK, bce->offset());
blockObj->initEnclosingNestedScope(EnclosingStaticScope(bce));
FinishPushBlockScope(bce, stmt, *blockObj);
JS_ASSERT(stmt->isBlockScope);
return true;
return EnterNestedScope(cx, bce, stmt, objbox, STMT_BLOCK);
}
// Patches |breaks| and |continues| unless the top statement info record
@ -835,10 +862,11 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
}
static bool
LeaveBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce)
LeaveNestedScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt)
{
StmtInfoBCE *stmt = bce->topStmt;
JS_ASSERT(stmt->isBlockScope);
JS_ASSERT(stmt == bce->topStmt);
JS_ASSERT(stmt->isNestedScope);
JS_ASSERT(stmt->isBlockScope == !(stmt->type == STMT_WITH));
uint32_t blockScopeIndex = stmt->blockScopeIndex;
#ifdef DEBUG
@ -848,20 +876,18 @@ LeaveBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce)
NestedScopeObject *staticScope = &blockObjBox->object->as<NestedScopeObject>();
JS_ASSERT(stmt->staticScope == staticScope);
JS_ASSERT(staticScope == bce->staticScope);
JS_ASSERT_IF(!stmt->isBlockScope, staticScope->is<StaticWithObject>());
#endif
JS_ASSERT(bce->staticScope->is<StaticBlockObject>());
bool blockOnChain = bce->staticScope->as<StaticBlockObject>().needsClone();
if (!PopStatementBCE(cx, bce))
return false;
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
if (Emit1(cx, bce, stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH) < 0)
return false;
bce->blockScopeList.recordEnd(blockScopeIndex, bce->offset());
if (blockOnChain) {
if (stmt->isBlockScope && stmt->staticScope->as<StaticBlockObject>().needsClone()) {
if (Emit1(cx, bce, JSOP_POPBLOCKSCOPE) < 0)
return false;
}
@ -1120,8 +1146,7 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *
while (!b->containsVarAtDepth(depth)) {
if (b->needsClone())
skippedScopes++;
b = b->enclosingBlock();
JS_ASSERT(b);
b = &b->enclosingNestedScope()->as<StaticBlockObject>();
}
if (!AssignHops(bce, pn, skippedScopes, &sc))
return false;
@ -1736,6 +1761,7 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
CheckSideEffects(cx, bce, pn->pn_kid3, answer);
case PN_BINARY:
case PN_BINARY_OBJ:
if (pn->isAssignment()) {
/*
* Assignment is presumed to be useful, even if the next operation
@ -1888,7 +1914,7 @@ BytecodeEmitter::needsImplicitThis()
} else {
JSObject *scope = sc->asGlobalSharedContext()->scopeChain();
while (scope) {
if (scope->is<WithObject>())
if (scope->is<DynamicWithObject>())
return true;
scope = scope->enclosingScope();
}
@ -2719,7 +2745,7 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
if (!LeaveBlockScope(cx, bce))
if (!LeaveNestedScope(cx, bce, &stmtInfo))
return false;
EMIT_UINT16_IMM_OP(JSOP_POPN, blockObj->slotCount());
} else {
@ -4269,7 +4295,7 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
if (!EmitTree(cx, bce, letBody->pn_expr))
return false;
if (!LeaveBlockScope(cx, bce))
if (!LeaveNestedScope(cx, bce, &stmtInfo))
return false;
JSOp leaveOp = letBody->getOp();
@ -4305,7 +4331,7 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!EmitTree(cx, bce, pn->pn_expr))
return false;
if (!LeaveBlockScope(cx, bce))
if (!LeaveNestedScope(cx, bce, &stmtInfo))
return false;
EMIT_UINT16_IMM_OP(JSOP_POPN, slots);
@ -4319,15 +4345,13 @@ EmitWith(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
StmtInfoBCE stmtInfo(cx);
if (!EmitTree(cx, bce, pn->pn_left))
return false;
PushStatementBCE(bce, &stmtInfo, STMT_WITH, bce->offset());
if (Emit1(cx, bce, JSOP_ENTERWITH) < 0)
if (!EnterNestedScope(cx, bce, &stmtInfo, pn->pn_binary_obj, STMT_WITH))
return false;
if (!EmitTree(cx, bce, pn->pn_right))
return false;
if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
if (!LeaveNestedScope(cx, bce, &stmtInfo))
return false;
return PopStatementBCE(cx, bce);
return true;
}
static bool
@ -4474,7 +4498,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
return false;
if (letDecl) {
if (!LeaveBlockScope(cx, bce))
if (!LeaveNestedScope(cx, bce, &letStmt))
return false;
}
@ -4637,7 +4661,7 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
return false;
if (letDecl) {
if (!LeaveBlockScope(cx, bce))
if (!LeaveNestedScope(cx, bce, &letStmt))
return false;
EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
}

View File

@ -49,6 +49,7 @@ ContainsVarOrConst(ParseNode *pn)
return pnt;
return ContainsVarOrConst(pn->pn_kid3);
case PN_BINARY:
case PN_BINARY_OBJ:
/*
* Limit recursion if pn is a binary expression, which can't contain a
* var statement.
@ -327,6 +328,7 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
break;
case PN_BINARY:
case PN_BINARY_OBJ:
if (pn->isKind(PNK_OR) || pn->isKind(PNK_AND)) {
// Propagate Condition context through logical connectives.
SyntacticContext kidsc = SyntacticContext::Other;

View File

@ -385,8 +385,10 @@ class FullParseHandler
return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
}
ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body) {
return new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end), expr, body);
ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body,
ObjectBox *staticWith) {
return new_<BinaryObjNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end),
expr, body, staticWith);
}
ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) {

View File

@ -310,6 +310,7 @@ class NameResolver
return false;
break;
case PN_BINARY:
case PN_BINARY_OBJ:
if (!resolve(cur->pn_left, prefix))
return false;

View File

@ -170,6 +170,7 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
stack->pushUnlessNull(pn->pn_kid3);
break;
case PN_BINARY:
case PN_BINARY_OBJ:
if (pn->pn_left != pn->pn_right)
stack->pushUnlessNull(pn->pn_left);
stack->pushUnlessNull(pn->pn_right);
@ -382,6 +383,15 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
pn->pn_iflags = opn->pn_iflags;
break;
case PN_BINARY_OBJ:
NULLCHECK(pn->pn_left = cloneParseTree(opn->pn_left));
if (opn->pn_right != opn->pn_left)
NULLCHECK(pn->pn_right = cloneParseTree(opn->pn_right));
else
pn->pn_right = pn->pn_left;
pn->pn_binary_obj = opn->pn_binary_obj;
break;
case PN_UNARY:
NULLCHECK(pn->pn_kid = cloneParseTree(opn->pn_kid));
break;
@ -548,6 +558,9 @@ ParseNode::dump(int indent)
case PN_BINARY:
((BinaryNode *) this)->dump(indent);
break;
case PN_BINARY_OBJ:
((BinaryObjNode *) this)->dump(indent);
break;
case PN_TERNARY:
((TernaryNode *) this)->dump(indent);
break;
@ -618,6 +631,18 @@ BinaryNode::dump(int indent)
fprintf(stderr, ")");
}
void
BinaryObjNode::dump(int indent)
{
const char *name = parseNodeNames[getKind()];
fprintf(stderr, "(%s ", name);
indent += strlen(name) + 2;
DumpParseTree(pn_left, indent);
IndentNewLine(indent);
DumpParseTree(pn_right, indent);
fprintf(stderr, ")");
}
void
TernaryNode::dump(int indent)
{

View File

@ -288,7 +288,7 @@ enum ParseNodeKind
* pn_kid3: catch block statements
* PNK_BREAK name pn_atom: label or null
* PNK_CONTINUE name pn_atom: label or null
* PNK_WITH binary pn_left: head expr, pn_right: body
* PNK_WITH binary-obj pn_left: head expr; pn_right: body; pn_binary_obj: StaticWithObject
* PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes
* PNK_CONST each name node has either
* pn_used: false
@ -420,6 +420,7 @@ enum ParseNodeArity
PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
PN_UNARY, /* one kid, plus a couple of scalars */
PN_BINARY, /* two kids, plus a couple of scalars */
PN_BINARY_OBJ, /* two kids, plus an objbox */
PN_TERNARY, /* three kids */
PN_CODE, /* module or function definition node */
PN_LIST, /* generic singly linked list */
@ -516,7 +517,10 @@ class ParseNode
struct { /* two kids if binary */
ParseNode *left;
ParseNode *right;
unsigned iflags; /* JSITER_* flags for PNK_FOR node */
union {
unsigned iflags; /* JSITER_* flags for PNK_FOR node */
ObjectBox *objbox; /* Only for PN_BINARY_OBJ */
};
} binary;
struct { /* one kid if unary */
ParseNode *kid;
@ -570,6 +574,7 @@ class ParseNode
#define pn_right pn_u.binary.right
#define pn_pval pn_u.binary.pval
#define pn_iflags pn_u.binary.iflags
#define pn_binary_obj pn_u.binary.objbox
#define pn_kid pn_u.unary.kid
#define pn_prologue pn_u.unary.prologue
#define pn_atom pn_u.name.atom
@ -905,6 +910,30 @@ struct BinaryNode : public ParseNode
#endif
};
struct BinaryObjNode : public ParseNode
{
BinaryObjNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right,
ObjectBox *objbox)
: ParseNode(kind, op, PN_BINARY_OBJ, pos)
{
pn_left = left;
pn_right = right;
pn_binary_obj = objbox;
}
static inline BinaryObjNode *create(ParseNodeKind kind, FullParseHandler *handler) {
return (BinaryObjNode *) ParseNode::create(kind, PN_BINARY_OBJ, handler);
}
static bool test(const ParseNode &node) {
return node.isArity(PN_BINARY_OBJ);
}
#ifdef DEBUG
void dump(int indent);
#endif
};
struct TernaryNode : public ParseNode
{
TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3)

View File

@ -535,7 +535,7 @@ FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunct
//
JSObject *scope = outerpc->sc->asGlobalSharedContext()->scopeChain();
while (scope) {
if (scope->is<WithObject>())
if (scope->is<DynamicWithObject>())
inWith = true;
scope = scope->enclosingScope();
}
@ -2774,7 +2774,7 @@ static void
PopStatementPC(TokenStream &ts, ParseContext<ParseHandler> *pc)
{
RootedNestedScopeObject scopeObj(ts.context(), pc->topStmt->staticScope);
JS_ASSERT(!!scopeObj == (pc->topStmt->isBlockScope));
JS_ASSERT(!!scopeObj == pc->topStmt->isNestedScope);
FinishPopStatement(pc);
@ -3196,7 +3196,8 @@ Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInf
PushStatementPC(pc, stmt, STMT_BLOCK);
blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
FinishPushBlockScope(pc, stmt, *blockObj.get());
FinishPushNestedScope(pc, stmt, *blockObj.get());
stmt->isBlockScope = true;
Node pn = handler.newLexicalScope(blockbox);
if (!pn)
@ -3593,7 +3594,7 @@ Parser<FullParseHandler>::letDeclaration()
* lacks the SIF_SCOPE flag, it must be a try, catch, or finally
* block.
*/
stmt->isBlockScope = true;
stmt->isBlockScope = stmt->isNestedScope = true;
stmt->downScope = pc->topScopeStmt;
pc->topScopeStmt = stmt;
@ -4896,9 +4897,16 @@ Parser<FullParseHandler>::withStatement()
StmtInfoPC stmtInfo(context);
PushStatementPC(pc, &stmtInfo, STMT_WITH);
Rooted<StaticWithObject *> staticWith(context, StaticWithObject::create(context));
if (!staticWith)
return null();
staticWith->initEnclosingNestedScopeFromParser(pc->staticScope);
FinishPushNestedScope(pc, &stmtInfo, *staticWith);
Node innerBlock = statement();
if (!innerBlock)
return null();
PopStatementPC(tokenStream, pc);
pc->sc->setBindingsAccessedDynamically();
@ -4914,7 +4922,10 @@ Parser<FullParseHandler>::withStatement()
handler.deoptimizeUsesWithin(lexdep, TokenPos(begin, pos().begin));
}
return handler.newWithStatement(begin, objectExpr, innerBlock);
ObjectBox *staticWithBox = newObjectBox(staticWith);
if (!staticWithBox)
return null();
return handler.newWithStatement(begin, objectExpr, innerBlock, staticWithBox);
}
template <>
@ -5860,6 +5871,7 @@ CompExprTransplanter::transplant(ParseNode *pn)
break;
case PN_BINARY:
case PN_BINARY_OBJ:
if (!transplant(pn->pn_left))
return false;

View File

@ -389,22 +389,30 @@ enum StmtType {
// work with both types.
struct StmtInfoBase {
uint16_t type; /* statement type */
// Statement type (StmtType).
uint16_t type;
/*
* True if type is STMT_BLOCK, STMT_TRY, STMT_SWITCH, or
* STMT_FINALLY and the block contains at least one let-declaration.
*/
// True if type is STMT_BLOCK, STMT_TRY, STMT_SWITCH, or STMT_FINALLY and
// the block contains at least one let-declaration, or if type is
// STMT_CATCH.
bool isBlockScope:1;
/* for (let ...) induced block scope */
// True if isBlockScope or type == STMT_WITH.
bool isNestedScope:1;
// for (let ...) induced block scope
bool isForLetBlock:1;
RootedAtom label; /* name of LABEL */
Rooted<NestedScopeObject *> staticScope; /* scope object */
// Block label.
RootedAtom label;
// Compile-time scope chain node for this scope. Only set if
// isNestedScope.
Rooted<NestedScopeObject *> staticScope;
StmtInfoBase(ExclusiveContext *cx)
: isBlockScope(false), isForLetBlock(false), label(cx), staticScope(cx)
: isBlockScope(false), isNestedScope(false), isForLetBlock(false),
label(cx), staticScope(cx)
{}
bool maybeScope() const {
@ -412,12 +420,12 @@ struct StmtInfoBase {
}
bool linksScope() const {
return (STMT_WITH <= type && type <= STMT_CATCH) || isBlockScope;
return isNestedScope;
}
StaticBlockObject& staticBlock() const {
JS_ASSERT(isNestedScope);
JS_ASSERT(isBlockScope);
JS_ASSERT(staticScope);
return staticScope->as<StaticBlockObject>();
}
@ -437,6 +445,7 @@ PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type)
{
stmt->type = type;
stmt->isBlockScope = false;
stmt->isNestedScope = false;
stmt->isForLetBlock = false;
stmt->label = nullptr;
stmt->staticScope = nullptr;
@ -452,9 +461,9 @@ PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type)
template <class ContextT>
void
FinishPushBlockScope(ContextT *ct, typename ContextT::StmtInfo *stmt, NestedScopeObject &staticScope)
FinishPushNestedScope(ContextT *ct, typename ContextT::StmtInfo *stmt, NestedScopeObject &staticScope)
{
stmt->isBlockScope = true;
stmt->isNestedScope = true;
stmt->downScope = ct->topScopeStmt;
ct->topScopeStmt = stmt;
ct->staticScope = &staticScope;
@ -472,8 +481,10 @@ FinishPopStatement(ContextT *ct)
ct->topStmt = stmt->down;
if (stmt->linksScope()) {
ct->topScopeStmt = stmt->downScope;
if (stmt->isBlockScope)
ct->staticScope = stmt->staticBlock().enclosingBlock();
if (stmt->isNestedScope) {
JS_ASSERT(stmt->staticScope);
ct->staticScope = stmt->staticScope->enclosingNestedScope();
}
}
}

View File

@ -95,6 +95,8 @@ def main(argv):
op.add_option('--localLib', dest='local_lib', action='store',
type='string',
help='The location of libraries to push -- preferably stripped')
op.add_option('--repeat', type=int, default=1,
help='Repeat tests the given number of times.')
options, args = op.parse_args(argv)
if len(args) < 1:

View File

@ -98,3 +98,4 @@ assertEq(asmLink(asmCompileCached("g","ffis", USE_ASM + "var x=ffis.x|0; functio
var i32 = new Int32Array(4096);
i32[4] = 42;
assertEq(asmLink(asmCompileCached("g","ffis","buf", USE_ASM + "var i32=new g.Int32Array(buf); function f(i) { i=i|0; return i32[i>>2]|0 } return f"), this, null, i32.buffer)(4*4), 42);
assertEq(asmLink(asmCompileCached('glob', USE_ASM + 'var x=glob.Math.PI; function f() { return +x } return f'), this)(), Math.PI);

View File

@ -86,3 +86,17 @@ assertAsmTypeFail('glob', USE_ASM + 'var im=glob.Math.imul; function f(i) { i=i|
assertAsmTypeFail('glob', USE_ASM + 'var im=glob.Math.imul; function f(i) { i=i|0; i = im(i,i); } return f');
assertAsmTypeFail('glob', USE_ASM + 'var abs=glob.Math.abs; function f(i) { i=i|0; +abs(i|0); } return f');
assertAsmTypeFail('glob', USE_ASM + 'var abs=glob.Math.abs; function f(d) { d=+d; abs(d)|0; } return f');
assertAsmTypeFail('glob', USE_ASM + 'var tau=glob.Math.TAU; function f() {} return f');
assertAsmTypeFail('glob', USE_ASM + 'var pi=glob.Math.PI; function f() { return pi | 0 } return f');
assertAsmTypeFail('glob', USE_ASM + 'var pi=glob.Math.PI; function f() { return +pi() } return f');
assertAsmTypeFail('glob', USE_ASM + 'var pi=glob.Math.PI; function f() { pi = +3; } return f');
assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + 'var pi=glob.Math.PI; function f() {} return f'), {});
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var pi=glob.Math.PI; function f() {} return f'), {Math: {}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var pi=glob.Math.PI; function f() {} return f'), {Math: {PI: Math.cos}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var pi=glob.Math.PI; function f() {} return f'), {Math: {PI: Math.SQRT2}});
for (var c of ['E', 'LN10', 'LN2', 'LOG2E', 'LOG10E', 'PI', 'SQRT1_2', 'SQRT2']) {
var f = asmLink(asmCompile('glob', USE_ASM + 'var x=glob.Math.' + c +'; function f() { return +x } return f'), this);
assertEq(f(), eval('Math.' + c));
}

View File

@ -12,6 +12,7 @@
# include "vtune/VTuneWrapper.h"
#endif
#include "jsmath.h"
#include "jsprf.h"
#include "jsworkers.h"
#include "prmjtime.h"
@ -936,7 +937,7 @@ class MOZ_STACK_CLASS ModuleCompiler
FuncPtrTable,
FFI,
ArrayView,
MathBuiltin
MathBuiltinFunction
};
private:
@ -951,7 +952,7 @@ class MOZ_STACK_CLASS ModuleCompiler
uint32_t funcPtrTableIndex_;
uint32_t ffiIndex_;
ArrayBufferView::ViewType viewType_;
AsmJSMathBuiltin mathBuiltin_;
AsmJSMathBuiltinFunction mathBuiltinFunc_;
} u;
friend class ModuleCompiler;
@ -994,9 +995,9 @@ class MOZ_STACK_CLASS ModuleCompiler
JS_ASSERT(which_ == ArrayView);
return u.viewType_;
}
AsmJSMathBuiltin mathBuiltin() const {
JS_ASSERT(which_ == MathBuiltin);
return u.mathBuiltin_;
AsmJSMathBuiltinFunction mathBuiltinFunction() const {
JS_ASSERT(which_ == MathBuiltinFunction);
return u.mathBuiltinFunc_;
}
};
@ -1063,6 +1064,25 @@ class MOZ_STACK_CLASS ModuleCompiler
typedef HashMap<ExitDescriptor, unsigned, ExitDescriptor> ExitMap;
struct MathBuiltin
{
enum Kind { Function, Constant };
Kind kind;
union {
double cst;
AsmJSMathBuiltinFunction func;
} u;
MathBuiltin() : kind(Kind(-1)) {}
MathBuiltin(double cst) : kind(Constant) {
u.cst = cst;
}
MathBuiltin(AsmJSMathBuiltinFunction func) : kind(Function) {
u.func = func;
}
};
private:
struct SlowFunction
{
@ -1072,7 +1092,7 @@ class MOZ_STACK_CLASS ModuleCompiler
unsigned column;
};
typedef HashMap<PropertyName*, AsmJSMathBuiltin> MathNameMap;
typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
typedef HashMap<PropertyName*, Global*> GlobalMap;
typedef js::Vector<Func*> FuncVector;
typedef js::Vector<AsmJSGlobalAccess> GlobalAccessVector;
@ -1106,10 +1126,18 @@ class MOZ_STACK_CLASS ModuleCompiler
DebugOnly<bool> finishedFunctionBodies_;
bool addStandardLibraryMathName(const char *name, AsmJSMathBuiltin builtin) {
bool addStandardLibraryMathName(const char *name, AsmJSMathBuiltinFunction func) {
JSAtom *atom = Atomize(cx_, name, strlen(name));
if (!atom)
return false;
MathBuiltin builtin(func);
return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
}
bool addStandardLibraryMathName(const char *name, double cst) {
JSAtom *atom = Atomize(cx_, name, strlen(name));
if (!atom)
return false;
MathBuiltin builtin(cst);
return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
}
@ -1175,7 +1203,15 @@ class MOZ_STACK_CLASS ModuleCompiler
!addStandardLibraryMathName("abs", AsmJSMathBuiltin_abs) ||
!addStandardLibraryMathName("atan2", AsmJSMathBuiltin_atan2) ||
!addStandardLibraryMathName("imul", AsmJSMathBuiltin_imul) ||
!addStandardLibraryMathName("fround", AsmJSMathBuiltin_fround))
!addStandardLibraryMathName("fround", AsmJSMathBuiltin_fround) ||
!addStandardLibraryMathName("E", M_E) ||
!addStandardLibraryMathName("LN10", M_LN10) ||
!addStandardLibraryMathName("LN2", M_LN2) ||
!addStandardLibraryMathName("LOG2E", M_LOG2E) ||
!addStandardLibraryMathName("LOG10E", M_LOG10E) ||
!addStandardLibraryMathName("PI", M_PI) ||
!addStandardLibraryMathName("SQRT1_2", M_SQRT1_2) ||
!addStandardLibraryMathName("SQRT2", M_SQRT2))
{
return false;
}
@ -1289,7 +1325,7 @@ class MOZ_STACK_CLASS ModuleCompiler
FuncPtrTable &funcPtrTable(unsigned i) {
return funcPtrTables_[i];
}
bool lookupStandardLibraryMathName(PropertyName *name, AsmJSMathBuiltin *mathBuiltin) const {
bool lookupStandardLibraryMathName(PropertyName *name, MathBuiltin *mathBuiltin) const {
if (MathNameMap::Ptr p = standardLibraryMathNames_.lookup(name)) {
*mathBuiltin = p->value();
return true;
@ -1390,18 +1426,17 @@ class MOZ_STACK_CLASS ModuleCompiler
global->u.viewType_ = vt;
return globals_.putNew(varName, global);
}
bool addMathBuiltin(PropertyName *varName, AsmJSMathBuiltin mathBuiltin, PropertyName *fieldName) {
if (!module_->addMathBuiltin(mathBuiltin, fieldName))
bool addMathBuiltinFunction(PropertyName *varName, AsmJSMathBuiltinFunction func, PropertyName *fieldName) {
if (!module_->addMathBuiltinFunction(func, fieldName))
return false;
Global *global = moduleLifo_.new_<Global>(Global::MathBuiltin);
Global *global = moduleLifo_.new_<Global>(Global::MathBuiltinFunction);
if (!global)
return false;
global->u.mathBuiltin_ = mathBuiltin;
global->u.mathBuiltinFunc_ = func;
return globals_.putNew(varName, global);
}
bool addGlobalConstant(PropertyName *varName, double constant, PropertyName *fieldName) {
if (!module_->addGlobalConstant(constant, fieldName))
return false;
private:
bool addGlobalDoubleConstant(PropertyName *varName, double constant) {
Global *global = moduleLifo_.new_<Global>(Global::ConstantLiteral);
if (!global)
return false;
@ -1409,6 +1444,17 @@ class MOZ_STACK_CLASS ModuleCompiler
global->u.varOrConst.type_ = VarType::Double;
return globals_.putNew(varName, global);
}
public:
bool addMathBuiltinConstant(PropertyName *varName, double constant, PropertyName *fieldName) {
if (!module_->addMathBuiltinConstant(constant, fieldName))
return false;
return addGlobalDoubleConstant(varName, constant);
}
bool addGlobalConstant(PropertyName *varName, double constant, PropertyName *fieldName) {
if (!module_->addGlobalConstant(constant, fieldName))
return false;
return addGlobalDoubleConstant(varName, constant);
}
bool addExportedFunction(const Func *func, PropertyName *maybeFieldName) {
AsmJSModule::ArgCoercionVector argCoercions;
const VarTypeVector &args = func->sig().args();
@ -1774,8 +1820,8 @@ IsFloatCoercion(ModuleCompiler &m, ParseNode *pn, ParseNode **coercedExpr)
const ModuleCompiler::Global *global = m.lookupGlobal(callee->name());
if (!global ||
global->which() != ModuleCompiler::Global::MathBuiltin ||
global->mathBuiltin() != AsmJSMathBuiltin_fround)
global->which() != ModuleCompiler::Global::MathBuiltinFunction ||
global->mathBuiltinFunction() != AsmJSMathBuiltin_fround)
{
return false;
}
@ -3104,11 +3150,19 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo
if (!IsUseOfName(global, m.module().globalArgumentName()) || math != m.cx()->names().Math)
return m.fail(base, "expecting global.Math");
AsmJSMathBuiltin mathBuiltin;
ModuleCompiler::MathBuiltin mathBuiltin;
if (!m.lookupStandardLibraryMathName(field, &mathBuiltin))
return m.failName(initNode, "'%s' is not a standard Math builtin", field);
return m.addMathBuiltin(varName, mathBuiltin, field);
switch (mathBuiltin.kind) {
case ModuleCompiler::MathBuiltin::Function:
return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field);
case ModuleCompiler::MathBuiltin::Constant:
return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field);
default:
break;
}
MOZ_ASSUME_UNREACHABLE("unexpected or uninitialized math builtin type");
}
if (IsUseOfName(base, m.module().globalArgumentName())) {
@ -3366,7 +3420,7 @@ CheckVarRef(FunctionCompiler &f, ParseNode *varRef, MDefinition **def, Type *typ
break;
case ModuleCompiler::Global::Function:
case ModuleCompiler::Global::FFI:
case ModuleCompiler::Global::MathBuiltin:
case ModuleCompiler::Global::MathBuiltinFunction:
case ModuleCompiler::Global::FuncPtrTable:
case ModuleCompiler::Global::ArrayView:
return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name);
@ -4021,12 +4075,12 @@ CheckIsMaybeFloat(FunctionCompiler &f, ParseNode *argNode, Type type)
}
static bool
CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltin mathBuiltin,
CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltinFunction func,
RetType retType, MDefinition **def, Type *type)
{
unsigned arity = 0;
AsmJSImmKind doubleCallee, floatCallee;
switch (mathBuiltin) {
switch (func) {
case AsmJSMathBuiltin_imul: return CheckMathIMul(f, callNode, retType, def, type);
case AsmJSMathBuiltin_abs: return CheckMathAbs(f, callNode, retType, def, type);
case AsmJSMathBuiltin_sqrt: return CheckMathSqrt(f, callNode, retType, def, type);
@ -4043,7 +4097,7 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltin
case AsmJSMathBuiltin_log: arity = 1; doubleCallee = AsmJSImm_LogD; floatCallee = AsmJSImm_LogF; break;
case AsmJSMathBuiltin_pow: arity = 2; doubleCallee = AsmJSImm_PowD; floatCallee = AsmJSImm_Invalid; break;
case AsmJSMathBuiltin_atan2: arity = 2; doubleCallee = AsmJSImm_ATan2D; floatCallee = AsmJSImm_Invalid; break;
default: MOZ_ASSUME_UNREACHABLE("unexpected mathBuiltin");
default: MOZ_ASSUME_UNREACHABLE("unexpected mathBuiltin function");
}
if (retType == RetType::Float && floatCallee == AsmJSImm_Invalid)
@ -4088,8 +4142,8 @@ CheckCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **d
switch (global->which()) {
case ModuleCompiler::Global::FFI:
return CheckFFICall(f, call, global->ffiIndex(), retType, def, type);
case ModuleCompiler::Global::MathBuiltin:
return CheckMathBuiltinCall(f, call, global->mathBuiltin(), retType, def, type);
case ModuleCompiler::Global::MathBuiltinFunction:
return CheckMathBuiltinCall(f, call, global->mathBuiltinFunction(), retType, def, type);
case ModuleCompiler::Global::ConstantLiteral:
case ModuleCompiler::Global::ConstantImport:
case ModuleCompiler::Global::Variable:

View File

@ -143,7 +143,7 @@ ValidateArrayView(JSContext *cx, AsmJSModule::Global &global, HandleValue global
}
static bool
ValidateMathBuiltin(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal)
ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal)
{
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, cx->names().Math, &v))
@ -153,7 +153,7 @@ ValidateMathBuiltin(JSContext *cx, AsmJSModule::Global &global, HandleValue glob
return false;
Native native = nullptr;
switch (global.mathBuiltin()) {
switch (global.mathBuiltinFunction()) {
case AsmJSMathBuiltin_sin: native = math_sin; break;
case AsmJSMathBuiltin_cos: native = math_cos; break;
case AsmJSMathBuiltin_tan: native = math_tan; break;
@ -173,21 +173,26 @@ ValidateMathBuiltin(JSContext *cx, AsmJSModule::Global &global, HandleValue glob
}
if (!IsNativeFunction(v, native))
return LinkFail(cx, "bad Math.* builtin");
return LinkFail(cx, "bad Math.* builtin function");
return true;
}
static bool
ValidateGlobalConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal)
ValidateConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal)
{
RootedPropertyName field(cx, global.constantName());
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, field, &v))
return false;
RootedValue v(cx, globalVal);
if (global.constantKind() == AsmJSModule::Global::MathConstant) {
if (!GetDataProperty(cx, v, cx->names().Math, &v))
return false;
}
if (!GetDataProperty(cx, v, field, &v))
return false;
if (!v.isNumber())
return LinkFail(cx, "global constant value needs to be a number");
return LinkFail(cx, "math / global constant value needs to be a number");
// NaN != NaN
if (IsNaN(global.constantValue())) {
@ -269,12 +274,12 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
if (!ValidateArrayView(cx, global, globalVal, bufferVal))
return false;
break;
case AsmJSModule::Global::MathBuiltin:
if (!ValidateMathBuiltin(cx, global, globalVal))
case AsmJSModule::Global::MathBuiltinFunction:
if (!ValidateMathBuiltinFunction(cx, global, globalVal))
return false;
break;
case AsmJSModule::Global::Constant:
if (!ValidateGlobalConstant(cx, global, globalVal))
if (!ValidateConstant(cx, global, globalVal))
return false;
break;
}

View File

@ -34,7 +34,7 @@ enum AsmJSCoercion
};
// The asm.js spec recognizes this set of builtin Math functions.
enum AsmJSMathBuiltin
enum AsmJSMathBuiltinFunction
{
AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan,
AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
@ -97,8 +97,9 @@ class AsmJSModule
class Global
{
public:
enum Which { Variable, FFI, ArrayView, MathBuiltin, Constant };
enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant };
enum VarInitKind { InitConstant, InitImport };
enum ConstantKind { GlobalConstant, MathConstant };
private:
struct Pod {
@ -114,8 +115,11 @@ class AsmJSModule
} var;
uint32_t ffiIndex_;
ArrayBufferView::ViewType viewType_;
AsmJSMathBuiltin mathBuiltin_;
double constantValue_;
AsmJSMathBuiltinFunction mathBuiltinFunc_;
struct {
ConstantKind kind_;
double value_;
} constant;
} u;
} pod;
PropertyName *name_;
@ -179,20 +183,24 @@ class AsmJSModule
return pod.u.viewType_;
}
PropertyName *mathName() const {
JS_ASSERT(pod.which_ == MathBuiltin);
JS_ASSERT(pod.which_ == MathBuiltinFunction);
return name_;
}
AsmJSMathBuiltin mathBuiltin() const {
JS_ASSERT(pod.which_ == MathBuiltin);
return pod.u.mathBuiltin_;
AsmJSMathBuiltinFunction mathBuiltinFunction() const {
JS_ASSERT(pod.which_ == MathBuiltinFunction);
return pod.u.mathBuiltinFunc_;
}
PropertyName *constantName() const {
JS_ASSERT(pod.which_ == Constant);
return name_;
}
ConstantKind constantKind() const {
JS_ASSERT(pod.which_ == Constant);
return pod.u.constant.kind_;
}
double constantValue() const {
JS_ASSERT(pod.which_ == Constant);
return pod.u.constantValue_;
return pod.u.constant.value_;
}
size_t serializedSize() const;
@ -488,14 +496,21 @@ class AsmJSModule
g.pod.u.viewType_ = vt;
return globals_.append(g);
}
bool addMathBuiltin(AsmJSMathBuiltin mathBuiltin, PropertyName *field) {
Global g(Global::MathBuiltin, field);
g.pod.u.mathBuiltin_ = mathBuiltin;
bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName *field) {
Global g(Global::MathBuiltinFunction, field);
g.pod.u.mathBuiltinFunc_ = func;
return globals_.append(g);
}
bool addMathBuiltinConstant(double value, PropertyName *field) {
Global g(Global::Constant, field);
g.pod.u.constant.value_ = value;
g.pod.u.constant.kind_ = Global::MathConstant;
return globals_.append(g);
}
bool addGlobalConstant(double value, PropertyName *name) {
Global g(Global::Constant, name);
g.pod.u.constantValue_ = value;
g.pod.u.constant.value_ = value;
g.pod.u.constant.kind_ = Global::GlobalConstant;
return globals_.append(g);
}
bool addFuncPtrTable(unsigned numElems, uint32_t *globalDataOffset) {

View File

@ -2650,6 +2650,43 @@ BaselineCompiler::emit_JSOP_DEBUGLEAVEBLOCK()
return callVM(DebugLeaveBlockInfo);
}
typedef bool (*EnterWithFn)(JSContext *, BaselineFrame *, HandleValue, Handle<StaticWithObject *>);
static const VMFunction EnterWithInfo = FunctionInfo<EnterWithFn>(jit::EnterWith);
bool
BaselineCompiler::emit_JSOP_ENTERWITH()
{
StaticWithObject &withObj = script->getObject(pc)->as<StaticWithObject>();
// Pop "with" object to R0.
frame.popRegsAndSync(1);
// Call a stub to push the object onto the scope chain.
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
pushArg(ImmGCPtr(&withObj));
pushArg(R0);
pushArg(R1.scratchReg());
return callVM(EnterWithInfo);
}
typedef bool (*LeaveWithFn)(JSContext *, BaselineFrame *);
static const VMFunction LeaveWithInfo = FunctionInfo<LeaveWithFn>(jit::LeaveWith);
bool
BaselineCompiler::emit_JSOP_LEAVEWITH()
{
// Call a stub to pop the with object from the scope chain.
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
return callVM(LeaveWithInfo);
}
typedef bool (*GetAndClearExceptionFn)(JSContext *, MutableHandleValue);
static const VMFunction GetAndClearExceptionInfo =
FunctionInfo<GetAndClearExceptionFn>(GetAndClearException);

View File

@ -27,6 +27,8 @@ namespace jit {
_(JSOP_POP) \
_(JSOP_POPN) \
_(JSOP_POPNV) \
_(JSOP_ENTERWITH) \
_(JSOP_LEAVEWITH) \
_(JSOP_DUP) \
_(JSOP_DUP2) \
_(JSOP_SWAP) \

View File

@ -33,6 +33,16 @@ BaselineFrame::popOffScopeChain()
scopeChain_ = &scopeChain_->as<ScopeObject>().enclosingScope();
}
inline void
BaselineFrame::popWith(JSContext *cx)
{
if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
DebugScopes::onPopWith(this);
JS_ASSERT(scopeChain()->is<DynamicWithObject>());
popOffScopeChain();
}
inline bool
BaselineFrame::pushBlock(JSContext *cx, Handle<StaticBlockObject *> block)
{

View File

@ -110,6 +110,8 @@ class BaselineFrame
inline void pushOnScopeChain(ScopeObject &scope);
inline void popOffScopeChain();
inline void popWith(JSContext *cx);
CalleeToken calleeToken() const {
uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken();
return *(CalleeToken *)pointer;

View File

@ -5663,7 +5663,7 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
return true;
}
if (!scopeChain->is<ScopeObject>() || scopeChain->is<WithObject>())
if (!scopeChain->is<ScopeObject>() || scopeChain->is<DynamicWithObject>())
return true;
// Check for an 'own' property on the scope. There is no need to

View File

@ -347,6 +347,9 @@ JitRuntime::handleAccessViolation(JSRuntime *rt, void *faultingAddress)
// to SEGV while still inside the signal handler, and the process will terminate.
JSRuntime::AutoLockForOperationCallback lock(rt);
// Ion code in the runtime faulted after it was made inaccessible. Reset
// the code privileges and patch all loop backedges to perform an interrupt
// check instead.
ensureIonCodeAccessible(rt);
return true;
}
@ -362,18 +365,14 @@ JitRuntime::ensureIonCodeAccessible(JSRuntime *rt)
JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
#endif
if (!ionCodeProtected_)
return;
// Ion code in the runtime faulted after it was made inaccessible. Reset
// the code privileges and patch all loop backedges to perform an interrupt
// check instead.
ionAlloc_->toggleAllCodeAsAccessible(true);
ionCodeProtected_ = false;
if (ionCodeProtected_) {
ionAlloc_->toggleAllCodeAsAccessible(true);
ionCodeProtected_ = false;
}
if (rt->interrupt) {
// The interrupt handler needs to be invoked by this thread, but we
// are inside a signal handler and have no idea what is above us on the
// The interrupt handler needs to be invoked by this thread, but we may
// be inside a signal handler and have no idea what is above us on the
// stack (probably we are executing Ion code at an arbitrary point, but
// we could be elsewhere, say repatching a jump for an IonCache).
// Patch all backedges in the runtime so they will invoke the interrupt

View File

@ -512,7 +512,7 @@ HandleExceptionBaseline(JSContext *cx, const IonFrameIterator &frame, ResumeFrom
// Unwind scope chain (pop block objects).
if (cx->isExceptionPending())
UnwindScope(cx, si, tn->stackDepth);
UnwindScope(cx, si, script->main() + tn->start);
// Compute base pointer and stack pointer.
rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;

View File

@ -735,7 +735,7 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
{
// Unwind scope chain to stack depth 0.
ScopeIter si(frame, pc, cx);
UnwindScope(cx, si, 0);
UnwindScope(cx, si, frame->script()->main());
// If ScriptDebugEpilogue returns |true| we have to return the frame's
// return value. If it returns |false|, the debugger threw an exception.
@ -931,6 +931,19 @@ DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc)
return true;
}
bool
EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val, Handle<StaticWithObject *> templ)
{
return EnterWithOperation(cx, frame, val, templ);
}
bool
LeaveWith(JSContext *cx, BaselineFrame *frame)
{
frame->popWith(cx);
return true;
}
bool
InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t numStackValues)
{

View File

@ -16,6 +16,7 @@ namespace js {
class DeclEnvObject;
class ForkJoinContext;
class StaticWithObject;
namespace jit {
@ -273,6 +274,7 @@ template <> struct TypeToDataType<HandleObject> { static const DataType result =
template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<Handle<StaticWithObject *> > { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<Handle<StaticBlockObject *> > { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; };
@ -298,6 +300,9 @@ template <> struct TypeToArgProperties<HandlePropertyName> {
template <> struct TypeToArgProperties<HandleFunction> {
static const uint32_t result = TypeToArgProperties<JSFunction *>::result | VMFunction::ByRef;
};
template <> struct TypeToArgProperties<Handle<StaticWithObject *> > {
static const uint32_t result = TypeToArgProperties<StaticWithObject *>::result | VMFunction::ByRef;
};
template <> struct TypeToArgProperties<Handle<StaticBlockObject *> > {
static const uint32_t result = TypeToArgProperties<StaticBlockObject *>::result | VMFunction::ByRef;
};
@ -652,6 +657,10 @@ JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleO
bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn);
bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
bool EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val,
Handle<StaticWithObject *> templ);
bool LeaveWith(JSContext *cx, BaselineFrame *frame);
bool PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
bool PopBlockScope(JSContext *cx, BaselineFrame *frame);
bool DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc);

View File

@ -3777,7 +3777,9 @@ MacroAssemblerARMCompat::callWithABI(void *fun, MoveOp::Type result)
case MoveOp::FLOAT32: passedArgTypes_ |= ArgType_Float32; break;
default: MOZ_ASSUME_UNREACHABLE("Invalid return type");
}
#ifdef DEBUG
AssertValidABIFunctionType(passedArgTypes_);
#endif
ABIFunctionType type = ABIFunctionType(passedArgTypes_);
fun = Simulator::RedirectNativeFunction(fun, type);
#endif

View File

@ -3679,24 +3679,30 @@ JSScript::makeTypes(JSContext *cx)
unsigned count = TypeScript::NumTypeSets(this);
types = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(StackTypeSet) * count));
if (!types) {
TypeScript *typeScript = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(StackTypeSet) * count));
if (!typeScript) {
cx->compartment()->types.setPendingNukeTypes(cx);
return false;
}
new(types) TypeScript();
new(typeScript) TypeScript();
TypeSet *typeArray = types->typeArray();
TypeSet *typeArray = typeScript->typeArray();
for (unsigned i = 0; i < count; i++)
new (&typeArray[i]) StackTypeSet();
{
AutoLockForCompilation lock(cx);
types = typeScript;
}
#ifdef DEBUG
for (unsigned i = 0; i < nTypeSets(); i++)
for (unsigned i = 0; i < nTypeSets(); i++) {
InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
i, id());
}
TypeSet *thisTypes = TypeScript::ThisTypes(this);
InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),

View File

@ -597,7 +597,7 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPE
uint32_t offset = script->pcToOffset(pc);
// See if this pc is the next typeset opcode after the last one looked up.
if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->nTypeSets()) {
if ((*hint + 1) < script->nTypeSets() && bytecodeMap[*hint + 1] == offset) {
(*hint)++;
return typeArray + *hint;
}

View File

@ -49,28 +49,6 @@ using mozilla::SpecificNaN;
using JS::ToNumber;
using JS::GenericNaN;
#ifndef M_E
#define M_E 2.7182818284590452354
#endif
#ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074
#endif
#ifndef M_LOG10E
#define M_LOG10E 0.43429448190325182765
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.70710678118654752440
#endif
static const JSConstDoubleSpec math_constants[] = {
{M_E, "E", 0, {0,0,0}},
{M_LOG2E, "LOG2E", 0, {0,0,0}},

View File

@ -11,6 +11,31 @@
#include "NamespaceImports.h"
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#ifndef M_E
# define M_E 2.7182818284590452354
#endif
#ifndef M_LOG2E
# define M_LOG2E 1.4426950408889634074
#endif
#ifndef M_LOG10E
# define M_LOG10E 0.43429448190325182765
#endif
#ifndef M_LN2
# define M_LN2 0.69314718055994530942
#endif
#ifndef M_LN10
# define M_LN10 2.30258509299404568402
#endif
#ifndef M_SQRT2
# define M_SQRT2 1.41421356237309504880
#endif
#ifndef M_SQRT1_2
# define M_SQRT1_2 0.70710678118654752440
#endif
namespace js {
typedef double (*UnaryFunType)(double);

View File

@ -5952,4 +5952,3 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Objects
#endif
}
}

View File

@ -433,8 +433,9 @@ SaveSharedScriptData(ExclusiveContext *, Handle<JSScript *>, SharedScriptData *,
enum XDRClassKind {
CK_BlockObject = 0,
CK_JSFunction = 1,
CK_JSObject = 2
CK_WithObject = 1,
CK_JSFunction = 2,
CK_JSObject = 3
};
template<XDRMode mode>
@ -766,6 +767,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
JSObject *obj = *objp;
if (obj->is<BlockObject>())
classk = CK_BlockObject;
else if (obj->is<StaticWithObject>())
classk = CK_WithObject;
else if (obj->is<JSFunction>())
classk = CK_JSFunction;
else if (obj->is<JSObject>() || obj->is<ArrayObject>())
@ -778,32 +781,40 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
return false;
switch (classk) {
case CK_BlockObject: {
case CK_BlockObject:
case CK_WithObject: {
/* Code the nested block's enclosing scope. */
uint32_t blockEnclosingScopeIndex = 0;
uint32_t enclosingStaticScopeIndex = 0;
if (mode == XDR_ENCODE) {
NestedScopeObject &scope = (*objp)->as<NestedScopeObject>();
if (NestedScopeObject *enclosing = scope.enclosingNestedScope())
blockEnclosingScopeIndex = FindScopeObjectIndex(script, *enclosing);
enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing);
else
blockEnclosingScopeIndex = UINT32_MAX;
enclosingStaticScopeIndex = UINT32_MAX;
}
if (!xdr->codeUint32(&blockEnclosingScopeIndex))
if (!xdr->codeUint32(&enclosingStaticScopeIndex))
return false;
Rooted<JSObject*> blockEnclosingScope(cx);
Rooted<JSObject*> enclosingStaticScope(cx);
if (mode == XDR_DECODE) {
if (blockEnclosingScopeIndex != UINT32_MAX) {
JS_ASSERT(blockEnclosingScopeIndex < i);
blockEnclosingScope = script->objects()->vector[blockEnclosingScopeIndex];
if (enclosingStaticScopeIndex != UINT32_MAX) {
JS_ASSERT(enclosingStaticScopeIndex < i);
enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
} else {
blockEnclosingScope = fun;
enclosingStaticScope = fun;
}
}
Rooted<StaticBlockObject*> tmp(cx, static_cast<StaticBlockObject *>(objp->get()));
if (!XDRStaticBlockObject(xdr, blockEnclosingScope, tmp.address()))
return false;
*objp = tmp;
if (classk == CK_BlockObject) {
Rooted<StaticBlockObject*> tmp(cx, static_cast<StaticBlockObject *>(objp->get()));
if (!XDRStaticBlockObject(xdr, enclosingStaticScope, tmp.address()))
return false;
*objp = tmp;
} else {
Rooted<StaticWithObject*> tmp(cx, static_cast<StaticWithObject *>(objp->get()));
if (!XDRStaticWithObject(xdr, enclosingStaticScope, tmp.address()))
return false;
*objp = tmp;
}
break;
}

View File

@ -396,7 +396,8 @@ class ReferenceFinder {
/* Certain classes of object are for internal use only. */
if (object->is<BlockObject>() ||
object->is<CallObject>() ||
object->is<WithObject>() ||
object->is<StaticWithObject>() ||
object->is<DynamicWithObject>() ||
object->is<DeclEnvObject>()) {
return JSVAL_VOID;
}

View File

@ -416,10 +416,11 @@ def run_tests_parallel(tests, prefix, options):
# This queue will contain the return value of the function
# processing the test results.
total_tests = len(tests) * options.repeat
result_process_return_queue = queue_manager.Queue()
result_process = Process(target=process_test_results_parallel,
args=(async_test_result_queue, result_process_return_queue,
notify_queue, len(tests), options))
notify_queue, total_tests, options))
result_process.start()
# Ensure that a SIGTERM is handled the same way as SIGINT
@ -441,15 +442,16 @@ def run_tests_parallel(tests, prefix, options):
try:
testcnt = 0
# Initially start as many jobs as allowed to run parallel
for i in range(min(options.max_jobs,len(tests))):
for i in range(min(options.max_jobs,total_tests)):
notify_queue.put(True)
# For every item in the notify queue, start one new worker.
# Every completed worker adds a new item to this queue.
while notify_queue.get():
if (testcnt < len(tests)):
if (testcnt < total_tests):
# Start one new worker
worker_process = Process(target=wrap_parallel_run_test, args=(tests[testcnt], prefix, async_test_result_queue, options))
test = tests[testcnt % len(tests)]
worker_process = Process(target=wrap_parallel_run_test, args=(test, prefix, async_test_result_queue, options))
worker_processes.append(worker_process)
worker_process.start()
testcnt += 1
@ -604,17 +606,19 @@ def process_test_results(results, num_tests, options):
return print_test_summary(num_tests, failures, complete, doing, options)
def get_serial_results(tests, prefix, options):
for test in tests:
yield run_test(test, prefix, options)
for i in xrange(0, options.repeat):
for test in tests:
yield run_test(test, prefix, options)
def run_tests(tests, prefix, options):
gen = get_serial_results(tests, prefix, options)
ok = process_test_results(gen, len(tests), options)
ok = process_test_results(gen, len(tests) * options.repeat, options)
return ok
def get_remote_results(tests, device, prefix, options):
for test in tests:
yield run_test_remote(test, device, prefix, options)
for i in xrange(0, options.repeat):
for test in tests:
yield run_test_remote(test, device, prefix, options)
def push_libs(options, device):
# This saves considerable time in pushing unnecessary libraries
@ -668,7 +672,7 @@ def run_tests_remote(tests, prefix, options):
# Run all tests.
gen = get_remote_results(tests, dm, prefix, options)
ok = process_test_results(gen, len(tests), options)
ok = process_test_results(gen, len(tests) * options.repeat, options)
return ok
def parse_jitflags(options):

View File

@ -5591,7 +5591,8 @@ IsDeclarative(Env *env)
static bool
IsWith(Env *env)
{
return env->is<DebugScopeObject>() && env->as<DebugScopeObject>().scope().is<WithObject>();
return env->is<DebugScopeObject>() &&
env->as<DebugScopeObject>().scope().is<DynamicWithObject>();
}
static bool
@ -5641,7 +5642,7 @@ DebuggerEnv_getObject(JSContext *cx, unsigned argc, Value *vp)
JSObject *obj;
if (IsWith(env)) {
obj = &env->as<DebugScopeObject>().scope().as<WithObject>().object();
obj = &env->as<DebugScopeObject>().scope().as<DynamicWithObject>().object();
} else {
obj = env;
JS_ASSERT(!obj->is<DebugScopeObject>());

View File

@ -183,8 +183,8 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName
return false;
} else {
Rooted<JSObject*> normalized(cx, obj);
if (normalized->getClass() == &WithObject::class_ && !shape->hasDefaultGetter())
normalized = &normalized->as<WithObject>().object();
if (normalized->is<DynamicWithObject>() && !shape->hasDefaultGetter())
normalized = &normalized->as<DynamicWithObject>().object();
if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
/* Fast path for Object instance properties. */
JS_ASSERT(shape->hasSlot());

View File

@ -831,9 +831,11 @@ js::TypeOfValue(const Value &v)
* Enter the new with scope using an object at sp[-1] and associate the depth
* of the with block with sp + stackIndex.
*/
static bool
EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stackDepth)
bool
js::EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val,
HandleObject staticWith)
{
JS_ASSERT(staticWith->is<StaticWithObject>());
RootedObject obj(cx);
if (val.isObject()) {
obj = &val.toObject();
@ -844,7 +846,7 @@ EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stack
}
RootedObject scopeChain(cx, frame.scopeChain());
WithObject *withobj = WithObject::create(cx, obj, scopeChain, stackDepth);
DynamicWithObject *withobj = DynamicWithObject::create(cx, obj, scopeChain, staticWith);
if (!withobj)
return false;
@ -852,23 +854,25 @@ EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stack
return true;
}
/* Unwind block and scope chains to match the given depth. */
// Unwind scope chain and iterator to match the static scope corresponding to
// the given bytecode position.
void
js::UnwindScope(JSContext *cx, ScopeIter &si, uint32_t stackDepth)
js::UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc)
{
for (; !si.done(); ++si) {
if (si.done())
return;
Rooted<NestedScopeObject *> staticScope(cx, si.frame().script()->getStaticScope(pc));
for (; si.staticScope() != staticScope; ++si) {
switch (si.type()) {
case ScopeIter::Block:
if (si.staticBlock().stackDepth() < stackDepth)
return;
if (cx->compartment()->debugMode())
DebugScopes::onPopBlock(cx, si);
if (si.staticBlock().needsClone())
si.frame().popBlock(cx);
break;
case ScopeIter::With:
if (si.scope().as<WithObject>().stackDepth() < stackDepth)
return;
si.frame().popWith(cx);
break;
case ScopeIter::Call:
@ -881,7 +885,7 @@ js::UnwindScope(JSContext *cx, ScopeIter &si, uint32_t stackDepth)
static void
ForcedReturn(JSContext *cx, ScopeIter &si, FrameRegs &regs)
{
UnwindScope(cx, si, 0);
UnwindScope(cx, si, regs.fp()->script()->main());
regs.setToEndOfScript();
}
@ -1006,7 +1010,7 @@ HandleError(JSContext *cx, FrameRegs &regs)
for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
JSTryNote *tn = *tni;
UnwindScope(cx, si, tn->stackDepth);
UnwindScope(cx, si, regs.fp()->script()->main() + tn->start);
/*
* Set pc to the first bytecode after the the try note to point
@ -1727,13 +1731,6 @@ END_CASE(JSOP_POP)
CASE(JSOP_POPN)
JS_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
REGS.sp -= GET_UINT16(REGS.pc);
#ifdef DEBUG
if (NestedScopeObject *scope = script->getStaticScope(REGS.pc + JSOP_POPN_LENGTH)) {
JS_ASSERT(scope->is<StaticBlockObject>());
StaticBlockObject &blockObj = scope->as<StaticBlockObject>();
JS_ASSERT(REGS.stackDepth() >= blockObj.stackDepth() + blockObj.slotCount());
}
#endif
END_CASE(JSOP_POPN)
CASE(JSOP_POPNV)
@ -1742,13 +1739,6 @@ CASE(JSOP_POPNV)
Value val = REGS.sp[-1];
REGS.sp -= GET_UINT16(REGS.pc);
REGS.sp[-1] = val;
#ifdef DEBUG
if (NestedScopeObject *scope = script->getStaticScope(REGS.pc + JSOP_POPNV_LENGTH)) {
JS_ASSERT(scope->is<StaticBlockObject>());
StaticBlockObject &blockObj = scope->as<StaticBlockObject>();
JS_ASSERT(REGS.stackDepth() >= blockObj.stackDepth() + blockObj.slotCount());
}
#endif
}
END_CASE(JSOP_POPNV)
@ -1759,28 +1749,18 @@ END_CASE(JSOP_SETRVAL)
CASE(JSOP_ENTERWITH)
{
RootedValue &val = rootValue0;
RootedObject &staticWith = rootObject0;
val = REGS.sp[-1];
REGS.sp--;
staticWith = script->getObject(REGS.pc);
if (!EnterWith(cx, REGS.fp(), val, REGS.stackDepth() - 1))
if (!EnterWithOperation(cx, REGS.fp(), val, staticWith))
goto error;
/*
* We must ensure that different "with" blocks have different stack depth
* associated with them. This allows the try handler search to properly
* recover the scope chain. Thus we must keep the stack at least at the
* current level.
*
* We set sp[-1] to the current "with" object to help asserting the
* enter/leave balance in [leavewith].
*/
REGS.sp[-1].setObject(*REGS.fp()->scopeChain());
}
END_CASE(JSOP_ENTERWITH)
CASE(JSOP_LEAVEWITH)
JS_ASSERT(REGS.sp[-1].toObject() == *REGS.fp()->scopeChain());
REGS.fp()->popWith(cx);
REGS.sp--;
END_CASE(JSOP_LEAVEWITH)
CASE(JSOP_RETURN)

View File

@ -318,9 +318,10 @@ TypeOfValue(const Value &v);
extern bool
HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
/* Unwind block and scope chains to match the given depth. */
// Unwind scope chain and iterator to match the static scope corresponding to
// the given bytecode position.
extern void
UnwindScope(JSContext *cx, ScopeIter &si, uint32_t stackDepth);
UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc);
/*
* Unwind for an uncatchable exception. This means not running finalizers, etc;
@ -450,6 +451,10 @@ bool
InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandlePropertyName name,
HandleObject val);
bool
EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, HandleObject staticWith);
bool
InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
HandleObject val);

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