зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
b25476080d
|
@ -1007,16 +1007,8 @@ pref("security.exthelperapp.disable_background_handling", true);
|
|||
// Inactivity time in milliseconds after which we shut down the OS.File worker.
|
||||
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
|
||||
pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking
|
||||
pref("apz.fling_curve_function_x1", "0.41");
|
||||
pref("apz.fling_curve_function_y1", "0.0");
|
||||
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_friction", "0.0019");
|
||||
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.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
|
||||
pref("layout.event-regions.enabled", true);
|
||||
|
|
|
@ -29,17 +29,12 @@ function serializeServiceWorkerInfo(aServiceWorkerInfo) {
|
|||
|
||||
let result = {};
|
||||
|
||||
Object.keys(aServiceWorkerInfo).forEach(property => {
|
||||
if (typeof aServiceWorkerInfo[property] == "function") {
|
||||
return;
|
||||
}
|
||||
if (property === "principal") {
|
||||
result.principal = {
|
||||
origin: aServiceWorkerInfo.principal.originNoSuffix,
|
||||
originAttributes: aServiceWorkerInfo.principal.originAttributes
|
||||
};
|
||||
return;
|
||||
}
|
||||
result.principal = {
|
||||
origin: aServiceWorkerInfo.principal.originNoSuffix,
|
||||
originAttributes: aServiceWorkerInfo.principal.originAttributes
|
||||
};
|
||||
|
||||
["scope", "scriptSpec"].forEach(property => {
|
||||
result[property] = aServiceWorkerInfo[property];
|
||||
});
|
||||
|
||||
|
|
|
@ -761,7 +761,7 @@
|
|||
}
|
||||
|
||||
// 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.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
|
||||
}
|
||||
|
|
|
@ -324,7 +324,6 @@ skip-if = buildapp == 'mulet'
|
|||
[browser_identity_UI.js]
|
||||
[browser_insecureLoginForms.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_postData.js]
|
||||
[browser_lastAccessedTab.js]
|
||||
|
|
|
@ -12,6 +12,14 @@ add_task(function* test_keyword_bookmarklet() {
|
|||
yield promisePageShow();
|
||||
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;" })
|
||||
|
||||
// Enter bookmarklet keyword in the URL bar
|
||||
|
@ -21,7 +29,19 @@ add_task(function* test_keyword_bookmarklet() {
|
|||
|
||||
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() {
|
||||
|
|
|
@ -4224,7 +4224,6 @@ cairo-uikit)
|
|||
CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
|
||||
MOZ_USER_DIR="Mozilla"
|
||||
MOZ_FS_LAYOUT=bundle
|
||||
AC_DEFINE(MOZ_SINGLE_PROCESS_APZ)
|
||||
;;
|
||||
|
||||
cairo-android)
|
||||
|
@ -4798,11 +4797,8 @@ MOZ_ARG_ENABLE_BOOL(android-apz,
|
|||
MOZ_ANDROID_APZ=1,
|
||||
MOZ_ANDROID_APZ=)
|
||||
if test -n "$MOZ_ANDROID_APZ"; then
|
||||
dnl Do this if defined in confvars.sh
|
||||
AC_DEFINE(MOZ_ANDROID_APZ)
|
||||
if test -z "$MOZ_B2GDROID"; then
|
||||
AC_DEFINE(MOZ_SINGLE_PROCESS_APZ)
|
||||
fi
|
||||
dnl Do this if defined in confvars.sh
|
||||
AC_DEFINE(MOZ_ANDROID_APZ)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
|
|
@ -229,7 +229,7 @@ function installCache(app) {
|
|||
return;
|
||||
|
||||
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 we install the cache anyway, it won't be updateable. If we don't install
|
||||
|
|
|
@ -7509,7 +7509,9 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
|
|||
if (IsFileImage(file, type)) {
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = type;
|
||||
SlurpFileToString(file, item->data());
|
||||
nsAutoCString data;
|
||||
SlurpFileToString(file, data);
|
||||
item->data() = data;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -7669,11 +7671,10 @@ nsContentUtils::ToWidgetPoint(const CSSPoint& aPoint,
|
|||
const nsPoint& aOffset,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
nsPoint point = CSSPoint::ToAppUnits(aPoint) + aOffset;
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
point = point.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
|
||||
#endif
|
||||
return LayoutDeviceIntPoint::FromAppUnitsRounded(point, aPresContext->AppUnitsPerDevPixel());
|
||||
return LayoutDeviceIntPoint::FromAppUnitsRounded(
|
||||
(CSSPoint::ToAppUnits(aPoint) +
|
||||
aOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution()),
|
||||
aPresContext->AppUnitsPerDevPixel());
|
||||
}
|
||||
|
||||
nsView*
|
||||
|
|
|
@ -286,11 +286,10 @@ already_AddRefed<nsIScriptTimeoutHandler>
|
|||
NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
|
||||
const nsAString& aExpression, ErrorResult& aError)
|
||||
{
|
||||
ErrorResult rv;
|
||||
bool allowEval = false;
|
||||
RefPtr<nsJSScriptTimeoutHandler> handler =
|
||||
new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, rv);
|
||||
if (rv.Failed() || !allowEval) {
|
||||
new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, aError);
|
||||
if (aError.Failed() || !allowEval) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,61 +5,66 @@
|
|||
* loads. The policy we are enforcing is outlined here:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=593387#c17
|
||||
*/
|
||||
var newBrowser;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
add_task(function* test() {
|
||||
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();
|
||||
gBrowser.selectedTab = newTab;
|
||||
newBrowser = gBrowser.getBrowserForTab(newTab);
|
||||
//alert(newBrowser.contentWindow);
|
||||
// Run next test (try the same with a content top-level context)
|
||||
yield BrowserTestUtils.loadURI(newBrowser, "http://example.com/");
|
||||
yield BrowserTestUtils.browserLoaded(newBrowser);
|
||||
|
||||
newBrowser.addEventListener("load", testXFOFrameInChrome, true);
|
||||
newBrowser.contentWindow.location = "chrome://global/content/mozilla.xhtml";
|
||||
}
|
||||
|
||||
function testXFOFrameInChrome() {
|
||||
newBrowser.removeEventListener("load", testXFOFrameInChrome, true);
|
||||
yield ContentTask.spawn(newBrowser, null, testXFOFrameInContent);
|
||||
});
|
||||
});
|
||||
|
||||
function testXFOFrameInChrome(newBrowser) {
|
||||
// Insert an iframe that specifies "X-Frame-Options: DENY" and verify
|
||||
// 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");
|
||||
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.removeEventListener("load", arguments.callee, true);
|
||||
frame.addEventListener("load", function loaded() {
|
||||
frame.removeEventListener("load", loaded, true);
|
||||
|
||||
// Test that the frame loaded
|
||||
var test = this.contentDocument.getElementById("test");
|
||||
is(test.tagName, "H1", "wrong element type");
|
||||
is(test.textContent, "deny", "wrong textContent");
|
||||
|
||||
// Run next test (try the same with a content top-level context)
|
||||
newBrowser.addEventListener("load", testXFOFrameInContent, true);
|
||||
newBrowser.contentWindow.location = "http://example.com/";
|
||||
deferred.resolve();
|
||||
}, true);
|
||||
|
||||
newBrowser.contentDocument.body.appendChild(frame);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testXFOFrameInContent() {
|
||||
newBrowser.removeEventListener("load", testXFOFrameInContent, true);
|
||||
|
||||
function testXFOFrameInContent(newBrowser) {
|
||||
// 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
|
||||
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.addEventListener("load", function() {
|
||||
frame.removeEventListener("load", arguments.callee, true);
|
||||
frame.addEventListener("load", function loaded() {
|
||||
frame.removeEventListener("load", loaded, true);
|
||||
|
||||
// Test that the frame DID NOT load
|
||||
var test = this.contentDocument.getElementById("test");
|
||||
is(test, undefined, "should be about:blank");
|
||||
is(test, null, "should be about:blank");
|
||||
|
||||
// Finalize the test
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
deferred.resolve();
|
||||
}, true);
|
||||
|
||||
newBrowser.contentDocument.body.appendChild(frame);
|
||||
content.document.body.appendChild(frame);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -2487,14 +2487,24 @@ CanvasRenderingContext2D::UpdateFilter()
|
|||
// rects
|
||||
//
|
||||
|
||||
// bug 1074733
|
||||
// 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
|
||||
// the appropriate rect by flipping negative dimensions. This prevents
|
||||
// draw targets from receiving "empty" rects later on.
|
||||
static void
|
||||
NormalizeRect(double& aX, double& aY, double& aWidth, double& aHeight)
|
||||
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
|
||||
// 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
|
||||
// the appropriate rect by flipping negative dimensions. This prevents
|
||||
// draw targets from receiving "empty" rects later on.
|
||||
if (aWidth < 0) {
|
||||
aWidth = -aWidth;
|
||||
aX -= aWidth;
|
||||
|
@ -2503,13 +2513,16 @@ NormalizeRect(double& aX, double& aY, double& aWidth, double& aHeight)
|
|||
aHeight = -aHeight;
|
||||
aY -= aHeight;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::ClearRect(double x, double y, double w,
|
||||
double h)
|
||||
{
|
||||
NormalizeRect(x, y, w, h);
|
||||
if(!ValidateRect(x, y, w, h)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTarget();
|
||||
|
||||
|
@ -2524,7 +2537,9 @@ CanvasRenderingContext2D::FillRect(double x, double y, double w,
|
|||
{
|
||||
const ContextState &state = CurrentState();
|
||||
|
||||
NormalizeRect(x, y, w, h);
|
||||
if(!ValidateRect(x, y, w, h)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.patternStyles[Style::FILL]) {
|
||||
CanvasPattern::RepeatMode repeat =
|
||||
|
@ -2599,7 +2614,10 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w,
|
|||
if (!w && !h) {
|
||||
return;
|
||||
}
|
||||
NormalizeRect(x, y, w, h);
|
||||
|
||||
if(!ValidateRect(x, y, w, h)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
|
@ -4375,8 +4393,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
|
|||
MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6);
|
||||
|
||||
if (optional_argc == 6) {
|
||||
NormalizeRect(sx, sy, sw, sh);
|
||||
NormalizeRect(dx, dy, dw, dh);
|
||||
if (!ValidateRect(sx, sy, sw, sh) ||
|
||||
!ValidateRect(dx, dy, dw, dh)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> srcSurf;
|
||||
|
|
|
@ -21536,6 +21536,20 @@ isPixel(ctx, 50,25, 0,255,0,255, 0);
|
|||
|
||||
</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>
|
||||
|
||||
function asyncTestsDone() {
|
||||
|
@ -24835,7 +24849,13 @@ try {
|
|||
} catch (e) {
|
||||
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
|
||||
try {
|
||||
test_2d_drawImage_animated_apng();
|
||||
|
|
|
@ -935,11 +935,9 @@ Event::GetScreenCoords(nsPresContext* aPresContext,
|
|||
nsPoint pt =
|
||||
LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
|
||||
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
if (aPresContext->PresShell()) {
|
||||
pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
|
||||
pt = pt.RemoveResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
|
||||
}
|
||||
#endif
|
||||
|
||||
pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(),
|
||||
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
|
||||
|
|
|
@ -760,15 +760,17 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
if (content)
|
||||
mCurrentTargetContent = content;
|
||||
|
||||
// NOTE: Don't refer TextComposition::IsComposing() since DOM Level 3
|
||||
// Events defines that KeyboardEvent.isComposing is true when it's
|
||||
// NOTE: Don't refer TextComposition::IsComposing() since UI Events
|
||||
// defines that KeyboardEvent.isComposing is true when it's
|
||||
// dispatched after compositionstart and compositionend.
|
||||
// TextComposition::IsComposing() is false even before
|
||||
// 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 =
|
||||
IMEStateManager::GetTextCompositionFor(keyEvent);
|
||||
keyEvent->mIsComposing = !!composition;
|
||||
IMEStateManager::GetTextCompositionFor(aPresContext);
|
||||
aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
|
||||
}
|
||||
break;
|
||||
case eWheel:
|
||||
|
|
|
@ -1144,11 +1144,21 @@ IMEStateManager::DispatchCompositionEvent(
|
|||
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("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 } }, "
|
||||
"aIsSynthesized=%s), tabParent=%p",
|
||||
aEventTargetNode, aPresContext,
|
||||
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.mPropagationStopped),
|
||||
GetBoolName(aIsSynthesized), tabParent.get()));
|
||||
|
@ -1164,7 +1174,7 @@ IMEStateManager::DispatchCompositionEvent(
|
|||
EnsureTextCompositionArray();
|
||||
|
||||
RefPtr<TextComposition> composition =
|
||||
sTextCompositions->GetCompositionFor(aCompositionEvent->widget);
|
||||
sTextCompositions->GetCompositionFor(aCompositionEvent);
|
||||
if (!composition) {
|
||||
// If synthesized event comes after delayed native composition events
|
||||
// for request of commit or cancel, we should ignore it.
|
||||
|
@ -1278,8 +1288,18 @@ IMEStateManager::OnCompositionEventDiscarded(
|
|||
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("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),
|
||||
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)));
|
||||
|
||||
if (!aCompositionEvent->mFlags.mIsTrusted) {
|
||||
|
@ -1649,11 +1669,27 @@ IMEStateManager::GetTextCompositionFor(nsIWidget* aWidget)
|
|||
|
||||
// static
|
||||
already_AddRefed<TextComposition>
|
||||
IMEStateManager::GetTextCompositionFor(WidgetGUIEvent* aGUIEvent)
|
||||
IMEStateManager::GetTextCompositionFor(
|
||||
const WidgetCompositionEvent* aCompositionEvent)
|
||||
{
|
||||
MOZ_ASSERT(aGUIEvent->AsCompositionEvent() || aGUIEvent->AsKeyboardEvent(),
|
||||
"aGUIEvent has to be WidgetCompositionEvent or WidgetKeyboardEvent");
|
||||
return GetTextCompositionFor(aGUIEvent->widget);
|
||||
if (!sTextCompositions) {
|
||||
return nullptr;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -181,11 +181,17 @@ public:
|
|||
|
||||
/**
|
||||
* Returns TextComposition instance for the event.
|
||||
*
|
||||
* @param aGUIEvent Should be a composition event which is being dispatched.
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -39,8 +39,7 @@ TextComposition::TextComposition(nsPresContext* aPresContext,
|
|||
: mPresContext(aPresContext)
|
||||
, mNode(aNode)
|
||||
, mTabParent(aTabParent)
|
||||
, mNativeContext(
|
||||
aCompositionEvent->widget->GetInputContext().mNativeIMEContext)
|
||||
, mNativeContext(aCompositionEvent->mNativeIMEContext)
|
||||
, mCompositionStartOffset(0)
|
||||
, mCompositionTargetOffset(0)
|
||||
, mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
|
||||
|
@ -54,6 +53,7 @@ TextComposition::TextComposition(nsPresContext* aPresContext,
|
|||
Preferences::GetBool("dom.compositionevent.allow_control_characters",
|
||||
false))
|
||||
{
|
||||
MOZ_ASSERT(aCompositionEvent->mNativeIMEContext.IsValid());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -66,12 +66,6 @@ TextComposition::Destroy()
|
|||
// this being destroyed for cleaning up the stuff.
|
||||
}
|
||||
|
||||
bool
|
||||
TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
|
||||
{
|
||||
return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
|
||||
}
|
||||
|
||||
bool
|
||||
TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const
|
||||
{
|
||||
|
@ -114,6 +108,7 @@ TextComposition::CloneAndDispatchAs(
|
|||
compositionEvent.time = aCompositionEvent->time;
|
||||
compositionEvent.timeStamp = aCompositionEvent->timeStamp;
|
||||
compositionEvent.mData = aCompositionEvent->mData;
|
||||
compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
|
||||
compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
|
||||
compositionEvent.mFlags.mIsSynthesizedForTests =
|
||||
aCompositionEvent->mFlags.mIsSynthesizedForTests;
|
||||
|
@ -613,6 +608,7 @@ TextComposition::CompositionEventDispatcher::Run()
|
|||
switch (mEventMessage) {
|
||||
case eCompositionStart: {
|
||||
WidgetCompositionEvent compStart(true, eCompositionStart, widget);
|
||||
compStart.mNativeIMEContext = mTextComposition->mNativeContext;
|
||||
WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
|
||||
ContentEventHandler handler(presContext);
|
||||
handler.OnQuerySelectedText(&selectedText);
|
||||
|
@ -629,6 +625,7 @@ TextComposition::CompositionEventDispatcher::Run()
|
|||
case eCompositionCommitAsIs:
|
||||
case eCompositionCommit: {
|
||||
WidgetCompositionEvent compEvent(true, mEventMessage, widget);
|
||||
compEvent.mNativeIMEContext = mTextComposition->mNativeContext;
|
||||
if (mEventMessage != eCompositionCommitAsIs) {
|
||||
compEvent.mData = mData;
|
||||
}
|
||||
|
@ -650,16 +647,25 @@ TextComposition::CompositionEventDispatcher::Run()
|
|||
******************************************************************************/
|
||||
|
||||
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) {
|
||||
if (ElementAt(i - 1)->MatchesNativeContext(aWidget)) {
|
||||
if (ElementAt(i - 1)->GetNativeIMEContext() == aNativeIMEContext) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return NoIndex;
|
||||
}
|
||||
|
||||
TextCompositionArray::index_type
|
||||
TextCompositionArray::IndexOf(nsIWidget* aWidget)
|
||||
{
|
||||
return IndexOf(aWidget->GetNativeIMEContext());
|
||||
}
|
||||
|
||||
TextCompositionArray::index_type
|
||||
TextCompositionArray::IndexOf(nsPresContext* aPresContext)
|
||||
{
|
||||
|
@ -693,6 +699,27 @@ TextCompositionArray::GetCompositionFor(nsIWidget* aWidget)
|
|||
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*
|
||||
TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext,
|
||||
nsINode* aNode)
|
||||
|
|
|
@ -76,7 +76,10 @@ public:
|
|||
// came from nsDOMWindowUtils.
|
||||
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.
|
||||
|
@ -191,7 +194,7 @@ private:
|
|||
|
||||
// mNativeContext stores a opaque pointer. This works as the "ID" for this
|
||||
// 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.
|
||||
nsWeakPtr mEditorWeak;
|
||||
|
@ -400,11 +403,19 @@ class TextCompositionArray final :
|
|||
public nsAutoTArray<RefPtr<TextComposition>, 2>
|
||||
{
|
||||
public:
|
||||
// Looking for per native IME context.
|
||||
index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
|
||||
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, nsINode* aNode);
|
||||
|
||||
TextComposition* GetCompositionFor(nsIWidget* aWidget);
|
||||
TextComposition* GetCompositionFor(nsPresContext* aPresContext);
|
||||
TextComposition* GetCompositionFor(nsPresContext* aPresContext,
|
||||
nsINode* aNode);
|
||||
TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
|
||||
|
|
|
@ -4980,7 +4980,7 @@ HTMLMediaElement::GetTopLevelPrincipal()
|
|||
|
||||
NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
|
||||
{
|
||||
MOZ_ASSERT(mAudioChannelAgent);
|
||||
MOZ_ASSERT(mAudioChannelAgent);
|
||||
|
||||
if (!OwnerDoc()->GetInnerWindow()) {
|
||||
return NS_OK;
|
||||
|
@ -4995,7 +4995,7 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
|
|||
uint64_t id = window->WindowID();
|
||||
MediaStreamGraph* msg =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
|
||||
AudioChannel::Normal);
|
||||
mAudioChannel);
|
||||
|
||||
if (GetSrcMediaStream()) {
|
||||
mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());
|
||||
|
|
|
@ -235,20 +235,19 @@ parent:
|
|||
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
|
||||
* noCompositionEvent true if no composition event is fired by commit or
|
||||
* cancel
|
||||
* composition Text to commit before ending the composition
|
||||
* cancel Set true if composition should be cancelled.
|
||||
*
|
||||
* if cancel is true,
|
||||
* widget should return empty string for composition
|
||||
* if cancel is false,
|
||||
* widget should return the current composition text
|
||||
* isCommitted Returns true if the request causes composition
|
||||
* being committed synchronously.
|
||||
* committedString Returns committed string. The may be non-empty
|
||||
* 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)
|
||||
returns (bool noCompositionEvent, nsString composition);
|
||||
prio(urgent) sync RequestIMEToCommitComposition(bool cancel)
|
||||
returns (bool isCommitted, nsString committedString);
|
||||
|
||||
/**
|
||||
* OnEventNeedingAckHandled() is called after a child process dispatches a
|
||||
|
@ -296,8 +295,7 @@ parent:
|
|||
nsCString[] disabledCommands);
|
||||
|
||||
prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
|
||||
int32_t IMEOpen,
|
||||
intptr_t NativeIMEContext);
|
||||
int32_t IMEOpen);
|
||||
|
||||
prio(urgent) async SetInputContext(int32_t IMEEnabled,
|
||||
int32_t IMEOpen,
|
||||
|
|
|
@ -2321,16 +2321,19 @@ TabParent::GetRenderFrame()
|
|||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvEndIMEComposition(const bool& aCancel,
|
||||
bool* aNoCompositionEvent,
|
||||
nsString* aComposition)
|
||||
TabParent::RecvRequestIMEToCommitComposition(const bool& aCancel,
|
||||
bool* aIsCommitted,
|
||||
nsString* aCommittedString)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
*aIsCommitted = false;
|
||||
return true;
|
||||
}
|
||||
*aNoCompositionEvent =
|
||||
!mContentCache.RequestToCommitComposition(widget, aCancel, *aComposition);
|
||||
|
||||
*aIsCommitted =
|
||||
mContentCache.RequestIMEToCommitComposition(widget, aCancel,
|
||||
*aCommittedString);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2363,21 +2366,18 @@ TabParent::RecvSetPluginFocused(const bool& aFocused)
|
|||
|
||||
bool
|
||||
TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
|
||||
int32_t* aIMEOpen,
|
||||
intptr_t* aNativeIMEContext)
|
||||
int32_t* aIMEOpen)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
*aIMEEnabled = IMEState::DISABLED;
|
||||
*aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
|
||||
*aNativeIMEContext = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
InputContext context = widget->GetInputContext();
|
||||
*aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
|
||||
*aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
|
||||
*aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,17 +187,16 @@ public:
|
|||
virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
|
||||
const widget::IMENotification& aEventMessage) override;
|
||||
virtual bool RecvOnEventNeedingAckHandled(const EventMessage& aMessage) override;
|
||||
virtual bool RecvEndIMEComposition(const bool& aCancel,
|
||||
bool* aNoCompositionEvent,
|
||||
nsString* aComposition) override;
|
||||
virtual bool RecvRequestIMEToCommitComposition(const bool& aCancel,
|
||||
bool* aIsCommitted,
|
||||
nsString* aCommittedString) override;
|
||||
virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
|
||||
const int32_t& aPanelX,
|
||||
const int32_t& aPanelY,
|
||||
nsString* aCommitted) override;
|
||||
virtual bool RecvSetPluginFocused(const bool& aFocused) override;
|
||||
virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
|
||||
int32_t* aIMEOpen,
|
||||
intptr_t* aNativeIMEContext) override;
|
||||
int32_t* aIMEOpen) override;
|
||||
virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
|
||||
const int32_t& aIMEOpen,
|
||||
const nsString& aType,
|
||||
|
|
|
@ -2112,22 +2112,17 @@ MediaDecoderStateMachine::SeekCompleted()
|
|||
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
|
||||
// call MediaDecoderStateMachine::Seek to reset our state to SEEKING
|
||||
// if we need to seek again.
|
||||
|
||||
bool isLiveStream = mResource->IsLiveStream();
|
||||
State nextState;
|
||||
if (mPendingSeek.Exists()) {
|
||||
// A new seek target came in while we were processing the old one. No rest
|
||||
// for the 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) {
|
||||
// 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
|
||||
|
@ -2135,11 +2130,26 @@ MediaDecoderStateMachine::SeekCompleted()
|
|||
DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime);
|
||||
// Explicitly set our state so we don't decode further, and so
|
||||
// we report playback ended to the media element.
|
||||
SetState(DECODER_STATE_COMPLETED);
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
nextState = DECODER_STATE_COMPLETED;
|
||||
} else {
|
||||
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();
|
||||
} else {
|
||||
SetState(nextState);
|
||||
}
|
||||
|
||||
// Ensure timestamps are up to date.
|
||||
|
@ -2153,7 +2163,6 @@ MediaDecoderStateMachine::SeekCompleted()
|
|||
// if we need to buffer after the seek.
|
||||
mQuickBuffering = false;
|
||||
|
||||
mCurrentSeek.Resolve(mState == DECODER_STATE_COMPLETED, __func__);
|
||||
ScheduleStateMachine();
|
||||
|
||||
if (video) {
|
||||
|
|
|
@ -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+
|
||||
[test_SeekNoData_mp4.html]
|
||||
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]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_Sequence_mp4.html]
|
||||
|
|
|
@ -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>
|
|
@ -22,6 +22,8 @@ extern "C" {
|
|||
#include "MediaMetadataManager.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::media;
|
||||
|
@ -148,6 +150,17 @@ OggReader::~OggReader()
|
|||
{
|
||||
ogg_sync_clear(&mOggState);
|
||||
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() {
|
||||
|
@ -704,10 +717,13 @@ bool OggReader::DecodeAudioData()
|
|||
return true;
|
||||
}
|
||||
|
||||
void OggReader::SetChained(bool aIsChained) {
|
||||
void OggReader::SetChained() {
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mIsChained = aIsChained;
|
||||
if (mIsChained) {
|
||||
return;
|
||||
}
|
||||
mIsChained = true;
|
||||
}
|
||||
mOnMediaNotSeekable.Notify();
|
||||
}
|
||||
|
@ -800,7 +816,7 @@ bool OggReader::ReadOggChain()
|
|||
}
|
||||
|
||||
if (chained) {
|
||||
SetChained(true);
|
||||
SetChained();
|
||||
{
|
||||
auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate;
|
||||
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.
|
||||
// It's probably from a new "link" in a "chained" ogg. Don't
|
||||
// bother even trying to find a duration...
|
||||
SetChained(true);
|
||||
SetChained();
|
||||
endTime = -1;
|
||||
break;
|
||||
}
|
||||
|
@ -1913,7 +1929,7 @@ media::TimeIntervals OggReader::GetBuffered()
|
|||
// ogg), return OK to abort the finding any further ranges. This
|
||||
// prevents us searching through the rest of the media when we
|
||||
// may not be able to extract timestamps from it.
|
||||
SetChained(true);
|
||||
SetChained();
|
||||
return buffered;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ private:
|
|||
|
||||
// Set this media as being a chain and notifies the state machine that the
|
||||
// media is no longer seekable.
|
||||
void SetChained(bool aIsChained);
|
||||
void SetChained();
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -280,21 +280,23 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason)
|
|||
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};
|
||||
params.BackBufferWidth = 1;
|
||||
params.BackBufferHeight = 1;
|
||||
params.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
params.BackBufferCount = 1;
|
||||
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
params.hDeviceWindow = ::GetShellWindow();
|
||||
params.hDeviceWindow = nullptr;
|
||||
params.Windowed = TRUE;
|
||||
params.Flags = D3DPRESENTFLAG_VIDEO;
|
||||
|
||||
RefPtr<IDirect3DDevice9Ex> device;
|
||||
hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
::GetShellWindow(),
|
||||
nullptr,
|
||||
D3DCREATE_FPU_PRESERVE |
|
||||
D3DCREATE_MULTITHREADED |
|
||||
D3DCREATE_MIXED_VERTEXPROCESSING,
|
||||
|
|
|
@ -79,6 +79,11 @@ SpeechTaskCallback::OnPause()
|
|||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
[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);
|
||||
return NS_OK;
|
||||
|
||||
|
@ -91,6 +96,11 @@ SpeechTaskCallback::OnResume()
|
|||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
[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);
|
||||
return NS_OK;
|
||||
|
||||
|
@ -120,6 +130,9 @@ void
|
|||
SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex)
|
||||
{
|
||||
mCurrentIndex = aIndex;
|
||||
if (!mTask) {
|
||||
return;
|
||||
}
|
||||
mTask->DispatchBoundary(NS_LITERAL_STRING("word"),
|
||||
GetTimeDurationFromStart(), mCurrentIndex);
|
||||
}
|
||||
|
@ -127,6 +140,9 @@ SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex)
|
|||
void
|
||||
SpeechTaskCallback::OnError(uint32_t aIndex)
|
||||
{
|
||||
if (!mTask) {
|
||||
return;
|
||||
}
|
||||
mTask->DispatchError(GetTimeDurationFromStart(), aIndex);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,11 @@ SapiCallback::OnPause()
|
|||
if (FAILED(mSapiClient->Pause())) {
|
||||
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);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -86,6 +91,11 @@ SapiCallback::OnResume()
|
|||
if (FAILED(mSapiClient->Resume())) {
|
||||
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);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -125,6 +125,7 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
|||
, mIsWhitelistedForShumway(false)
|
||||
, mWindowType(NPWindowTypeWindow)
|
||||
, mDrawingModel(kDefaultDrawingModel)
|
||||
, mLastRecordedDrawingModel(-1)
|
||||
, mFrameID(0)
|
||||
#if defined(OS_WIN)
|
||||
, mPluginHWND(nullptr)
|
||||
|
@ -809,6 +810,8 @@ PluginInstanceParent::SetCurrentImage(Image* aImage)
|
|||
nsAutoTArray<ImageContainer::NonOwningImage,1> imageList;
|
||||
imageList.AppendElement(holder);
|
||||
mImageContainer->SetCurrentImages(imageList);
|
||||
|
||||
RecordDrawingModel();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -973,6 +976,7 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
|
|||
PLUGIN_LOG_DEBUG((" (RecvShow invalidated for surface %p)",
|
||||
mFrontSurface.get()));
|
||||
|
||||
RecordDrawingModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1380,6 +1384,7 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
|||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
RecordDrawingModel();
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -2363,3 +2368,28 @@ PluginInstanceParent::Cast(NPP aInstance, PluginAsyncSurrogate** aSurrogate)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -376,6 +376,9 @@ private:
|
|||
|
||||
void SetCurrentImage(layers::Image* aImage);
|
||||
|
||||
// Update Telemetry with the current drawing model.
|
||||
void RecordDrawingModel();
|
||||
|
||||
private:
|
||||
PluginModuleParent* mParent;
|
||||
RefPtr<PluginAsyncSurrogate> mSurrogate;
|
||||
|
@ -387,6 +390,11 @@ private:
|
|||
NPWindowType mWindowType;
|
||||
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;
|
||||
|
||||
// This is used to tell the compositor that it should invalidate the ImageLayer.
|
||||
|
|
|
@ -154,6 +154,9 @@ partial interface Document {
|
|||
attribute EventHandler onbeforescriptexecute;
|
||||
attribute EventHandler onafterscriptexecute;
|
||||
|
||||
[Pref="dom.select_events.enabled"]
|
||||
attribute EventHandler onselectionchange;
|
||||
|
||||
/**
|
||||
* True if this document is synthetic : stand alone image, video, audio file,
|
||||
* etc.
|
||||
|
|
|
@ -1987,14 +1987,14 @@ nsEditor::StopPreservingSelection()
|
|||
}
|
||||
|
||||
void
|
||||
nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent)
|
||||
nsEditor::EnsureComposition(mozilla::WidgetCompositionEvent* aCompositionEvent)
|
||||
{
|
||||
if (mComposition) {
|
||||
return;
|
||||
}
|
||||
// The compositionstart event must cause creating new TextComposition
|
||||
// instance at being dispatched by IMEStateManager.
|
||||
mComposition = IMEStateManager::GetTextCompositionFor(aEvent);
|
||||
mComposition = IMEStateManager::GetTextCompositionFor(aCompositionEvent);
|
||||
if (!mComposition) {
|
||||
MOZ_CRASH("IMEStateManager doesn't return proper composition");
|
||||
}
|
||||
|
|
|
@ -413,7 +413,7 @@ protected:
|
|||
* EnsureComposition() should be called by composition event handlers. This
|
||||
* 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);
|
||||
|
||||
|
|
|
@ -2219,7 +2219,7 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
|
|||
SetState(PANNING);
|
||||
}
|
||||
} else if (mState == PANNING_LOCKED_Y) {
|
||||
if (!IsCloseToVertical(angle, gfxPrefs::APZAxisLockAngle())) {
|
||||
if (!IsCloseToVertical(angle, gfxPrefs::APZAxisBreakoutAngle())) {
|
||||
mX.SetAxisLocked(false);
|
||||
SetState(PANNING);
|
||||
}
|
||||
|
|
|
@ -548,11 +548,12 @@ Pan(const RefPtr<InputReceiver>& aTarget,
|
|||
nsEventStatus (*aOutEventStatuses)[4] = 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
|
||||
// time when the events are actually processed, rather than when we deliver
|
||||
// them.
|
||||
gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f);
|
||||
gfxPrefs::SetAPZTouchMoveTolerance(0.0f);
|
||||
const int OVERCOME_TOUCH_TOLERANCE = 1;
|
||||
|
||||
const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
|
||||
|
|
|
@ -415,6 +415,28 @@ APZCCallbackHelper::GetRootContentDocumentPresShellForContent(nsIContent* aConte
|
|||
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
|
||||
APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
|
||||
const ScrollableLayerGuid& aGuid)
|
||||
|
@ -423,24 +445,21 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
|
|||
if (aGuid.mScrollId == FrameMetrics::NULL_SCROLL_ID) {
|
||||
return input;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
|
||||
if (!content) {
|
||||
return input;
|
||||
}
|
||||
|
||||
#if !defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
// First, scale inversely by the root content document's pres shell
|
||||
// resolution to cancel the scale-to-resolution transform that the
|
||||
// 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
|
||||
// compositor-side transforms) because APZ doesn't know about it.
|
||||
if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
|
||||
if (nsIPresShell* shell = GetRootDocumentPresShell(content)) {
|
||||
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
|
||||
// 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
|
||||
|
@ -451,22 +470,9 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
|
|||
// 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
|
||||
// transform for the layer that the input hit.
|
||||
|
||||
void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
|
||||
if (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;
|
||||
}
|
||||
return input;
|
||||
|
|
|
@ -147,7 +147,6 @@ ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint,
|
|||
}
|
||||
|
||||
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
// CalculateRectToZoomTo performs a hit test on the frame associated with the
|
||||
// Root Content Document. Unfortunately that frame does not know about the
|
||||
// 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;
|
||||
point.x = point.x / resolution;
|
||||
point.y = point.y / resolution;
|
||||
#endif // MOZ_SINGLE_PROCESS_APZ
|
||||
CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
|
||||
|
||||
uint32_t presShellId;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "base/eintr_wrapper.h"
|
||||
|
||||
#include "chrome/common/child_process_info.h"
|
||||
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
|
@ -41,6 +43,8 @@ CreateTransport(base::ProcessId aProcIdOne,
|
|||
fd1 = dup(fd1);
|
||||
fd2 = dup(fd2);
|
||||
if (fd1 < 0 || fd2 < 0) {
|
||||
HANDLE_EINTR(close(fd1));
|
||||
HANDLE_EINTR(close(fd2));
|
||||
return NS_ERROR_DUPLICATE_HANDLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -553,7 +553,6 @@ DynamicallyLinkModule(JSContext* cx, const CallArgs& args, AsmJSModule& module)
|
|||
return false;
|
||||
break;
|
||||
case AsmJSModule::Global::ArrayView:
|
||||
case AsmJSModule::Global::SharedArrayView:
|
||||
case AsmJSModule::Global::ArrayViewCtor:
|
||||
if (!ValidateArrayView(cx, global, globalVal))
|
||||
return false;
|
||||
|
|
|
@ -100,7 +100,7 @@ class AsmJSModule
|
|||
class Global
|
||||
{
|
||||
public:
|
||||
enum Which { Variable, FFI, ArrayView, ArrayViewCtor, SharedArrayView, MathBuiltinFunction,
|
||||
enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
|
||||
AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation, ByteLength };
|
||||
enum VarInitKind { InitConstant, InitImport };
|
||||
enum ConstantKind { GlobalConstant, MathConstant };
|
||||
|
@ -189,17 +189,13 @@ class AsmJSModule
|
|||
// var i32 = new I32(buffer);
|
||||
// the second import has nothing to validate and thus has a null field.
|
||||
PropertyName* maybeViewName() const {
|
||||
MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == SharedArrayView || pod.which_ == ArrayViewCtor);
|
||||
MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
|
||||
return name_;
|
||||
}
|
||||
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_;
|
||||
}
|
||||
void makeViewShared() {
|
||||
MOZ_ASSERT(pod.which_ == ArrayView);
|
||||
pod.which_ = SharedArrayView;
|
||||
}
|
||||
PropertyName* mathName() const {
|
||||
MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
|
||||
return name_;
|
||||
|
@ -910,20 +906,18 @@ class AsmJSModule
|
|||
g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++;
|
||||
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(!pod.hasArrayView_ || (pod.isSharedView_ == isSharedView));
|
||||
pod.hasArrayView_ = true;
|
||||
pod.isSharedView_ = isSharedView;
|
||||
pod.isSharedView_ = false;
|
||||
Global g(Global::ArrayView, maybeField);
|
||||
g.pod.u.viewType_ = vt;
|
||||
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(field);
|
||||
MOZ_ASSERT(!pod.isSharedView_ || isSharedView);
|
||||
pod.isSharedView_ = isSharedView;
|
||||
pod.isSharedView_ = false;
|
||||
Global g(Global::ArrayViewCtor, field);
|
||||
g.pod.u.viewType_ = vt;
|
||||
return globals_.append(g);
|
||||
|
@ -978,19 +972,9 @@ class AsmJSModule
|
|||
Global& global(unsigned i) {
|
||||
return globals_[i];
|
||||
}
|
||||
bool isValidViewSharedness(bool shared) const {
|
||||
if (pod.hasArrayView_)
|
||||
return pod.isSharedView_ == shared;
|
||||
return !pod.isSharedView_ || shared;
|
||||
}
|
||||
void setViewsAreShared() {
|
||||
if (pod.hasArrayView_)
|
||||
pod.isSharedView_ = true;
|
||||
for (size_t i=0 ; i < globals_.length() ; i++) {
|
||||
Global& g = globals_[i];
|
||||
if (g.which() == Global::ArrayView)
|
||||
g.makeViewShared();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
|
|
@ -1014,7 +1014,6 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
uint32_t ffiIndex_;
|
||||
struct {
|
||||
Scalar::Type viewType_;
|
||||
bool isSharedView_;
|
||||
} viewInfo;
|
||||
AsmJSMathBuiltinFunction mathBuiltinFunc_;
|
||||
AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
|
||||
|
@ -1072,14 +1071,6 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
MOZ_ASSERT(isAnyArrayView());
|
||||
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 {
|
||||
return which_ == MathBuiltinFunction;
|
||||
}
|
||||
|
@ -1402,18 +1393,16 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
global->u.varOrConst.type_ = Type::var(importType).which();
|
||||
return globals_.putNew(varName, global);
|
||||
}
|
||||
bool addArrayView(PropertyName* varName, Scalar::Type vt, PropertyName* maybeField,
|
||||
bool isSharedView)
|
||||
bool addArrayView(PropertyName* varName, Scalar::Type vt, PropertyName* maybeField)
|
||||
{
|
||||
if (!arrayViews_.append(ArrayView(varName, vt)))
|
||||
return false;
|
||||
Global* global = validationLifo_.new_<Global>(Global::ArrayView);
|
||||
if (!global)
|
||||
return false;
|
||||
if (!module().addArrayView(vt, maybeField, isSharedView))
|
||||
if (!module().addArrayView(vt, maybeField))
|
||||
return false;
|
||||
global->u.viewInfo.viewType_ = vt;
|
||||
global->u.viewInfo.isSharedView_ = isSharedView;
|
||||
return globals_.putNew(varName, global);
|
||||
}
|
||||
bool addMathBuiltinFunction(PropertyName* varName, AsmJSMathBuiltinFunction func,
|
||||
|
@ -1497,14 +1486,13 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
global->u.changeHeap.srcEnd_ = fn->pn_pos.end;
|
||||
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);
|
||||
if (!global)
|
||||
return false;
|
||||
if (!module().addArrayViewCtor(vt, fieldName, isSharedView))
|
||||
if (!module().addArrayViewCtor(vt, fieldName))
|
||||
return false;
|
||||
global->u.viewInfo.viewType_ = vt;
|
||||
global->u.viewInfo.isSharedView_ = isSharedView;
|
||||
return globals_.putNew(varName, global);
|
||||
}
|
||||
bool addFFI(PropertyName* varName, PropertyName* field) {
|
||||
|
@ -1612,6 +1600,10 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
return module().minHeapLength();
|
||||
}
|
||||
|
||||
bool usesSharedMemory() const {
|
||||
return atomicsPresent_;
|
||||
}
|
||||
|
||||
// Error handling.
|
||||
bool hasAlreadyFailed() const {
|
||||
return !!errorString_;
|
||||
|
@ -1740,14 +1732,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
}
|
||||
|
||||
void startFunctionBodies() {
|
||||
if (atomicsPresent_) {
|
||||
for (GlobalMap::Range r = globals_.all() ; !r.empty() ; r.popFront()) {
|
||||
Global* g = r.front().value();
|
||||
if (g->isAnyArrayView())
|
||||
g->setViewIsSharedView();
|
||||
}
|
||||
if (atomicsPresent_)
|
||||
module().setViewsAreShared();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2472,10 +2458,9 @@ CheckGlobalVariableInitImport(ModuleValidator& m, PropertyName* varName, ParseNo
|
|||
}
|
||||
|
||||
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();
|
||||
*shared = false;
|
||||
if (name == names.Int8Array) {
|
||||
*type = Scalar::Int8;
|
||||
} else if (name == names.Uint8Array) {
|
||||
|
@ -2526,7 +2511,6 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
|
|||
|
||||
PropertyName* field;
|
||||
Scalar::Type type;
|
||||
bool shared = false;
|
||||
if (ctorExpr->isKind(PNK_DOT)) {
|
||||
ParseNode* base = DotBase(ctorExpr);
|
||||
|
||||
|
@ -2534,7 +2518,7 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
|
|||
return m.failName(base, "expecting '%s.*Array", globalName);
|
||||
|
||||
field = DotMember(ctorExpr);
|
||||
if (!IsArrayViewCtorName(m, field, &type, &shared))
|
||||
if (!IsArrayViewCtorName(m, field, &type))
|
||||
return m.fail(ctorExpr, "could not match typed array name");
|
||||
} else {
|
||||
if (!ctorExpr->isKind(PNK_NAME))
|
||||
|
@ -2550,16 +2534,12 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
|
|||
|
||||
field = nullptr;
|
||||
type = global->viewType();
|
||||
shared = global->viewIsSharedView();
|
||||
}
|
||||
|
||||
if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
|
||||
return false;
|
||||
|
||||
if (!m.module().isValidViewSharedness(shared))
|
||||
return m.failName(ctorExpr, "%s has different sharedness than previous view constructors", globalName);
|
||||
|
||||
return m.addArrayView(varName, type, field, shared);
|
||||
return m.addArrayView(varName, type, field);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -2695,12 +2675,8 @@ CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initN
|
|||
return m.addByteLength(varName);
|
||||
|
||||
Scalar::Type type;
|
||||
bool shared = false;
|
||||
if (IsArrayViewCtorName(m, field, &type, &shared)) {
|
||||
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);
|
||||
}
|
||||
if (IsArrayViewCtorName(m, field, &type))
|
||||
return m.addArrayViewCtor(varName, type, 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();
|
||||
|
||||
#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))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -104,7 +104,8 @@ class FunctionCompiler
|
|||
curBlock_->initSlot(info().localSlot(i.index()), ins);
|
||||
if (!mirGen_.ensureBallast())
|
||||
return false;
|
||||
localTypes_.append(args[i.index()]);
|
||||
if (!localTypes_.append(args[i.index()]))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < func_.numVarInits(); i++) {
|
||||
|
@ -134,7 +135,8 @@ class FunctionCompiler
|
|||
curBlock_->initSlot(info().localSlot(firstVarSlot + i), ins);
|
||||
if (!mirGen_.ensureBallast())
|
||||
return false;
|
||||
localTypes_.append(v.type());
|
||||
if (!localTypes_.append(v.type()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1129,12 +1131,20 @@ class FunctionCompiler
|
|||
if (!switchBlock)
|
||||
return true;
|
||||
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++) {
|
||||
if (!cases[i])
|
||||
mir->addCase(defaultIndex);
|
||||
else
|
||||
mir->addCase(mir->addSuccessor(cases[i]));
|
||||
if (!cases[i]) {
|
||||
if (!mir->addCase(defaultIndex))
|
||||
return false;
|
||||
} else {
|
||||
size_t caseIndex;
|
||||
if (!mir->addSuccessor(cases[i], &caseIndex))
|
||||
return false;
|
||||
if (!mir->addCase(caseIndex))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (curBlock_) {
|
||||
MBasicBlock* next;
|
||||
|
|
|
@ -238,12 +238,6 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
|
|||
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.
|
||||
if (args.length() < 1) {
|
||||
args.rval().setUndefined();
|
||||
|
|
|
@ -2783,27 +2783,31 @@ BytecodeEmitter::emitNameIncDec(ParseNode* pn)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitElemOperands(ParseNode* pn, JSOp op)
|
||||
BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
|
||||
{
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
|
||||
if (!emitTree(pn->pn_left))
|
||||
return false;
|
||||
|
||||
if (op == JSOP_CALLELEM && !emit1(JSOP_DUP))
|
||||
return false;
|
||||
if (opts == EmitElemOption::IncDec) {
|
||||
if (!emit1(JSOP_CHECKOBJCOERCIBLE))
|
||||
return false;
|
||||
} else if (opts == EmitElemOption::Call) {
|
||||
if (!emit1(JSOP_DUP))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitTree(pn->pn_right))
|
||||
return false;
|
||||
|
||||
bool isSetElem = op == JSOP_SETELEM || op == JSOP_STRICTSETELEM;
|
||||
if (isSetElem && !emit2(JSOP_PICK, 2))
|
||||
if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 2))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
|
||||
BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
|
||||
{
|
||||
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
|
||||
// it inside both the GETELEM and the SETELEM.
|
||||
if (opts == SuperElem_IncDec && !emit1(JSOP_TOID))
|
||||
if (opts == EmitElemOption::IncDec && !emit1(JSOP_TOID))
|
||||
return false;
|
||||
|
||||
if (!emitGetThisForSuperBase(pn->pn_left))
|
||||
return false;
|
||||
|
||||
if (opts == SuperElem_Call) {
|
||||
if (opts == EmitElemOption::Call) {
|
||||
if (!emit1(JSOP_SWAP))
|
||||
return false;
|
||||
|
||||
|
@ -2835,7 +2839,7 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
|
|||
if (!emit1(JSOP_SUPERBASE))
|
||||
return false;
|
||||
|
||||
if (opts == SuperElem_Set && !emit2(JSOP_PICK, 3))
|
||||
if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -2854,17 +2858,23 @@ BytecodeEmitter::emitElemOpBase(JSOp op)
|
|||
bool
|
||||
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
|
||||
BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
|
||||
{
|
||||
SuperElemOptions opts = SuperElem_Get;
|
||||
EmitElemOption opts = EmitElemOption::Get;
|
||||
if (isCall)
|
||||
opts = SuperElem_Call;
|
||||
opts = EmitElemOption::Call;
|
||||
else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
|
||||
opts = SuperElem_Set;
|
||||
opts = EmitElemOption::Set;
|
||||
|
||||
if (!emitSuperElemOperands(pn, opts))
|
||||
return false;
|
||||
|
@ -2885,10 +2895,10 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
|
|||
bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
|
||||
|
||||
if (isSuper) {
|
||||
if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec))
|
||||
if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
|
||||
return false;
|
||||
} else {
|
||||
if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
|
||||
if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3465,10 +3475,34 @@ BytecodeEmitter::emitSetThis(ParseNode* pn)
|
|||
|
||||
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;
|
||||
switch (setOp) {
|
||||
case JSOP_SETLOCAL: getOp = JSOP_GETLOCAL; break;
|
||||
case JSOP_SETALIASEDVAR: getOp = JSOP_GETALIASEDVAR; break;
|
||||
case JSOP_SETLOCAL:
|
||||
getOp = JSOP_GETLOCAL;
|
||||
setOp = JSOP_INITLEXICAL;
|
||||
break;
|
||||
case JSOP_SETALIASEDVAR:
|
||||
getOp = JSOP_GETALIASEDVAR;
|
||||
setOp = JSOP_INITALIASEDLEXICAL;
|
||||
break;
|
||||
default: MOZ_CRASH("Unexpected op");
|
||||
}
|
||||
|
||||
|
@ -4379,13 +4413,25 @@ BytecodeEmitter::emitVariables(ParseNode* pn, VarEmitOption emitOption)
|
|||
* i' to be hoisted out of the loop.
|
||||
*/
|
||||
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
|
||||
* function f(){} precedes the var, detect simple name assignment
|
||||
* here and initialize the name.
|
||||
*/
|
||||
// To allow the front end to rewrite |var f = x;| as |f = x;| when a
|
||||
// |function f(){}| precedes the var, detect simple name assignment
|
||||
// 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 (!emitSingleVariable(pn, binding->pn_left, binding->pn_right, emitOption))
|
||||
return false;
|
||||
|
|
|
@ -519,7 +519,8 @@ struct BytecodeEmitter
|
|||
// 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
|
||||
// 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 emitElemOp(ParseNode* pn, JSOp op);
|
||||
|
@ -654,8 +655,7 @@ struct BytecodeEmitter
|
|||
bool emitClass(ParseNode* pn);
|
||||
bool emitSuperPropLHS(ParseNode* superBase, 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, SuperElemOptions opts = SuperElem_Get);
|
||||
bool emitSuperElemOperands(ParseNode* pn, EmitElemOption opts = EmitElemOption::Get);
|
||||
bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
|
||||
};
|
||||
|
||||
|
|
|
@ -125,8 +125,12 @@ SharedContext::computeAllowSyntax(JSObject* staticScope)
|
|||
// Any function supports new.target.
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = it.fun().allowSuperProperty();
|
||||
if (it.maybeFunctionBox())
|
||||
if (it.maybeFunctionBox()) {
|
||||
superScopeAlreadyNeedsHomeObject_ = it.maybeFunctionBox()->needsHomeObject();
|
||||
allowSuperCall_ = it.maybeFunctionBox()->isDerivedClassConstructor();
|
||||
} else {
|
||||
allowSuperCall_ = it.fun().isDerivedClassConstructor();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7470,11 +7474,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
if (!tokenStream.peekToken(&ignored, TokenStream::Operand))
|
||||
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);
|
||||
if (!arrowFunc)
|
||||
return null();
|
||||
|
@ -8890,7 +8889,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
tt == TOK_NO_SUBS_TEMPLATE)
|
||||
{
|
||||
if (handler.isSuperBase(lhs)) {
|
||||
if (!pc->sc->isFunctionBox() || !pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
|
||||
if (!pc->sc->allowSuperCall()) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
|
||||
return null();
|
||||
}
|
||||
|
|
|
@ -202,6 +202,7 @@ class SharedContext
|
|||
|
||||
bool allowNewTarget_;
|
||||
bool allowSuperProperty_;
|
||||
bool allowSuperCall_;
|
||||
bool inWith_;
|
||||
bool needsThisTDZChecks_;
|
||||
bool superScopeAlreadyNeedsHomeObject_;
|
||||
|
@ -217,6 +218,7 @@ class SharedContext
|
|||
thisBinding_(ThisBinding::Global),
|
||||
allowNewTarget_(false),
|
||||
allowSuperProperty_(false),
|
||||
allowSuperCall_(false),
|
||||
inWith_(false),
|
||||
needsThisTDZChecks_(false),
|
||||
superScopeAlreadyNeedsHomeObject_(false)
|
||||
|
@ -244,6 +246,7 @@ class SharedContext
|
|||
|
||||
bool allowNewTarget() const { return allowNewTarget_; }
|
||||
bool allowSuperProperty() const { return allowSuperProperty_; }
|
||||
bool allowSuperCall() const { return allowSuperCall_; }
|
||||
bool inWith() const { return inWith_; }
|
||||
bool needsThisTDZChecks() const { return needsThisTDZChecks_; }
|
||||
|
||||
|
|
|
@ -877,13 +877,15 @@ TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated,
|
|||
ungetChar('*');
|
||||
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
|
||||
// exception that we should stop and drop everything for.
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t length = tokenbuf.length();
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -6,6 +6,8 @@ for (var i = 0; i < 10; i++) {
|
|||
gcslice()
|
||||
}
|
||||
|
||||
if (!this.SharedArrayBuffer)
|
||||
quit(0);
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
x = new SharedArrayBuffer(4)
|
||||
|
|
|
@ -3588,8 +3588,7 @@ BaselineCompiler::emit_JSOP_RETRVAL()
|
|||
return emitReturn();
|
||||
}
|
||||
|
||||
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue,
|
||||
MutableHandleValue);
|
||||
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, MutableHandleValue);
|
||||
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation);
|
||||
|
||||
bool
|
||||
|
@ -3605,10 +3604,7 @@ BaselineCompiler::emit_JSOP_TOID()
|
|||
|
||||
prepareVMCall();
|
||||
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
|
||||
|
||||
pushArg(R0);
|
||||
pushArg(R1);
|
||||
pushArg(ImmPtr(pc));
|
||||
pushArg(ImmGCPtr(script));
|
||||
|
||||
|
@ -3621,6 +3617,32 @@ BaselineCompiler::emit_JSOP_TOID()
|
|||
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);
|
||||
static const VMFunction ToStringInfo = FunctionInfo<ToStringFn>(ToStringSlow);
|
||||
|
||||
|
|
|
@ -219,7 +219,8 @@ namespace jit {
|
|||
_(JSOP_INITHIDDENPROP_SETTER) \
|
||||
_(JSOP_INITHIDDENELEM) \
|
||||
_(JSOP_INITHIDDENELEM_GETTER) \
|
||||
_(JSOP_INITHIDDENELEM_SETTER)
|
||||
_(JSOP_INITHIDDENELEM_SETTER) \
|
||||
_(JSOP_CHECKOBJCOERCIBLE)
|
||||
|
||||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
|
|
|
@ -2769,6 +2769,11 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
|||
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.
|
||||
MOZ_ASSERT(stack[2] == objv);
|
||||
stack[2] = rhs;
|
||||
|
|
|
@ -9061,7 +9061,7 @@ CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)
|
|||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue,
|
||||
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
|
||||
MutableHandleValue);
|
||||
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation);
|
||||
|
||||
|
@ -9076,7 +9076,6 @@ CodeGenerator::visitToIdV(LToIdV* lir)
|
|||
OutOfLineCode* ool = oolCallVM(ToIdInfo, lir,
|
||||
ArgList(ImmGCPtr(current->mir()->info().script()),
|
||||
ImmPtr(lir->mir()->resumePoint()->pc()),
|
||||
ToValue(lir, LToIdV::Object),
|
||||
ToValue(lir, LToIdV::Index)),
|
||||
StoreValueTo(out));
|
||||
|
||||
|
@ -10369,6 +10368,22 @@ CodeGenerator::visitCheckReturn(LCheckReturn* ins)
|
|||
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
|
||||
CodeGenerator::visitRandom(LRandom* ins)
|
||||
{
|
||||
|
|
|
@ -345,6 +345,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
void visitNewTarget(LNewTarget* ins);
|
||||
void visitArrowNewTarget(LArrowNewTarget* ins);
|
||||
void visitCheckReturn(LCheckReturn* ins);
|
||||
void visitCheckObjCoercible(LCheckObjCoercible* ins);
|
||||
|
||||
void visitCheckOverRecursed(LCheckOverRecursed* lir);
|
||||
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
|
||||
|
|
|
@ -354,9 +354,10 @@ class ExecutableAllocator
|
|||
// At this point, local |pool| is the owner.
|
||||
|
||||
if (m_smallPools.length() < maxSmallPools) {
|
||||
// We haven't hit the maximum number of live pools; add the new pool.
|
||||
m_smallPools.append(pool);
|
||||
pool->addRef();
|
||||
// We haven't hit the maximum number of live pools; add the new pool.
|
||||
// If append() OOMs, we just return an unshared allocator.
|
||||
if (m_smallPools.append(pool))
|
||||
pool->addRef();
|
||||
} else {
|
||||
// Find the pool with the least space.
|
||||
int iMin = 0;
|
||||
|
|
|
@ -134,7 +134,9 @@ class LinearSum
|
|||
: terms_(other.terms_.allocPolicy()),
|
||||
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
|
||||
|
|
|
@ -615,7 +615,8 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
|
|||
return true;
|
||||
}
|
||||
}
|
||||
loopHeaders_.append(LoopHeader(start, entry));
|
||||
if (!loopHeaders_.append(LoopHeader(start, entry)))
|
||||
return false;
|
||||
|
||||
jsbytecode* last = nullptr;
|
||||
jsbytecode* earlier = nullptr;
|
||||
|
@ -2098,6 +2099,9 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_NEWTARGET:
|
||||
return jsop_newtarget();
|
||||
|
||||
case JSOP_CHECKOBJCOERCIBLE:
|
||||
return jsop_checkobjcoercible();
|
||||
|
||||
#ifdef DEBUG
|
||||
case JSOP_PUSHBLOCKSCOPE:
|
||||
case JSOP_FRESHENBLOCKSCOPE:
|
||||
|
@ -3419,8 +3423,12 @@ IonBuilder::tableSwitch(JSOp op, jssrcnote* sn)
|
|||
MBasicBlock* defaultcase = newBlock(current, defaultpc);
|
||||
if (!defaultcase)
|
||||
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
|
||||
jsbytecode* casepc = nullptr;
|
||||
|
@ -3448,14 +3456,22 @@ IonBuilder::tableSwitch(JSOp op, jssrcnote* sn)
|
|||
if (!caseblock)
|
||||
return ControlStatus_Error;
|
||||
|
||||
tableswitch->addBlock(caseblock);
|
||||
if (!tableswitch->addBlock(caseblock))
|
||||
return ControlStatus_Error;
|
||||
|
||||
// Add constant to indicate which case this is for use by
|
||||
// processNextTableSwitchCase.
|
||||
MConstant* constant = MConstant::New(alloc(), Int32Value(i + low));
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -5389,7 +5405,7 @@ IonBuilder::selectInliningTargets(const ObjectVector& targets, CallInfo& callInf
|
|||
inlineable = false;
|
||||
}
|
||||
|
||||
choiceSet.append(inlineable);
|
||||
choiceSet.infallibleAppend(inlineable);
|
||||
if (inlineable)
|
||||
*numInlineable += 1;
|
||||
}
|
||||
|
@ -5881,7 +5897,8 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec
|
|||
|
||||
// Connect the inline path to the returnBlock.
|
||||
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);
|
||||
retPhi->addInput(retVal);
|
||||
|
@ -10309,6 +10326,31 @@ IonBuilder::jsop_rest()
|
|||
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
|
||||
IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed)
|
||||
{
|
||||
|
@ -13021,7 +13063,7 @@ IonBuilder::jsop_toid()
|
|||
return true;
|
||||
|
||||
MDefinition* index = current->pop();
|
||||
MToId* ins = MToId::New(alloc(), current->peek(-1), index);
|
||||
MToId* ins = MToId::New(alloc(), index);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
|
|
@ -738,6 +738,7 @@ class IonBuilder
|
|||
bool jsop_setaliasedvar(ScopeCoordinate sc);
|
||||
bool jsop_debugger();
|
||||
bool jsop_newtarget();
|
||||
bool jsop_checkobjcoercible();
|
||||
|
||||
/* Inlining. */
|
||||
|
||||
|
|
|
@ -1097,8 +1097,7 @@ void
|
|||
LIRGenerator::visitToId(MToId* ins)
|
||||
{
|
||||
LToIdV* lir = new(alloc()) LToIdV(tempDouble());
|
||||
useBox(lir, LToIdV::Object, ins->lhs());
|
||||
useBox(lir, LToIdV::Index, ins->rhs());
|
||||
useBox(lir, LToIdV::Index, ins->input());
|
||||
defineBox(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
@ -4331,6 +4330,19 @@ LIRGenerator::visitCheckReturn(MCheckReturn* ins)
|
|||
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
|
||||
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
|
||||
{
|
||||
|
|
|
@ -310,6 +310,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
|
||||
void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
|
||||
void visitCheckReturn(MCheckReturn* ins);
|
||||
void visitCheckObjCoercible(MCheckObjCoercible* ins);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -2536,11 +2536,11 @@ class MTableSwitch final
|
|||
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_.empty());
|
||||
successors_.append(successor);
|
||||
return successors_.length() - 1;
|
||||
*index = successors_.length();
|
||||
return successors_.append(successor);
|
||||
}
|
||||
|
||||
MBasicBlock* getSuccessor(size_t i) const override {
|
||||
|
@ -2581,14 +2581,15 @@ class MTableSwitch final
|
|||
return high() - low() + 1;
|
||||
}
|
||||
|
||||
size_t addDefault(MBasicBlock* block) {
|
||||
bool addDefault(MBasicBlock* block, size_t* index = nullptr) {
|
||||
MOZ_ASSERT(successors_.empty());
|
||||
successors_.append(block);
|
||||
return 0;
|
||||
if (index)
|
||||
*index = 0;
|
||||
return successors_.append(block);
|
||||
}
|
||||
|
||||
void addCase(size_t successorIndex) {
|
||||
cases_.append(successorIndex);
|
||||
bool addCase(size_t successorIndex) {
|
||||
return cases_.append(successorIndex);
|
||||
}
|
||||
|
||||
MBasicBlock* getBlock(size_t i) const {
|
||||
|
@ -2596,8 +2597,8 @@ class MTableSwitch final
|
|||
return blocks_[i];
|
||||
}
|
||||
|
||||
void addBlock(MBasicBlock* block) {
|
||||
blocks_.append(block);
|
||||
bool addBlock(MBasicBlock* block) {
|
||||
return blocks_.append(block);
|
||||
}
|
||||
|
||||
MDefinition* getOperand(size_t index) const override {
|
||||
|
@ -5371,11 +5372,11 @@ class MTypeOf
|
|||
};
|
||||
|
||||
class MToId
|
||||
: public MBinaryInstruction,
|
||||
: public MUnaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
{
|
||||
MToId(MDefinition* object, MDefinition* index)
|
||||
: MBinaryInstruction(object, index)
|
||||
explicit MToId(MDefinition* index)
|
||||
: MUnaryInstruction(index)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
}
|
||||
|
@ -5383,8 +5384,8 @@ class MToId
|
|||
public:
|
||||
INSTRUCTION_HEADER(ToId)
|
||||
|
||||
static MToId* New(TempAllocator& alloc, MDefinition* object, MDefinition* index) {
|
||||
return new(alloc) MToId(object, index);
|
||||
static MToId* New(TempAllocator& alloc, MDefinition* index) {
|
||||
return new(alloc) MToId(index);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10646,8 +10647,8 @@ class MDispatchInstruction
|
|||
}
|
||||
|
||||
public:
|
||||
void addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
|
||||
map_.append(Entry(func, funcGroup, block));
|
||||
bool addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
|
||||
return map_.append(Entry(func, funcGroup, block));
|
||||
}
|
||||
uint32_t numCases() const {
|
||||
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
|
||||
: public MUnaryInstruction,
|
||||
public NoTypePolicy::Data
|
||||
|
|
|
@ -279,7 +279,8 @@ namespace jit {
|
|||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget) \
|
||||
_(CheckReturn)
|
||||
_(CheckReturn) \
|
||||
_(CheckObjCoercible)
|
||||
|
||||
// Forward declarations of MIR types.
|
||||
#define FORWARD_DECLARE(op) class M##op;
|
||||
|
|
|
@ -65,9 +65,13 @@ struct AllocationIntegrityState
|
|||
|
||||
InstructionInfo(const InstructionInfo& o)
|
||||
{
|
||||
inputs.appendAll(o.inputs);
|
||||
temps.appendAll(o.temps);
|
||||
outputs.appendAll(o.outputs);
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!inputs.appendAll(o.inputs) ||
|
||||
!temps.appendAll(o.temps) ||
|
||||
!outputs.appendAll(o.outputs))
|
||||
{
|
||||
oomUnsafe.crash("InstructionInfo::InstructionInfo");
|
||||
}
|
||||
}
|
||||
};
|
||||
Vector<InstructionInfo, 0, SystemAllocPolicy> instructions;
|
||||
|
@ -76,7 +80,9 @@ struct AllocationIntegrityState
|
|||
Vector<InstructionInfo, 5, SystemAllocPolicy> phis;
|
||||
BlockInfo() {}
|
||||
BlockInfo(const BlockInfo& o) {
|
||||
phis.appendAll(o.phis);
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!phis.appendAll(o.phis))
|
||||
oomUnsafe.crash("BlockInfo::BlockInfo");
|
||||
}
|
||||
};
|
||||
Vector<BlockInfo, 0, SystemAllocPolicy> blocks;
|
||||
|
|
|
@ -1311,6 +1311,15 @@ BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* 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
|
||||
BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
|
||||
{
|
||||
|
|
|
@ -738,6 +738,8 @@ bool ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber);
|
|||
bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
|
||||
bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
|
||||
|
||||
bool ThrowObjectCoercible(JSContext* cx, HandleValue v);
|
||||
|
||||
bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -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:
|
||||
LIR_HEADER(ToIdV)
|
||||
|
@ -1286,8 +1286,7 @@ class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1>
|
|||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
static const size_t Object = 0;
|
||||
static const size_t Index = BOX_PIECES;
|
||||
static const size_t Index = 0;
|
||||
|
||||
MToId* mir() const {
|
||||
return mir_->toToId();
|
||||
|
@ -7397,6 +7396,14 @@ class LCheckReturn : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0
|
|||
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 js
|
||||
|
||||
|
|
|
@ -367,6 +367,7 @@
|
|||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget) \
|
||||
_(CheckReturn)
|
||||
_(CheckReturn) \
|
||||
_(CheckObjCoercible)
|
||||
|
||||
#endif /* jit_shared_LOpcodes_shared_h */
|
||||
|
|
|
@ -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_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_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_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include <algorithm> // for std::max
|
||||
#include <fcntl.h>
|
||||
|
@ -802,10 +801,15 @@ GenerateSeed(uint64_t* seedBuffer, size_t length)
|
|||
if (fd >= 0) {
|
||||
ssize_t size = length * sizeof(seedBuffer[0]);
|
||||
ssize_t nread = read(fd, (char *) seedBuffer, size);
|
||||
MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
|
||||
mozilla::Unused << nread;
|
||||
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
|
||||
# error "Platform needs to implement random_generateSeed()"
|
||||
#endif
|
||||
|
|
|
@ -2231,11 +2231,12 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject s
|
|||
|
||||
// See note above RuntimeLexicalErrorObject.
|
||||
if (pobj == scope) {
|
||||
if (IsUninitializedLexicalSlot(scope, shape)) {
|
||||
if (name != cx->names().dotThis && IsUninitializedLexicalSlot(scope, shape)) {
|
||||
scope = RuntimeLexicalErrorObject::create(cx, scope, JSMSG_UNINITIALIZED_LEXICAL);
|
||||
if (!scope)
|
||||
return false;
|
||||
} 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);
|
||||
if (!scope)
|
||||
return false;
|
||||
|
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -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");
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
function f() { return "inner"; }
|
||||
}
|
||||
|
||||
function f() { return "outer"; }
|
||||
|
||||
reportCompare(f(), "inner");
|
|
@ -132,9 +132,6 @@ function testClasses() {
|
|||
assertClass("class NAME { }", []);
|
||||
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
|
||||
assertClassError("class NAME extends null { constructor() 1 }", SyntaxError);
|
||||
|
||||
|
|
|
@ -4373,8 +4373,8 @@ Debugger::setupTraceLogger(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!GetProperty(cx, obj, obj, ids[i], &v))
|
||||
return false;
|
||||
|
||||
textIds.append(textId);
|
||||
values.append(ToBoolean(v));
|
||||
textIds.infallibleAppend(textId);
|
||||
values.infallibleAppend(ToBoolean(v));
|
||||
}
|
||||
|
||||
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 && 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. */
|
||||
if (!code.isString()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
|
||||
|
|
|
@ -427,7 +427,9 @@ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
|
|||
for (size_t i = 0; i < waiting.length(); i++) {
|
||||
ParseTask* task = waiting[i];
|
||||
if (task->runtimeMatches(rt)) {
|
||||
newTasks.append(task);
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!newTasks.append(task))
|
||||
oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
|
||||
HelperThreadState().remove(waiting, &i);
|
||||
}
|
||||
}
|
||||
|
@ -444,8 +446,11 @@ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// for uninitialized lets.
|
||||
return CheckUninitializedLexical(cx, name, vp);
|
||||
|
@ -391,18 +395,14 @@ NegOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue val
|
|||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue objval,
|
||||
HandleValue idval, MutableHandleValue res)
|
||||
ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval,
|
||||
MutableHandleValue res)
|
||||
{
|
||||
if (idval.isInt32()) {
|
||||
res.set(idval);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* obj = ToObjectFromStack(cx, objval);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
RootedId id(cx);
|
||||
if (!ToPropertyKey(cx, idval, &id))
|
||||
return false;
|
||||
|
|
|
@ -1740,7 +1740,6 @@ CASE(JSOP_NOP)
|
|||
CASE(JSOP_UNUSED14)
|
||||
CASE(JSOP_UNUSED65)
|
||||
CASE(JSOP_BACKPATCH)
|
||||
CASE(JSOP_UNUSED163)
|
||||
CASE(JSOP_UNUSED177)
|
||||
CASE(JSOP_UNUSED178)
|
||||
CASE(JSOP_UNUSED179)
|
||||
|
@ -2422,10 +2421,9 @@ CASE(JSOP_TOID)
|
|||
* 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.
|
||||
*/
|
||||
ReservedRooted<Value> objval(&rootValue0, REGS.sp[-2]);
|
||||
ReservedRooted<Value> idval(&rootValue1, REGS.sp[-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;
|
||||
}
|
||||
END_CASE(JSOP_TOID)
|
||||
|
@ -3232,10 +3230,7 @@ CASE(JSOP_SETLOCAL)
|
|||
{
|
||||
uint32_t i = GET_LOCALNO(REGS.pc);
|
||||
|
||||
// Derived class constructors store the TDZ Value in the .this slot
|
||||
// before a super() call.
|
||||
MOZ_ASSERT_IF(!script->isDerivedClassConstructor(),
|
||||
!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
|
||||
MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
|
||||
|
||||
REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
|
||||
}
|
||||
|
@ -3893,6 +3888,14 @@ 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()
|
||||
{
|
||||
char numBuf[12];
|
||||
|
@ -4837,9 +4840,6 @@ js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
|
|||
{
|
||||
RootedFunction fun(cx, frame.callee());
|
||||
|
||||
MOZ_ASSERT(fun->isClassConstructor());
|
||||
MOZ_ASSERT(fun->nonLazyScript()->isDerivedClassConstructor());
|
||||
|
||||
const char* name = "anonymous";
|
||||
JSAutoByteString str;
|
||||
if (fun->atom()) {
|
||||
|
|
|
@ -1668,7 +1668,14 @@
|
|||
* Stack: =>
|
||||
*/ \
|
||||
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.
|
||||
*
|
||||
|
@ -2122,15 +2129,12 @@
|
|||
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
|
||||
* 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.
|
||||
* Replace the top-of-stack value propertyNameValue with
|
||||
* ToPropertyKey(propertyNameValue).
|
||||
* Category: Literals
|
||||
* Type: Object
|
||||
* Operands:
|
||||
* Stack: baseValue, propertyNameValue => baseValue, propertyKey
|
||||
* Stack: propertyNameValue => propertyKey
|
||||
*/ \
|
||||
macro(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, JOF_BYTE) \
|
||||
\
|
||||
|
|
|
@ -306,8 +306,10 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
|
|||
if (!atomsCompartment || !atomsCompartment->init(nullptr))
|
||||
return false;
|
||||
|
||||
gc.zones.append(atomsZone.get());
|
||||
atomsZone->compartments.append(atomsCompartment.get());
|
||||
if (!gc.zones.append(atomsZone.get()))
|
||||
return false;
|
||||
if (!atomsZone->compartments.append(atomsCompartment.get()))
|
||||
return false;
|
||||
|
||||
atomsCompartment->setIsSystem(true);
|
||||
|
||||
|
|
|
@ -953,7 +953,7 @@ class ClonedBlockObject : public BlockObject
|
|||
// Attempting to access anything on this scope throws the appropriate
|
||||
// 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.
|
||||
class RuntimeLexicalErrorObject : public ScopeObject
|
||||
{
|
||||
|
|
|
@ -3875,7 +3875,11 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
|
|||
RootedFunction function(cx, this->function());
|
||||
Vector<uint32_t, 32> pcOffsets(cx);
|
||||
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))
|
||||
continue;
|
||||
|
|
|
@ -29,11 +29,11 @@ namespace js {
|
|||
*
|
||||
* 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 =
|
||||
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 "
|
||||
"removed MSG_DEFs from js.msg, you should increment "
|
||||
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
|
||||
|
|
|
@ -4575,13 +4575,9 @@ nsDisplayResolution::HitTest(nsDisplayListBuilder* aBuilder,
|
|||
HitTestState* aState,
|
||||
nsTArray<nsIFrame*> *aOutFrames)
|
||||
{
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
nsIPresShell* presShell = mFrame->PresContext()->PresShell();
|
||||
nsRect rect = aRect.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
|
||||
mList.HitTest(aBuilder, rect, aState, aOutFrames);
|
||||
#else
|
||||
mList.HitTest(aBuilder, aRect, aState, aOutFrames);
|
||||
#endif // MOZ_SINGLE_PROCESS_APZ
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
|
|
|
@ -1416,7 +1416,12 @@ public:
|
|||
virtual nsresult SetResolution(float aResolution) = 0;
|
||||
float GetResolution() { return mResolution.valueOr(1.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?
|
||||
|
|
|
@ -2021,9 +2021,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
|
|||
nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x),
|
||||
presContext->DevPixelsToAppUnits(aPoint.y));
|
||||
pt = pt - view->ViewToWidgetOffset();
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
pt = pt.RemoveResolution(presContext->PresShell()->GetCumulativeScaleResolution());
|
||||
#endif // MOZ_SINGLE_PROCESS_APZ
|
||||
pt = pt.RemoveResolution(presContext->PresShell()->GetCumulativeNonRootScaleResolution());
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
|
@ -2059,12 +2057,10 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
|
|||
int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
int32_t localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
widgetToView = widgetToView.ScaleToOtherAppUnits(rootAPD, localAPD);
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
nsIPresShell* shell = aFrame->PresContext()->PresShell();
|
||||
|
||||
// XXX Bug 1224748 - Update nsLayoutUtils functions to correctly handle nsPresShell resolution
|
||||
widgetToView = widgetToView.RemoveResolution(shell->GetCumulativeScaleResolution());
|
||||
#endif
|
||||
widgetToView = widgetToView.RemoveResolution(shell->GetCumulativeNonRootScaleResolution());
|
||||
|
||||
/* 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.
|
||||
|
@ -2812,10 +2808,8 @@ nsLayoutUtils::TranslateViewToWidget(nsPresContext* aPresContext,
|
|||
return LayoutDeviceIntPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
nsPoint pt = aPt + viewOffset;
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
pt = pt.ApplyResolution(aPresContext->PresShell()->GetCumulativeScaleResolution());
|
||||
#endif // MOZ_SINGLE_PROCESS_APZ
|
||||
nsPoint pt = (aPt +
|
||||
viewOffset).ApplyResolution(aPresContext->PresShell()->GetCumulativeNonRootScaleResolution());
|
||||
LayoutDeviceIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(pt.x),
|
||||
aPresContext->AppUnitsToDevPixels(pt.y));
|
||||
return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget);
|
||||
|
|
|
@ -5330,13 +5330,16 @@ float PresShell::GetCumulativeResolution()
|
|||
return resolution;
|
||||
}
|
||||
|
||||
float PresShell::GetCumulativeScaleResolution()
|
||||
float PresShell::GetCumulativeNonRootScaleResolution()
|
||||
{
|
||||
float resolution = 1.0;
|
||||
nsIPresShell* currentShell = this;
|
||||
while (currentShell) {
|
||||
resolution *= currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
|
||||
nsPresContext* parentCtx = currentShell->GetPresContext()->GetParentPresContext();
|
||||
nsPresContext* currentCtx = currentShell->GetPresContext();
|
||||
if (currentCtx != currentCtx->GetRootPresContext()) {
|
||||
resolution *= currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
|
||||
}
|
||||
nsPresContext* parentCtx = currentCtx->GetParentPresContext();
|
||||
if (parentCtx) {
|
||||
currentShell = parentCtx->PresShell();
|
||||
} else {
|
||||
|
|
|
@ -218,7 +218,7 @@ public:
|
|||
}
|
||||
virtual bool ScaleToResolution() const override;
|
||||
virtual float GetCumulativeResolution() override;
|
||||
virtual float GetCumulativeScaleResolution() override;
|
||||
virtual float GetCumulativeNonRootScaleResolution() override;
|
||||
|
||||
//nsIViewObserver interface
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ support-files =
|
|||
file_bug1018265.xul
|
||||
|
||||
[test_bug370436.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[test_bug396367-1.html]
|
||||
[test_bug396367-2.html]
|
||||
[test_bug420499.xul]
|
||||
|
|
|
@ -442,12 +442,10 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
aBuilder->EnterPresShell(subdocRootFrame,
|
||||
pointerEventsNone && !passPointerEventsToChildren);
|
||||
|
||||
#if defined(MOZ_SINGLE_PROCESS_APZ)
|
||||
if (!haveDisplayPort) {
|
||||
// Remove nsPresShell resolution
|
||||
dirty = dirty.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
dirty = aDirtyRect;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче