merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-12-11 11:38:17 +01:00
commit b25476080d
137 changed files with 1696 additions and 752 deletions

View File

@ -1007,16 +1007,8 @@ pref("security.exthelperapp.disable_background_handling", true);
// Inactivity time in milliseconds after which we shut down the OS.File worker. // Inactivity time in milliseconds after which we shut down the OS.File worker.
pref("osfile.reset_worker_delay", 5000); pref("osfile.reset_worker_delay", 5000);
// APZC preferences.
#ifdef MOZ_WIDGET_GONK
pref("apz.allow_zooming", true);
#endif
// Gaia relies heavily on scroll events for now, so lets fire them
// more often than the default value (100).
pref("apz.pan_repaint_interval", 16);
// APZ physics settings, tuned by UX designers // APZ physics settings, tuned by UX designers
pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking
pref("apz.fling_curve_function_x1", "0.41"); pref("apz.fling_curve_function_x1", "0.41");
pref("apz.fling_curve_function_y1", "0.0"); pref("apz.fling_curve_function_y1", "0.0");
pref("apz.fling_curve_function_x2", "0.80"); pref("apz.fling_curve_function_x2", "0.80");
@ -1024,29 +1016,7 @@ pref("apz.fling_curve_function_y2", "1.0");
pref("apz.fling_curve_threshold_inches_per_ms", "0.01"); pref("apz.fling_curve_threshold_inches_per_ms", "0.01");
pref("apz.fling_friction", "0.0019"); pref("apz.fling_friction", "0.0019");
pref("apz.max_velocity_inches_per_ms", "0.07"); pref("apz.max_velocity_inches_per_ms", "0.07");
pref("apz.touch_start_tolerance", "0.1");
#ifdef MOZ_WIDGET_GONK
pref("apz.touch_move_tolerance", "0.03");
#endif
// Tweak default displayport values to reduce the risk of running out of
// memory when zooming in
pref("apz.x_skate_size_multiplier", "1.25");
pref("apz.y_skate_size_multiplier", "1.5");
pref("apz.x_stationary_size_multiplier", "1.5");
pref("apz.y_stationary_size_multiplier", "1.8");
pref("apz.enlarge_displayport_when_clipped", true);
// Use "sticky" axis locking
pref("apz.axis_lock.mode", 2);
// Overscroll-related settings
pref("apz.overscroll.enabled", true); pref("apz.overscroll.enabled", true);
pref("apz.overscroll.stretch_factor", "0.35");
pref("apz.overscroll.spring_stiffness", "0.0018");
pref("apz.overscroll.spring_friction", "0.015");
pref("apz.overscroll.stop_distance_threshold", "5.0");
pref("apz.overscroll.stop_velocity_threshold", "0.01");
// For event-regions based hit-testing // For event-regions based hit-testing
pref("layout.event-regions.enabled", true); pref("layout.event-regions.enabled", true);

View File

@ -29,17 +29,12 @@ function serializeServiceWorkerInfo(aServiceWorkerInfo) {
let result = {}; let result = {};
Object.keys(aServiceWorkerInfo).forEach(property => {
if (typeof aServiceWorkerInfo[property] == "function") {
return;
}
if (property === "principal") {
result.principal = { result.principal = {
origin: aServiceWorkerInfo.principal.originNoSuffix, origin: aServiceWorkerInfo.principal.originNoSuffix,
originAttributes: aServiceWorkerInfo.principal.originAttributes originAttributes: aServiceWorkerInfo.principal.originAttributes
}; };
return;
} ["scope", "scriptSpec"].forEach(property => {
result[property] = aServiceWorkerInfo[property]; result[property] = aServiceWorkerInfo[property];
}); });

View File

@ -761,7 +761,7 @@
} }
// If the browser was playing audio, we should remove the playing state. // If the browser was playing audio, we should remove the playing state.
if (this.mTab.hasAttribute("soundplaying")) { if (this.mTab.hasAttribute("soundplaying") && this.mBrowser.lastURI != aLocation) {
this.mTab.removeAttribute("soundplaying"); this.mTab.removeAttribute("soundplaying");
this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]); this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
} }

View File

@ -324,7 +324,6 @@ skip-if = buildapp == 'mulet'
[browser_identity_UI.js] [browser_identity_UI.js]
[browser_insecureLoginForms.js] [browser_insecureLoginForms.js]
[browser_keywordBookmarklets.js] [browser_keywordBookmarklets.js]
skip-if = e10s # Bug 1102025 - different principals for the bookmarklet only in e10s mode (unclear if test or 'real' issue)
[browser_keywordSearch.js] [browser_keywordSearch.js]
[browser_keywordSearch_postData.js] [browser_keywordSearch_postData.js]
[browser_lastAccessedTab.js] [browser_lastAccessedTab.js]

View File

@ -12,6 +12,14 @@ add_task(function* test_keyword_bookmarklet() {
yield promisePageShow(); yield promisePageShow();
let originalPrincipal = gBrowser.contentPrincipal; let originalPrincipal = gBrowser.contentPrincipal;
function getPrincipalURI() {
return ContentTask.spawn(tab.linkedBrowser, null, function() {
return content.document.nodePrincipal.URI.spec;
});
}
let originalPrincipalURI = yield getPrincipalURI();
yield PlacesUtils.keywords.insert({ keyword: "bm", url: "javascript:1;" }) yield PlacesUtils.keywords.insert({ keyword: "bm", url: "javascript:1;" })
// Enter bookmarklet keyword in the URL bar // Enter bookmarklet keyword in the URL bar
@ -21,7 +29,19 @@ add_task(function* test_keyword_bookmarklet() {
yield promisePageShow(); yield promisePageShow();
ok(gBrowser.contentPrincipal.equals(originalPrincipal), "javascript bookmarklet should inherit principal"); let newPrincipalURI = yield getPrincipalURI();
is(newPrincipalURI, originalPrincipalURI, "content has the same principal");
// In e10s, null principals don't round-trip so the same null principal sent
// from the child will be a new null principal. Verify that this is the
// case.
if (tab.linkedBrowser.isRemoteBrowser) {
ok(originalPrincipal.isNullPrincipal && gBrowser.contentPrincipal.isNullPrincipal,
"both principals should be null principals in the parent");
} else {
ok(gBrowser.contentPrincipal.equals(originalPrincipal),
"javascript bookmarklet should inherit principal");
}
}); });
function* promisePageShow() { function* promisePageShow() {

View File

@ -4224,7 +4224,6 @@ cairo-uikit)
CXXFLAGS="$CXXFLAGS $TK_CFLAGS" CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
MOZ_USER_DIR="Mozilla" MOZ_USER_DIR="Mozilla"
MOZ_FS_LAYOUT=bundle MOZ_FS_LAYOUT=bundle
AC_DEFINE(MOZ_SINGLE_PROCESS_APZ)
;; ;;
cairo-android) cairo-android)
@ -4800,9 +4799,6 @@ MOZ_ARG_ENABLE_BOOL(android-apz,
if test -n "$MOZ_ANDROID_APZ"; then if test -n "$MOZ_ANDROID_APZ"; then
dnl Do this if defined in confvars.sh dnl Do this if defined in confvars.sh
AC_DEFINE(MOZ_ANDROID_APZ) AC_DEFINE(MOZ_ANDROID_APZ)
if test -z "$MOZ_B2GDROID"; then
AC_DEFINE(MOZ_SINGLE_PROCESS_APZ)
fi
fi fi
dnl ======================================================== dnl ========================================================

View File

@ -229,7 +229,7 @@ function installCache(app) {
return; return;
let principal = let principal =
Services.scriptSecurityManager.createCodebasePrincipal(app.origin, {appId: aApp.localId}); Services.scriptSecurityManager.createCodebasePrincipal(app.origin, {appId: app.localId});
// If the build has been correctly configured, this should not happen! // If the build has been correctly configured, this should not happen!
// If we install the cache anyway, it won't be updateable. If we don't install // If we install the cache anyway, it won't be updateable. If we don't install

View File

@ -7509,7 +7509,9 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
if (IsFileImage(file, type)) { if (IsFileImage(file, type)) {
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = type; item->flavor() = type;
SlurpFileToString(file, item->data()); nsAutoCString data;
SlurpFileToString(file, data);
item->data() = data;
} }
continue; continue;
@ -7669,11 +7671,10 @@ nsContentUtils::ToWidgetPoint(const CSSPoint& aPoint,
const nsPoint& aOffset, const nsPoint& aOffset,
nsPresContext* aPresContext) nsPresContext* aPresContext)
{ {
nsPoint point = CSSPoint::ToAppUnits(aPoint) + aOffset; return LayoutDeviceIntPoint::FromAppUnitsRounded(
#if defined(MOZ_SINGLE_PROCESS_APZ) (CSSPoint::ToAppUnits(aPoint) +
point = point.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution()); aOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution()),
#endif aPresContext->AppUnitsPerDevPixel());
return LayoutDeviceIntPoint::FromAppUnitsRounded(point, aPresContext->AppUnitsPerDevPixel());
} }
nsView* nsView*

View File

@ -286,11 +286,10 @@ already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow, NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
const nsAString& aExpression, ErrorResult& aError) const nsAString& aExpression, ErrorResult& aError)
{ {
ErrorResult rv;
bool allowEval = false; bool allowEval = false;
RefPtr<nsJSScriptTimeoutHandler> handler = RefPtr<nsJSScriptTimeoutHandler> handler =
new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, rv); new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, aError);
if (rv.Failed() || !allowEval) { if (aError.Failed() || !allowEval) {
return nullptr; return nullptr;
} }

View File

@ -5,61 +5,66 @@
* loads. The policy we are enforcing is outlined here: * loads. The policy we are enforcing is outlined here:
* https://bugzilla.mozilla.org/show_bug.cgi?id=593387#c17 * https://bugzilla.mozilla.org/show_bug.cgi?id=593387#c17
*/ */
var newBrowser;
function test() { add_task(function* test() {
waitForExplicitFinish(); yield BrowserTestUtils.withNewTab({ gBrowser,
url: "chrome://global/content/mozilla.xhtml" },
function* (newBrowser) {
// NB: We load the chrome:// page in the parent process.
yield testXFOFrameInChrome(newBrowser);
var newTab = gBrowser.addTab(); // Run next test (try the same with a content top-level context)
gBrowser.selectedTab = newTab; yield BrowserTestUtils.loadURI(newBrowser, "http://example.com/");
newBrowser = gBrowser.getBrowserForTab(newTab); yield BrowserTestUtils.browserLoaded(newBrowser);
//alert(newBrowser.contentWindow);
newBrowser.addEventListener("load", testXFOFrameInChrome, true); yield ContentTask.spawn(newBrowser, null, testXFOFrameInContent);
newBrowser.contentWindow.location = "chrome://global/content/mozilla.xhtml"; });
} });
function testXFOFrameInChrome() {
newBrowser.removeEventListener("load", testXFOFrameInChrome, true);
function testXFOFrameInChrome(newBrowser) {
// Insert an iframe that specifies "X-Frame-Options: DENY" and verify // Insert an iframe that specifies "X-Frame-Options: DENY" and verify
// that it loads, since the top context is chrome // that it loads, since the top context is chrome
var deferred = {};
deferred.promise = new Promise((resolve) => {
deferred.resolve = resolve;
});
var frame = newBrowser.contentDocument.createElement("iframe"); var frame = newBrowser.contentDocument.createElement("iframe");
frame.src = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny"; frame.src = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny";
frame.addEventListener("load", function() { frame.addEventListener("load", function loaded() {
frame.removeEventListener("load", arguments.callee, true); frame.removeEventListener("load", loaded, true);
// Test that the frame loaded // Test that the frame loaded
var test = this.contentDocument.getElementById("test"); var test = this.contentDocument.getElementById("test");
is(test.tagName, "H1", "wrong element type"); is(test.tagName, "H1", "wrong element type");
is(test.textContent, "deny", "wrong textContent"); is(test.textContent, "deny", "wrong textContent");
deferred.resolve();
// Run next test (try the same with a content top-level context)
newBrowser.addEventListener("load", testXFOFrameInContent, true);
newBrowser.contentWindow.location = "http://example.com/";
}, true); }, true);
newBrowser.contentDocument.body.appendChild(frame); newBrowser.contentDocument.body.appendChild(frame);
return deferred.promise;
} }
function testXFOFrameInContent() { function testXFOFrameInContent(newBrowser) {
newBrowser.removeEventListener("load", testXFOFrameInContent, true);
// Insert an iframe that specifies "X-Frame-Options: DENY" and verify that it // Insert an iframe that specifies "X-Frame-Options: DENY" and verify that it
// is blocked from loading since the top browsing context is another site // is blocked from loading since the top browsing context is another site
var frame = newBrowser.contentDocument.createElement("iframe"); var deferred = {};
deferred.promise = new Promise((resolve) => {
deferred.resolve = resolve;
});
var frame = content.document.createElement("iframe");
frame.src = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny"; frame.src = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny";
frame.addEventListener("load", function() { frame.addEventListener("load", function loaded() {
frame.removeEventListener("load", arguments.callee, true); frame.removeEventListener("load", loaded, true);
// Test that the frame DID NOT load // Test that the frame DID NOT load
var test = this.contentDocument.getElementById("test"); var test = this.contentDocument.getElementById("test");
is(test, undefined, "should be about:blank"); is(test, null, "should be about:blank");
// Finalize the test deferred.resolve();
gBrowser.removeCurrentTab();
finish();
}, true); }, true);
newBrowser.contentDocument.body.appendChild(frame); content.document.body.appendChild(frame);
return deferred.promise;
} }

View File

@ -2487,14 +2487,24 @@ CanvasRenderingContext2D::UpdateFilter()
// rects // rects
// //
static bool
ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight)
{
// bug 1018527
// The values of canvas API input are in double precision, but Moz2D APIs are
// using float precision. Bypass canvas API calls when the input is out of
// float precision to avoid precision problem
if (!std::isfinite((float)aX) | !std::isfinite((float)aY) |
!std::isfinite((float)aWidth) | !std::isfinite((float)aHeight)) {
return false;
}
// bug 1074733 // bug 1074733
// The canvas spec does not forbid rects with negative w or h, so given // The canvas spec does not forbid rects with negative w or h, so given
// corners (x, y), (x+w, y), (x+w, y+h), and (x, y+h) we must generate // corners (x, y), (x+w, y), (x+w, y+h), and (x, y+h) we must generate
// the appropriate rect by flipping negative dimensions. This prevents // the appropriate rect by flipping negative dimensions. This prevents
// draw targets from receiving "empty" rects later on. // draw targets from receiving "empty" rects later on.
static void
NormalizeRect(double& aX, double& aY, double& aWidth, double& aHeight)
{
if (aWidth < 0) { if (aWidth < 0) {
aWidth = -aWidth; aWidth = -aWidth;
aX -= aWidth; aX -= aWidth;
@ -2503,13 +2513,16 @@ NormalizeRect(double& aX, double& aY, double& aWidth, double& aHeight)
aHeight = -aHeight; aHeight = -aHeight;
aY -= aHeight; aY -= aHeight;
} }
return true;
} }
void void
CanvasRenderingContext2D::ClearRect(double x, double y, double w, CanvasRenderingContext2D::ClearRect(double x, double y, double w,
double h) double h)
{ {
NormalizeRect(x, y, w, h); if(!ValidateRect(x, y, w, h)) {
return;
}
EnsureTarget(); EnsureTarget();
@ -2524,7 +2537,9 @@ CanvasRenderingContext2D::FillRect(double x, double y, double w,
{ {
const ContextState &state = CurrentState(); const ContextState &state = CurrentState();
NormalizeRect(x, y, w, h); if(!ValidateRect(x, y, w, h)) {
return;
}
if (state.patternStyles[Style::FILL]) { if (state.patternStyles[Style::FILL]) {
CanvasPattern::RepeatMode repeat = CanvasPattern::RepeatMode repeat =
@ -2599,7 +2614,10 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w,
if (!w && !h) { if (!w && !h) {
return; return;
} }
NormalizeRect(x, y, w, h);
if(!ValidateRect(x, y, w, h)) {
return;
}
EnsureTarget(); EnsureTarget();
if (!IsTargetValid()) { if (!IsTargetValid()) {
@ -4375,8 +4393,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6); MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6);
if (optional_argc == 6) { if (optional_argc == 6) {
NormalizeRect(sx, sy, sw, sh); if (!ValidateRect(sx, sy, sw, sh) ||
NormalizeRect(dx, dy, dw, dh); !ValidateRect(dx, dy, dw, dh)) {
return;
}
} }
RefPtr<SourceSurface> srcSurf; RefPtr<SourceSurface> srcSurf;

View File

@ -21536,6 +21536,20 @@ isPixel(ctx, 50,25, 0,255,0,255, 0);
</script> </script>
<!-- [[[ test_2d.clearRect.testdoubleprecision.html ]]] -->
<p>Canvas test: 2d.clearRect.testdoubleprecision</p>
<canvas id="c690" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<script>
function test_2d_clearRect_testdoubleprecision() {
var canvas = document.getElementById('c690');
ctx = canvas.getContext('2d');
ctx.setTransform(1, 1, 1, 1, 0, 0);
ctx.clearRect(-1.79e+308, 0, 1.79e+308, 8);
}
</script>
<script> <script>
function asyncTestsDone() { function asyncTestsDone() {
@ -24835,6 +24849,12 @@ try {
} catch (e) { } catch (e) {
ok(false, "unexpected exception thrown in: test_type_replace"); ok(false, "unexpected exception thrown in: test_type_replace");
} }
try {
test_2d_clearRect_testdoubleprecision();
} catch(e) {
throw e;
ok(false, "unexpected exception thrown in: test_2d_clearRect_testdoubleprecision");
}
//run the asynchronous tests //run the asynchronous tests
try { try {

View File

@ -935,11 +935,9 @@ Event::GetScreenCoords(nsPresContext* aPresContext,
nsPoint pt = nsPoint pt =
LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
#if defined(MOZ_SINGLE_PROCESS_APZ)
if (aPresContext->PresShell()) { if (aPresContext->PresShell()) {
pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeScaleResolution()); pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
} }
#endif
pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(), pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(),
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());

View File

@ -760,15 +760,17 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
if (content) if (content)
mCurrentTargetContent = content; mCurrentTargetContent = content;
// NOTE: Don't refer TextComposition::IsComposing() since DOM Level 3 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
// Events defines that KeyboardEvent.isComposing is true when it's // defines that KeyboardEvent.isComposing is true when it's
// dispatched after compositionstart and compositionend. // dispatched after compositionstart and compositionend.
// TextComposition::IsComposing() is false even before // TextComposition::IsComposing() is false even before
// compositionend if there is no composing string. // compositionend if there is no composing string.
WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); // And also don't expose other document's composition state.
// A native IME context is typically shared by multiple documents.
// So, don't use GetTextCompositionFor(nsIWidget*) here.
RefPtr<TextComposition> composition = RefPtr<TextComposition> composition =
IMEStateManager::GetTextCompositionFor(keyEvent); IMEStateManager::GetTextCompositionFor(aPresContext);
keyEvent->mIsComposing = !!composition; aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
} }
break; break;
case eWheel: case eWheel:

View File

@ -1144,11 +1144,21 @@ IMEStateManager::DispatchCompositionEvent(
MOZ_LOG(sISMLog, LogLevel::Info, MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, " ("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
"aPresContext=0x%p, aCompositionEvent={ message=%s, " "aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
"mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
"mOriginProcessID=0x%X }, widget(0x%p)={ "
"GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
"mOriginProcessID=0x%X }, Destroyed()=%s }, "
"mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, " "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
"aIsSynthesized=%s), tabParent=%p", "aIsSynthesized=%s), tabParent=%p",
aEventTargetNode, aPresContext, aEventTargetNode, aPresContext,
ToChar(aCompositionEvent->mMessage), ToChar(aCompositionEvent->mMessage),
aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
aCompositionEvent->mNativeIMEContext.mOriginProcessID,
aCompositionEvent->widget.get(),
aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
GetBoolName(aCompositionEvent->widget->Destroyed()),
GetBoolName(aCompositionEvent->mFlags.mIsTrusted), GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
GetBoolName(aCompositionEvent->mFlags.mPropagationStopped), GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
GetBoolName(aIsSynthesized), tabParent.get())); GetBoolName(aIsSynthesized), tabParent.get()));
@ -1164,7 +1174,7 @@ IMEStateManager::DispatchCompositionEvent(
EnsureTextCompositionArray(); EnsureTextCompositionArray();
RefPtr<TextComposition> composition = RefPtr<TextComposition> composition =
sTextCompositions->GetCompositionFor(aCompositionEvent->widget); sTextCompositions->GetCompositionFor(aCompositionEvent);
if (!composition) { if (!composition) {
// If synthesized event comes after delayed native composition events // If synthesized event comes after delayed native composition events
// for request of commit or cancel, we should ignore it. // for request of commit or cancel, we should ignore it.
@ -1278,8 +1288,18 @@ IMEStateManager::OnCompositionEventDiscarded(
MOZ_LOG(sISMLog, LogLevel::Info, MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ " ("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ "
"mMessage=%s, mFlags={ mIsTrusted=%s } })", "mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
"mOriginProcessID=0x%X }, widget(0x%p)={ "
"GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
"mOriginProcessID=0x%X }, Destroyed()=%s }, "
"mFlags={ mIsTrusted=%s } })",
ToChar(aCompositionEvent->mMessage), ToChar(aCompositionEvent->mMessage),
aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
aCompositionEvent->mNativeIMEContext.mOriginProcessID,
aCompositionEvent->widget.get(),
aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
GetBoolName(aCompositionEvent->widget->Destroyed()),
GetBoolName(aCompositionEvent->mFlags.mIsTrusted))); GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
if (!aCompositionEvent->mFlags.mIsTrusted) { if (!aCompositionEvent->mFlags.mIsTrusted) {
@ -1649,11 +1669,27 @@ IMEStateManager::GetTextCompositionFor(nsIWidget* aWidget)
// static // static
already_AddRefed<TextComposition> already_AddRefed<TextComposition>
IMEStateManager::GetTextCompositionFor(WidgetGUIEvent* aGUIEvent) IMEStateManager::GetTextCompositionFor(
const WidgetCompositionEvent* aCompositionEvent)
{ {
MOZ_ASSERT(aGUIEvent->AsCompositionEvent() || aGUIEvent->AsKeyboardEvent(), if (!sTextCompositions) {
"aGUIEvent has to be WidgetCompositionEvent or WidgetKeyboardEvent"); return nullptr;
return GetTextCompositionFor(aGUIEvent->widget); }
RefPtr<TextComposition> textComposition =
sTextCompositions->GetCompositionFor(aCompositionEvent);
return textComposition.forget();
}
// static
already_AddRefed<TextComposition>
IMEStateManager::GetTextCompositionFor(nsPresContext* aPresContext)
{
if (!sTextCompositions) {
return nullptr;
}
RefPtr<TextComposition> textComposition =
sTextCompositions->GetCompositionFor(aPresContext);
return textComposition.forget();
} }
} // namespace mozilla } // namespace mozilla

View File

@ -181,11 +181,17 @@ public:
/** /**
* Returns TextComposition instance for the event. * Returns TextComposition instance for the event.
*
* @param aGUIEvent Should be a composition event which is being dispatched.
*/ */
static already_AddRefed<TextComposition> static already_AddRefed<TextComposition>
GetTextCompositionFor(WidgetGUIEvent* aGUIEvent); GetTextCompositionFor(const WidgetCompositionEvent* aCompositionEvent);
/**
* Returns TextComposition instance for the pres context.
* Be aware, even if another pres context which shares native IME context with
* specified pres context has composition, this returns nullptr.
*/
static already_AddRefed<TextComposition>
GetTextCompositionFor(nsPresContext* aPresContext);
/** /**
* Send a notification to IME. It depends on the IME or platform spec what * Send a notification to IME. It depends on the IME or platform spec what

View File

@ -39,8 +39,7 @@ TextComposition::TextComposition(nsPresContext* aPresContext,
: mPresContext(aPresContext) : mPresContext(aPresContext)
, mNode(aNode) , mNode(aNode)
, mTabParent(aTabParent) , mTabParent(aTabParent)
, mNativeContext( , mNativeContext(aCompositionEvent->mNativeIMEContext)
aCompositionEvent->widget->GetInputContext().mNativeIMEContext)
, mCompositionStartOffset(0) , mCompositionStartOffset(0)
, mCompositionTargetOffset(0) , mCompositionTargetOffset(0)
, mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests) , mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
@ -54,6 +53,7 @@ TextComposition::TextComposition(nsPresContext* aPresContext,
Preferences::GetBool("dom.compositionevent.allow_control_characters", Preferences::GetBool("dom.compositionevent.allow_control_characters",
false)) false))
{ {
MOZ_ASSERT(aCompositionEvent->mNativeIMEContext.IsValid());
} }
void void
@ -66,12 +66,6 @@ TextComposition::Destroy()
// this being destroyed for cleaning up the stuff. // this being destroyed for cleaning up the stuff.
} }
bool
TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
{
return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
}
bool bool
TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const
{ {
@ -114,6 +108,7 @@ TextComposition::CloneAndDispatchAs(
compositionEvent.time = aCompositionEvent->time; compositionEvent.time = aCompositionEvent->time;
compositionEvent.timeStamp = aCompositionEvent->timeStamp; compositionEvent.timeStamp = aCompositionEvent->timeStamp;
compositionEvent.mData = aCompositionEvent->mData; compositionEvent.mData = aCompositionEvent->mData;
compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
compositionEvent.mOriginalMessage = aCompositionEvent->mMessage; compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
compositionEvent.mFlags.mIsSynthesizedForTests = compositionEvent.mFlags.mIsSynthesizedForTests =
aCompositionEvent->mFlags.mIsSynthesizedForTests; aCompositionEvent->mFlags.mIsSynthesizedForTests;
@ -613,6 +608,7 @@ TextComposition::CompositionEventDispatcher::Run()
switch (mEventMessage) { switch (mEventMessage) {
case eCompositionStart: { case eCompositionStart: {
WidgetCompositionEvent compStart(true, eCompositionStart, widget); WidgetCompositionEvent compStart(true, eCompositionStart, widget);
compStart.mNativeIMEContext = mTextComposition->mNativeContext;
WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget); WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
ContentEventHandler handler(presContext); ContentEventHandler handler(presContext);
handler.OnQuerySelectedText(&selectedText); handler.OnQuerySelectedText(&selectedText);
@ -629,6 +625,7 @@ TextComposition::CompositionEventDispatcher::Run()
case eCompositionCommitAsIs: case eCompositionCommitAsIs:
case eCompositionCommit: { case eCompositionCommit: {
WidgetCompositionEvent compEvent(true, mEventMessage, widget); WidgetCompositionEvent compEvent(true, mEventMessage, widget);
compEvent.mNativeIMEContext = mTextComposition->mNativeContext;
if (mEventMessage != eCompositionCommitAsIs) { if (mEventMessage != eCompositionCommitAsIs) {
compEvent.mData = mData; compEvent.mData = mData;
} }
@ -650,16 +647,25 @@ TextComposition::CompositionEventDispatcher::Run()
******************************************************************************/ ******************************************************************************/
TextCompositionArray::index_type TextCompositionArray::index_type
TextCompositionArray::IndexOf(nsIWidget* aWidget) TextCompositionArray::IndexOf(const NativeIMEContext& aNativeIMEContext)
{ {
if (!aNativeIMEContext.IsValid()) {
return NoIndex;
}
for (index_type i = Length(); i > 0; --i) { for (index_type i = Length(); i > 0; --i) {
if (ElementAt(i - 1)->MatchesNativeContext(aWidget)) { if (ElementAt(i - 1)->GetNativeIMEContext() == aNativeIMEContext) {
return i - 1; return i - 1;
} }
} }
return NoIndex; return NoIndex;
} }
TextCompositionArray::index_type
TextCompositionArray::IndexOf(nsIWidget* aWidget)
{
return IndexOf(aWidget->GetNativeIMEContext());
}
TextCompositionArray::index_type TextCompositionArray::index_type
TextCompositionArray::IndexOf(nsPresContext* aPresContext) TextCompositionArray::IndexOf(nsPresContext* aPresContext)
{ {
@ -693,6 +699,27 @@ TextCompositionArray::GetCompositionFor(nsIWidget* aWidget)
return ElementAt(i); return ElementAt(i);
} }
TextComposition*
TextCompositionArray::GetCompositionFor(
const WidgetCompositionEvent* aCompositionEvent)
{
index_type i = IndexOf(aCompositionEvent->mNativeIMEContext);
if (i == NoIndex) {
return nullptr;
}
return ElementAt(i);
}
TextComposition*
TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext)
{
index_type i = IndexOf(aPresContext);
if (i == NoIndex) {
return nullptr;
}
return ElementAt(i);
}
TextComposition* TextComposition*
TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext, TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext,
nsINode* aNode) nsINode* aNode)

View File

@ -76,7 +76,10 @@ public:
// came from nsDOMWindowUtils. // came from nsDOMWindowUtils.
bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; } bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
bool MatchesNativeContext(nsIWidget* aWidget) const; const widget::NativeIMEContext& GetNativeIMEContext() const
{
return mNativeContext;
}
/** /**
* This is called when IMEStateManager stops managing the instance. * This is called when IMEStateManager stops managing the instance.
@ -191,7 +194,7 @@ private:
// mNativeContext stores a opaque pointer. This works as the "ID" for this // mNativeContext stores a opaque pointer. This works as the "ID" for this
// composition. Don't access the instance, it may not be available. // composition. Don't access the instance, it may not be available.
void* mNativeContext; widget::NativeIMEContext mNativeContext;
// mEditorWeak is a weak reference to the focused editor handling composition. // mEditorWeak is a weak reference to the focused editor handling composition.
nsWeakPtr mEditorWeak; nsWeakPtr mEditorWeak;
@ -400,11 +403,19 @@ class TextCompositionArray final :
public nsAutoTArray<RefPtr<TextComposition>, 2> public nsAutoTArray<RefPtr<TextComposition>, 2>
{ {
public: public:
// Looking for per native IME context.
index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
index_type IndexOf(nsIWidget* aWidget); index_type IndexOf(nsIWidget* aWidget);
TextComposition* GetCompositionFor(nsIWidget* aWidget);
TextComposition* GetCompositionFor(
const WidgetCompositionEvent* aCompositionEvent);
// Looking for per nsPresContext
index_type IndexOf(nsPresContext* aPresContext); index_type IndexOf(nsPresContext* aPresContext);
index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode); index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
TextComposition* GetCompositionFor(nsIWidget* aWidget); TextComposition* GetCompositionFor(nsPresContext* aPresContext);
TextComposition* GetCompositionFor(nsPresContext* aPresContext, TextComposition* GetCompositionFor(nsPresContext* aPresContext,
nsINode* aNode); nsINode* aNode);
TextComposition* GetCompositionInContent(nsPresContext* aPresContext, TextComposition* GetCompositionInContent(nsPresContext* aPresContext,

View File

@ -4995,7 +4995,7 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
uint64_t id = window->WindowID(); uint64_t id = window->WindowID();
MediaStreamGraph* msg = MediaStreamGraph* msg =
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER, MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
AudioChannel::Normal); mAudioChannel);
if (GetSrcMediaStream()) { if (GetSrcMediaStream()) {
mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream()); mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());

View File

@ -235,20 +235,19 @@ parent:
IMENotification notification); IMENotification notification);
/** /**
* Instructs chrome to end any pending composition * Requests chrome to commit or cancel composition of IME.
* *
* cancel true if composition should be cancelled * cancel Set true if composition should be cancelled.
* noCompositionEvent true if no composition event is fired by commit or
* cancel
* composition Text to commit before ending the composition
* *
* if cancel is true, * isCommitted Returns true if the request causes composition
* widget should return empty string for composition * being committed synchronously.
* if cancel is false, * committedString Returns committed string. The may be non-empty
* widget should return the current composition text * string even if cancel is true because IME may
* try to restore selected string which was
* replaced with the composition.
*/ */
prio(urgent) sync EndIMEComposition(bool cancel) prio(urgent) sync RequestIMEToCommitComposition(bool cancel)
returns (bool noCompositionEvent, nsString composition); returns (bool isCommitted, nsString committedString);
/** /**
* OnEventNeedingAckHandled() is called after a child process dispatches a * OnEventNeedingAckHandled() is called after a child process dispatches a
@ -296,8 +295,7 @@ parent:
nsCString[] disabledCommands); nsCString[] disabledCommands);
prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled, prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
int32_t IMEOpen, int32_t IMEOpen);
intptr_t NativeIMEContext);
prio(urgent) async SetInputContext(int32_t IMEEnabled, prio(urgent) async SetInputContext(int32_t IMEEnabled,
int32_t IMEOpen, int32_t IMEOpen,

View File

@ -2321,16 +2321,19 @@ TabParent::GetRenderFrame()
} }
bool bool
TabParent::RecvEndIMEComposition(const bool& aCancel, TabParent::RecvRequestIMEToCommitComposition(const bool& aCancel,
bool* aNoCompositionEvent, bool* aIsCommitted,
nsString* aComposition) nsString* aCommittedString)
{ {
nsCOMPtr<nsIWidget> widget = GetWidget(); nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) { if (!widget) {
*aIsCommitted = false;
return true; return true;
} }
*aNoCompositionEvent =
!mContentCache.RequestToCommitComposition(widget, aCancel, *aComposition); *aIsCommitted =
mContentCache.RequestIMEToCommitComposition(widget, aCancel,
*aCommittedString);
return true; return true;
} }
@ -2363,21 +2366,18 @@ TabParent::RecvSetPluginFocused(const bool& aFocused)
bool bool
TabParent::RecvGetInputContext(int32_t* aIMEEnabled, TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen, int32_t* aIMEOpen)
intptr_t* aNativeIMEContext)
{ {
nsCOMPtr<nsIWidget> widget = GetWidget(); nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) { if (!widget) {
*aIMEEnabled = IMEState::DISABLED; *aIMEEnabled = IMEState::DISABLED;
*aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; *aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
*aNativeIMEContext = 0;
return true; return true;
} }
InputContext context = widget->GetInputContext(); InputContext context = widget->GetInputContext();
*aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled); *aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
*aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen); *aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
*aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
return true; return true;
} }

View File

@ -187,17 +187,16 @@ public:
virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache, virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
const widget::IMENotification& aEventMessage) override; const widget::IMENotification& aEventMessage) override;
virtual bool RecvOnEventNeedingAckHandled(const EventMessage& aMessage) override; virtual bool RecvOnEventNeedingAckHandled(const EventMessage& aMessage) override;
virtual bool RecvEndIMEComposition(const bool& aCancel, virtual bool RecvRequestIMEToCommitComposition(const bool& aCancel,
bool* aNoCompositionEvent, bool* aIsCommitted,
nsString* aComposition) override; nsString* aCommittedString) override;
virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent, virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
const int32_t& aPanelX, const int32_t& aPanelX,
const int32_t& aPanelY, const int32_t& aPanelY,
nsString* aCommitted) override; nsString* aCommitted) override;
virtual bool RecvSetPluginFocused(const bool& aFocused) override; virtual bool RecvSetPluginFocused(const bool& aFocused) override;
virtual bool RecvGetInputContext(int32_t* aIMEEnabled, virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen, int32_t* aIMEOpen) override;
intptr_t* aNativeIMEContext) override;
virtual bool RecvSetInputContext(const int32_t& aIMEEnabled, virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
const int32_t& aIMEOpen, const int32_t& aIMEOpen,
const nsString& aType, const nsString& aType,

View File

@ -2112,22 +2112,17 @@ MediaDecoderStateMachine::SeekCompleted()
newCurrentTime = video ? video->mTime : seekTime; newCurrentTime = video ? video->mTime : seekTime;
} }
if (mDecodingFirstFrame) {
// We were resuming from dormant, or initiated a seek early.
// We can fire loadeddata now.
FinishDecodeFirstFrame();
}
// Change state to DECODING or COMPLETED now. SeekingStopped will // Change state to DECODING or COMPLETED now. SeekingStopped will
// call MediaDecoderStateMachine::Seek to reset our state to SEEKING // call MediaDecoderStateMachine::Seek to reset our state to SEEKING
// if we need to seek again. // if we need to seek again.
bool isLiveStream = mResource->IsLiveStream(); bool isLiveStream = mResource->IsLiveStream();
State nextState;
if (mPendingSeek.Exists()) { if (mPendingSeek.Exists()) {
// A new seek target came in while we were processing the old one. No rest // A new seek target came in while we were processing the old one. No rest
// for the seeking. // for the seeking.
DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING"); DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING");
SetState(DECODER_STATE_SEEKING); nextState = DECODER_STATE_SEEKING;
} else if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) { } else if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
// Seeked to end of media, move to COMPLETED state. Note we don't do // Seeked to end of media, move to COMPLETED state. Note we don't do
// this when playing a live stream, since the end of media will advance // this when playing a live stream, since the end of media will advance
@ -2135,11 +2130,26 @@ MediaDecoderStateMachine::SeekCompleted()
DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime); DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime);
// Explicitly set our state so we don't decode further, and so // Explicitly set our state so we don't decode further, and so
// we report playback ended to the media element. // we report playback ended to the media element.
SetState(DECODER_STATE_COMPLETED); nextState = DECODER_STATE_COMPLETED;
DispatchDecodeTasksIfNeeded();
} else { } else {
DECODER_LOG("Changed state from SEEKING (to %lld) to DECODING", seekTime); DECODER_LOG("Changed state from SEEKING (to %lld) to DECODING", seekTime);
nextState = DECODER_STATE_DECODING;
}
// We want to resolve the seek request prior finishing the first frame
// to ensure that the seeked event is fired prior loadeded.
mCurrentSeek.Resolve(nextState == DECODER_STATE_COMPLETED, __func__);
if (mDecodingFirstFrame) {
// We were resuming from dormant, or initiated a seek early.
// We can fire loadeddata now.
FinishDecodeFirstFrame();
}
if (nextState == DECODER_STATE_DECODING) {
StartDecoding(); StartDecoding();
} else {
SetState(nextState);
} }
// Ensure timestamps are up to date. // Ensure timestamps are up to date.
@ -2153,7 +2163,6 @@ MediaDecoderStateMachine::SeekCompleted()
// if we need to buffer after the seek. // if we need to buffer after the seek.
mQuickBuffering = false; mQuickBuffering = false;
mCurrentSeek.Resolve(mState == DECODER_STATE_COMPLETED, __func__);
ScheduleStateMachine(); ScheduleStateMachine();
if (video) { if (video) {

View File

@ -81,6 +81,8 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac"))
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
[test_SeekNoData_mp4.html] [test_SeekNoData_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
[test_SeekedEvent_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
[test_SeekTwice_mp4.html] [test_SeekTwice_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
[test_Sequence_mp4.html] [test_Sequence_mp4.html]

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<head>
<title>MSE: Check that seeked event is fired prior loadeddata</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="mediasource.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
runWithMSE(function(ms, el) {
el.controls = true;
el._seeked = false;
el._loadeddata = false;
el._playing = false;
el.addEventListener("seeked", function() {
ok(true, "got seeked event");
is(el._loadeddata, false, "can't have received loadeddata prior seeked");
is(el._playing, false, "can't be playing prior seeked");
el._seeked = true;
});
el.addEventListener("loadeddata", function() {
ok(true, "got loadeddata event");
is(el._seeked, true, "must have received seeked prior loadeddata");
is(el._playing, false, "can't be playing prior playing");
el._loadeddata = true;
});
el.addEventListener("playing", function() {
ok(true, "got playing");
is(el._seeked, true, "must have received seeked prior playing");
is(el._loadeddata, true, "must have received loadeddata prior playing");
el._playing = true;
});
once(ms, 'sourceopen').then(function() {
ok(true, "Receive a sourceopen event");
var videosb = ms.addSourceBuffer("video/mp4");
is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
fetchAndLoad(videosb, 'bipbop/bipbop_video', ['init'], '.mp4')
.then(once.bind(null, el, "loadedmetadata"))
.then(function() {
el.play();
videosb.timestampOffset = 2;
is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
// Load [2, 3.606).
var promises = [];
promises.push(once(el, "play"));
promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', ['1'], '.m4s'));
return Promise.all(promises);
})
.then(function() {
return fetchAndLoad(videosb, 'bipbop/bipbop_video', ['2'], '.m4s');
})
.then(function() {
is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
el.currentTime = 2;
var promises = [];
promises.push(once(el, "seeked"));
promises.push(once(el, "playing"));
return Promise.all(promises);
})
.then(function() {
ok(true, "completed seek");
SimpleTest.finish();
});
});
});
</script>
</pre>
</body>
</html>

View File

@ -22,6 +22,8 @@ extern "C" {
#include "MediaMetadataManager.h" #include "MediaMetadataManager.h"
#include "nsISeekableStream.h" #include "nsISeekableStream.h"
#include "gfx2DGlue.h" #include "gfx2DGlue.h"
#include "mozilla/Telemetry.h"
#include "nsPrintfCString.h"
using namespace mozilla::gfx; using namespace mozilla::gfx;
using namespace mozilla::media; using namespace mozilla::media;
@ -148,6 +150,17 @@ OggReader::~OggReader()
{ {
ogg_sync_clear(&mOggState); ogg_sync_clear(&mOggState);
MOZ_COUNT_DTOR(OggReader); MOZ_COUNT_DTOR(OggReader);
if (HasAudio() || HasVideo()) {
// If we were able to initialize our decoders, report whether we encountered
// a chained stream or not.
ReentrantMonitorAutoEnter mon(mMonitor);
bool isChained = mIsChained;
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
LOG(LogLevel::Debug, (nsPrintfCString("Reporting telemetry MEDIA_OGG_LOADED_IS_CHAINED=%d", isChained).get()));
Telemetry::Accumulate(Telemetry::ID::MEDIA_OGG_LOADED_IS_CHAINED, isChained);
});
AbstractThread::MainThread()->Dispatch(task.forget());
}
} }
nsresult OggReader::Init() { nsresult OggReader::Init() {
@ -704,10 +717,13 @@ bool OggReader::DecodeAudioData()
return true; return true;
} }
void OggReader::SetChained(bool aIsChained) { void OggReader::SetChained() {
{ {
ReentrantMonitorAutoEnter mon(mMonitor); ReentrantMonitorAutoEnter mon(mMonitor);
mIsChained = aIsChained; if (mIsChained) {
return;
}
mIsChained = true;
} }
mOnMediaNotSeekable.Notify(); mOnMediaNotSeekable.Notify();
} }
@ -800,7 +816,7 @@ bool OggReader::ReadOggChain()
} }
if (chained) { if (chained) {
SetChained(true); SetChained();
{ {
auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate; auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate;
mTimedMetadataEvent.Notify( mTimedMetadataEvent.Notify(
@ -1139,7 +1155,7 @@ int64_t OggReader::RangeEndTime(int64_t aStartOffset,
// This page is from a bitstream which we haven't encountered yet. // This page is from a bitstream which we haven't encountered yet.
// It's probably from a new "link" in a "chained" ogg. Don't // It's probably from a new "link" in a "chained" ogg. Don't
// bother even trying to find a duration... // bother even trying to find a duration...
SetChained(true); SetChained();
endTime = -1; endTime = -1;
break; break;
} }
@ -1913,7 +1929,7 @@ media::TimeIntervals OggReader::GetBuffered()
// ogg), return OK to abort the finding any further ranges. This // ogg), return OK to abort the finding any further ranges. This
// prevents us searching through the rest of the media when we // prevents us searching through the rest of the media when we
// may not be able to extract timestamps from it. // may not be able to extract timestamps from it.
SetChained(true); SetChained();
return buffered; return buffered;
} }
} }

View File

@ -252,7 +252,7 @@ private:
// Set this media as being a chain and notifies the state machine that the // Set this media as being a chain and notifies the state machine that the
// media is no longer seekable. // media is no longer seekable.
void SetChained(bool aIsChained); void SetChained();
// Returns the next Ogg packet for an bitstream/codec state. Returns a // Returns the next Ogg packet for an bitstream/codec state. Returns a
// pointer to an ogg_packet on success, or nullptr if the read failed. // pointer to an ogg_packet on success, or nullptr if the read failed.

View File

@ -280,21 +280,23 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason)
return hr; return hr;
} }
// Create D3D9DeviceEx. // Create D3D9DeviceEx. We pass null HWNDs here even though the documentation
// suggests that one of them should not be. At this point in time Chromium
// does the same thing for video acceleration.
D3DPRESENT_PARAMETERS params = {0}; D3DPRESENT_PARAMETERS params = {0};
params.BackBufferWidth = 1; params.BackBufferWidth = 1;
params.BackBufferHeight = 1; params.BackBufferHeight = 1;
params.BackBufferFormat = D3DFMT_UNKNOWN; params.BackBufferFormat = D3DFMT_UNKNOWN;
params.BackBufferCount = 1; params.BackBufferCount = 1;
params.SwapEffect = D3DSWAPEFFECT_DISCARD; params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.hDeviceWindow = ::GetShellWindow(); params.hDeviceWindow = nullptr;
params.Windowed = TRUE; params.Windowed = TRUE;
params.Flags = D3DPRESENTFLAG_VIDEO; params.Flags = D3DPRESENTFLAG_VIDEO;
RefPtr<IDirect3DDevice9Ex> device; RefPtr<IDirect3DDevice9Ex> device;
hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, D3DDEVTYPE_HAL,
::GetShellWindow(), nullptr,
D3DCREATE_FPU_PRESERVE | D3DCREATE_FPU_PRESERVE |
D3DCREATE_MULTITHREADED | D3DCREATE_MULTITHREADED |
D3DCREATE_MIXED_VERTEXPROCESSING, D3DCREATE_MIXED_VERTEXPROCESSING,

View File

@ -79,6 +79,11 @@ SpeechTaskCallback::OnPause()
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
[mSpeechSynthesizer pauseSpeakingAtBoundary:NSSpeechImmediateBoundary]; [mSpeechSynthesizer pauseSpeakingAtBoundary:NSSpeechImmediateBoundary];
if (!mTask) {
// When calling pause() on child porcess, it may not receive end event
// from chrome process yet.
return NS_ERROR_FAILURE;
}
mTask->DispatchPause(GetTimeDurationFromStart(), mCurrentIndex); mTask->DispatchPause(GetTimeDurationFromStart(), mCurrentIndex);
return NS_OK; return NS_OK;
@ -91,6 +96,11 @@ SpeechTaskCallback::OnResume()
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
[mSpeechSynthesizer continueSpeaking]; [mSpeechSynthesizer continueSpeaking];
if (!mTask) {
// When calling resume() on child porcess, it may not receive end event
// from chrome process yet.
return NS_ERROR_FAILURE;
}
mTask->DispatchResume(GetTimeDurationFromStart(), mCurrentIndex); mTask->DispatchResume(GetTimeDurationFromStart(), mCurrentIndex);
return NS_OK; return NS_OK;
@ -120,6 +130,9 @@ void
SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex) SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex)
{ {
mCurrentIndex = aIndex; mCurrentIndex = aIndex;
if (!mTask) {
return;
}
mTask->DispatchBoundary(NS_LITERAL_STRING("word"), mTask->DispatchBoundary(NS_LITERAL_STRING("word"),
GetTimeDurationFromStart(), mCurrentIndex); GetTimeDurationFromStart(), mCurrentIndex);
} }
@ -127,6 +140,9 @@ SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex)
void void
SpeechTaskCallback::OnError(uint32_t aIndex) SpeechTaskCallback::OnError(uint32_t aIndex)
{ {
if (!mTask) {
return;
}
mTask->DispatchError(GetTimeDurationFromStart(), aIndex); mTask->DispatchError(GetTimeDurationFromStart(), aIndex);
} }

View File

@ -76,6 +76,11 @@ SapiCallback::OnPause()
if (FAILED(mSapiClient->Pause())) { if (FAILED(mSapiClient->Pause())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (!mTask) {
// When calling pause() on child porcess, it may not receive end event
// from chrome process yet.
return NS_ERROR_FAILURE;
}
mTask->DispatchPause(GetTickCount() - mStartingTime, mCurrentIndex); mTask->DispatchPause(GetTickCount() - mStartingTime, mCurrentIndex);
return NS_OK; return NS_OK;
} }
@ -86,6 +91,11 @@ SapiCallback::OnResume()
if (FAILED(mSapiClient->Resume())) { if (FAILED(mSapiClient->Resume())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (!mTask) {
// When calling resume() on child porcess, it may not receive end event
// from chrome process yet.
return NS_ERROR_FAILURE;
}
mTask->DispatchResume(GetTickCount() - mStartingTime, mCurrentIndex); mTask->DispatchResume(GetTickCount() - mStartingTime, mCurrentIndex);
return NS_OK; return NS_OK;
} }

View File

@ -125,6 +125,7 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
, mIsWhitelistedForShumway(false) , mIsWhitelistedForShumway(false)
, mWindowType(NPWindowTypeWindow) , mWindowType(NPWindowTypeWindow)
, mDrawingModel(kDefaultDrawingModel) , mDrawingModel(kDefaultDrawingModel)
, mLastRecordedDrawingModel(-1)
, mFrameID(0) , mFrameID(0)
#if defined(OS_WIN) #if defined(OS_WIN)
, mPluginHWND(nullptr) , mPluginHWND(nullptr)
@ -809,6 +810,8 @@ PluginInstanceParent::SetCurrentImage(Image* aImage)
nsAutoTArray<ImageContainer::NonOwningImage,1> imageList; nsAutoTArray<ImageContainer::NonOwningImage,1> imageList;
imageList.AppendElement(holder); imageList.AppendElement(holder);
mImageContainer->SetCurrentImages(imageList); mImageContainer->SetCurrentImages(imageList);
RecordDrawingModel();
} }
bool bool
@ -973,6 +976,7 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
PLUGIN_LOG_DEBUG((" (RecvShow invalidated for surface %p)", PLUGIN_LOG_DEBUG((" (RecvShow invalidated for surface %p)",
mFrontSurface.get())); mFrontSurface.get()));
RecordDrawingModel();
return true; return true;
} }
@ -1380,6 +1384,7 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
return NPERR_GENERIC_ERROR; return NPERR_GENERIC_ERROR;
} }
RecordDrawingModel();
return NPERR_NO_ERROR; return NPERR_NO_ERROR;
} }
@ -2363,3 +2368,28 @@ PluginInstanceParent::Cast(NPP aInstance, PluginAsyncSurrogate** aSurrogate)
return instancePtr; return instancePtr;
} }
void
PluginInstanceParent::RecordDrawingModel()
{
int mode = -1;
switch (mWindowType) {
case NPWindowTypeWindow:
// We use 0=windowed since there is no specific NPDrawingModel value.
mode = 0;
break;
case NPWindowTypeDrawable:
mode = mDrawingModel + 1;
break;
default:
MOZ_ASSERT_UNREACHABLE("bad window type");
return;
}
if (mode == mLastRecordedDrawingModel) {
return;
}
MOZ_ASSERT(mode >= 0);
Telemetry::Accumulate(Telemetry::PLUGIN_DRAWING_MODEL, mode);
mLastRecordedDrawingModel = mode;
}

View File

@ -376,6 +376,9 @@ private:
void SetCurrentImage(layers::Image* aImage); void SetCurrentImage(layers::Image* aImage);
// Update Telemetry with the current drawing model.
void RecordDrawingModel();
private: private:
PluginModuleParent* mParent; PluginModuleParent* mParent;
RefPtr<PluginAsyncSurrogate> mSurrogate; RefPtr<PluginAsyncSurrogate> mSurrogate;
@ -387,6 +390,11 @@ private:
NPWindowType mWindowType; NPWindowType mWindowType;
int16_t mDrawingModel; int16_t mDrawingModel;
// Since plugins may request different drawing models to find a compatible
// one, we only record the drawing model after a SetWindow call and if the
// drawing model has changed.
int mLastRecordedDrawingModel;
nsDataHashtable<nsPtrHashKey<NPObject>, PluginScriptableObjectParent*> mScriptableObjects; nsDataHashtable<nsPtrHashKey<NPObject>, PluginScriptableObjectParent*> mScriptableObjects;
// This is used to tell the compositor that it should invalidate the ImageLayer. // This is used to tell the compositor that it should invalidate the ImageLayer.

View File

@ -154,6 +154,9 @@ partial interface Document {
attribute EventHandler onbeforescriptexecute; attribute EventHandler onbeforescriptexecute;
attribute EventHandler onafterscriptexecute; attribute EventHandler onafterscriptexecute;
[Pref="dom.select_events.enabled"]
attribute EventHandler onselectionchange;
/** /**
* True if this document is synthetic : stand alone image, video, audio file, * True if this document is synthetic : stand alone image, video, audio file,
* etc. * etc.

View File

@ -1987,14 +1987,14 @@ nsEditor::StopPreservingSelection()
} }
void void
nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent) nsEditor::EnsureComposition(mozilla::WidgetCompositionEvent* aCompositionEvent)
{ {
if (mComposition) { if (mComposition) {
return; return;
} }
// The compositionstart event must cause creating new TextComposition // The compositionstart event must cause creating new TextComposition
// instance at being dispatched by IMEStateManager. // instance at being dispatched by IMEStateManager.
mComposition = IMEStateManager::GetTextCompositionFor(aEvent); mComposition = IMEStateManager::GetTextCompositionFor(aCompositionEvent);
if (!mComposition) { if (!mComposition) {
MOZ_CRASH("IMEStateManager doesn't return proper composition"); MOZ_CRASH("IMEStateManager doesn't return proper composition");
} }

View File

@ -413,7 +413,7 @@ protected:
* EnsureComposition() should be called by composition event handlers. This * EnsureComposition() should be called by composition event handlers. This
* tries to get the composition for the event and set it to mComposition. * tries to get the composition for the event and set it to mComposition.
*/ */
void EnsureComposition(mozilla::WidgetGUIEvent* aEvent); void EnsureComposition(mozilla::WidgetCompositionEvent* aCompositionEvent);
nsresult GetSelection(int16_t aSelectionType, nsISelection** aSelection); nsresult GetSelection(int16_t aSelectionType, nsISelection** aSelection);

View File

@ -2219,7 +2219,7 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
SetState(PANNING); SetState(PANNING);
} }
} else if (mState == PANNING_LOCKED_Y) { } else if (mState == PANNING_LOCKED_Y) {
if (!IsCloseToVertical(angle, gfxPrefs::APZAxisLockAngle())) { if (!IsCloseToVertical(angle, gfxPrefs::APZAxisBreakoutAngle())) {
mX.SetAxisLocked(false); mX.SetAxisLocked(false);
SetState(PANNING); SetState(PANNING);
} }

View File

@ -548,11 +548,12 @@ Pan(const RefPtr<InputReceiver>& aTarget,
nsEventStatus (*aOutEventStatuses)[4] = nullptr, nsEventStatus (*aOutEventStatuses)[4] = nullptr,
uint64_t* aOutInputBlockId = nullptr) uint64_t* aOutInputBlockId = nullptr)
{ {
// Reduce the touch start tolerance to a tiny value. // Reduce the touch start and move tolerance to a tiny value.
// We can't use a scoped pref because this value might be read at some later // We can't use a scoped pref because this value might be read at some later
// time when the events are actually processed, rather than when we deliver // time when the events are actually processed, rather than when we deliver
// them. // them.
gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f); gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f);
gfxPrefs::SetAPZTouchMoveTolerance(0.0f);
const int OVERCOME_TOUCH_TOLERANCE = 1; const int OVERCOME_TOUCH_TOLERANCE = 1;
const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50); const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);

View File

@ -415,6 +415,28 @@ APZCCallbackHelper::GetRootContentDocumentPresShellForContent(nsIContent* aConte
return context->PresShell(); return context->PresShell();
} }
static nsIPresShell*
GetRootDocumentPresShell(nsIContent* aContent)
{
nsIDocument* doc = aContent->GetComposedDoc();
if (!doc) {
return nullptr;
}
nsIPresShell* shell = doc->GetShell();
if (!shell) {
return nullptr;
}
nsPresContext* context = shell->GetPresContext();
if (!context) {
return nullptr;
}
context = context->GetRootPresContext();
if (!context) {
return nullptr;
}
return context->PresShell();
}
CSSPoint CSSPoint
APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
const ScrollableLayerGuid& aGuid) const ScrollableLayerGuid& aGuid)
@ -423,24 +445,21 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
if (aGuid.mScrollId == FrameMetrics::NULL_SCROLL_ID) { if (aGuid.mScrollId == FrameMetrics::NULL_SCROLL_ID) {
return input; return input;
} }
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId); nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
if (!content) { if (!content) {
return input; return input;
} }
#if !defined(MOZ_SINGLE_PROCESS_APZ)
// First, scale inversely by the root content document's pres shell // First, scale inversely by the root content document's pres shell
// resolution to cancel the scale-to-resolution transform that the // resolution to cancel the scale-to-resolution transform that the
// compositor adds to the layer with the pres shell resolution. The points // compositor adds to the layer with the pres shell resolution. The points
// sent to Gecko by APZ don't have this transform unapplied (unlike other // sent to Gecko by APZ don't have this transform unapplied (unlike other
// compositor-side transforms) because APZ doesn't know about it. // compositor-side transforms) because APZ doesn't know about it.
if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) { if (nsIPresShell* shell = GetRootDocumentPresShell(content)) {
input = input / shell->GetResolution(); input = input / shell->GetResolution();
} }
#endif
// Apply the callback-transform. // Now apply the callback-transform.
// XXX: technically we need to walk all the way up the layer tree from the layer // XXX: technically we need to walk all the way up the layer tree from the layer
// represented by |aGuid.mScrollId| up to the root of the layer tree and apply // represented by |aGuid.mScrollId| up to the root of the layer tree and apply
// the input transforms at each level in turn. However, it is quite difficult // the input transforms at each level in turn. However, it is quite difficult
@ -451,22 +470,9 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
// some things transformed improperly. In practice we should rarely hit scenarios // some things transformed improperly. In practice we should rarely hit scenarios
// where any of this matters, so I'm skipping it for now and just doing the single // where any of this matters, so I'm skipping it for now and just doing the single
// transform for the layer that the input hit. // transform for the layer that the input hit.
void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform); void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
if (property) { if (property) {
CSSPoint delta = (*static_cast<CSSPoint*>(property)); CSSPoint delta = (*static_cast<CSSPoint*>(property));
#if defined(MOZ_SINGLE_PROCESS_APZ)
// The delta is in root content document coordinate space while the
// aInput point is in root document coordinate space so convert the
// delta to root document space before adding it to the aInput point.
float resolution = 1.0f;
if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
resolution = shell->GetResolution();
}
delta.x = delta.x * resolution;
delta.y = delta.y * resolution;
#endif // MOZ_SINGLE_PROCESS_APZ
input += delta; input += delta;
} }
return input; return input;

View File

@ -147,7 +147,6 @@ ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint,
} }
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid); CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
#if defined(MOZ_SINGLE_PROCESS_APZ)
// CalculateRectToZoomTo performs a hit test on the frame associated with the // CalculateRectToZoomTo performs a hit test on the frame associated with the
// Root Content Document. Unfortunately that frame does not know about the // Root Content Document. Unfortunately that frame does not know about the
// resolution of the document and so we must remove it before calculating // resolution of the document and so we must remove it before calculating
@ -156,7 +155,6 @@ ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint,
const float resolution = presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f; const float resolution = presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f;
point.x = point.x / resolution; point.x = point.x / resolution;
point.y = point.y / resolution; point.y = point.y / resolution;
#endif // MOZ_SINGLE_PROCESS_APZ
CSSRect zoomToRect = CalculateRectToZoomTo(document, point); CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
uint32_t presShellId; uint32_t presShellId;

View File

@ -9,6 +9,8 @@
#include <string> #include <string>
#include "base/eintr_wrapper.h"
#include "chrome/common/child_process_info.h" #include "chrome/common/child_process_info.h"
#include "mozilla/ipc/Transport.h" #include "mozilla/ipc/Transport.h"
@ -41,6 +43,8 @@ CreateTransport(base::ProcessId aProcIdOne,
fd1 = dup(fd1); fd1 = dup(fd1);
fd2 = dup(fd2); fd2 = dup(fd2);
if (fd1 < 0 || fd2 < 0) { if (fd1 < 0 || fd2 < 0) {
HANDLE_EINTR(close(fd1));
HANDLE_EINTR(close(fd2));
return NS_ERROR_DUPLICATE_HANDLE; return NS_ERROR_DUPLICATE_HANDLE;
} }

View File

@ -553,7 +553,6 @@ DynamicallyLinkModule(JSContext* cx, const CallArgs& args, AsmJSModule& module)
return false; return false;
break; break;
case AsmJSModule::Global::ArrayView: case AsmJSModule::Global::ArrayView:
case AsmJSModule::Global::SharedArrayView:
case AsmJSModule::Global::ArrayViewCtor: case AsmJSModule::Global::ArrayViewCtor:
if (!ValidateArrayView(cx, global, globalVal)) if (!ValidateArrayView(cx, global, globalVal))
return false; return false;

View File

@ -100,7 +100,7 @@ class AsmJSModule
class Global class Global
{ {
public: public:
enum Which { Variable, FFI, ArrayView, ArrayViewCtor, SharedArrayView, MathBuiltinFunction, enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation, ByteLength }; AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation, ByteLength };
enum VarInitKind { InitConstant, InitImport }; enum VarInitKind { InitConstant, InitImport };
enum ConstantKind { GlobalConstant, MathConstant }; enum ConstantKind { GlobalConstant, MathConstant };
@ -189,17 +189,13 @@ class AsmJSModule
// var i32 = new I32(buffer); // var i32 = new I32(buffer);
// the second import has nothing to validate and thus has a null field. // the second import has nothing to validate and thus has a null field.
PropertyName* maybeViewName() const { PropertyName* maybeViewName() const {
MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == SharedArrayView || pod.which_ == ArrayViewCtor); MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
return name_; return name_;
} }
Scalar::Type viewType() const { Scalar::Type viewType() const {
MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == SharedArrayView || pod.which_ == ArrayViewCtor); MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
return pod.u.viewType_; return pod.u.viewType_;
} }
void makeViewShared() {
MOZ_ASSERT(pod.which_ == ArrayView);
pod.which_ = SharedArrayView;
}
PropertyName* mathName() const { PropertyName* mathName() const {
MOZ_ASSERT(pod.which_ == MathBuiltinFunction); MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
return name_; return name_;
@ -910,20 +906,18 @@ class AsmJSModule
g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++; g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++;
return globals_.append(g); return globals_.append(g);
} }
bool addArrayView(Scalar::Type vt, PropertyName* maybeField, bool isSharedView) { bool addArrayView(Scalar::Type vt, PropertyName* maybeField) {
MOZ_ASSERT(!isFinished()); MOZ_ASSERT(!isFinished());
MOZ_ASSERT(!pod.hasArrayView_ || (pod.isSharedView_ == isSharedView));
pod.hasArrayView_ = true; pod.hasArrayView_ = true;
pod.isSharedView_ = isSharedView; pod.isSharedView_ = false;
Global g(Global::ArrayView, maybeField); Global g(Global::ArrayView, maybeField);
g.pod.u.viewType_ = vt; g.pod.u.viewType_ = vt;
return globals_.append(g); return globals_.append(g);
} }
bool addArrayViewCtor(Scalar::Type vt, PropertyName* field, bool isSharedView) { bool addArrayViewCtor(Scalar::Type vt, PropertyName* field) {
MOZ_ASSERT(!isFinished()); MOZ_ASSERT(!isFinished());
MOZ_ASSERT(field); MOZ_ASSERT(field);
MOZ_ASSERT(!pod.isSharedView_ || isSharedView); pod.isSharedView_ = false;
pod.isSharedView_ = isSharedView;
Global g(Global::ArrayViewCtor, field); Global g(Global::ArrayViewCtor, field);
g.pod.u.viewType_ = vt; g.pod.u.viewType_ = vt;
return globals_.append(g); return globals_.append(g);
@ -978,19 +972,9 @@ class AsmJSModule
Global& global(unsigned i) { Global& global(unsigned i) {
return globals_[i]; return globals_[i];
} }
bool isValidViewSharedness(bool shared) const {
if (pod.hasArrayView_)
return pod.isSharedView_ == shared;
return !pod.isSharedView_ || shared;
}
void setViewsAreShared() { void setViewsAreShared() {
if (pod.hasArrayView_) if (pod.hasArrayView_)
pod.isSharedView_ = true; pod.isSharedView_ = true;
for (size_t i=0 ; i < globals_.length() ; i++) {
Global& g = globals_[i];
if (g.which() == Global::ArrayView)
g.makeViewShared();
}
} }
/*************************************************************************/ /*************************************************************************/

View File

@ -1014,7 +1014,6 @@ class MOZ_STACK_CLASS ModuleValidator
uint32_t ffiIndex_; uint32_t ffiIndex_;
struct { struct {
Scalar::Type viewType_; Scalar::Type viewType_;
bool isSharedView_;
} viewInfo; } viewInfo;
AsmJSMathBuiltinFunction mathBuiltinFunc_; AsmJSMathBuiltinFunction mathBuiltinFunc_;
AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_; AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
@ -1072,14 +1071,6 @@ class MOZ_STACK_CLASS ModuleValidator
MOZ_ASSERT(isAnyArrayView()); MOZ_ASSERT(isAnyArrayView());
return u.viewInfo.viewType_; return u.viewInfo.viewType_;
} }
bool viewIsSharedView() const {
MOZ_ASSERT(isAnyArrayView());
return u.viewInfo.isSharedView_;
}
void setViewIsSharedView() {
MOZ_ASSERT(isAnyArrayView());
u.viewInfo.isSharedView_ = true;
}
bool isMathFunction() const { bool isMathFunction() const {
return which_ == MathBuiltinFunction; return which_ == MathBuiltinFunction;
} }
@ -1402,18 +1393,16 @@ class MOZ_STACK_CLASS ModuleValidator
global->u.varOrConst.type_ = Type::var(importType).which(); global->u.varOrConst.type_ = Type::var(importType).which();
return globals_.putNew(varName, global); return globals_.putNew(varName, global);
} }
bool addArrayView(PropertyName* varName, Scalar::Type vt, PropertyName* maybeField, bool addArrayView(PropertyName* varName, Scalar::Type vt, PropertyName* maybeField)
bool isSharedView)
{ {
if (!arrayViews_.append(ArrayView(varName, vt))) if (!arrayViews_.append(ArrayView(varName, vt)))
return false; return false;
Global* global = validationLifo_.new_<Global>(Global::ArrayView); Global* global = validationLifo_.new_<Global>(Global::ArrayView);
if (!global) if (!global)
return false; return false;
if (!module().addArrayView(vt, maybeField, isSharedView)) if (!module().addArrayView(vt, maybeField))
return false; return false;
global->u.viewInfo.viewType_ = vt; global->u.viewInfo.viewType_ = vt;
global->u.viewInfo.isSharedView_ = isSharedView;
return globals_.putNew(varName, global); return globals_.putNew(varName, global);
} }
bool addMathBuiltinFunction(PropertyName* varName, AsmJSMathBuiltinFunction func, bool addMathBuiltinFunction(PropertyName* varName, AsmJSMathBuiltinFunction func,
@ -1497,14 +1486,13 @@ class MOZ_STACK_CLASS ModuleValidator
global->u.changeHeap.srcEnd_ = fn->pn_pos.end; global->u.changeHeap.srcEnd_ = fn->pn_pos.end;
return globals_.putNew(name, global); return globals_.putNew(name, global);
} }
bool addArrayViewCtor(PropertyName* varName, Scalar::Type vt, PropertyName* fieldName, bool isSharedView) { bool addArrayViewCtor(PropertyName* varName, Scalar::Type vt, PropertyName* fieldName) {
Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor); Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
if (!global) if (!global)
return false; return false;
if (!module().addArrayViewCtor(vt, fieldName, isSharedView)) if (!module().addArrayViewCtor(vt, fieldName))
return false; return false;
global->u.viewInfo.viewType_ = vt; global->u.viewInfo.viewType_ = vt;
global->u.viewInfo.isSharedView_ = isSharedView;
return globals_.putNew(varName, global); return globals_.putNew(varName, global);
} }
bool addFFI(PropertyName* varName, PropertyName* field) { bool addFFI(PropertyName* varName, PropertyName* field) {
@ -1612,6 +1600,10 @@ class MOZ_STACK_CLASS ModuleValidator
return module().minHeapLength(); return module().minHeapLength();
} }
bool usesSharedMemory() const {
return atomicsPresent_;
}
// Error handling. // Error handling.
bool hasAlreadyFailed() const { bool hasAlreadyFailed() const {
return !!errorString_; return !!errorString_;
@ -1740,15 +1732,9 @@ class MOZ_STACK_CLASS ModuleValidator
} }
void startFunctionBodies() { void startFunctionBodies() {
if (atomicsPresent_) { if (atomicsPresent_)
for (GlobalMap::Range r = globals_.all() ; !r.empty() ; r.popFront()) {
Global* g = r.front().value();
if (g->isAnyArrayView())
g->setViewIsSharedView();
}
module().setViewsAreShared(); module().setViewsAreShared();
} }
}
}; };
} // namespace } // namespace
@ -2472,10 +2458,9 @@ CheckGlobalVariableInitImport(ModuleValidator& m, PropertyName* varName, ParseNo
} }
static bool static bool
IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type, bool* shared) IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type)
{ {
JSAtomState& names = m.cx()->names(); JSAtomState& names = m.cx()->names();
*shared = false;
if (name == names.Int8Array) { if (name == names.Int8Array) {
*type = Scalar::Int8; *type = Scalar::Int8;
} else if (name == names.Uint8Array) { } else if (name == names.Uint8Array) {
@ -2526,7 +2511,6 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
PropertyName* field; PropertyName* field;
Scalar::Type type; Scalar::Type type;
bool shared = false;
if (ctorExpr->isKind(PNK_DOT)) { if (ctorExpr->isKind(PNK_DOT)) {
ParseNode* base = DotBase(ctorExpr); ParseNode* base = DotBase(ctorExpr);
@ -2534,7 +2518,7 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
return m.failName(base, "expecting '%s.*Array", globalName); return m.failName(base, "expecting '%s.*Array", globalName);
field = DotMember(ctorExpr); field = DotMember(ctorExpr);
if (!IsArrayViewCtorName(m, field, &type, &shared)) if (!IsArrayViewCtorName(m, field, &type))
return m.fail(ctorExpr, "could not match typed array name"); return m.fail(ctorExpr, "could not match typed array name");
} else { } else {
if (!ctorExpr->isKind(PNK_NAME)) if (!ctorExpr->isKind(PNK_NAME))
@ -2550,16 +2534,12 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
field = nullptr; field = nullptr;
type = global->viewType(); type = global->viewType();
shared = global->viewIsSharedView();
} }
if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName)) if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
return false; return false;
if (!m.module().isValidViewSharedness(shared)) return m.addArrayView(varName, type, field);
return m.failName(ctorExpr, "%s has different sharedness than previous view constructors", globalName);
return m.addArrayView(varName, type, field, shared);
} }
static bool static bool
@ -2695,12 +2675,8 @@ CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initN
return m.addByteLength(varName); return m.addByteLength(varName);
Scalar::Type type; Scalar::Type type;
bool shared = false; if (IsArrayViewCtorName(m, field, &type))
if (IsArrayViewCtorName(m, field, &type, &shared)) { return m.addArrayViewCtor(varName, type, field);
if (!m.module().isValidViewSharedness(shared))
return m.failName(initNode, "'%s' has different sharedness than previous view constructors", field);
return m.addArrayViewCtor(varName, type, field, shared);
}
return m.failName(initNode, "'%s' is not a standard constant or typed array name", field); return m.failName(initNode, "'%s' is not a standard constant or typed array name", field);
} }
@ -6787,6 +6763,12 @@ CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList,
m.startFunctionBodies(); m.startFunctionBodies();
#if !defined(ENABLE_SHARED_ARRAY_BUFFER)
if (m.usesSharedMemory())
return m.failOffset(m.parser().tokenStream.currentToken().pos.begin,
"shared memory and atomics not supported by this build");
#endif
if (!CheckFunctions(m)) if (!CheckFunctions(m))
return false; return false;

View File

@ -104,7 +104,8 @@ class FunctionCompiler
curBlock_->initSlot(info().localSlot(i.index()), ins); curBlock_->initSlot(info().localSlot(i.index()), ins);
if (!mirGen_.ensureBallast()) if (!mirGen_.ensureBallast())
return false; return false;
localTypes_.append(args[i.index()]); if (!localTypes_.append(args[i.index()]))
return false;
} }
for (unsigned i = 0; i < func_.numVarInits(); i++) { for (unsigned i = 0; i < func_.numVarInits(); i++) {
@ -134,7 +135,8 @@ class FunctionCompiler
curBlock_->initSlot(info().localSlot(firstVarSlot + i), ins); curBlock_->initSlot(info().localSlot(firstVarSlot + i), ins);
if (!mirGen_.ensureBallast()) if (!mirGen_.ensureBallast())
return false; return false;
localTypes_.append(v.type()); if (!localTypes_.append(v.type()))
return false;
} }
return true; return true;
@ -1129,12 +1131,20 @@ class FunctionCompiler
if (!switchBlock) if (!switchBlock)
return true; return true;
MTableSwitch* mir = switchBlock->lastIns()->toTableSwitch(); MTableSwitch* mir = switchBlock->lastIns()->toTableSwitch();
size_t defaultIndex = mir->addDefault(defaultBlock); size_t defaultIndex;
if (!mir->addDefault(defaultBlock, &defaultIndex))
return false;
for (unsigned i = 0; i < cases.length(); i++) { for (unsigned i = 0; i < cases.length(); i++) {
if (!cases[i]) if (!cases[i]) {
mir->addCase(defaultIndex); if (!mir->addCase(defaultIndex))
else return false;
mir->addCase(mir->addSuccessor(cases[i])); } else {
size_t caseIndex;
if (!mir->addSuccessor(cases[i], &caseIndex))
return false;
if (!mir->addCase(caseIndex))
return false;
}
} }
if (curBlock_) { if (curBlock_) {
MBasicBlock* next; MBasicBlock* next;

View File

@ -238,12 +238,6 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
return false; return false;
} }
if (evalType == DIRECT_EVAL && caller.script()->isDerivedClassConstructor()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DISABLED_DERIVED_CLASS,
"direct eval");
return false;
}
// ES5 15.1.2.1 step 1. // ES5 15.1.2.1 step 1.
if (args.length() < 1) { if (args.length() < 1) {
args.rval().setUndefined(); args.rval().setUndefined();

View File

@ -2783,27 +2783,31 @@ BytecodeEmitter::emitNameIncDec(ParseNode* pn)
} }
bool bool
BytecodeEmitter::emitElemOperands(ParseNode* pn, JSOp op) BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
{ {
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_BINARY));
if (!emitTree(pn->pn_left)) if (!emitTree(pn->pn_left))
return false; return false;
if (op == JSOP_CALLELEM && !emit1(JSOP_DUP)) if (opts == EmitElemOption::IncDec) {
if (!emit1(JSOP_CHECKOBJCOERCIBLE))
return false; return false;
} else if (opts == EmitElemOption::Call) {
if (!emit1(JSOP_DUP))
return false;
}
if (!emitTree(pn->pn_right)) if (!emitTree(pn->pn_right))
return false; return false;
bool isSetElem = op == JSOP_SETELEM || op == JSOP_STRICTSETELEM; if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 2))
if (isSetElem && !emit2(JSOP_PICK, 2))
return false; return false;
return true; return true;
} }
bool bool
BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts) BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
{ {
MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper()); MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper());
@ -2817,13 +2821,13 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
// We need to convert the key to an object id first, so that we do not do // We need to convert the key to an object id first, so that we do not do
// it inside both the GETELEM and the SETELEM. // it inside both the GETELEM and the SETELEM.
if (opts == SuperElem_IncDec && !emit1(JSOP_TOID)) if (opts == EmitElemOption::IncDec && !emit1(JSOP_TOID))
return false; return false;
if (!emitGetThisForSuperBase(pn->pn_left)) if (!emitGetThisForSuperBase(pn->pn_left))
return false; return false;
if (opts == SuperElem_Call) { if (opts == EmitElemOption::Call) {
if (!emit1(JSOP_SWAP)) if (!emit1(JSOP_SWAP))
return false; return false;
@ -2835,7 +2839,7 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
if (!emit1(JSOP_SUPERBASE)) if (!emit1(JSOP_SUPERBASE))
return false; return false;
if (opts == SuperElem_Set && !emit2(JSOP_PICK, 3)) if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
return false; return false;
return true; return true;
@ -2854,17 +2858,23 @@ BytecodeEmitter::emitElemOpBase(JSOp op)
bool bool
BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op) BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op)
{ {
return emitElemOperands(pn, op) && emitElemOpBase(op); EmitElemOption opts = EmitElemOption::Get;
if (op == JSOP_CALLELEM)
opts = EmitElemOption::Call;
else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
opts = EmitElemOption::Set;
return emitElemOperands(pn, opts) && emitElemOpBase(op);
} }
bool bool
BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall) BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
{ {
SuperElemOptions opts = SuperElem_Get; EmitElemOption opts = EmitElemOption::Get;
if (isCall) if (isCall)
opts = SuperElem_Call; opts = EmitElemOption::Call;
else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER) else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
opts = SuperElem_Set; opts = EmitElemOption::Set;
if (!emitSuperElemOperands(pn, opts)) if (!emitSuperElemOperands(pn, opts))
return false; return false;
@ -2885,10 +2895,10 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper(); bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
if (isSuper) { if (isSuper) {
if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec)) if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
return false; return false;
} else { } else {
if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM)) if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec))
return false; return false;
} }
@ -3465,10 +3475,34 @@ BytecodeEmitter::emitSetThis(ParseNode* pn)
JSOp setOp = name->getOp(); JSOp setOp = name->getOp();
// Handle the eval case. Only accept the strict variant, as eval in a
// derived class constructor must be strict.
if (setOp == JSOP_STRICTSETNAME) {
if (!emitAtomOp(name, JSOP_GETNAME))
return false;
if (!emit1(JSOP_CHECKTHISREINIT))
return false;
if (!emit1(JSOP_POP))
return false;
if (!emitAtomOp(name, JSOP_BINDNAME))
return false;
if (!emit1(JSOP_SWAP))
return false;
return emitAtomOp(name, setOp);
}
JSOp getOp; JSOp getOp;
switch (setOp) { switch (setOp) {
case JSOP_SETLOCAL: getOp = JSOP_GETLOCAL; break; case JSOP_SETLOCAL:
case JSOP_SETALIASEDVAR: getOp = JSOP_GETALIASEDVAR; break; getOp = JSOP_GETLOCAL;
setOp = JSOP_INITLEXICAL;
break;
case JSOP_SETALIASEDVAR:
getOp = JSOP_GETALIASEDVAR;
setOp = JSOP_INITALIASEDLEXICAL;
break;
default: MOZ_CRASH("Unexpected op"); default: MOZ_CRASH("Unexpected op");
} }
@ -4379,13 +4413,25 @@ BytecodeEmitter::emitVariables(ParseNode* pn, VarEmitOption emitOption)
* i' to be hoisted out of the loop. * i' to be hoisted out of the loop.
*/ */
MOZ_ASSERT(binding->isOp(JSOP_NOP)); MOZ_ASSERT(binding->isOp(JSOP_NOP));
MOZ_ASSERT(emitOption != DefineVars && emitOption != AnnexB); MOZ_ASSERT(emitOption != DefineVars);
MOZ_ASSERT_IF(emitOption == AnnexB, binding->pn_left->isKind(PNK_NAME));
/* // To allow the front end to rewrite |var f = x;| as |f = x;| when a
* To allow the front end to rewrite var f = x; as f = x; when a // |function f(){}| precedes the var, detect simple name assignment
* function f(){} precedes the var, detect simple name assignment // here and initialize the name.
* here and initialize the name. //
*/ // There is a corner case where a function declaration synthesizes
// an Annex B declaration, which in turn gets rewritten later as a
// simple assignment due to hoisted function declaration of the
// same name. For example,
//
// {
// // Synthesizes an Annex B declaration because no 'f' binding
// // yet exists. This later gets rewritten as an assignment when
// // the outer function 'f' gets hoisted.
// function f() {}
// }
// function f() {}
if (binding->pn_left->isKind(PNK_NAME)) { if (binding->pn_left->isKind(PNK_NAME)) {
if (!emitSingleVariable(pn, binding->pn_left, binding->pn_right, emitOption)) if (!emitSingleVariable(pn, binding->pn_left, binding->pn_right, emitOption))
return false; return false;

View File

@ -519,7 +519,8 @@ struct BytecodeEmitter
// Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
// opcode onto the stack in the right order. In the case of SETELEM, the // opcode onto the stack in the right order. In the case of SETELEM, the
// value to be assigned must already be pushed. // value to be assigned must already be pushed.
bool emitElemOperands(ParseNode* pn, JSOp op); enum class EmitElemOption { Get, Set, Call, IncDec };
bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
bool emitElemOpBase(JSOp op); bool emitElemOpBase(JSOp op);
bool emitElemOp(ParseNode* pn, JSOp op); bool emitElemOp(ParseNode* pn, JSOp op);
@ -654,8 +655,7 @@ struct BytecodeEmitter
bool emitClass(ParseNode* pn); bool emitClass(ParseNode* pn);
bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false); bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false);
bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false); bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
enum SuperElemOptions { SuperElem_Get, SuperElem_Set, SuperElem_Call, SuperElem_IncDec }; bool emitSuperElemOperands(ParseNode* pn, EmitElemOption opts = EmitElemOption::Get);
bool emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts = SuperElem_Get);
bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false); bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
}; };

View File

@ -125,8 +125,12 @@ SharedContext::computeAllowSyntax(JSObject* staticScope)
// Any function supports new.target. // Any function supports new.target.
allowNewTarget_ = true; allowNewTarget_ = true;
allowSuperProperty_ = it.fun().allowSuperProperty(); allowSuperProperty_ = it.fun().allowSuperProperty();
if (it.maybeFunctionBox()) if (it.maybeFunctionBox()) {
superScopeAlreadyNeedsHomeObject_ = it.maybeFunctionBox()->needsHomeObject(); superScopeAlreadyNeedsHomeObject_ = it.maybeFunctionBox()->needsHomeObject();
allowSuperCall_ = it.maybeFunctionBox()->isDerivedClassConstructor();
} else {
allowSuperCall_ = it.fun().isDerivedClassConstructor();
}
break; break;
} }
} }
@ -7470,11 +7474,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.peekToken(&ignored, TokenStream::Operand)) if (!tokenStream.peekToken(&ignored, TokenStream::Operand))
return null(); return null();
if (pc->sc->isFunctionBox() && pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
report(ParseError, false, null(), JSMSG_DISABLED_DERIVED_CLASS, "arrow functions");
return null();
}
Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator); Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator);
if (!arrowFunc) if (!arrowFunc)
return null(); return null();
@ -8890,7 +8889,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
tt == TOK_NO_SUBS_TEMPLATE) tt == TOK_NO_SUBS_TEMPLATE)
{ {
if (handler.isSuperBase(lhs)) { if (handler.isSuperBase(lhs)) {
if (!pc->sc->isFunctionBox() || !pc->sc->asFunctionBox()->isDerivedClassConstructor()) { if (!pc->sc->allowSuperCall()) {
report(ParseError, false, null(), JSMSG_BAD_SUPERCALL); report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
return null(); return null();
} }

View File

@ -202,6 +202,7 @@ class SharedContext
bool allowNewTarget_; bool allowNewTarget_;
bool allowSuperProperty_; bool allowSuperProperty_;
bool allowSuperCall_;
bool inWith_; bool inWith_;
bool needsThisTDZChecks_; bool needsThisTDZChecks_;
bool superScopeAlreadyNeedsHomeObject_; bool superScopeAlreadyNeedsHomeObject_;
@ -217,6 +218,7 @@ class SharedContext
thisBinding_(ThisBinding::Global), thisBinding_(ThisBinding::Global),
allowNewTarget_(false), allowNewTarget_(false),
allowSuperProperty_(false), allowSuperProperty_(false),
allowSuperCall_(false),
inWith_(false), inWith_(false),
needsThisTDZChecks_(false), needsThisTDZChecks_(false),
superScopeAlreadyNeedsHomeObject_(false) superScopeAlreadyNeedsHomeObject_(false)
@ -244,6 +246,7 @@ class SharedContext
bool allowNewTarget() const { return allowNewTarget_; } bool allowNewTarget() const { return allowNewTarget_; }
bool allowSuperProperty() const { return allowSuperProperty_; } bool allowSuperProperty() const { return allowSuperProperty_; }
bool allowSuperCall() const { return allowSuperCall_; }
bool inWith() const { return inWith_; } bool inWith() const { return inWith_; }
bool needsThisTDZChecks() const { return needsThisTDZChecks_; } bool needsThisTDZChecks() const { return needsThisTDZChecks_; }

View File

@ -877,13 +877,15 @@ TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated,
ungetChar('*'); ungetChar('*');
break; break;
} }
tokenbuf.append(c); if (!tokenbuf.append(c))
return false;
} }
if (tokenbuf.empty()) if (tokenbuf.empty()) {
// The directive's URL was missing, but this is not quite an // The directive's URL was missing, but this is not quite an
// exception that we should stop and drop everything for. // exception that we should stop and drop everything for.
return true; return true;
}
size_t length = tokenbuf.length(); size_t length = tokenbuf.length();

View File

@ -0,0 +1,33 @@
// Check gating of shared memory features in asm.js (bug 1171540,
// bug 1231624).
//
// In asm.js, importing any atomic is a signal that shared memory is
// being used. If an atomic is imported, and if shared memory is
// disabled in the build or in the run then a type error should be
// signaled for the module at the end of the declaration section and
// the module should not be an asm.js module.
if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
quit(0);
// This code is not run, we only care whether it compiles as asm.js.
function module_a(stdlib, foreign, heap) {
"use asm";
var i32a = new stdlib.Int32Array(heap);
var ld = stdlib.Atomics.load;
// There should be a type error around this line if shared memory
// is not enabled.
function do_load() {
var v = 0;
v = ld(i32a, 0)|0; // It's not actually necessary to use the atomic op
return v|0;
}
return { load: do_load };
}
assertEq(isAsmJSModule(module_a), !!this.SharedArrayBuffer);

View File

@ -6,6 +6,8 @@ for (var i = 0; i < 10; i++) {
gcslice() gcslice()
} }
if (!this.SharedArrayBuffer)
quit(0);
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
x = new SharedArrayBuffer(4) x = new SharedArrayBuffer(4)

View File

@ -3588,8 +3588,7 @@ BaselineCompiler::emit_JSOP_RETRVAL()
return emitReturn(); return emitReturn();
} }
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue, typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, MutableHandleValue);
MutableHandleValue);
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation); static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation);
bool bool
@ -3605,10 +3604,7 @@ BaselineCompiler::emit_JSOP_TOID()
prepareVMCall(); prepareVMCall();
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
pushArg(R0); pushArg(R0);
pushArg(R1);
pushArg(ImmPtr(pc)); pushArg(ImmPtr(pc));
pushArg(ImmGCPtr(script)); pushArg(ImmGCPtr(script));
@ -3621,6 +3617,32 @@ BaselineCompiler::emit_JSOP_TOID()
return true; return true;
} }
typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible);
bool
BaselineCompiler::emit_JSOP_CHECKOBJCOERCIBLE()
{
frame.syncStack(0);
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
Label fail, done;
masm.branchTestUndefined(Assembler::Equal, R0, &fail);
masm.branchTestNull(Assembler::NotEqual, R0, &done);
masm.bind(&fail);
prepareVMCall();
pushArg(R0);
if (!callVM(ThrowObjectCoercibleInfo))
return false;
masm.bind(&done);
return true;
}
typedef JSString* (*ToStringFn)(JSContext*, HandleValue); typedef JSString* (*ToStringFn)(JSContext*, HandleValue);
static const VMFunction ToStringInfo = FunctionInfo<ToStringFn>(ToStringSlow); static const VMFunction ToStringInfo = FunctionInfo<ToStringFn>(ToStringSlow);

View File

@ -219,7 +219,8 @@ namespace jit {
_(JSOP_INITHIDDENPROP_SETTER) \ _(JSOP_INITHIDDENPROP_SETTER) \
_(JSOP_INITHIDDENELEM) \ _(JSOP_INITHIDDENELEM) \
_(JSOP_INITHIDDENELEM_GETTER) \ _(JSOP_INITHIDDENELEM_GETTER) \
_(JSOP_INITHIDDENELEM_SETTER) _(JSOP_INITHIDDENELEM_SETTER) \
_(JSOP_CHECKOBJCOERCIBLE)
class BaselineCompiler : public BaselineCompilerSpecific class BaselineCompiler : public BaselineCompilerSpecific
{ {

View File

@ -2769,6 +2769,11 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
return false; return false;
} }
// Don't try to attach stubs that wish to be hidden. We don't know how to
// have different enumerability in the stubs for the moment.
if (op == JSOP_INITHIDDENELEM)
return true;
// Overwrite the object on the stack (pushed for the decompiler) with the rhs. // Overwrite the object on the stack (pushed for the decompiler) with the rhs.
MOZ_ASSERT(stack[2] == objv); MOZ_ASSERT(stack[2] == objv);
stack[2] = rhs; stack[2] = rhs;

View File

@ -9061,7 +9061,7 @@ CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)
masm.jump(ool->rejoin()); masm.jump(ool->rejoin());
} }
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue, typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
MutableHandleValue); MutableHandleValue);
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation); static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation);
@ -9076,7 +9076,6 @@ CodeGenerator::visitToIdV(LToIdV* lir)
OutOfLineCode* ool = oolCallVM(ToIdInfo, lir, OutOfLineCode* ool = oolCallVM(ToIdInfo, lir,
ArgList(ImmGCPtr(current->mir()->info().script()), ArgList(ImmGCPtr(current->mir()->info().script()),
ImmPtr(lir->mir()->resumePoint()->pc()), ImmPtr(lir->mir()->resumePoint()->pc()),
ToValue(lir, LToIdV::Object),
ToValue(lir, LToIdV::Index)), ToValue(lir, LToIdV::Index)),
StoreValueTo(out)); StoreValueTo(out));
@ -10369,6 +10368,22 @@ CodeGenerator::visitCheckReturn(LCheckReturn* ins)
masm.bind(&noChecks); masm.bind(&noChecks);
} }
typedef bool (*ThrowObjCoercibleFn)(JSContext*, HandleValue);
static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo<ThrowObjCoercibleFn>(ThrowObjectCoercible);
void
CodeGenerator::visitCheckObjCoercible(LCheckObjCoercible* ins)
{
ValueOperand checkValue = ToValue(ins, LCheckObjCoercible::CheckValue);
Label fail, done;
masm.branchTestNull(Assembler::Equal, checkValue, &fail);
masm.branchTestUndefined(Assembler::NotEqual, checkValue, &done);
masm.bind(&fail);
pushArg(checkValue);
callVM(ThrowObjectCoercibleInfo, ins);
masm.bind(&done);
}
void void
CodeGenerator::visitRandom(LRandom* ins) CodeGenerator::visitRandom(LRandom* ins)
{ {

View File

@ -345,6 +345,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitNewTarget(LNewTarget* ins); void visitNewTarget(LNewTarget* ins);
void visitArrowNewTarget(LArrowNewTarget* ins); void visitArrowNewTarget(LArrowNewTarget* ins);
void visitCheckReturn(LCheckReturn* ins); void visitCheckReturn(LCheckReturn* ins);
void visitCheckObjCoercible(LCheckObjCoercible* ins);
void visitCheckOverRecursed(LCheckOverRecursed* lir); void visitCheckOverRecursed(LCheckOverRecursed* lir);
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool); void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);

View File

@ -355,7 +355,8 @@ class ExecutableAllocator
if (m_smallPools.length() < maxSmallPools) { if (m_smallPools.length() < maxSmallPools) {
// We haven't hit the maximum number of live pools; add the new pool. // We haven't hit the maximum number of live pools; add the new pool.
m_smallPools.append(pool); // If append() OOMs, we just return an unshared allocator.
if (m_smallPools.append(pool))
pool->addRef(); pool->addRef();
} else { } else {
// Find the pool with the least space. // Find the pool with the least space.

View File

@ -134,7 +134,9 @@ class LinearSum
: terms_(other.terms_.allocPolicy()), : terms_(other.terms_.allocPolicy()),
constant_(other.constant_) constant_(other.constant_)
{ {
terms_.appendAll(other.terms_); AutoEnterOOMUnsafeRegion oomUnsafe;
if (!terms_.appendAll(other.terms_))
oomUnsafe.crash("LinearSum::LinearSum");
} }
// These return false on an integer overflow, and afterwards the sum must // These return false on an integer overflow, and afterwards the sum must

View File

@ -615,7 +615,8 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
return true; return true;
} }
} }
loopHeaders_.append(LoopHeader(start, entry)); if (!loopHeaders_.append(LoopHeader(start, entry)))
return false;
jsbytecode* last = nullptr; jsbytecode* last = nullptr;
jsbytecode* earlier = nullptr; jsbytecode* earlier = nullptr;
@ -2098,6 +2099,9 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_NEWTARGET: case JSOP_NEWTARGET:
return jsop_newtarget(); return jsop_newtarget();
case JSOP_CHECKOBJCOERCIBLE:
return jsop_checkobjcoercible();
#ifdef DEBUG #ifdef DEBUG
case JSOP_PUSHBLOCKSCOPE: case JSOP_PUSHBLOCKSCOPE:
case JSOP_FRESHENBLOCKSCOPE: case JSOP_FRESHENBLOCKSCOPE:
@ -3419,8 +3423,12 @@ IonBuilder::tableSwitch(JSOp op, jssrcnote* sn)
MBasicBlock* defaultcase = newBlock(current, defaultpc); MBasicBlock* defaultcase = newBlock(current, defaultpc);
if (!defaultcase) if (!defaultcase)
return ControlStatus_Error; return ControlStatus_Error;
tableswitch->addDefault(defaultcase);
tableswitch->addBlock(defaultcase); if (!tableswitch->addDefault(defaultcase))
return ControlStatus_Error;
if (!tableswitch->addBlock(defaultcase))
return ControlStatus_Error;
// Create cases // Create cases
jsbytecode* casepc = nullptr; jsbytecode* casepc = nullptr;
@ -3448,14 +3456,22 @@ IonBuilder::tableSwitch(JSOp op, jssrcnote* sn)
if (!caseblock) if (!caseblock)
return ControlStatus_Error; return ControlStatus_Error;
tableswitch->addBlock(caseblock); if (!tableswitch->addBlock(caseblock))
return ControlStatus_Error;
// Add constant to indicate which case this is for use by // Add constant to indicate which case this is for use by
// processNextTableSwitchCase. // processNextTableSwitchCase.
MConstant* constant = MConstant::New(alloc(), Int32Value(i + low)); MConstant* constant = MConstant::New(alloc(), Int32Value(i + low));
caseblock->add(constant); caseblock->add(constant);
} }
tableswitch->addCase(tableswitch->addSuccessor(caseblock)); size_t caseIndex;
if (!tableswitch->addSuccessor(caseblock, &caseIndex))
return ControlStatus_Error;
if (!tableswitch->addCase(caseIndex))
return ControlStatus_Error;
pc2 += JUMP_OFFSET_LEN; pc2 += JUMP_OFFSET_LEN;
} }
@ -5389,7 +5405,7 @@ IonBuilder::selectInliningTargets(const ObjectVector& targets, CallInfo& callInf
inlineable = false; inlineable = false;
} }
choiceSet.append(inlineable); choiceSet.infallibleAppend(inlineable);
if (inlineable) if (inlineable)
*numInlineable += 1; *numInlineable += 1;
} }
@ -5881,7 +5897,8 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec
// Connect the inline path to the returnBlock. // Connect the inline path to the returnBlock.
ObjectGroup* funcGroup = target->isSingleton() ? nullptr : target->group(); ObjectGroup* funcGroup = target->isSingleton() ? nullptr : target->group();
dispatch->addCase(target, funcGroup, inlineBlock); if (!dispatch->addCase(target, funcGroup, inlineBlock))
return false;
MDefinition* retVal = inlineReturnBlock->peek(-1); MDefinition* retVal = inlineReturnBlock->peek(-1);
retPhi->addInput(retVal); retPhi->addInput(retVal);
@ -10309,6 +10326,31 @@ IonBuilder::jsop_rest()
return true; return true;
} }
bool
IonBuilder::jsop_checkobjcoercible()
{
MDefinition* toCheck = current->peek(-1);
if (!toCheck->mightBeType(MIRType_Undefined) &&
!toCheck->mightBeType(MIRType_Null))
{
toCheck->setImplicitlyUsedUnchecked();
return true;
}
MOZ_ASSERT(toCheck->type() == MIRType_Value ||
toCheck->type() == MIRType_Null ||
toCheck->type() == MIRType_Undefined);
// If we want to squeeze more perf here, we can throw without checking,
// if IsNullOrUndefined(toCheck->type()). Since this is a failure case,
// it should be OK.
MCheckObjCoercible* check = MCheckObjCoercible::New(alloc(), current->pop());
current->add(check);
current->push(check);
return resumeAfter(check);
}
uint32_t uint32_t
IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed) IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed)
{ {
@ -13021,7 +13063,7 @@ IonBuilder::jsop_toid()
return true; return true;
MDefinition* index = current->pop(); MDefinition* index = current->pop();
MToId* ins = MToId::New(alloc(), current->peek(-1), index); MToId* ins = MToId::New(alloc(), index);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);

View File

@ -738,6 +738,7 @@ class IonBuilder
bool jsop_setaliasedvar(ScopeCoordinate sc); bool jsop_setaliasedvar(ScopeCoordinate sc);
bool jsop_debugger(); bool jsop_debugger();
bool jsop_newtarget(); bool jsop_newtarget();
bool jsop_checkobjcoercible();
/* Inlining. */ /* Inlining. */

View File

@ -1097,8 +1097,7 @@ void
LIRGenerator::visitToId(MToId* ins) LIRGenerator::visitToId(MToId* ins)
{ {
LToIdV* lir = new(alloc()) LToIdV(tempDouble()); LToIdV* lir = new(alloc()) LToIdV(tempDouble());
useBox(lir, LToIdV::Object, ins->lhs()); useBox(lir, LToIdV::Index, ins->input());
useBox(lir, LToIdV::Index, ins->rhs());
defineBox(lir, ins); defineBox(lir, ins);
assignSafepoint(lir, ins); assignSafepoint(lir, ins);
} }
@ -4331,6 +4330,19 @@ LIRGenerator::visitCheckReturn(MCheckReturn* ins)
redefine(ins, retVal); redefine(ins, retVal);
} }
void
LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins)
{
MDefinition* checkVal = ins->checkValue();
MOZ_ASSERT(checkVal->type() == MIRType_Value);
LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible();
useBoxAtStart(lir, LCheckObjCoercible::CheckValue, checkVal);
redefine(ins, checkVal);
add(lir, ins);
assignSafepoint(lir, ins);
}
static void static void
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint) SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
{ {

View File

@ -310,6 +310,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitAtomicIsLockFree(MAtomicIsLockFree* ins); void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins); void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
void visitCheckReturn(MCheckReturn* ins); void visitCheckReturn(MCheckReturn* ins);
void visitCheckObjCoercible(MCheckObjCoercible* ins);
}; };
} // namespace jit } // namespace jit

View File

@ -2536,11 +2536,11 @@ class MTableSwitch final
return successors_.length(); return successors_.length();
} }
size_t addSuccessor(MBasicBlock* successor) { bool addSuccessor(MBasicBlock* successor, size_t* index) {
MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2)); MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2));
MOZ_ASSERT(!successors_.empty()); MOZ_ASSERT(!successors_.empty());
successors_.append(successor); *index = successors_.length();
return successors_.length() - 1; return successors_.append(successor);
} }
MBasicBlock* getSuccessor(size_t i) const override { MBasicBlock* getSuccessor(size_t i) const override {
@ -2581,14 +2581,15 @@ class MTableSwitch final
return high() - low() + 1; return high() - low() + 1;
} }
size_t addDefault(MBasicBlock* block) { bool addDefault(MBasicBlock* block, size_t* index = nullptr) {
MOZ_ASSERT(successors_.empty()); MOZ_ASSERT(successors_.empty());
successors_.append(block); if (index)
return 0; *index = 0;
return successors_.append(block);
} }
void addCase(size_t successorIndex) { bool addCase(size_t successorIndex) {
cases_.append(successorIndex); return cases_.append(successorIndex);
} }
MBasicBlock* getBlock(size_t i) const { MBasicBlock* getBlock(size_t i) const {
@ -2596,8 +2597,8 @@ class MTableSwitch final
return blocks_[i]; return blocks_[i];
} }
void addBlock(MBasicBlock* block) { bool addBlock(MBasicBlock* block) {
blocks_.append(block); return blocks_.append(block);
} }
MDefinition* getOperand(size_t index) const override { MDefinition* getOperand(size_t index) const override {
@ -5371,11 +5372,11 @@ class MTypeOf
}; };
class MToId class MToId
: public MBinaryInstruction, : public MUnaryInstruction,
public BoxInputsPolicy::Data public BoxInputsPolicy::Data
{ {
MToId(MDefinition* object, MDefinition* index) explicit MToId(MDefinition* index)
: MBinaryInstruction(object, index) : MUnaryInstruction(index)
{ {
setResultType(MIRType_Value); setResultType(MIRType_Value);
} }
@ -5383,8 +5384,8 @@ class MToId
public: public:
INSTRUCTION_HEADER(ToId) INSTRUCTION_HEADER(ToId)
static MToId* New(TempAllocator& alloc, MDefinition* object, MDefinition* index) { static MToId* New(TempAllocator& alloc, MDefinition* index) {
return new(alloc) MToId(object, index); return new(alloc) MToId(index);
} }
}; };
@ -10646,8 +10647,8 @@ class MDispatchInstruction
} }
public: public:
void addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) { bool addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
map_.append(Entry(func, funcGroup, block)); return map_.append(Entry(func, funcGroup, block));
} }
uint32_t numCases() const { uint32_t numCases() const {
return map_.length(); return map_.length();
@ -13365,6 +13366,29 @@ class MDebugger : public MNullaryInstruction
} }
}; };
class MCheckObjCoercible
: public MUnaryInstruction,
public BoxInputsPolicy::Data
{
explicit MCheckObjCoercible(MDefinition* toCheck)
: MUnaryInstruction(toCheck)
{
setGuard();
setResultType(MIRType_Value);
setResultTypeSet(toCheck->resultTypeSet());
}
public:
INSTRUCTION_HEADER(CheckObjCoercible)
static MCheckObjCoercible* New(TempAllocator& alloc, MDefinition* toCheck) {
return new(alloc) MCheckObjCoercible(toCheck);
}
MDefinition* checkValue() {
return getOperand(0);
}
};
class MAsmJSNeg class MAsmJSNeg
: public MUnaryInstruction, : public MUnaryInstruction,
public NoTypePolicy::Data public NoTypePolicy::Data

View File

@ -279,7 +279,8 @@ namespace jit {
_(Debugger) \ _(Debugger) \
_(NewTarget) \ _(NewTarget) \
_(ArrowNewTarget) \ _(ArrowNewTarget) \
_(CheckReturn) _(CheckReturn) \
_(CheckObjCoercible)
// Forward declarations of MIR types. // Forward declarations of MIR types.
#define FORWARD_DECLARE(op) class M##op; #define FORWARD_DECLARE(op) class M##op;

View File

@ -65,9 +65,13 @@ struct AllocationIntegrityState
InstructionInfo(const InstructionInfo& o) InstructionInfo(const InstructionInfo& o)
{ {
inputs.appendAll(o.inputs); AutoEnterOOMUnsafeRegion oomUnsafe;
temps.appendAll(o.temps); if (!inputs.appendAll(o.inputs) ||
outputs.appendAll(o.outputs); !temps.appendAll(o.temps) ||
!outputs.appendAll(o.outputs))
{
oomUnsafe.crash("InstructionInfo::InstructionInfo");
}
} }
}; };
Vector<InstructionInfo, 0, SystemAllocPolicy> instructions; Vector<InstructionInfo, 0, SystemAllocPolicy> instructions;
@ -76,7 +80,9 @@ struct AllocationIntegrityState
Vector<InstructionInfo, 5, SystemAllocPolicy> phis; Vector<InstructionInfo, 5, SystemAllocPolicy> phis;
BlockInfo() {} BlockInfo() {}
BlockInfo(const BlockInfo& o) { BlockInfo(const BlockInfo& o) {
phis.appendAll(o.phis); AutoEnterOOMUnsafeRegion oomUnsafe;
if (!phis.appendAll(o.phis))
oomUnsafe.crash("BlockInfo::BlockInfo");
} }
}; };
Vector<BlockInfo, 0, SystemAllocPolicy> blocks; Vector<BlockInfo, 0, SystemAllocPolicy> blocks;

View File

@ -1311,6 +1311,15 @@ BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
return ThrowUninitializedThis(cx, frame); return ThrowUninitializedThis(cx, frame);
} }
bool
ThrowObjectCoercible(JSContext* cx, HandleValue v)
{
MOZ_ASSERT(v.isUndefined() || v.isNull());
MOZ_ALWAYS_FALSE(ToObjectSlow(cx, v, false));
return false;
}
bool bool
BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res) BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
{ {

View File

@ -738,6 +738,8 @@ bool ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber);
bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame); bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v); bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
bool ThrowObjectCoercible(JSContext* cx, HandleValue v);
bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res); bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
} // namespace jit } // namespace jit

View File

@ -1276,7 +1276,7 @@ class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1>
} }
}; };
class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1> class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
{ {
public: public:
LIR_HEADER(ToIdV) LIR_HEADER(ToIdV)
@ -1286,8 +1286,7 @@ class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1>
setTemp(0, temp); setTemp(0, temp);
} }
static const size_t Object = 0; static const size_t Index = 0;
static const size_t Index = BOX_PIECES;
MToId* mir() const { MToId* mir() const {
return mir_->toToId(); return mir_->toToId();
@ -7397,6 +7396,14 @@ class LCheckReturn : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0
LIR_HEADER(CheckReturn) LIR_HEADER(CheckReturn)
}; };
class LCheckObjCoercible : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
{
public:
static const size_t CheckValue = 0;
LIR_HEADER(CheckObjCoercible)
};
} // namespace jit } // namespace jit
} // namespace js } // namespace js

View File

@ -367,6 +367,7 @@
_(Debugger) \ _(Debugger) \
_(NewTarget) \ _(NewTarget) \
_(ArrowNewTarget) \ _(ArrowNewTarget) \
_(CheckReturn) _(CheckReturn) \
_(CheckObjCoercible)
#endif /* jit_shared_LOpcodes_shared_h */ #endif /* jit_shared_LOpcodes_shared_h */

View File

@ -105,7 +105,6 @@ MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can'
MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}") MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null") MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null")
MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors")
MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor") MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor")
MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")

View File

@ -13,7 +13,6 @@
#include "mozilla/FloatingPoint.h" #include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/unused.h"
#include <algorithm> // for std::max #include <algorithm> // for std::max
#include <fcntl.h> #include <fcntl.h>
@ -802,10 +801,15 @@ GenerateSeed(uint64_t* seedBuffer, size_t length)
if (fd >= 0) { if (fd >= 0) {
ssize_t size = length * sizeof(seedBuffer[0]); ssize_t size = length * sizeof(seedBuffer[0]);
ssize_t nread = read(fd, (char *) seedBuffer, size); ssize_t nread = read(fd, (char *) seedBuffer, size);
MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
mozilla::Unused << nread;
close(fd); close(fd);
MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
if (nread == size)
return;
} }
// Use PRMJ_Now() if we couldn't read from /dev/urandom.
for (size_t i = 0; i < length; i++)
seedBuffer[i] = PRMJ_Now();
#else #else
# error "Platform needs to implement random_generateSeed()" # error "Platform needs to implement random_generateSeed()"
#endif #endif

View File

@ -2231,11 +2231,12 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject s
// See note above RuntimeLexicalErrorObject. // See note above RuntimeLexicalErrorObject.
if (pobj == scope) { if (pobj == scope) {
if (IsUninitializedLexicalSlot(scope, shape)) { if (name != cx->names().dotThis && IsUninitializedLexicalSlot(scope, shape)) {
scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_UNINITIALIZED_LEXICAL); scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_UNINITIALIZED_LEXICAL);
if (!scope) if (!scope)
return false; return false;
} else if (scope->is<ScopeObject>() && !scope->is<DeclEnvObject>() && !shape->writable()) { } else if (scope->is<ScopeObject>() && !scope->is<DeclEnvObject>() && !shape->writable()) {
MOZ_ASSERT(name != cx->names().dotThis);
scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_BAD_CONST_ASSIGN); scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_BAD_CONST_ASSIGN);
if (!scope) if (!scope)
return false; return false;

View File

@ -0,0 +1,19 @@
// Make sure it doesn't matter when we make the arrow function
var test = `
new class extends class { } {
constructor() {
let arrow = () => this;
assertThrowsInstanceOf(arrow, ReferenceError);
super();
assertEq(arrow(), this);
}
}();
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,18 @@
var test = `
new class extends class { } {
constructor() {
let a1 = () => this;
let a2 = (() => super());
assertThrowsInstanceOf(a1, ReferenceError);
assertEq(a2(), a1());
}
}();
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,20 @@
var test = `
let arrow;
class foo extends class { } {
constructor() {
arrow = () => this;
super();
}
}
assertEq(new foo(), arrow());
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,45 @@
var test = `
let superArrow;
let thisArrow;
let thisStash;
class base {
constructor() {
// We run this constructor twice as part of the double init check
if (!thisStash)
thisStash = {prop:45};
return thisStash;
}
}
class foo extends base {
constructor() {
superArrow = (()=>super());
thisArrow = ()=>this;
}
}
// Populate the arrow function saves. Since we never invoke super(), we throw
assertThrowsInstanceOf(()=>new foo(), ReferenceError);
// No |this| binding in the closure, yet
assertThrowsInstanceOf(thisArrow, ReferenceError);
// call super()
superArrow();
// Can't call it twice
assertThrowsInstanceOf(superArrow, ReferenceError);
// Oh look, |this| is populated, now.
assertEq(thisArrow(), thisStash);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,17 @@
var test = `
new class extends class { } {
constructor() {
super();
assertEq(this, (()=>this)());
assertEq(this, eval("this"));
}
}();
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,41 @@
var test = `
new class extends class { } {
constructor() {
(()=>eval("super()"))();
assertEq(this, eval("this"));
assertEq(this, (()=>this)());
}
}();
new class extends class { } {
constructor() {
(()=>(()=>super())())();
assertEq(this, eval("this"));
assertEq(this, (()=>this)());
}
}();
new class extends class { } {
constructor() {
eval("(()=>super())()");
assertEq(this, eval("this"));
assertEq(this, (()=>this)());
}
}();
new class extends class { } {
constructor() {
eval("eval('super()')");
assertEq(this, eval("this"));
assertEq(this, (()=>this)());
}
}();
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,25 @@
var test = `
new class extends class { } {
constructor() {
assertEq(eval("super(); this"), this);
assertEq(this, eval("this"));
assertEq(this, (()=>this)());
}
}();
new class extends class { } {
constructor() {
(()=>super())();
assertEq(this, eval("this"));
assertEq(this, (()=>this)());
}
}();
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -1,38 +0,0 @@
// |reftest| skip-if(!xulRuntime.shell)
var test = `
class base {
constructor() {
eval('');
(()=>0)();
}
}
class derived extends base {
constructor() {
eval('');
}
}
// Make sure eval and arrows are still valid in non-derived constructors.
new base();
// Eval throws in derived class constructors, in both class expressions and
// statements.
assertThrowsInstanceOf((() => new derived()), InternalError);
assertThrowsInstanceOf((() => new class extends base { constructor() { eval('') } }()), InternalError);
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); };
g.eval("new class foo extends null { constructor() { debugger; return {}; } }()");
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,31 @@
var test = `
// #1
function base() { }
base.prototype = {
test() {
--super[1];
}
}
var d = new base();
d.test();
// #2
class test2 {
test() {
super[1]++;
}
}
var d = new test2();
d.test()
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,7 @@
{
function f() { return "inner"; }
}
function f() { return "outer"; }
reportCompare(f(), "inner");

View File

@ -132,9 +132,6 @@ function testClasses() {
assertClass("class NAME { }", []); assertClass("class NAME { }", []);
assertClass("class NAME extends null { }", [], lit(null)); assertClass("class NAME extends null { }", [], lit(null));
// For now, disallow arrow functions in derived class constructors
assertClassError("class NAME extends null { constructor() { (() => 0); }", InternalError);
// Derived class constructor must have curly brackets // Derived class constructor must have curly brackets
assertClassError("class NAME extends null { constructor() 1 }", SyntaxError); assertClassError("class NAME extends null { constructor() 1 }", SyntaxError);

View File

@ -4373,8 +4373,8 @@ Debugger::setupTraceLogger(JSContext* cx, unsigned argc, Value* vp)
if (!GetProperty(cx, obj, obj, ids[i], &v)) if (!GetProperty(cx, obj, obj, ids[i], &v))
return false; return false;
textIds.append(textId); textIds.infallibleAppend(textId);
values.append(ToBoolean(v)); values.infallibleAppend(ToBoolean(v));
} }
MOZ_ASSERT(ids.length() == textIds.length()); MOZ_ASSERT(ids.length() == textIds.length());
@ -6724,13 +6724,6 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code
MOZ_ASSERT_IF(iter, !scope); MOZ_ASSERT_IF(iter, !scope);
MOZ_ASSERT_IF(!iter, scope && IsGlobalLexicalScope(scope)); MOZ_ASSERT_IF(!iter, scope && IsGlobalLexicalScope(scope));
if (iter && iter->script()->isDerivedClassConstructor()) {
MOZ_ASSERT(iter->isFunctionFrame() && iter->calleeTemplate()->isClassConstructor());
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DISABLED_DERIVED_CLASS,
"debugger eval");
return false;
}
/* Check the first argument, the eval code string. */ /* Check the first argument, the eval code string. */
if (!code.isString()) { if (!code.isString()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE, JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,

View File

@ -427,7 +427,9 @@ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
for (size_t i = 0; i < waiting.length(); i++) { for (size_t i = 0; i < waiting.length(); i++) {
ParseTask* task = waiting[i]; ParseTask* task = waiting[i];
if (task->runtimeMatches(rt)) { if (task->runtimeMatches(rt)) {
newTasks.append(task); AutoEnterOOMUnsafeRegion oomUnsafe;
if (!newTasks.append(task))
oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
HelperThreadState().remove(waiting, &i); HelperThreadState().remove(waiting, &i);
} }
} }
@ -444,8 +446,11 @@ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
AutoLockHelperThreadState lock; AutoLockHelperThreadState lock;
for (size_t i = 0; i < newTasks.length(); i++) {
HelperThreadState().parseWorklist().append(newTasks[i]); AutoEnterOOMUnsafeRegion oomUnsafe;
if (!HelperThreadState().parseWorklist().appendAll(newTasks))
oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
}
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER); HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
} }

View File

@ -204,6 +204,10 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName
} }
} }
// We do our own explicit checking for |this|
if (name == cx->names().dotThis)
return true;
// NAME operations are the slow paths already, so unconditionally check // NAME operations are the slow paths already, so unconditionally check
// for uninitialized lets. // for uninitialized lets.
return CheckUninitializedLexical(cx, name, vp); return CheckUninitializedLexical(cx, name, vp);
@ -391,18 +395,14 @@ NegOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue val
} }
static MOZ_ALWAYS_INLINE bool static MOZ_ALWAYS_INLINE bool
ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue objval, ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval,
HandleValue idval, MutableHandleValue res) MutableHandleValue res)
{ {
if (idval.isInt32()) { if (idval.isInt32()) {
res.set(idval); res.set(idval);
return true; return true;
} }
JSObject* obj = ToObjectFromStack(cx, objval);
if (!obj)
return false;
RootedId id(cx); RootedId id(cx);
if (!ToPropertyKey(cx, idval, &id)) if (!ToPropertyKey(cx, idval, &id))
return false; return false;

View File

@ -1740,7 +1740,6 @@ CASE(JSOP_NOP)
CASE(JSOP_UNUSED14) CASE(JSOP_UNUSED14)
CASE(JSOP_UNUSED65) CASE(JSOP_UNUSED65)
CASE(JSOP_BACKPATCH) CASE(JSOP_BACKPATCH)
CASE(JSOP_UNUSED163)
CASE(JSOP_UNUSED177) CASE(JSOP_UNUSED177)
CASE(JSOP_UNUSED178) CASE(JSOP_UNUSED178)
CASE(JSOP_UNUSED179) CASE(JSOP_UNUSED179)
@ -2422,10 +2421,9 @@ CASE(JSOP_TOID)
* but we need to avoid the observable stringification the second time. * but we need to avoid the observable stringification the second time.
* There must be an object value below the id, which will not be popped. * There must be an object value below the id, which will not be popped.
*/ */
ReservedRooted<Value> objval(&rootValue0, REGS.sp[-2]);
ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]); ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
MutableHandleValue res = REGS.stackHandleAt(-1); MutableHandleValue res = REGS.stackHandleAt(-1);
if (!ToIdOperation(cx, script, REGS.pc, objval, idval, res)) if (!ToIdOperation(cx, script, REGS.pc, idval, res))
goto error; goto error;
} }
END_CASE(JSOP_TOID) END_CASE(JSOP_TOID)
@ -3232,10 +3230,7 @@ CASE(JSOP_SETLOCAL)
{ {
uint32_t i = GET_LOCALNO(REGS.pc); uint32_t i = GET_LOCALNO(REGS.pc);
// Derived class constructors store the TDZ Value in the .this slot MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
// before a super() call.
MOZ_ASSERT_IF(!script->isDerivedClassConstructor(),
!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
REGS.fp()->unaliasedLocal(i) = REGS.sp[-1]; REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
} }
@ -3893,6 +3888,14 @@ CASE(JSOP_CLASSCONSTRUCTOR)
} }
END_CASE(JSOP_CLASSCONSTRUCTOR) END_CASE(JSOP_CLASSCONSTRUCTOR)
CASE(JSOP_CHECKOBJCOERCIBLE)
{
ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
if (checkVal.isNullOrUndefined() && !ToObjectFromStack(cx, checkVal))
goto error;
}
END_CASE(JSOP_CHECKOBJCOERCIBLE)
DEFAULT() DEFAULT()
{ {
char numBuf[12]; char numBuf[12];
@ -4837,9 +4840,6 @@ js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
{ {
RootedFunction fun(cx, frame.callee()); RootedFunction fun(cx, frame.callee());
MOZ_ASSERT(fun->isClassConstructor());
MOZ_ASSERT(fun->nonLazyScript()->isDerivedClassConstructor());
const char* name = "anonymous"; const char* name = "anonymous";
JSAutoByteString str; JSAutoByteString str;
if (fun->atom()) { if (fun->atom()) {

View File

@ -1668,7 +1668,14 @@
* Stack: => * Stack: =>
*/ \ */ \
macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \ macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \
macro(JSOP_UNUSED163, 163,"unused163", NULL, 1, 0, 1, JOF_BYTE) \ /*
* Throw if the value on the stack is not coerscible to an object (is |null| or |undefined|).
* Category: Literals
* Type: Object
* Operands:
* Stack: val => val
*/ \
macro(JSOP_CHECKOBJCOERCIBLE, 163, "checkobjcoercible", NULL, 1, 1, 1, JOF_BYTE) \
/* /*
* Find the function to invoke with |super()| on the scope chain. * Find the function to invoke with |super()| on the scope chain.
* *
@ -2122,15 +2129,12 @@
macro(JSOP_REST, 224, "rest", NULL, 1, 0, 1, JOF_BYTE|JOF_TYPESET) \ macro(JSOP_REST, 224, "rest", NULL, 1, 0, 1, JOF_BYTE|JOF_TYPESET) \
\ \
/* /*
* First, throw a TypeError if baseValue is null or undefined. Then, * Replace the top-of-stack value propertyNameValue with
* replace the top-of-stack value propertyNameValue with * ToPropertyKey(propertyNameValue).
* ToPropertyKey(propertyNameValue). This opcode implements ES6 12.3.2.1
* steps 7-10. It is also used to implement computed property names; in
* that case, baseValue is always an object, so the first step is a no-op.
* Category: Literals * Category: Literals
* Type: Object * Type: Object
* Operands: * Operands:
* Stack: baseValue, propertyNameValue => baseValue, propertyKey * Stack: propertyNameValue => propertyKey
*/ \ */ \
macro(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, JOF_BYTE) \ macro(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, JOF_BYTE) \
\ \

View File

@ -306,8 +306,10 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
if (!atomsCompartment || !atomsCompartment->init(nullptr)) if (!atomsCompartment || !atomsCompartment->init(nullptr))
return false; return false;
gc.zones.append(atomsZone.get()); if (!gc.zones.append(atomsZone.get()))
atomsZone->compartments.append(atomsCompartment.get()); return false;
if (!atomsZone->compartments.append(atomsCompartment.get()))
return false;
atomsCompartment->setIsSystem(true); atomsCompartment->setIsSystem(true);

View File

@ -953,7 +953,7 @@ class ClonedBlockObject : public BlockObject
// Attempting to access anything on this scope throws the appropriate // Attempting to access anything on this scope throws the appropriate
// ReferenceError. // ReferenceError.
// //
// ES6 'const' bindings induce a runtime assignment when assigned to outside // ES6 'const' bindings induce a runtime error when assigned to outside
// of initialization, regardless of strictness. // of initialization, regardless of strictness.
class RuntimeLexicalErrorObject : public ScopeObject class RuntimeLexicalErrorObject : public ScopeObject
{ {

View File

@ -3875,7 +3875,11 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
RootedFunction function(cx, this->function()); RootedFunction function(cx, this->function());
Vector<uint32_t, 32> pcOffsets(cx); Vector<uint32_t, 32> pcOffsets(cx);
for (ScriptFrameIter iter(cx); !iter.done(); ++iter) { for (ScriptFrameIter iter(cx); !iter.done(); ++iter) {
pcOffsets.append(iter.script()->pcToOffset(iter.pc())); {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
oomUnsafe.crash("rollbackPartiallyInitializedObjects");
}
if (!iter.isConstructing() || !iter.matchCallee(cx, function)) if (!iter.isConstructing() || !iter.matchCallee(cx, function))
continue; continue;

View File

@ -29,11 +29,11 @@ namespace js {
* *
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/ */
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 327; static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 329;
static const uint32_t XDR_BYTECODE_VERSION = static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 425, static_assert(JSErr_Limit == 424,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment " "removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "

View File

@ -4575,13 +4575,9 @@ nsDisplayResolution::HitTest(nsDisplayListBuilder* aBuilder,
HitTestState* aState, HitTestState* aState,
nsTArray<nsIFrame*> *aOutFrames) nsTArray<nsIFrame*> *aOutFrames)
{ {
#if defined(MOZ_SINGLE_PROCESS_APZ)
nsIPresShell* presShell = mFrame->PresContext()->PresShell(); nsIPresShell* presShell = mFrame->PresContext()->PresShell();
nsRect rect = aRect.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f); nsRect rect = aRect.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
mList.HitTest(aBuilder, rect, aState, aOutFrames); mList.HitTest(aBuilder, rect, aState, aOutFrames);
#else
mList.HitTest(aBuilder, aRect, aState, aOutFrames);
#endif // MOZ_SINGLE_PROCESS_APZ
} }
already_AddRefed<Layer> already_AddRefed<Layer>

View File

@ -1416,7 +1416,12 @@ public:
virtual nsresult SetResolution(float aResolution) = 0; virtual nsresult SetResolution(float aResolution) = 0;
float GetResolution() { return mResolution.valueOr(1.0); } float GetResolution() { return mResolution.valueOr(1.0); }
virtual float GetCumulativeResolution() = 0; virtual float GetCumulativeResolution() = 0;
virtual float GetCumulativeScaleResolution() = 0;
/**
* Calculate the cumulative scale resolution from this document up to
* but not including the root document.
*/
virtual float GetCumulativeNonRootScaleResolution() = 0;
/** /**
* Was the current resolution set by the user or just default initialized? * Was the current resolution set by the user or just default initialized?

View File

@ -2021,9 +2021,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x), nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x),
presContext->DevPixelsToAppUnits(aPoint.y)); presContext->DevPixelsToAppUnits(aPoint.y));
pt = pt - view->ViewToWidgetOffset(); pt = pt - view->ViewToWidgetOffset();
#if defined(MOZ_SINGLE_PROCESS_APZ) pt = pt.RemoveResolution(presContext->PresShell()->GetCumulativeNonRootScaleResolution());
pt = pt.RemoveResolution(presContext->PresShell()->GetCumulativeScaleResolution());
#endif // MOZ_SINGLE_PROCESS_APZ
return pt; return pt;
} }
} }
@ -2059,12 +2057,10 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel(); int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
int32_t localAPD = aFrame->PresContext()->AppUnitsPerDevPixel(); int32_t localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
widgetToView = widgetToView.ScaleToOtherAppUnits(rootAPD, localAPD); widgetToView = widgetToView.ScaleToOtherAppUnits(rootAPD, localAPD);
#if defined(MOZ_SINGLE_PROCESS_APZ)
nsIPresShell* shell = aFrame->PresContext()->PresShell(); nsIPresShell* shell = aFrame->PresContext()->PresShell();
// XXX Bug 1224748 - Update nsLayoutUtils functions to correctly handle nsPresShell resolution // XXX Bug 1224748 - Update nsLayoutUtils functions to correctly handle nsPresShell resolution
widgetToView = widgetToView.RemoveResolution(shell->GetCumulativeScaleResolution()); widgetToView = widgetToView.RemoveResolution(shell->GetCumulativeNonRootScaleResolution());
#endif
/* If we encountered a transform, we can't do simple arithmetic to figure /* If we encountered a transform, we can't do simple arithmetic to figure
* out how to convert back to aFrame's coordinates and must use the CTM. * out how to convert back to aFrame's coordinates and must use the CTM.
@ -2812,10 +2808,8 @@ nsLayoutUtils::TranslateViewToWidget(nsPresContext* aPresContext,
return LayoutDeviceIntPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); return LayoutDeviceIntPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
} }
nsPoint pt = aPt + viewOffset; nsPoint pt = (aPt +
#if defined(MOZ_SINGLE_PROCESS_APZ) viewOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
pt = pt.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
#endif // MOZ_SINGLE_PROCESS_APZ
LayoutDeviceIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(pt.x), LayoutDeviceIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(pt.x),
aPresContext->AppUnitsToDevPixels(pt.y)); aPresContext->AppUnitsToDevPixels(pt.y));
return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget); return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget);

View File

@ -5330,13 +5330,16 @@ float PresShell::GetCumulativeResolution()
return resolution; return resolution;
} }
float PresShell::GetCumulativeScaleResolution() float PresShell::GetCumulativeNonRootScaleResolution()
{ {
float resolution = 1.0; float resolution = 1.0;
nsIPresShell* currentShell = this; nsIPresShell* currentShell = this;
while (currentShell) { while (currentShell) {
nsPresContext* currentCtx = currentShell->GetPresContext();
if (currentCtx != currentCtx->GetRootPresContext()) {
resolution *= currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f; resolution *= currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
nsPresContext* parentCtx = currentShell->GetPresContext()->GetParentPresContext(); }
nsPresContext* parentCtx = currentCtx->GetParentPresContext();
if (parentCtx) { if (parentCtx) {
currentShell = parentCtx->PresShell(); currentShell = parentCtx->PresShell();
} else { } else {

View File

@ -218,7 +218,7 @@ public:
} }
virtual bool ScaleToResolution() const override; virtual bool ScaleToResolution() const override;
virtual float GetCumulativeResolution() override; virtual float GetCumulativeResolution() override;
virtual float GetCumulativeScaleResolution() override; virtual float GetCumulativeNonRootScaleResolution() override;
//nsIViewObserver interface //nsIViewObserver interface

View File

@ -20,6 +20,7 @@ support-files =
file_bug1018265.xul file_bug1018265.xul
[test_bug370436.html] [test_bug370436.html]
skip-if = buildapp == 'b2g'
[test_bug396367-1.html] [test_bug396367-1.html]
[test_bug396367-2.html] [test_bug396367-2.html]
[test_bug420499.xul] [test_bug420499.xul]

View File

@ -442,12 +442,10 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder->EnterPresShell(subdocRootFrame, aBuilder->EnterPresShell(subdocRootFrame,
pointerEventsNone && !passPointerEventsToChildren); pointerEventsNone && !passPointerEventsToChildren);
#if defined(MOZ_SINGLE_PROCESS_APZ)
if (!haveDisplayPort) { if (!haveDisplayPort) {
// Remove nsPresShell resolution // Remove nsPresShell resolution
dirty = dirty.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f); dirty = dirty.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
} }
#endif
} else { } else {
dirty = aDirtyRect; dirty = aDirtyRect;
} }

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