import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1085783 (Part 1) - Snap both the fill and dest rects using UserToDeviceSnapped() when pixel snapping images. r=roc (97c8ea37a9)
- Bug 1085783 (Part 2) - Add a test for rounding behavior when high-quality downscaling. r=roc (2851c696c4)
- Bug 1218851. Fix comments related to nsIPresShell::RenderDocument and flags RENDER_DOCUMENT_RELATIVE and RENDER_IGNORE_VIEWPORT_SCROLLING. r=roc (897eb061a2)
- Bug 1223255 - Use Animation::AnimationTimeToTimeStamp instead of timeline->ToTimeStamp. r=bbirtles (b05fc6c868)
- Bug 1216030 - Part 1: Remove CanAnimate_HasGeometricProperty. r=dbaron (8f8f380828)
- Bug 1216030 - Part 2: Remove gfxPlatform::OffMainThreadCompositingEnabled from CanAnimatePropertyOnCompositor. r=dbaron (983f626f3d)
- Bug 1216030 - Part 3: Move AreAsyncAnimationsEnabled check outside animation properties loop. r=dbaron (273b21d3a9)
- Bug 1216030 - Part 4: Move IsCompositorAnimationDisabledForFrame outside animation properties loop. r=dbaron (4f5ba30f2d)
- Bug 1216030 - Part 5: Add KeyframeEffectReadOnly::CanAnimateTransformOnCompositor. r=bbirtles (a87ab8f397)
- Bug 1216030 - Part 6: Add KeyframeEffectReadOnly::IsGeometricProperty. r=bbirtles (9dbb1c9fe0)
- Bug 1216030 - Part 7: Add nsIFrame::RefusedAsyncAnimation. r=dbaron (9b0582e9e7)
- Bug 1216030 - Part 8: Add KeyframeEffectReadOnly::GetAnimationFrame. r=bbirtles (3915b03b48)
- Bug 1216030 - Part 9: We don't need to call CanPerformOnCompositorThread in RequestRestyle. (fe46feecdb)
- Bug 1216030 - Part 8.5: Animation::CanThrottle() should check that all animation properties are running on compositor. r=bbirtles (dbee36ccc7)
- Bug 1216030 - Part 10: Remove CanAnimate_AllowPartial flag. r=bbirtles (eb30ac714f)
- Bug 1216030 - Part 11: Add KeyframeEffect::CanAnimatePropertyOnCompositor. r=bbirtles (f71cb641ec)
- Bug 1216030 - Part 12: Pass nsIFrame to CanPerformOnCompositorThread to avoid redundant process for getting nsIFrame. r=dbaron (c9dbe043ad)
- Bug 1216030 - Part 13: Remove existsProperty check from CanPerformOnCompositorThread. r=dbaron (e3dde151af)
- Bug 1216030 - Part 14: Add KeyframeEffectReadOnly::GetPresContext and KeyframeEffectReadonly::GetRenderedDocument. r=bbirtles (7edbf430e9)
- Bug 1216030 - Part 15: Add KeyframeEffectReadOnly::GetCollection. r=bbirtles (2652435de5)
- Bug 1216030 - Part 16: Move CanThrottleAnimation and CanThrottleTransformChanges from AnimationCollection into KeyframeEffectReadOnly::CanThrottle. r=bbirtles (d890691ebb)
- Bug 1216030 - Part 17: Do not calculate unthrottle interval for transform animation every time. r=bbirtles (c7a3767422)
- Bug 1216030 - Part 18: Remove IsCurrent() check in assertion in CanThrottle. r=bbirtles (6de694634a)
- Bug 1181976 - Rename WillChangeBudgetWarning in dom/dom.properties to reflect string change. r=flod (abc159ebba)
- Bug 1191412 - Fix logic and text for the WillChange warning. r=roc (f2900114f1)
- Bug 1180899 - Do not clobber frame metrics on the root layer added during a previous paint if there is no other frame metrics for the root scroll frame. r=tn (30f2dcf21b)
- Bug 1208673 - Do HitTest with skipping non-leaf preserve-3d transform items. r=roc (a042872d32)
- Bug 947062 - Layerize background images with animated background-position if possible. r=mattwoodrow (075dedff4a)
- Bug 1172310. Don't add viewport frame bounds to the layer event regions because they are never the result of hit testing. r=roc (1ecdd06c0d)
- Bug 1213582. Don't flatten away opacity:0 containers. r=mattwoodrow (d1f9c205e1)
- Bug 1213582. Skip display items in ProcessDisplayItems if we only need items for event regions, and this item isn't one and doesn't have descendants. r=mattwoodrow (3511595652)
- Bug 1183085 - Correct the name for nsDisplayItem; r=roc (fb1a59294f)
- Bug 1183085 - Update description for nsDisplayList methods; r=roc (39eafdb099)
- Bug 1216851 - Don't include event regions when deciding if we can flatten opacity. r=roc (fc518688a4)
- Bug 1215412 - Apply perspective origin after transform origin. r=jwatt (a30f0351a3)
- Bug 1152263 - Ensure Matrix4x4::ProjectRectBounds being functional for Rect with zero width/height. r=mattwoodrow (5ca3086e04)
- Bug 1217012 - Use doubles when untransforming points since we need the extra precision. r=kip (81acd626e8)
- Bug 1042536 - Allow ImageLayer optimization to be used for some clipped background images. r=mstange (b9b89b2d25)
- Bug 1221677 - "[css-grid] Put the 'subgrid' support behind a pref, disabled by default". r=mats (400e9d865a)
- Bug 1150042 - Make nsLayoutUtils::DrawSingleUnscaledImage use CSSIntSize instead of unitless nsIntSize. r=dholbert (393062cd87)
- Bug 1173305 - Convert BasicTableLayoutStrategy to work with logical coordinates. r=dholbert (e133cad49a)
- namespace comment (6fc3ad3f4a)
- Bug 1220621. When removing a <col>, only create an anonymous colframe to replace it if one is really needed. r=dbaron (e29d8a7248)
- Bug 1178250 - Don't call ConsiderChildOverflow until the child has been placed in the right location when reflowing a vertical-rl table. r=dholbert (1327793032)
- Bug 1186998 - Align overflowing table-cell content to content-box. r=dholbert (d2356a20c0)
- Bug 1213465 - Combine DrawResults correctly in nsTablePainter. r=tn (61e725a4ad)
- minor (0df6057957)
- bits of Bug 1163227: Part5 (6a99380110)
- minor (59f78b2265)
- Bug 1206982 - getUserMedia s/PermissionDeniedError/SecurityError/. r=jesup (782b3536a2)
- Bug 1218799: Shutdown MediaManager engines from the MediaManager thread r=jib (351bba0486)
- Bug 1186708 - Fix debug-only assert (crash) on advanced browserWindow constraint. r=jesup (86fcfa999d)
- Bug 1170958 - Remove ProcessedMediaStream::ForwardTrackEnabled. r=roc,jesup (4663d7a46c)
- Bug 1223916 - Prohibit direct method calls at the parser level in self-hosted code. (r=till) (1489fbb2f3)
- Bug 1219057 - Do not show "Unable to print stack trace" for exception thrown while compiling top-level script. r=jandem (df74029ee8)
- Bug 1186973 - Evaluate assertEqBytecode: Print length as numbers. r=h4writer (57f9e68d53)
- Bug 1218636 - IonMonkey: MIPS64: Add support into shell. r=lth (dc4de53cf5)
- Bug 1192329 - Change JS shell to default to the standard version of JS (not 1.7+) 1/2; r=jorendorff (e40087f5b8)
- Bug 1192329 - Change JS shell to default to the standard version of JS (not 1.7+) 2/2; r=jorendorff (4d74d1f639)
- Bug 1192329 - Fix broken asm tests by explicitly setting js version; r=jorendorff (adf502c8db)
- Bug 1108603 - Evaluate ensure that the global is configured such that we can always clone singletons. r=jonco (8a888042dd)
- Bug 1184393 - Rename some js shell test variables for better readability; r=sfink (06e2293f34)
- Bug 1213104 - Pass the ProgressBar directly, since we are no longer using results; r=sfink (16b4af8c3e)
- Bug 1212756 - Fix jstests --debug option r=terrence (89caa65dc5)
- Bug 1213365 - Share environment control code between js and jit test harnesses; r=sfink (274c4f2d2e)
- Bug 1206987 - Only disable the GPF dialog during testing; r=sfink (a507b1b591)
- Bug 1212349 - Encapsulate the shell's per-runtime state r=jandem (4ec884973d)
- Bug 1215063 - Implement a simple module loader for the shell r=shu r=froydnj (a916f0ee03)
- Bug 1214051 - Reject NaN as a sampling probability, and test the floating point value range harder. r=jimb (842e822471)
- Bug 1225176 - Don't call wrap() in JitActivation constructor, it can GC and crash. r=fitzgen (d989a2b157)
- Bug 1218643 - remove support for deprecated asm.js heap length. r=luke (6ad156f10d)
- Bug 1224280 - Fix asm.js console warning when disabled by debugger and parsing off-thread. r=luke (7bf76d0a1f)
- Bug 1221660 - Part 1: Stop populating ParseNode::pn_offset most of the time. r=Waldo. (24d013fe30)
- Bug 1221660 - Part 2: Move pn_offset into a branch of the ParseNode::pn_u union. Add a subclass of ParseNode for PNK_CASE nodes. Merge PNK_DEFAULT with PNK_CASE. r=Waldo. (12514bc644)
- Bug 1200609 - Odin: Update comments and code mentioning interrupting via mprotect (r=benj) (a60ec9d0d0)
- Bug 1218644 - OdinMonkey: MIPS64: Add support for Loongson3. r=lth (57a1865d1d)
- Bug 1225392 part 1. Expose JSAPI for getting %IteratorPrototype%. r=efaust (816e68dddd)
- Bug 1225392 part 2. WebIDL autogenerated iterators should chain up to %IteratorPrototype%. r=qdot (834fc71f90)
- No bug. Reword a comment slightly because it confused me. r=woof!, DONTBUILD (c2c41d535a)
- Bug 1147752 - Keep typedefs consistent. r=jgilbert (605d63c0e4)
- Bug 1207672 - Add support for APPLE_framebuffer_multisample r=snorp (0f4ef4420d)
- Bug 1207205 - Remove fGetActiveUniformName. r=jrmuizel (9d1c97f194)
- Bug 1208513 - Add support for GL_APPLE_sync r=jgilbert (6d70401d89)
- Bug 1222175 - initialize base of ScaledFontDWrite before its members; r=Bas (120c5fa334)
- Bug 1217941 - remove <iomanip> from ScaleFactors2D.h; r=jrmuizel (e5a08d95e2)
- Bug 1222569 - fix initialization order in SourceSurfaceD2D1; r=Bas (484084f551)
- Bug 1208661 - Implement SourceSurfaceDual::GetDataSurface() for debugging purposes. r=BenWa (de255f344a)
- Bug 1185011: Add 'override' annotations to DataSourceSurface subclasses in SourceSurfaceRawData.h, to fix clang -Winconsistent-missing-override build warnings/errors. rs=ehsan (dc3ff4fa07)
- Bug 1222298 - GFX: 2D: Make convolverLS3 more like upstream. r=seth (06e555709d)
- Bug 1157065- GFX: 2D: Implement AlphaBoxBlur in LS3 MMI. r=jrmuizel (ca818df231)
- Bug 1220673 - Make DrawTargetCG::Mask() MOZ_CRASH (a649db3d99)
- Bug 1221616: Use ID2D1CommandList instead of a bitmap for temporary D2D drawing. r=jrmuizel (9785977521)
- Bug 1220624: Make MaskSurface properly take into account the possibilities of partial uploads. r=jrmuizel (9dd3d65880)
- Bug 1222569 - remove unused variable from DrawTargetD2D1.cpp; r=Bas (e6c5aa717b)
This commit is contained in:
2023-01-09 08:34:11 +08:00
parent 4b6d15646a
commit f29aba536a
152 changed files with 3608 additions and 1674 deletions
@@ -43,7 +43,7 @@ function runNext() {
ok(false, 'unexpected success, permission request should be denied');
runNext();
}, function failure(err) {
is(err.name, 'PermissionDeniedError', 'expected permission denied');
is(err.name, 'SecurityError', 'expected permission denied');
runNext();
});
} else {
+1
View File
@@ -76,6 +76,7 @@ included_inclnames_to_ignore = set([
'prthread.h', # NSPR
'prtypes.h', # NSPR
'selfhosted.out.h', # generated in $OBJDIR
'shellmoduleloader.out.h', # generated in $OBJDIR
'unicode/locid.h', # ICU
'unicode/numsys.h', # ICU
'unicode/timezone.h', # ICU
+43 -56
View File
@@ -457,6 +457,44 @@ Animation::GetCurrentOrPendingStartTime() const
return result;
}
TimeStamp
Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
{
// Initializes to null. Return the same object every time to benefit from
// return-value-optimization.
TimeStamp result;
// We *don't* check for mTimeline->TracksWallclockTime() here because that
// method only tells us if the timeline times can be converted to
// TimeStamps that can be compared to TimeStamp::Now() or not, *not*
// whether the timelines can be converted to TimeStamp values at all.
//
// Furthermore, we want to be able to use this method when the refresh driver
// is under test control (in which case TracksWallclockTime() will return
// false).
//
// Once we introduce timelines that are not time-based we will need to
// differentiate between them here and determine how to sort their events.
if (!mTimeline) {
return result;
}
// Check the time is convertible to a timestamp
if (aTime == TimeDuration::Forever() ||
mPlaybackRate == 0.0 ||
mStartTime.IsNull()) {
return result;
}
// Invert the standard relation:
// animation time = (timeline time - start time) * playback rate
TimeDuration timelineTime =
TimeDuration(aTime).MultDouble(1.0 / mPlaybackRate) + mStartTime.Value();
result = mTimeline->ToTimeStamp(timelineTime);
return result;
}
// https://w3c.github.io/web-animations/#silently-set-the-current-time
void
Animation::SilentlySetCurrentTime(const TimeDuration& aSeekTime)
@@ -574,7 +612,7 @@ Animation::CanThrottle() const
return true;
}
return IsRunningOnCompositor();
return mEffect->CanThrottle();
}
void
@@ -1017,46 +1055,6 @@ Animation::EffectEnd() const
+ mEffect->GetComputedTiming().mActiveDuration;
}
TimeStamp
Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
{
// Initializes to null. Return the same object every time to benefit from
// return-value-optimization.
TimeStamp result;
// We *don't* check for mTimeline->TracksWallclockTime() here because that
// method only tells us if the timeline times can be converted to
// TimeStamps that can be compared to TimeStamp::Now() or not, *not*
// whether the timelines can be converted to TimeStamp values at all.
//
// Since we never compare the result of this method with TimeStamp::Now()
// it is ok to return values even if mTimeline->TracksWallclockTime() is
// false. Furthermore, we want to be able to use this method when the
// refresh driver is under test control (in which case TracksWallclockTime()
// will return false).
//
// Once we introduce timelines that are not time-based we will need to
// differentiate between them here and determine how to sort their events.
if (!mTimeline) {
return result;
}
// Check the time is convertible to a timestamp
if (aTime == TimeDuration::Forever() ||
mPlaybackRate == 0.0 ||
mStartTime.IsNull()) {
return result;
}
// Invert the standard relation:
// animation time = (timeline time - start time) * playback rate
TimeDuration timelineTime =
TimeDuration(aTime).MultDouble(1.0 / mPlaybackRate) + mStartTime.Value();
result = mTimeline->ToTimeStamp(timelineTime);
return result;
}
nsIDocument*
Animation::GetRenderedDocument() const
{
@@ -1064,28 +1062,17 @@ Animation::GetRenderedDocument() const
return nullptr;
}
Element* targetElement;
nsCSSPseudoElements::Type pseudoType;
mEffect->GetTarget(targetElement, pseudoType);
if (!targetElement) {
return nullptr;
}
return targetElement->GetComposedDoc();
return mEffect->GetRenderedDocument();
}
nsPresContext*
Animation::GetPresContext() const
{
nsIDocument* doc = GetRenderedDocument();
if (!doc) {
if (!mEffect) {
return nullptr;
}
nsIPresShell* shell = doc->GetShell();
if (!shell) {
return nullptr;
}
return shell->GetPresContext();
return mEffect->GetPresContext();
}
AnimationCollection*
+11 -2
View File
@@ -230,6 +230,15 @@ public:
*/
Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
/**
* Converts a time in the timescale of this Animation's currentTime, to a
* TimeStamp. Returns a null TimeStamp if the conversion cannot be performed
* because of the current state of this Animation (e.g. it has no timeline, a
* zero playbackRate, an unresolved start time etc.) or the value of the time
* passed-in (e.g. an infinite time).
*/
TimeStamp AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const;
bool IsPausedOrPausing() const
{
return PlayState() == AnimationPlayState::Paused ||
@@ -295,6 +304,8 @@ public:
void NotifyEffectTimingUpdated();
AnimationCollection* GetCollection() const;
protected:
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void SilentlySetPlaybackRate(double aPlaybackRate);
@@ -350,12 +361,10 @@ protected:
bool IsPossiblyOrphanedPendingAnimation() const;
StickyTimeDuration EffectEnd() const;
TimeStamp AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const;
nsIDocument* GetRenderedDocument() const;
nsPresContext* GetPresContext() const;
virtual CommonAnimationManager* GetAnimationManager() const = 0;
AnimationCollection* GetCollection() const;
RefPtr<AnimationTimeline> mTimeline;
RefPtr<KeyframeEffectReadOnly> mEffect;
+282
View File
@@ -9,8 +9,10 @@
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/dom/PropertyIndexedKeyframesBinding.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
#include "mozilla/StyleAnimationValue.h"
#include "AnimationCommon.h"
#include "Layers.h" // For Layer
#include "nsCSSParser.h"
#include "nsCSSPropertySet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
@@ -466,6 +468,19 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
}
}
bool
KeyframeEffectReadOnly::IsPropertyRunningOnCompositor(
nsCSSProperty aProperty) const
{
const auto& info = LayerAnimationInfo::sRecords;
for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
if (info[i].mProperty == aProperty) {
return mIsPropertyRunningOnCompositor[i];
}
}
return false;
}
bool
KeyframeEffectReadOnly::IsRunningOnCompositor() const
{
@@ -1709,5 +1724,272 @@ KeyframeEffectReadOnly::GetFrames(JSContext*& aCx,
}
}
/* static */ const TimeDuration
KeyframeEffectReadOnly::OverflowRegionRefreshInterval()
{
// The amount of time we can wait between updating throttled animations
// on the main thread that influence the overflow region.
static const TimeDuration kOverflowRegionRefreshInterval =
TimeDuration::FromMilliseconds(200);
return kOverflowRegionRefreshInterval;
}
bool
KeyframeEffectReadOnly::CanThrottle() const
{
// Animation::CanThrottle checks for not in effect animations
// before calling this.
MOZ_ASSERT(IsInEffect(), "Effect should be in effect");
// Unthrottle if this animation is not current (i.e. it has passed the end).
// In future we may be able to throttle this case too, but we should only get
// occasional ticks while the animation is in this state so it doesn't matter
// too much.
if (!IsCurrent()) {
return false;
}
nsIFrame* frame = GetAnimationFrame();
if (!frame) {
// There are two possible cases here.
// a) No target element
// b) The target element has no frame, e.g. because it is in a display:none
// subtree.
// In either case we can throttle the animation because there is no
// need to update on the main thread.
return true;
}
// First we need to check layer generation and transform overflow
// prior to the IsPropertyRunningOnCompositor check because we should
// occasionally unthrottle these animations even if the animations are
// already running on compositor.
for (const LayerAnimationInfo::Record& record :
LayerAnimationInfo::sRecords) {
// Skip properties that are overridden in the cascade.
// (GetAnimationOfProperty, as called by HasAnimationOfProperty,
// only returns an animation if it currently wins in the cascade.)
if (!HasAnimationOfProperty(record.mProperty)) {
continue;
}
AnimationCollection* collection = GetCollection();
MOZ_ASSERT(collection,
"CanThrottle should be called on an effect associated with an animation");
layers::Layer* layer =
FrameLayerBuilder::GetDedicatedLayer(frame, record.mLayerType);
// Unthrottle if the layer needs to be brought up to date with the animation.
if (!layer ||
collection->mAnimationGeneration > layer->GetAnimationGeneration()) {
return false;
}
// If this is a transform animation that affects the overflow region,
// we should unthrottle the animation periodically.
if (record.mProperty == eCSSProperty_transform &&
!CanThrottleTransformChanges(*frame)) {
return false;
}
}
for (const AnimationProperty& property : mProperties) {
if (!IsPropertyRunningOnCompositor(property.mProperty)) {
return false;
}
}
return true;
}
bool
KeyframeEffectReadOnly::CanThrottleTransformChanges(nsIFrame& aFrame) const
{
// If we know that the animation cannot cause overflow,
// we can just disable flushes for this animation.
// If we don't show scrollbars, we don't care about overflow.
if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
return true;
}
nsPresContext* presContext = GetPresContext();
// CanThrottleTransformChanges is only called as part of a refresh driver tick
// in which case we expect to has a pres context.
MOZ_ASSERT(presContext);
TimeStamp now =
presContext->RefreshDriver()->MostRecentRefresh();
AnimationCollection* collection = GetCollection();
MOZ_ASSERT(collection,
"CanThrottleTransformChanges should be involved with animation collection");
TimeStamp styleRuleRefreshTime = collection->mStyleRuleRefreshTime;
// If this animation can cause overflow, we can throttle some of the ticks.
if (!styleRuleRefreshTime.IsNull() &&
(now - styleRuleRefreshTime) < OverflowRegionRefreshInterval()) {
return true;
}
// If the nearest scrollable ancestor has overflow:hidden,
// we don't care about overflow.
nsIScrollableFrame* scrollable =
nsLayoutUtils::GetNearestScrollableFrame(&aFrame);
if (!scrollable) {
return true;
}
ScrollbarStyles ss = scrollable->GetScrollbarStyles();
if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
return true;
}
return false;
}
nsIFrame*
KeyframeEffectReadOnly::GetAnimationFrame() const
{
if (!mTarget) {
return nullptr;
}
nsIFrame* frame = mTarget->GetPrimaryFrame();
if (!frame) {
return nullptr;
}
if (mPseudoType == nsCSSPseudoElements::ePseudo_before) {
frame = nsLayoutUtils::GetBeforeFrame(frame);
} else if (mPseudoType == nsCSSPseudoElements::ePseudo_after) {
frame = nsLayoutUtils::GetAfterFrame(frame);
} else {
MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
"unknown mPseudoType");
}
if (!frame) {
return nullptr;
}
return nsLayoutUtils::GetStyleFrame(frame);
}
nsIDocument*
KeyframeEffectReadOnly::GetRenderedDocument() const
{
if (!mTarget) {
return nullptr;
}
return mTarget->GetComposedDoc();
}
nsPresContext*
KeyframeEffectReadOnly::GetPresContext() const
{
nsIDocument* doc = GetRenderedDocument();
if (!doc) {
return nullptr;
}
nsIPresShell* shell = doc->GetShell();
if (!shell) {
return nullptr;
}
return shell->GetPresContext();
}
AnimationCollection *
KeyframeEffectReadOnly::GetCollection() const
{
return mAnimation ? mAnimation->GetCollection() : nullptr;
}
/* static */ bool
KeyframeEffectReadOnly::IsGeometricProperty(
const nsCSSProperty aProperty)
{
switch (aProperty) {
case eCSSProperty_bottom:
case eCSSProperty_height:
case eCSSProperty_left:
case eCSSProperty_right:
case eCSSProperty_top:
case eCSSProperty_width:
return true;
default:
return false;
}
}
/* static */ bool
KeyframeEffectReadOnly::CanAnimateTransformOnCompositor(
const nsIFrame* aFrame,
const nsIContent* aContent)
{
if (aFrame->Combines3DTransformWithAncestors() ||
aFrame->Extend3DContext()) {
if (aContent) {
nsCString message;
message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' "
"transforms is not supported. See bug 779598");
AnimationCollection::LogAsyncAnimationFailure(message, aContent);
}
return false;
}
// Note that testing BackfaceIsHidden() is not a sufficient test for
// what we need for animating backface-visibility correctly if we
// remove the above test for Extend3DContext(); that would require
// looking at backface-visibility on descendants as well.
if (aFrame->StyleDisplay()->BackfaceIsHidden()) {
if (aContent) {
nsCString message;
message.AppendLiteral("Gecko bug: Async animation of "
"'backface-visibility: hidden' transforms is not supported."
" See bug 1186204.");
AnimationCollection::LogAsyncAnimationFailure(message, aContent);
}
return false;
}
if (aFrame->IsSVGTransformed()) {
if (aContent) {
nsCString message;
message.AppendLiteral("Gecko bug: Async 'transform' animations of "
"aFrames with SVG transforms is not supported. See bug 779599");
AnimationCollection::LogAsyncAnimationFailure(message, aContent);
}
return false;
}
return true;
}
/* static */ bool
KeyframeEffectReadOnly::CanAnimatePropertyOnCompositor(
const nsIFrame* aFrame,
nsCSSProperty aProperty)
{
bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
if (IsGeometricProperty(aProperty)) {
if (shouldLog) {
nsCString message;
message.AppendLiteral("Performance warning: Async animation of "
"'transform' or 'opacity' not possible due to animation of geometric"
"properties on the same element");
AnimationCollection::LogAsyncAnimationFailure(message,
aFrame->GetContent());
}
return false;
}
if (aProperty == eCSSProperty_transform) {
if (!CanAnimateTransformOnCompositor(aFrame,
shouldLog ? aFrame->GetContent() : nullptr)) {
return false;
}
}
return true;
}
} // namespace dom
} // namespace mozilla
+33
View File
@@ -25,9 +25,14 @@
struct JSContext;
class nsCSSPropertySet;
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsPresContext;
namespace mozilla {
struct AnimationCollection;
class AnimValuesStyleRule;
namespace dom {
@@ -266,9 +271,22 @@ public:
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties);
// Returns true if |aProperty| is currently being animated on compositor.
bool IsPropertyRunningOnCompositor(nsCSSProperty aProperty) const;
// Returns true if at least one property is being animated on compositor.
bool IsRunningOnCompositor() const;
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
bool CanThrottle() const;
// Returns true |aProperty| can be run on compositor for |aFrame|.
static bool CanAnimatePropertyOnCompositor(const nsIFrame* aFrame,
nsCSSProperty aProperty);
nsIDocument* GetRenderedDocument() const;
nsPresContext* GetPresContext() const;
inline AnimationCollection* GetCollection() const;
protected:
virtual ~KeyframeEffectReadOnly();
void ResetIsRunningOnCompositor();
@@ -300,6 +318,21 @@ protected:
// restyle is performed, this member may temporarily become false even if
// the animation remains on the layer after the restyle.
bool mIsPropertyRunningOnCompositor[LayerAnimationInfo::kRecords];
private:
nsIFrame* GetAnimationFrame() const;
bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
// Returns true unless Gecko limitations prevent performing transform
// animations for |aFrame|. Any limitations that are encountered are
// logged using |aContent| to describe the affected content.
// If |aContent| is nullptr, no logging is performed
static bool CanAnimateTransformOnCompositor(const nsIFrame* aFrame,
const nsIContent* aContent);
static bool IsGeometricProperty(const nsCSSProperty aProperty);
static const TimeDuration OverflowRegionRefreshInterval();
};
} // namespace dom
+1 -1
View File
@@ -10,4 +10,4 @@
* designed to be used as input to the C preprocessor *only*.
*/
DOCUMENT_WARNING(WillChangeBudget)
DOCUMENT_WARNING(IgnoringWillChangeOverBudget)
+7
View File
@@ -3288,6 +3288,13 @@ GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
return JS_GetErrorPrototype(aCx);
}
inline
JSObject*
GetIteratorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
{
return JS_GetIteratorPrototype(aCx);
}
// Resolve an id on the given global object that wants to be included in
// Exposed=System webidl annotations. False return value means exception
// thrown.
+18
View File
@@ -580,6 +580,8 @@ def InterfacePrototypeObjectProtoGetter(descriptor):
protoGetter = "JS_GetArrayPrototype"
elif descriptor.interface.getExtendedAttribute("ExceptionClass"):
protoGetter = "GetErrorPrototype"
elif descriptor.interface.isIteratorInterface():
protoGetter = "GetIteratorPrototype"
else:
protoGetter = "JS_GetObjectPrototype"
protoHandleGetter = None
@@ -2259,6 +2261,22 @@ class MethodDefiner(PropertyDefiner):
"condition": MemberCondition(None, None)
})
# Output an @@iterator for generated iterator interfaces. This should
# not be necessary, but
# https://bugzilla.mozilla.org/show_bug.cgi?id=1091945 means that
# %IteratorPrototype%[@@iterator] is a broken puppy.
if (not static and
not unforgeable and
descriptor.interface.isIteratorInterface()):
self.regular.append({
"name": "@@iterator",
"methodInfo": False,
"selfHostedName": "IteratorIdentity",
"length": 0,
"flags": "0",
"condition": MemberCondition(None, None)
})
# Generate the maplike/setlike iterator, if one wasn't already
# generated by a method. If we already have an @@iterator symbol, fail.
if descriptor.interface.maplikeOrSetlikeOrIterable:
+22
View File
@@ -50,6 +50,9 @@
info("IterableSingle: Testing simple iterable creation and functionality");
itr = new TestInterfaceIterableSingle();
testExistence("IterableSingle: ", itr, base_properties);
var keys = [...itr.keys()];
var values = [...itr.values()];
var entries = [...itr.entries()];
var key_itr = itr.keys();
var value_itr = itr.values();
var entries_itr = itr.entries();
@@ -58,9 +61,17 @@
var value = value_itr.next();
var entry = entries_itr.next();
is(key.value, i, "IterableSingle: Key iterator value should be " + i);
is(key.value, keys[i],
"IterableSingle: Key iterator value should match destructuring " + i);
is(value.value, key.value, "IterableSingle: Value iterator value should be " + key.value);
is(value.value, values[i],
"IterableSingle: Value iterator value should match destructuring " + i);
is(entry.value[0], i, "IterableSingle: Entry iterator value 0 should be " + i);
is(entry.value[1], i, "IterableSingle: Entry iterator value 1 should be " + i);
is(entry.value[0], entries[i][0],
"IterableSingle: Entry iterator value 0 should match destructuring " + i);
is(entry.value[1], entries[i][1],
"IterableSingle: Entry iterator value 1 should match destructuring " + i);
}
var key = key_itr.next();
var value = value_itr.next();
@@ -80,6 +91,9 @@
itr = new TestInterfaceIterableDouble();
testExistence("IterableDouble: ", itr, base_properties);
var elements = [["a", "b"], ["c", "d"], ["e", "f"]]
var keys = [...itr.keys()];
var values = [...itr.values()];
var entries = [...itr.entries()];
var key_itr = itr.keys();
var value_itr = itr.values();
var entries_itr = itr.entries();
@@ -88,9 +102,17 @@
var value = value_itr.next();
var entry = entries_itr.next();
is(key.value, elements[i][0], "IterableDouble: Key iterator value should be " + elements[i][0]);
is(key.value, keys[i],
"IterableDouble: Key iterator value should match destructuring " + i);
is(value.value, elements[i][1], "IterableDouble: Value iterator value should be " + elements[i][1]);
is(value.value, values[i],
"IterableDouble: Value iterator value should match destructuring " + i);
is(entry.value[0], elements[i][0], "IterableDouble: Entry iterator value 0 should be " + elements[i][0]);
is(entry.value[1], elements[i][1], "IterableDouble: Entry iterator value 1 should be " + elements[i][1]);
is(entry.value[0], entries[i][0],
"IterableDouble: Entry iterator value 0 should match destructuring " + i);
is(entry.value[1], entries[i][1],
"IterableDouble: Entry iterator value 1 should match destructuring " + i);
}
var key = key_itr.next();
var value = value_itr.next();
+2 -2
View File
@@ -160,8 +160,8 @@ ImportXULIntoContentWarning=Importing XUL nodes into a content document is depre
XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead.
# LOCALIZATION NOTE: Do not translate "IndexedDB".
IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation.
# LOCALIZATION NOTE (WillChangeBudgetWarning): Do not translate Will-change, %1$S,%2$S,%3$S are numbers.
WillChangeBudgetWarning=Will-change memory consumption is too high. Surface area covers %1$S pixels, budget is the document surface area multiplied by %2$S (%3$S pixels). Occurences of will-change over the budget will be ignored.
# LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S are numbers.
IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. Budget limit is the document surface area multiplied by %1$S (%2$S px). Occurrences of will-change over the budget will be ignored.
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed.
# LOCALIZATION NOTE: Do not translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor"
@@ -169,3 +169,4 @@ PEExpectedVariableNameEOF=identifier for variable name
PEExpectedVariableName=Expected identifier for variable name but found '%1$S'.
PEExpectedVariableFallback=Expected variable reference fallback after ','.
PEExpectedVariableCommaOrCloseParen=Expected ',' or ')' after variable name in variable reference but found '%1$S'.
PESubgridNotSupported=Support for the 'subgrid' keyword of CSS Grid is not enabled.
+7 -3
View File
@@ -617,7 +617,7 @@ void
MediaFormatReader::NotifyError(TrackType aTrack)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("Decoder has requested more %s data", TrackTypeToStr(aTrack));
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
auto& decoder = GetDecoderData(aTrack);
decoder.mError = true;
ScheduleUpdate(aTrack);
@@ -636,7 +636,6 @@ void
MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
auto& decoder = GetDecoderData(aTrack);
decoder.mDemuxEOS = true;
decoder.mNeedDraining = true;
@@ -792,6 +791,8 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
return;
}
LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
// Decode all our demuxed frames.
bool samplesPending = false;
while (decoder.mQueuedSamples.Length()) {
@@ -1269,6 +1270,7 @@ MediaFormatReader::Seek(int64_t aTime, int64_t aUnused)
MOZ_ASSERT(OnTaskQueue());
LOG("aTime=(%lld)", aTime);
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise());
@@ -1321,7 +1323,7 @@ void
MediaFormatReader::OnSeekFailed(TrackType aTrack, DemuxerFailureReason aResult)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("%s failure = %d", TrackTypeToStr(aTrack), aResult);
LOGV("%s failure:%d", TrackTypeToStr(aTrack), aResult);
if (aTrack == TrackType::kVideoTrack) {
mVideo.mSeekRequest.Complete();
} else {
@@ -1381,6 +1383,7 @@ void
MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("Video seeked to %lld", aTime.ToMicroseconds());
mVideo.mSeekRequest.Complete();
if (HasAudio()) {
@@ -1409,6 +1412,7 @@ void
MediaFormatReader::OnAudioSeekCompleted(media::TimeUnit aTime)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("Audio seeked to %lld", aTime.ToMicroseconds());
mAudio.mSeekRequest.Complete();
mPendingSeekTime.reset();
mSeekPromise.Resolve(aTime.ToMicroseconds(), __func__);
+20 -38
View File
@@ -798,17 +798,6 @@ public:
}
}
// let us intervene for direct listeners when someone does track.enabled = false
virtual void SetTrackEnabled(TrackID aTrackID, bool aEnabled) override
{
// We encapsulate the SourceMediaStream and TrackUnion into one entity, so
// we can handle the disabling at the SourceMediaStream
// We need to find the input track ID for output ID aTrackID, so we let the TrackUnion
// forward the request to the source and translate the ID
GetInputStream()->AsProcessedStream()->ForwardTrackEnabled(aTrackID, aEnabled);
}
virtual DOMLocalMediaStream* AsDOMLocalMediaStream() override
{
return this;
@@ -1495,7 +1484,6 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId,
MediaManager::MediaManager()
: mMediaThread(nullptr)
, mMutex("mozilla::MediaManager")
, mBackend(nullptr) {
mPrefs.mFreq = 1000; // 1KHz test tone
mPrefs.mWidth = 0; // adaptive default
@@ -1898,7 +1886,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
(!privileged && !HostHasPermission(*docURI))) {
RefPtr<MediaStreamError> error =
new MediaStreamError(aWindow,
NS_LITERAL_STRING("PermissionDeniedError"));
NS_LITERAL_STRING("SecurityError"));
onFailure->OnError(error);
return NS_OK;
}
@@ -1930,12 +1918,12 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
if (!privileged) {
// only allow privileged content to set the window id
if (vc.mBrowserWindow.WasPassed()) {
vc.mBrowserWindow.Construct(-1);
vc.mBrowserWindow.Value() = -1;
}
if (vc.mAdvanced.WasPassed()) {
for (MediaTrackConstraintSet& cs : vc.mAdvanced.Value()) {
if (cs.mBrowserWindow.WasPassed()) {
cs.mBrowserWindow.Construct(-1);
cs.mBrowserWindow.Value() = -1;
}
}
}
@@ -1973,7 +1961,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
if (!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) {
RefPtr<MediaStreamError> error =
new MediaStreamError(aWindow,
NS_LITERAL_STRING("PermissionDeniedError"));
NS_LITERAL_STRING("SecurityError"));
onFailure->OnError(error);
return NS_OK;
}
@@ -2033,7 +2021,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) &&
(!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) {
RefPtr<MediaStreamError> error =
new MediaStreamError(aWindow, NS_LITERAL_STRING("PermissionDeniedError"));
new MediaStreamError(aWindow, NS_LITERAL_STRING("SecurityError"));
onFailure->OnError(error);
RemoveFromWindowList(windowID, listener);
return NS_OK;
@@ -2385,10 +2373,10 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
MediaEngine*
MediaManager::GetBackend(uint64_t aWindowId)
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
// Plugin backends as appropriate. The default engine also currently
// includes picture support for Android.
// This IS called off main-thread.
MutexAutoLock lock(mMutex);
if (!mBackend) {
MOZ_RELEASE_ASSERT(!sInShutdown); // we should never create a new backend in shutdown
#if defined(MOZ_WEBRTC)
@@ -2585,12 +2573,6 @@ MediaManager::Shutdown()
GetActiveWindows()->Clear();
mActiveCallbacks.Clear();
mCallIds.Clear();
{
MutexAutoLock lock(mMutex);
if (mBackend) {
mBackend->Shutdown(); // ok to invoke multiple times
}
}
// Because mMediaThread is not an nsThread, we must dispatch to it so it can
// clean up BackgroundChild. Continue stopping thread once this is done.
@@ -2598,26 +2580,32 @@ MediaManager::Shutdown()
class ShutdownTask : public Task
{
public:
ShutdownTask(already_AddRefed<MediaEngine> aBackend,
ShutdownTask(MediaManager* aManager,
nsRunnable* aReply)
: mReply(aReply)
, mBackend(aBackend) {}
: mManager(aManager)
, mReply(aReply) {}
private:
virtual void
Run()
{
LOG(("MediaManager Thread Shutdown"));
MOZ_ASSERT(MediaManager::IsInMediaThread());
// Must shutdown backend on MediaManager thread, since that's where we started it from!
{
if (mManager->mBackend) {
mManager->mBackend->Shutdown(); // ok to invoke multiple times
}
}
mozilla::ipc::BackgroundChild::CloseForCurrentThread();
// must explicitly do this before dispatching the reply, since the reply may kill us with Stop()
mBackend = nullptr; // last reference, will invoke Shutdown() again
mManager->mBackend = nullptr; // last reference, will invoke Shutdown() again
if (NS_FAILED(NS_DispatchToMainThread(mReply.forget()))) {
LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown"));
}
}
RefPtr<MediaManager> mManager;
RefPtr<nsRunnable> mReply;
RefPtr<MediaEngine> mBackend;
};
// Post ShutdownTask to execute on mMediaThread and pass in a lambda
@@ -2630,14 +2618,8 @@ MediaManager::Shutdown()
// note that this == sSingleton
RefPtr<MediaManager> that(sSingleton);
// Release the backend (and call Shutdown()) from within the MediaManager thread
RefPtr<MediaEngine> temp;
{
MutexAutoLock lock(mMutex);
temp = mBackend.forget();
}
// Don't use MediaManager::PostTask() because we're sInShutdown=true here!
mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(
temp.forget(),
mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(this,
media::NewRunnableFrom([this, that]() mutable {
LOG(("MediaManager shutdown lambda running, releasing MediaManager singleton and thread"));
if (mMediaThread) {
@@ -2700,7 +2682,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
array->Count(&len);
if (!len) {
// neither audio nor video were selected
task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
task->Denied(NS_LITERAL_STRING("SecurityError"));
return NS_OK;
}
bool videoFound = false, audioFound = false;
@@ -2737,7 +2719,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
} else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
nsString errorMessage(NS_LITERAL_STRING("PermissionDeniedError"));
nsString errorMessage(NS_LITERAL_STRING("SecurityError"));
if (aSubject) {
nsCOMPtr<nsISupportsString> msg(do_QueryInterface(aSubject));
+1 -2
View File
@@ -533,8 +533,7 @@ private:
nsAutoPtr<base::Thread> mMediaThread;
nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
Mutex mMutex;
// protected with mMutex:
// ONLY accessed from MediaManagerThread
RefPtr<MediaEngine> mBackend;
static StaticRefPtr<MediaManager> sSingleton;
+1 -1
View File
@@ -230,7 +230,7 @@ MediaPermissionRequest::Cancel()
{
nsString callID;
mRequest->GetCallID(callID);
NotifyPermissionDeny(callID, NS_LITERAL_STRING("PermissionDeniedError"));
NotifyPermissionDeny(callID, NS_LITERAL_STRING("SecurityError"));
return NS_OK;
}
+2 -2
View File
@@ -20,8 +20,8 @@ BaseMediaMgrError::BaseMediaMgrError(const nsAString& aName,
if (mMessage.IsEmpty()) {
if (mName.EqualsLiteral("NotFoundError")) {
mMessage.AssignLiteral("The object can not be found here.");
} else if (mName.EqualsLiteral("PermissionDeniedError")) {
mMessage.AssignLiteral("The user did not grant permission for the operation.");
} else if (mName.EqualsLiteral("SecurityError")) {
mMessage.AssignLiteral("The operation is insecure.");
} else if (mName.EqualsLiteral("SourceUnavailableError")) {
mMessage.AssignLiteral("The source of the MediaStream could not be "
"accessed due to a hardware error (e.g. lock from another process).");
-5
View File
@@ -1112,11 +1112,6 @@ public:
virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) = 0;
void SetAutofinishImpl(bool aAutofinish) { mAutofinish = aAutofinish; }
/**
* Forward SetTrackEnabled() to the input MediaStream(s) and translate the ID
*/
virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) {};
// Only valid after MediaStreamGraphImpl::UpdateStreamOrder() has run.
// A DelayNode is considered to break a cycle and so this will not return
// true for echo loops, only for muted cycles.
-12
View File
@@ -149,18 +149,6 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
}
}
// Forward SetTrackEnabled(output_track_id, enabled) to the Source MediaStream,
// translating the output track ID into the correct ID in the source.
void TrackUnionStream::ForwardTrackEnabled(TrackID aOutputID, bool aEnabled)
{
for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) {
if (mTrackMap[i].mOutputTrackID == aOutputID) {
mTrackMap[i].mInputPort->GetSource()->
SetTrackEnabled(mTrackMap[i].mInputTrackID, aEnabled);
}
}
}
uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
GraphTime aFrom)
{
-4
View File
@@ -21,10 +21,6 @@ public:
virtual void RemoveInput(MediaInputPort* aPort) override;
virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
// Forward SetTrackEnabled(output_track_id, enabled) to the Source MediaStream,
// translating the output track ID into the correct ID in the source.
virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) override;
protected:
// Only non-ended tracks are allowed to persist in this map.
struct TrackMapEntry {
+2 -1
View File
@@ -13,6 +13,7 @@
#include "nsContentTypeParser.h"
#include "VideoUtils.h"
#include "mozilla/Logging.h"
#include "nsMimeTypes.h"
#ifdef XP_WIN
#include "mozilla/WindowsVersion.h"
@@ -112,7 +113,7 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
return false;
}
#ifdef MOZ_GONK_MEDIACODEC
#ifdef MOZ_GONK_MEDIACODEC
if (aMIMETypeExcludingCodecs.EqualsASCII(VIDEO_3GPP)) {
return Preferences::GetBool("media.gonk.enabled", false);
}
@@ -29,16 +29,16 @@ var tests = [
error: null },
{ message: "full screensharing requires permission",
constraints: { video: { mediaSource: 'screen' } },
error: "PermissionDeniedError" },
error: "SecurityError" },
{ message: "application screensharing requires permission",
constraints: { video: { mediaSource: 'application' } },
error: "PermissionDeniedError" },
error: "SecurityError" },
{ message: "window screensharing requires permission",
constraints: { video: { mediaSource: 'window' } },
error: "PermissionDeniedError" },
error: "SecurityError" },
{ message: "browser screensharing requires permission",
constraints: { video: { mediaSource: 'browser' } },
error: "PermissionDeniedError" },
error: "SecurityError" },
{ message: "unknown mediaSource in video fails",
constraints: { video: { mediaSource: 'uncle' } },
error: "OverconstrainedError",
@@ -72,6 +72,7 @@ skip-if = buildapp == 'mulet'
skip-if = e10s || buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
[test_for_of.html]
[test_frameElementWrapping.html]
[test_pointerPreserves3D.html]
[test_framedhistoryframes.html]
[test_idleapi_permissions.html]
skip-if = e10s || buildapp == 'b2g' || buildapp == 'mulet'
@@ -0,0 +1,25 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for pointer events with preserve-3d</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div>
<div>
<div style="transform-style: preserve-3d; transform: rotateX(90deg);">
<div id="color" style="transform: rotateX(-90deg); display: block; background-color: blue; width: 200px; height: 200px;"></div>
</div>
</div>
</div>
<script class="testbody" type="text/javascript">
function runTest() {
var target = document.elementFromPoint(100, 110);
ok(target == document.getElementById("color"), "Find the right target.");
}
runTest();
</script>
</body>
</html>
+1
View File
@@ -1147,6 +1147,7 @@ public:
static void ShutDown();
static bool HasSSE2();
static bool HasVMX();
/** Make sure that the given dimensions don't overflow a 32-bit signed int
* using 4 bytes per pixel; optionally, make sure that either dimension
+19
View File
@@ -568,14 +568,33 @@ AlphaBoxBlur::Blur(uint8_t* aData)
BoxBlur_NEON(aData, horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0],
verticalLobes[2][1], integralImage, integralImageStride);
} else
#endif
#ifdef USE_VMX
if (Factory::HasVMX()) {
BoxBlur_VMX(aData, horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0],
verticalLobes[0][1], integralImage, integralImageStride);
BoxBlur_VMX(aData, horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0],
verticalLobes[1][1], integralImage, integralImageStride);
BoxBlur_VMX(aData, horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0],
verticalLobes[2][1], integralImage, integralImageStride);
} else
#endif
{
#ifdef _MIPS_ARCH_LOONGSON3A
BoxBlur_LS3(aData, horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0],
verticalLobes[0][1], integralImage, integralImageStride);
BoxBlur_LS3(aData, horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0],
verticalLobes[1][1], integralImage, integralImageStride);
BoxBlur_LS3(aData, horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0],
verticalLobes[2][1], integralImage, integralImageStride);
#else
BoxBlur_C(aData, horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0],
verticalLobes[0][1], integralImage, integralImageStride);
BoxBlur_C(aData, horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0],
verticalLobes[1][1], integralImage, integralImageStride);
BoxBlur_C(aData, horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0],
verticalLobes[2][1], integralImage, integralImageStride);
#endif
}
}
}
+10
View File
@@ -129,6 +129,16 @@ private:
int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe,
int32_t aBottomLobe, uint32_t *aIntegralImage, size_t aIntegralImageStride);
#endif
#ifdef _MIPS_ARCH_LOONGSON3A
void BoxBlur_LS3(uint8_t* aData,
int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe,
int32_t aBottomLobe, uint32_t *aIntegralImage, size_t aIntegralImageStride);
#endif
#ifdef USE_VMX
void BoxBlur_VMX(uint8_t* aData,
int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe,
int32_t aBottomLobe, uint32_t *aIntegralImage, size_t aIntegralImageStride);
#endif
static CheckedInt<int32_t> RoundUpToMultipleOf4(int32_t aVal);
+588
View File
@@ -0,0 +1,588 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Blur.h"
#include <string.h>
#ifdef _MIPS_ARCH_LOONGSON3A
#include "MMIHelpers.h"
namespace mozilla {
namespace gfx {
typedef struct { double l; double h; } __m128i;
MOZ_ALWAYS_INLINE
__m128i loadUnaligned128(__m128i *p)
{
__m128i v;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"gsldlc1 %[vh], 0xf(%[p]) \n\t"
"gsldrc1 %[vh], 0x8(%[p]) \n\t"
"gsldlc1 %[vl], 0x7(%[p]) \n\t"
"gsldrc1 %[vl], 0x0(%[p]) \n\t"
".set pop \n\t"
:[vh]"=f"(v.h), [vl]"=f"(v.l)
:[p]"r"(p)
:"memory"
);
return v;
}
MOZ_ALWAYS_INLINE
__m128i Divide(__m128i aValues, __m128i aDivisor)
{
uint64_t tmp;
double srl32;
__m128i mask, ra, p4321, t1, t2;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"li %[tmp], 0x80000000 \n\t"
"mtc1 %[tmp], %[ral] \n\t"
"xor %[maskl], %[maskl], %[maskl] \n\t"
"mov.d %[rah], %[ral] \n\t"
"li %[tmp], 0xffffffff \n\t"
"mthc1 %[tmp], %[maskl] \n\t"
"mov.d %[maskh], %[maskl] \n\t"
".set pop \n\t"
:[rah]"=f"(ra.h), [ral]"=f"(ra.l),
[maskh]"=f"(mask.h), [maskl]"=f"(mask.l),
[tmp]"=&r"(tmp)
);
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"ori %[tmp], $0, 32 \n\t"
"mtc1 %[tmp], %[srl32] \n\t"
_mm_pmuluw(t1, av, ad)
_mm_psrld(t2, av, srl32)
_mm_pmuluw(t2, t2, ad)
// Add 1 << 31 before shifting or masking the lower 32 bits away, so that the
// result is rounded.
_mm_paddd(t1, t1, ra)
_mm_psrld(t1, t1, srl32)
_mm_paddd(t2, t2, ra)
_mm_and(t2, t2, mask)
_mm_or(p4321, t1, t2)
".set pop \n\t"
:[p4321h]"=&f"(p4321.h), [p4321l]"=&f"(p4321.l),
[t1h]"=&f"(t1.h), [t1l]"=&f"(t1.l),
[t2h]"=&f"(t2.h), [t2l]"=&f"(t2.l),
[srl32]"=&f"(srl32), [tmp]"=&r"(tmp)
:[rah]"f"(ra.h), [ral]"f"(ra.l),
[maskh]"f"(mask.h), [maskl]"f"(mask.l),
[avh]"f"(aValues.h), [avl]"f"(aValues.l),
[adh]"f"(aDivisor.h), [adl]"f"(aDivisor.l)
);
return p4321;
}
MOZ_ALWAYS_INLINE
__m128i BlurFourPixels(const __m128i& aTopLeft, const __m128i& aTopRight,
const __m128i& aBottomRight, const __m128i& aBottomLeft,
const __m128i& aDivisor)
{
__m128i values;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_psubw(val, abr, atr)
_mm_psubw(val, val, abl)
_mm_paddw(val, val, atl)
".set pop \n\t"
:[valh]"=&f"(values.h), [vall]"=&f"(values.l)
:[abrh]"f"(aBottomRight.h), [abrl]"f"(aBottomRight.l),
[atrh]"f"(aTopRight.h), [atrl]"f"(aTopRight.l),
[ablh]"f"(aBottomLeft.h), [abll]"f"(aBottomLeft.l),
[atlh]"f"(aTopLeft.h), [atll]"f"(aTopLeft.l)
);
return Divide(values, aDivisor);
}
MOZ_ALWAYS_INLINE
void LoadIntegralRowFromRow(uint32_t *aDest, const uint8_t *aSource,
int32_t aSourceWidth, int32_t aLeftInflation,
int32_t aRightInflation)
{
int32_t currentRowSum = 0;
for (int x = 0; x < aLeftInflation; x++) {
currentRowSum += aSource[0];
aDest[x] = currentRowSum;
}
for (int x = aLeftInflation; x < (aSourceWidth + aLeftInflation); x++) {
currentRowSum += aSource[(x - aLeftInflation)];
aDest[x] = currentRowSum;
}
for (int x = (aSourceWidth + aLeftInflation); x < (aSourceWidth + aLeftInflation + aRightInflation); x++) {
currentRowSum += aSource[aSourceWidth - 1];
aDest[x] = currentRowSum;
}
}
// This function calculates an integral of four pixels stored in the 4
// 32-bit integers on aPixels. i.e. for { 30, 50, 80, 100 } this returns
// { 30, 80, 160, 260 }. This seems to be the fastest way to do this after
// much testing.
MOZ_ALWAYS_INLINE
__m128i AccumulatePixelSums(__m128i aPixels)
{
uint64_t tr;
double tmp, s4, s64;
__m128i sumPixels, currentPixels, zero;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_xor(z, z, z)
"li %[tr], 64 \n\t"
"mtc1 %[tr], %[s64] \n\t"
"li %[tr], 32 \n\t"
"mtc1 %[tr], %[s4] \n\t"
_mm_psllq(cp, ap, s4, s64, t)
_mm_paddw(sp, ap, cp)
_mm_punpckldq(cp, z, sp)
_mm_paddw(sp, sp, cp)
".set pop \n\t"
:[sph]"=&f"(sumPixels.h), [spl]"=&f"(sumPixels.l),
[cph]"=&f"(currentPixels.h), [cpl]"=&f"(currentPixels.l),
[zh]"=&f"(zero.h), [zl]"=&f"(zero.l),
[s4]"=&f"(s4), [s64]"=&f"(s64), [t]"=&f"(tmp), [tr]"=&r"(tr)
:[aph]"f"(aPixels.h), [apl]"f"(aPixels.l)
);
return sumPixels;
}
MOZ_ALWAYS_INLINE
void GenerateIntegralImage_LS3(int32_t aLeftInflation, int32_t aRightInflation,
int32_t aTopInflation, int32_t aBottomInflation,
uint32_t *aIntegralImage, size_t aIntegralImageStride,
uint8_t *aSource, int32_t aSourceStride, const IntSize &aSize)
{
MOZ_ASSERT(!(aLeftInflation & 3));
uint32_t stride32bit = aIntegralImageStride / 4;
IntSize integralImageSize(aSize.width + aLeftInflation + aRightInflation,
aSize.height + aTopInflation + aBottomInflation);
LoadIntegralRowFromRow(aIntegralImage, aSource, aSize.width, aLeftInflation, aRightInflation);
for (int y = 1; y < aTopInflation + 1; y++) {
uint32_t *intRow = aIntegralImage + (y * stride32bit);
uint32_t *intPrevRow = aIntegralImage + (y - 1) * stride32bit;
uint32_t *intFirstRow = aIntegralImage;
for (int x = 0; x < integralImageSize.width; x += 4) {
__m128i firstRow, previousRow;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"gslqc1 %[frh], %[frl], (%[fr]) \n\t"
"gslqc1 %[prh], %[prl], (%[pr]) \n\t"
_mm_paddw(fr, fr, pr)
"gssqc1 %[frh], %[frl], (%[r]) \n\t"
".set pop \n\t"
:[frh]"=&f"(firstRow.h), [frl]"=&f"(firstRow.l),
[prh]"=&f"(previousRow.h), [prl]"=&f"(previousRow.l)
:[fr]"r"(intFirstRow + x), [pr]"r"(intPrevRow + x),
[r]"r"(intRow + x)
:"memory"
);
}
}
uint64_t tmp;
double s44, see;
__m128i zero;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"li %[tmp], 0xee \n\t"
"mtc1 %[tmp], %[see] \n\t"
"li %[tmp], 0x44 \n\t"
"mtc1 %[tmp], %[s44] \n\t"
_mm_xor(zero, zero, zero)
".set pop \n\t"
:[tmp]"=&r"(tmp), [s44]"=f"(s44), [see]"=f"(see),
[zeroh]"=f"(zero.h), [zerol]"=f"(zero.l)
);
for (int y = aTopInflation + 1; y < (aSize.height + aTopInflation); y++) {
__m128i currentRowSum;
uint32_t *intRow = aIntegralImage + (y * stride32bit);
uint32_t *intPrevRow = aIntegralImage + (y - 1) * stride32bit;
uint8_t *sourceRow = aSource + aSourceStride * (y - aTopInflation);
uint32_t pixel = sourceRow[0];
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_xor(cr, cr, cr)
".set pop \n\t"
:[crh]"=f"(currentRowSum.h), [crl]"=f"(currentRowSum.l)
);
for (int x = 0; x < aLeftInflation; x += 4) {
__m128i sumPixels, t;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"mtc1 %[pix], %[spl] \n\t"
"punpcklwd %[spl], %[spl], %[spl] \n\t"
"mov.d %[sph], %[spl] \n\t"
"pshufh %[sph], %[spl], %[s44] \n\t"
"pshufh %[spl], %[spl], %[s44] \n\t"
".set pop \n\t"
:[sph]"=&f"(sumPixels.h), [spl]"=&f"(sumPixels.l)
:[pix]"r"(pixel), [s44]"f"(s44)
);
sumPixels = AccumulatePixelSums(sumPixels);
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_paddw(sp, sp, cr)
"pshufh %[crh], %[sph], %[see] \n\t"
"pshufh %[crl], %[sph], %[see] \n\t"
"gslqc1 %[th], %[tl], (%[pr]) \n\t"
_mm_paddw(t, sp, t)
"gssqc1 %[th], %[tl], (%[r]) \n\t"
".set pop \n\t"
:[th]"=&f"(t.h), [tl]"=&f"(t.l),
[sph]"+f"(sumPixels.h), [spl]"+f"(sumPixels.l),
[crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
:[r]"r"(intRow + x), [pr]"r"(intPrevRow + x), [see]"f"(see)
:"memory"
);
}
for (int x = aLeftInflation; x < (aSize.width + aLeftInflation); x += 4) {
uint32_t pixels = *(uint32_t*)(sourceRow + (x - aLeftInflation));
__m128i sumPixels, t;
// It's important to shuffle here. When we exit this loop currentRowSum
// has to be set to sumPixels, so that the following loop can get the
// correct pixel for the currentRowSum. The highest order pixel in
// currentRowSum could've originated from accumulation in the stride.
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"pshufh %[crl], %[crh], %[see] \n\t"
"pshufh %[crh], %[crh], %[see] \n\t"
"mtc1 %[pix], %[spl] \n\t"
"punpcklwd %[spl], %[spl], %[spl] \n\t"
"mov.d %[sph], %[spl] \n\t"
_mm_punpcklbh(sp, sp, zero)
_mm_punpcklhw(sp, sp, zero)
".set pop \n\t"
:[sph]"=&f"(sumPixels.h), [spl]"=&f"(sumPixels.l),
[crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
:[pix]"r"(pixels), [see]"f"(see),
[zeroh]"f"(zero.h), [zerol]"f"(zero.l)
);
sumPixels = AccumulatePixelSums(sumPixels);
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_paddw(sp, sp, cr)
"mov.d %[crh], %[sph] \n\t"
"mov.d %[crl], %[spl] \n\t"
"gslqc1 %[th], %[tl], (%[pr]) \n\t"
_mm_paddw(t, sp, t)
"gssqc1 %[th], %[tl], (%[r]) \n\t"
".set pop \n\t"
:[th]"=&f"(t.h), [tl]"=&f"(t.l),
[sph]"+f"(sumPixels.h), [spl]"+f"(sumPixels.l),
[crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
:[r]"r"(intRow + x), [pr]"r"(intPrevRow + x)
:"memory"
);
}
pixel = sourceRow[aSize.width - 1];
int x = (aSize.width + aLeftInflation);
if ((aSize.width & 3)) {
// Deal with unaligned portion. Get the correct pixel from currentRowSum,
// see explanation above.
uint32_t intCurrentRowSum = ((uint32_t*)&currentRowSum)[(aSize.width % 4) - 1];
for (; x < integralImageSize.width; x++) {
// We could be unaligned here!
if (!(x & 3)) {
// aligned!
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"mtc1 %[cr], %[crl] \n\t"
"punpcklwd %[crl], %[crl], %[crl] \n\t"
"mov.d %[crh], %[crl] \n\t"
".set pop \n\t"
:[crh]"=f"(currentRowSum.h), [crl]"=f"(currentRowSum.l)
:[cr]"r"(intCurrentRowSum)
);
break;
}
intCurrentRowSum += pixel;
intRow[x] = intPrevRow[x] + intCurrentRowSum;
}
} else {
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"pshufh %[crl], %[crh], %[see] \n\t"
"pshufh %[crh], %[crh], %[see] \n\t"
".set pop \n\t"
:[crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
:[see]"f"(see)
);
}
for (; x < integralImageSize.width; x += 4) {
__m128i sumPixels, t;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"mtc1 %[pix], %[spl] \n\t"
"punpcklwd %[spl], %[spl], %[spl] \n\t"
"mov.d %[sph], %[spl] \n\t"
".set pop \n\t"
:[sph]"=f"(sumPixels.h), [spl]"=f"(sumPixels.l)
:[pix]"r"(pixel)
);
sumPixels = AccumulatePixelSums(sumPixels);
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_paddw(sp, sp, cr)
"pshufh %[crh], %[sph], %[see] \n\t"
"pshufh %[crl], %[sph], %[see] \n\t"
"gslqc1 %[th], %[tl], (%[pr]) \n\t"
_mm_paddw(t, sp, t)
"gssqc1 %[th], %[tl], (%[r]) \n\t"
".set pop \n\t"
:[th]"=&f"(t.h), [tl]"=&f"(t.l),
[sph]"+f"(sumPixels.h), [spl]"+f"(sumPixels.l),
[crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
:[r]"r"(intRow + x), [pr]"r"(intPrevRow + x), [see]"f"(see)
:"memory"
);
}
}
if (aBottomInflation) {
// Store the last valid row of our source image in the last row of
// our integral image. This will be overwritten with the correct values
// in the upcoming loop.
LoadIntegralRowFromRow(aIntegralImage + (integralImageSize.height - 1) * stride32bit,
aSource + (aSize.height - 1) * aSourceStride, aSize.width, aLeftInflation, aRightInflation);
for (int y = aSize.height + aTopInflation; y < integralImageSize.height; y++) {
__m128i *intRow = (__m128i*)(aIntegralImage + (y * stride32bit));
__m128i *intPrevRow = (__m128i*)(aIntegralImage + (y - 1) * stride32bit);
__m128i *intLastRow = (__m128i*)(aIntegralImage + (integralImageSize.height - 1) * stride32bit);
for (int x = 0; x < integralImageSize.width; x += 4) {
__m128i t1, t2;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"gslqc1 %[t1h], %[t1l], (%[lr]) \n\t"
"gslqc1 %[t2h], %[t2l], (%[pr]) \n\t"
_mm_paddw(t1, t1, t2)
"gssqc1 %[t1h], %[t1l], (%[r]) \n\t"
".set pop \n\t"
:[t1h]"=&f"(t1.h), [t1l]"=&f"(t1.l),
[t2h]"=&f"(t2.h), [t2l]"=&f"(t2.l)
:[r]"r"(intRow + (x / 4)),
[lr]"r"(intLastRow + (x / 4)),
[pr]"r"(intPrevRow + (x / 4))
:"memory"
);
}
}
}
}
/**
* Attempt to do an in-place box blur using an integral image.
*/
void
AlphaBoxBlur::BoxBlur_LS3(uint8_t* aData,
int32_t aLeftLobe,
int32_t aRightLobe,
int32_t aTopLobe,
int32_t aBottomLobe,
uint32_t *aIntegralImage,
size_t aIntegralImageStride)
{
IntSize size = GetSize();
MOZ_ASSERT(size.height > 0);
// Our 'left' or 'top' lobe will include the current pixel. i.e. when
// looking at an integral image the value of a pixel at 'x,y' is calculated
// using the value of the integral image values above/below that.
aLeftLobe++;
aTopLobe++;
int32_t boxSize = (aLeftLobe + aRightLobe) * (aTopLobe + aBottomLobe);
MOZ_ASSERT(boxSize > 0);
if (boxSize == 1) {
return;
}
uint32_t reciprocal = uint32_t((uint64_t(1) << 32) / boxSize);
uint32_t stride32bit = aIntegralImageStride / 4;
int32_t leftInflation = RoundUpToMultipleOf4(aLeftLobe).value();
GenerateIntegralImage_LS3(leftInflation, aRightLobe, aTopLobe, aBottomLobe,
aIntegralImage, aIntegralImageStride, aData,
mStride, size);
__m128i divisor, zero;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
"mtc1 %[rec], %[divl] \n\t"
"punpcklwd %[divl], %[divl], %[divl] \n\t"
"mov.d %[divh], %[divl] \n\t"
_mm_xor(zero, zero, zero)
".set pop \n\t"
:[divh]"=f"(divisor.h), [divl]"=f"(divisor.l),
[zeroh]"=f"(zero.h), [zerol]"=f"(zero.l)
:[rec]"r"(reciprocal)
);
// This points to the start of the rectangle within the IntegralImage that overlaps
// the surface being blurred.
uint32_t *innerIntegral = aIntegralImage + (aTopLobe * stride32bit) + leftInflation;
IntRect skipRect = mSkipRect;
int32_t stride = mStride;
uint8_t *data = aData;
for (int32_t y = 0; y < size.height; y++) {
bool inSkipRectY = y > skipRect.y && y < skipRect.YMost();
uint32_t *topLeftBase = innerIntegral + ((y - aTopLobe) * ptrdiff_t(stride32bit) - aLeftLobe);
uint32_t *topRightBase = innerIntegral + ((y - aTopLobe) * ptrdiff_t(stride32bit) + aRightLobe);
uint32_t *bottomRightBase = innerIntegral + ((y + aBottomLobe) * ptrdiff_t(stride32bit) + aRightLobe);
uint32_t *bottomLeftBase = innerIntegral + ((y + aBottomLobe) * ptrdiff_t(stride32bit) - aLeftLobe);
int32_t x = 0;
// Process 16 pixels at a time for as long as possible.
for (; x <= size.width - 16; x += 16) {
if (inSkipRectY && x > skipRect.x && x < skipRect.XMost()) {
x = skipRect.XMost() - 16;
// Trigger early jump on coming loop iterations, this will be reset
// next line anyway.
inSkipRectY = false;
continue;
}
__m128i topLeft;
__m128i topRight;
__m128i bottomRight;
__m128i bottomLeft;
topLeft = loadUnaligned128((__m128i*)(topLeftBase + x));
topRight = loadUnaligned128((__m128i*)(topRightBase + x));
bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x));
bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x));
__m128i result1 = BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
topLeft = loadUnaligned128((__m128i*)(topLeftBase + x + 4));
topRight = loadUnaligned128((__m128i*)(topRightBase + x + 4));
bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x + 4));
bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x + 4));
__m128i result2 = BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
topLeft = loadUnaligned128((__m128i*)(topLeftBase + x + 8));
topRight = loadUnaligned128((__m128i*)(topRightBase + x + 8));
bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x + 8));
bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x + 8));
__m128i result3 = BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
topLeft = loadUnaligned128((__m128i*)(topLeftBase + x + 12));
topRight = loadUnaligned128((__m128i*)(topRightBase + x + 12));
bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x + 12));
bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x + 12));
__m128i result4 = BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
double t;
__m128i final;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_packsswh(r3, r3, r4, t)
_mm_packsswh(f, r1, r2, t)
_mm_packushb(f, f, r3, t)
"gssdlc1 %[fh], 0xf(%[d]) \n\t"
"gssdrc1 %[fh], 0x8(%[d]) \n\t"
"gssdlc1 %[fl], 0x7(%[d]) \n\t"
"gssdrc1 %[fl], 0x0(%[d]) \n\t"
".set pop \n\t"
:[fh]"=&f"(final.h), [fl]"=&f"(final.l),
[r3h]"+f"(result3.h), [r3l]"+f"(result3.l),
[t]"=&f"(t)
:[r1h]"f"(result1.h), [r1l]"f"(result1.l),
[r2h]"f"(result2.h), [r2l]"f"(result2.l),
[r4h]"f"(result4.h), [r4l]"f"(result4.l),
[d]"r"(data + stride * y + x)
:"memory"
);
}
// Process the remaining pixels 4 bytes at a time.
for (; x < size.width; x += 4) {
if (inSkipRectY && x > skipRect.x && x < skipRect.XMost()) {
x = skipRect.XMost() - 4;
// Trigger early jump on coming loop iterations, this will be reset
// next line anyway.
inSkipRectY = false;
continue;
}
__m128i topLeft = loadUnaligned128((__m128i*)(topLeftBase + x));
__m128i topRight = loadUnaligned128((__m128i*)(topRightBase + x));
__m128i bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x));
__m128i bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x));
__m128i result = BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
double t;
__m128i final;
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
_mm_packsswh(f, r, zero, t)
_mm_packushb(f, f, zero, t)
"swc1 %[fl], (%[d]) \n\t"
".set pop \n\t"
:[fh]"=&f"(final.h), [fl]"=&f"(final.l),
[t]"=&f"(t)
:[d]"r"(data + stride * y + x),
[rh]"f"(result.h), [rl]"f"(result.l),
[zeroh]"f"(zero.h), [zerol]"f"(zero.l)
:"memory"
);
}
}
}
}
}
#endif /* _MIPS_ARCH_LOONGSON3A */
+1
View File
@@ -1940,6 +1940,7 @@ DrawTargetCG::Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aDrawOptions)
{
MOZ_CRASH("not completely implemented");
MarkChanged();
CGContextSaveGState(mCg);
+26 -36
View File
@@ -254,8 +254,9 @@ DrawTargetD2D1::ClearRect(const Rect &aRect)
return;
}
mDC->SetTarget(mTempBitmap);
mDC->Clear();
RefPtr<ID2D1CommandList> list;
mDC->CreateCommandList(getter_AddRefs(list));
mDC->SetTarget(list);
IntRect addClipRect;
RefPtr<ID2D1Geometry> geom = GetClippedGeometry(&addClipRect);
@@ -267,7 +268,9 @@ DrawTargetD2D1::ClearRect(const Rect &aRect)
mDC->PopAxisAlignedClip();
mDC->SetTarget(mBitmap);
mDC->DrawImage(mTempBitmap, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT);
list->Close();
mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT);
PopClip();
@@ -284,7 +287,12 @@ DrawTargetD2D1::MaskSurface(const Pattern &aSource,
RefPtr<ID2D1Bitmap> bitmap;
RefPtr<ID2D1Image> image = GetImageForSurface(aMask, ExtendMode::CLAMP);
Matrix mat = Matrix::Translation(aOffset);
RefPtr<ID2D1Image> image = GetImageForSurface(aMask, mat, ExtendMode::CLAMP, nullptr);
MOZ_ASSERT(!mat.HasNonTranslation());
aOffset.x = mat._31;
aOffset.y = mat._32;
if (!image) {
gfxWarning() << "Failed to get image for surface.";
@@ -296,14 +304,16 @@ DrawTargetD2D1::MaskSurface(const Pattern &aSource,
// FillOpacityMask only works if the antialias mode is MODE_ALIASED
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
IntSize size = aMask->GetSize();
Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
image->QueryInterface((ID2D1Bitmap**)&bitmap);
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
if (!bitmap) {
gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces.";
return;
}
IntSize size = IntSize(bitmap->GetSize().width, bitmap->GetSize().height);
Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
@@ -854,18 +864,8 @@ DrawTargetD2D1::Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat)
mFormat = aFormat;
D3D11_TEXTURE2D_DESC desc;
aTexture->GetDesc(&desc);
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
mSize.width = desc.Width;
mSize.height = desc.Height;
props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mTempBitmap));
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 2CreateBitmap failure " << mSize << " Code: " << hexa(hr);
return false;
}
// This single solid color brush system is not very 'threadsafe', however,
// issueing multiple drawing commands simultaneously to a single drawtarget
@@ -922,16 +922,6 @@ DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
return false;
}
props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
hr = mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mTempBitmap));
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D2D1.1] failed to create new TempBitmap " << aSize << " Code: " << hexa(hr);
return false;
}
mDC->SetTarget(mBitmap);
hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush));
@@ -1038,8 +1028,8 @@ DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
PopAllClips();
mDC->SetTarget(mTempBitmap);
mDC->Clear(D2D1::ColorF(0, 0));
mDC->CreateCommandList(getter_AddRefs(mCommandList));
mDC->SetTarget(mCommandList);
PushAllClips();
FlushTransformToDC();
@@ -1058,10 +1048,11 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
PopAllClips();
RefPtr<ID2D1Image> image;
mDC->GetTarget(getter_AddRefs(image));
mDC->SetTarget(mBitmap);
mCommandList->Close();
RefPtr<ID2D1CommandList> source = mCommandList;
mCommandList = nullptr;
mDC->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true;
@@ -1089,7 +1080,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
} else {
PushAllClips();
}
mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
mDC->DrawImage(source, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
if (tmpBitmap) {
RefPtr<ID2D1BitmapBrush> brush;
@@ -1128,7 +1119,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
mBlendEffect->SetInput(0, tmpBitmap);
mBlendEffect->SetInput(1, mTempBitmap);
mBlendEffect->SetInput(1, source);
mBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
PushAllClips();
@@ -1161,7 +1152,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform));
radialGradientEffect->SetInput(0, image);
radialGradientEffect->SetInput(0, source);
mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
}
@@ -1473,7 +1464,6 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
return CreateTransparentBlackBrush();
}
bool useSamplingRect = false;
if (pat->mSamplingRect.IsEmpty()) {
RefPtr<ID2D1Bitmap> bitmap;
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
+1 -1
View File
@@ -200,7 +200,7 @@ private:
IntRect mCurrentClipBounds;
mutable RefPtr<ID2D1DeviceContext> mDC;
RefPtr<ID2D1Bitmap1> mBitmap;
RefPtr<ID2D1Bitmap1> mTempBitmap;
RefPtr<ID2D1CommandList> mCommandList;
RefPtr<ID2D1Effect> mBlendEffect;
RefPtr<ID2D1SolidColorBrush> mSolidColorBrush;
+11
View File
@@ -241,6 +241,17 @@ Factory::HasSSE2()
#endif
}
bool
Factory::HasVMX()
{
#if (defined(__powerpc__) || defined(__POWERPC__)) \
&& (defined(__ALTIVEC__) || defined(__APPLE_ALTIVEC__))
return true;
#else
return false;
#endif
}
// If the size is "reasonable", we want gfxCriticalError to assert, so
// this is the option set up for it.
inline int LoggerOptionsBasedOnSize(const IntSize& aSize)
+31 -17
View File
@@ -186,8 +186,10 @@ Matrix4x4::TransformBounds(const RectTyped<UnknownUnits, F>& aRect) const
return RectTyped<UnknownUnits, F>(min_x, min_y, max_x - min_x, max_y - min_y);
}
Point4D ComputePerspectivePlaneIntercept(const Point4D& aFirst,
const Point4D& aSecond)
template<class F>
Point4DTyped<UnknownUnits, F>
ComputePerspectivePlaneIntercept(const Point4DTyped<UnknownUnits, F>& aFirst,
const Point4DTyped<UnknownUnits, F>& aSecond)
{
// This function will always return a point with a w value of 0.
// The X, Y, and Z components will point towards an infinite vanishing
@@ -204,7 +206,9 @@ Point4D ComputePerspectivePlaneIntercept(const Point4D& aFirst,
return aFirst + (aSecond - aFirst) * t;
}
Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const
template <class F>
RectTyped<UnknownUnits, F>
Matrix4x4::ProjectRectBounds(const RectTyped<UnknownUnits, F>& aRect, const RectTyped<UnknownUnits, F>& aClip) const
{
// This function must never return std::numeric_limits<Float>::max() or any
// other arbitrary large value in place of inifinity. This often occurs when
@@ -230,26 +234,26 @@ Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const
// Callers should pass an aClip value that represents the extents to clip
// the result to, in the same coordinate system as aRect.
Point4D points[4];
Point4DTyped<UnknownUnits, F> points[4];
points[0] = ProjectPoint(aRect.TopLeft());
points[1] = ProjectPoint(aRect.TopRight());
points[2] = ProjectPoint(aRect.BottomRight());
points[3] = ProjectPoint(aRect.BottomLeft());
Float min_x = std::numeric_limits<Float>::max();
Float min_y = std::numeric_limits<Float>::max();
Float max_x = -std::numeric_limits<Float>::max();
Float max_y = -std::numeric_limits<Float>::max();
F min_x = std::numeric_limits<F>::max();
F min_y = std::numeric_limits<F>::max();
F max_x = -std::numeric_limits<F>::max();
F max_y = -std::numeric_limits<F>::max();
for (int i=0; i<4; i++) {
// Only use points that exist above the w=0 plane
if (points[i].HasPositiveWCoord()) {
Point point2d = aClip.ClampPoint(points[i].As2DPoint());
min_x = std::min<Float>(point2d.x, min_x);
max_x = std::max<Float>(point2d.x, max_x);
min_y = std::min<Float>(point2d.y, min_y);
max_y = std::max<Float>(point2d.y, max_y);
PointTyped<UnknownUnits, F> point2d = aClip.ClampPoint(points[i].As2DPoint());
min_x = std::min<F>(point2d.x, min_x);
max_x = std::max<F>(point2d.x, max_x);
min_y = std::min<F>(point2d.y, min_y);
max_y = std::max<F>(point2d.y, max_y);
}
int next = (i == 3) ? 0 : i + 1;
@@ -257,7 +261,8 @@ Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const
// If the line between two points crosses the w=0 plane, then interpolate
// to find the point of intersection with the w=0 plane and use that
// instead.
Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]);
Point4DTyped<UnknownUnits, F> intercept =
ComputePerspectivePlaneIntercept(points[i], points[next]);
// Since intercept.w will always be 0 here, we interpret x,y,z as a
// direction towards an infinite vanishing point.
if (intercept.x < 0.0f) {
@@ -273,11 +278,11 @@ Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const
}
}
if (max_x <= min_x || max_y <= min_y) {
return Rect(0, 0, 0, 0);
if (max_x < min_x || max_y < min_y) {
return RectTyped<UnknownUnits, F>(0, 0, 0, 0);
}
return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
return RectTyped<UnknownUnits, F>(min_x, min_y, max_x - min_x, max_y - min_y);
}
template<class F>
@@ -638,5 +643,14 @@ template
RectDouble
Matrix4x4::TransformBounds(const RectDouble& aRect) const;
template
Rect
Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect& aClip) const;
template
RectDouble
Matrix4x4::ProjectRectBounds(const RectDouble& aRect, const RectDouble& aClip) const;
} // namespace gfx
} // namespace mozilla
+8 -4
View File
@@ -507,20 +507,24 @@ public:
return *this;
}
Point4D ProjectPoint(const Point& aPoint) const {
template<class F>
Point4DTyped<UnknownUnits, F>
ProjectPoint(const PointTyped<UnknownUnits, F>& aPoint) const {
// Find a value for z that will transform to 0.
// The transformed value of z is computed as:
// z' = aPoint.x * _13 + aPoint.y * _23 + z * _33 + _43;
// Solving for z when z' = 0 gives us:
float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
F z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
// Compute the transformed point
return *this * Point4D(aPoint.x, aPoint.y, z, 1);
return *this * Point4DTyped<UnknownUnits, F>(aPoint.x, aPoint.y, z, 1);
}
Rect ProjectRectBounds(const Rect& aRect, const Rect &aClip) const;
template<class F>
RectTyped<UnknownUnits, F>
ProjectRectBounds(const RectTyped<UnknownUnits, F>& aRect, const RectTyped<UnknownUnits, F>& aClip) const;
/**
* TransformAndClipBounds transforms aRect as a bounding box, while clipping
-1
View File
@@ -7,7 +7,6 @@
#define MOZILLA_GFX_SCALEFACTORS2D_H_
#include <ostream>
#include <iomanip>
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
+2 -2
View File
@@ -19,8 +19,8 @@ class ScaledFontDWrite final : public ScaledFontBase
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite)
ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize)
: mFontFace(aFont)
, ScaledFontBase(aSize)
: ScaledFontBase(aSize)
, mFontFace(aFont)
{}
ScaledFontDWrite(uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
+1 -1
View File
@@ -15,8 +15,8 @@ SourceSurfaceD2D1::SourceSurfaceD2D1(ID2D1Image *aImage, ID2D1DeviceContext *aDC
DrawTargetD2D1 *aDT)
: mImage(aImage)
, mDC(aDC)
, mDrawTarget(aDT)
, mDevice(Factory::GetD2D1Device())
, mDrawTarget(aDT)
{
aImage->QueryInterface((ID2D1Bitmap1**)getter_AddRefs(mRealizedBitmap));
+6 -2
View File
@@ -27,8 +27,12 @@ public:
virtual IntSize GetSize() const { return mA->GetSize(); }
virtual SurfaceFormat GetFormat() const { return mA->GetFormat(); }
/* Readback from this surface type is not supported! */
virtual already_AddRefed<DataSourceSurface> GetDataSurface() { return nullptr; }
// This is implemented for debugging purposes only (used by dumping
// client-side textures for paint dumps), for which we don't care about
// component alpha, so we just use the first of the two surfaces.
virtual already_AddRefed<DataSourceSurface> GetDataSurface() {
return mA->GetDataSurface();
}
private:
friend class DualSurface;
friend class DualPattern;
+13 -13
View File
@@ -16,7 +16,7 @@ namespace gfx {
class SourceSurfaceRawData : public DataSourceSurface
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRawData)
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRawData, override)
SourceSurfaceRawData()
: mMapCount(0)
{}
@@ -26,12 +26,12 @@ public:
MOZ_ASSERT(mMapCount == 0);
}
virtual uint8_t *GetData() { return mRawData; }
virtual int32_t Stride() { return mStride; }
virtual uint8_t *GetData() override { return mRawData; }
virtual int32_t Stride() override { return mStride; }
virtual SurfaceType GetType() const { return SurfaceType::DATA; }
virtual IntSize GetSize() const { return mSize; }
virtual SurfaceFormat GetFormat() const { return mFormat; }
virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
virtual IntSize GetSize() const override { return mSize; }
virtual SurfaceFormat GetFormat() const override { return mFormat; }
bool InitWrappingData(unsigned char *aData,
const IntSize &aSize,
@@ -39,7 +39,7 @@ public:
SurfaceFormat aFormat,
bool aOwnData);
virtual void GuaranteePersistance();
virtual void GuaranteePersistance() override;
// Althought Map (and Moz2D in general) isn't normally threadsafe,
// we want to allow it for SourceSurfaceRawData since it should
@@ -79,7 +79,7 @@ private:
class SourceSurfaceAlignedRawData : public DataSourceSurface
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceAlignedRawData)
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceAlignedRawData, override)
SourceSurfaceAlignedRawData()
: mMapCount(0)
{}
@@ -88,12 +88,12 @@ public:
MOZ_ASSERT(mMapCount == 0);
}
virtual uint8_t *GetData() { return mArray; }
virtual int32_t Stride() { return mStride; }
virtual uint8_t *GetData() override { return mArray; }
virtual int32_t Stride() override { return mStride; }
virtual SurfaceType GetType() const { return SurfaceType::DATA; }
virtual IntSize GetSize() const { return mSize; }
virtual SurfaceFormat GetFormat() const { return mFormat; }
virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
virtual IntSize GetSize() const override { return mSize; }
virtual SurfaceFormat GetFormat() const override { return mFormat; }
bool Init(const IntSize &aSize,
SurfaceFormat aFormat,
+32 -30
View File
@@ -37,13 +37,13 @@
namespace skia {
// Convolves horizontally along a single row. The row data is given in
// |src_data| and continues for the [begin, end) of the filter.
// |src_data| and continues for the num_values() of the filter.
void ConvolveHorizontally_LS3(const unsigned char* src_data,
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row) {
int num_values = filter.num_values();
int tmp, filter_offset, filter_length;
double zero, mask[3], shuf_50, shuf_fa;
double zero, mask[4], shuf_50, shuf_fa;
asm volatile (
".set push \n\t"
@@ -51,27 +51,28 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
"xor %[zero], %[zero], %[zero] \n\t"
// |mask| will be used to decimate all extra filter coefficients that are
// loaded by SIMD when |filter_length| is not divisible by 4.
// mask[0] is not used in following algorithm.
"li %[tmp], 1 \n\t"
"dsll32 %[tmp], 0x10 \n\t"
"daddiu %[tmp], -1 \n\t"
"dmtc1 %[tmp], %[mask2] \n\t"
"dmtc1 %[tmp], %[mask3] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask2] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask1] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask0] \n\t"
"ori %[tmp], $0, 0x50 \n\t"
"mtc1 %[tmp], %[shuf_50] \n\t"
"ori %[tmp], $0, 0xfa \n\t"
"mtc1 %[tmp], %[shuf_fa] \n\t"
".set pop \n\t"
:[zero]"=f"(zero), [mask0]"=f"(mask[0]),
[mask1]"=f"(mask[1]), [mask2]"=f"(mask[2]),
:[zero]"=f"(zero), [mask1]"=f"(mask[1]),
[mask2]"=f"(mask[2]), [mask3]"=f"(mask[3]),
[shuf_50]"=f"(shuf_50), [shuf_fa]"=f"(shuf_fa),
[tmp]"=&r"(tmp)
);
// Output one pixel each iteration, calculating all channels (RGBA) together.
for (int out_x = begin; out_x < end; out_x++) {
for (int out_x = 0; out_x < num_values; out_x++) {
const ConvolutionFilter1D::Fixed* filter_values =
filter.FilterForValue(out_x, &filter_offset, &filter_length);
double accumh, accuml;
@@ -203,7 +204,7 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
[mul_hih]"=&f"(mul_hih), [mul_hil]"=&f"(mul_hil),
[mul_loh]"=&f"(mul_loh), [mul_lol]"=&f"(mul_lol)
:[fval]"r"(filter_values), [rtf]"r"(row_to_filter),
[zeroh]"f"(zero), [zerol]"f"(zero), [mask]"f"(mask[r-1]),
[zeroh]"f"(zero), [zerol]"f"(zero), [mask]"f"(mask[r]),
[shuf_50]"f"(shuf_50), [shuf_fa]"f"(shuf_fa)
);
}
@@ -235,15 +236,15 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
}
// Convolves horizontally along four rows. The row data is given in
// |src_data| and continues for the [begin, end) of the filter.
// |src_data| and continues for the num_values() of the filter.
// The algorithm is almost same as |ConvolveHorizontally_LS3|. Please
// refer to that function for detailed comments.
void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row[4]) {
int num_values = filter.num_values();
int tmp, filter_offset, filter_length;
double zero, mask[3], shuf_50, shuf_fa;
double zero, mask[4], shuf_50, shuf_fa;
asm volatile (
".set push \n\t"
@@ -251,27 +252,28 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
"xor %[zero], %[zero], %[zero] \n\t"
// |mask| will be used to decimate all extra filter coefficients that are
// loaded by SIMD when |filter_length| is not divisible by 4.
// mask[0] is not used in following algorithm.
"li %[tmp], 1 \n\t"
"dsll32 %[tmp], 0x10 \n\t"
"daddiu %[tmp], -1 \n\t"
"dmtc1 %[tmp], %[mask2] \n\t"
"dmtc1 %[tmp], %[mask3] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask2] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask1] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask0] \n\t"
"ori %[tmp], $0, 0x50 \n\t"
"mtc1 %[tmp], %[shuf_50] \n\t"
"ori %[tmp], $0, 0xfa \n\t"
"mtc1 %[tmp], %[shuf_fa] \n\t"
".set pop \n\t"
:[zero]"=f"(zero), [mask0]"=f"(mask[0]),
[mask1]"=f"(mask[1]), [mask2]"=f"(mask[2]),
:[zero]"=f"(zero), [mask1]"=f"(mask[1]),
[mask2]"=f"(mask[2]), [mask3]"=f"(mask[3]),
[shuf_50]"=f"(shuf_50), [shuf_fa]"=f"(shuf_fa),
[tmp]"=&r"(tmp)
);
// Output one pixel each iteration, calculating all channels (RGBA) together.
for (int out_x = begin; out_x < end; out_x++) {
for (int out_x = 0; out_x < num_values; out_x++) {
const ConvolutionFilter1D::Fixed* filter_values =
filter.FilterForValue(out_x, &filter_offset, &filter_length);
double accum0h, accum0l, accum1h, accum1l;
@@ -385,7 +387,7 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
:[coeffh]"=&f"(coeffh), [coeffl]"=&f"(coeffl),
[coeff16loh]"=&f"(coeff16loh), [coeff16lol]"=&f"(coeff16lol),
[coeff16hih]"=&f"(coeff16hih), [coeff16hil]"=&f"(coeff16hil)
:[fval]"r"(filter_values), [mask]"f"(mask[r-1]),
:[fval]"r"(filter_values), [mask]"f"(mask[r]),
[shuf_50]"f"(shuf_50), [shuf_fa]"f"(shuf_fa)
);
@@ -440,16 +442,17 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
// Does vertical convolution to produce one output row. The filter values and
// length are given in the first two parameters. These are applied to each
// of the rows pointed to in the |source_data_rows| array, with each row
// being |end - begin| wide.
// being |pixel_width| wide.
//
// The output must have room for |(end - begin) * 4| bytes.
// The output must have room for |pixel_width * 4| bytes.
template<bool has_alpha>
void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values,
int filter_length,
unsigned char* const* source_data_rows,
int begin, int end,
int pixel_width,
unsigned char* out_row) {
uint64_t tmp;
int width = pixel_width & ~3;
double zero, sra, coeff16h, coeff16l;
double accum0h, accum0l, accum1h, accum1l;
double accum2h, accum2l, accum3h, accum3l;
@@ -468,7 +471,7 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
);
// Output four pixels per iteration (16 bytes).
for (out_x = begin; out_x + 3 < end; out_x += 4) {
for (out_x = 0; out_x < width; out_x += 4) {
// Accumulated result for each pixel. 32 bits per RGBA channel.
asm volatile (
".set push \n\t"
@@ -651,8 +654,7 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
// When the width of the output is not divisible by 4, We need to save one
// pixel (4 bytes) each time. And also the fourth pixel is always absent.
int r = end - out_x;
if (r > 0) {
if (pixel_width & 3) {
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
@@ -793,7 +795,7 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
:[s4]"=f"(s4), [s64]"=f"(s64),
[tmp]"=&r"(tmp)
);
for (; out_x < end; out_x++) {
for (int out_x = width; out_x < pixel_width; out_x++) {
double t;
asm volatile (
@@ -815,14 +817,14 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
void ConvolveVertically_LS3(const ConvolutionFilter1D::Fixed* filter_values,
int filter_length,
unsigned char* const* source_data_rows,
int begin, int end,
int pixel_width,
unsigned char* out_row, bool has_alpha) {
if (has_alpha) {
ConvolveVertically_LS3_impl<true>(filter_values, filter_length,
source_data_rows, begin, end, out_row);
source_data_rows, pixel_width, out_row);
} else {
ConvolveVertically_LS3_impl<false>(filter_values, filter_length,
source_data_rows, begin, end, out_row);
source_data_rows, pixel_width, out_row);
}
}
+1 -3
View File
@@ -40,7 +40,6 @@ namespace skia {
// Convolves horizontally along a single row. The row data is given in
// |src_data| and continues for the [begin, end) of the filter.
void ConvolveHorizontally_LS3(const unsigned char* src_data,
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row);
@@ -49,7 +48,6 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
// The algorithm is almost same as |ConvolveHorizontally_LS3|. Please
// refer to that function for detailed comments.
void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row[4]);
@@ -62,7 +60,7 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
void ConvolveVertically_LS3(const ConvolutionFilter1D::Fixed* filter_values,
int filter_length,
unsigned char* const* source_data_rows,
int begin, int end,
int pixel_width,
unsigned char* out_row, bool has_alpha);
} // namespace skia
+3
View File
@@ -115,6 +115,9 @@ if CONFIG['INTEL_ARCHITECTURE']:
if CONFIG['MOZ_ENABLE_SKIA']:
SOURCES['convolverSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
elif CONFIG['CPU_ARCH'].startswith('mips'):
SOURCES += [
'BlurLS3.cpp',
]
if CONFIG['MOZ_ENABLE_SKIA']:
SOURCES += [
'convolverLS3.cpp',
+21 -14
View File
@@ -77,6 +77,7 @@ static const char *sExtensionNames[] = {
"GL_ANGLE_timer_query",
"GL_APPLE_client_storage",
"GL_APPLE_framebuffer_multisample",
"GL_APPLE_sync",
"GL_APPLE_texture_range",
"GL_APPLE_vertex_array_object",
"GL_ARB_ES2_compatibility",
@@ -780,7 +781,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
if (!IsSupported(GLFeature::framebuffer_object)) {
// Check for aux symbols based on extensions
if (IsSupported(GLFeature::framebuffer_object_EXT_OES))
{
@@ -808,11 +808,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
IsExtensionSupported(GLContext::EXT_framebuffer_blit) ||
IsExtensionSupported(GLContext::NV_framebuffer_blit))
{
if (IsSupported(GLFeature::framebuffer_blit)) {
SymLoadStruct extSymbols[] = {
EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV),
END_SYMBOLS
@@ -823,11 +819,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
IsExtensionSupported(GLContext::APPLE_framebuffer_multisample) ||
IsExtensionSupported(GLContext::EXT_framebuffer_multisample) ||
IsExtensionSupported(GLContext::EXT_multisampled_render_to_texture))
{
if (IsSupported(GLFeature::framebuffer_multisample)) {
SymLoadStruct extSymbols[] = {
EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT),
END_SYMBOLS
@@ -1428,10 +1420,11 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
if (IsSupported(GLFeature::uniform_buffer_object)) {
// Note: Don't query for glGetActiveUniformName because it is not
// supported by GL ES 3.
SymLoadStruct uboSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetUniformIndices, { "GetUniformIndices", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetActiveUniformsiv, { "GetActiveUniformsiv", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetActiveUniformName, { "GetActiveUniformName", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetUniformBlockIndex, { "GetUniformBlockIndex", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockiv, { "GetActiveUniformBlockiv", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockName, { "GetActiveUniformBlockName", nullptr } },
@@ -1542,7 +1535,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
if (IsSupported(GLFeature::read_buffer)) {
SymLoadStruct extSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
{ (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
END_SYMBOLS
};
@@ -1554,6 +1547,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsExtensionSupported(APPLE_framebuffer_multisample)) {
SymLoadStruct extSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fResolveMultisampleFramebufferAPPLE, { "ResolveMultisampleFramebufferAPPLE", nullptr } },
END_SYMBOLS
};
if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
NS_ERROR("GL supports APPLE_framebuffer_multisample without supplying its functions.");
MarkExtensionUnsupported(APPLE_framebuffer_multisample);
ClearSymbols(extSymbols);
}
}
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
@@ -2906,7 +2913,7 @@ GLContext::GetReadFB()
if (mScreen)
return mScreen->GetReadFB();
GLenum bindEnum = IsSupported(GLFeature::framebuffer_blit)
GLenum bindEnum = IsSupported(GLFeature::split_framebuffer)
? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
: LOCAL_GL_FRAMEBUFFER_BINDING;
+12 -9
View File
@@ -124,6 +124,7 @@ enum class GLFeature {
sRGB_framebuffer,
sRGB_texture,
sampler_objects,
split_framebuffer,
standard_derivatives,
sync,
texture_3D,
@@ -390,6 +391,7 @@ public:
ANGLE_timer_query,
APPLE_client_storage,
APPLE_framebuffer_multisample,
APPLE_sync,
APPLE_texture_range,
APPLE_vertex_array_object,
ARB_ES2_compatibility,
@@ -3011,15 +3013,6 @@ public:
AFTER_GL_CALL;
}
void fGetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize,
GLsizei* length, GLchar* uniformName)
{
ASSERT_SYMBOL_PRESENT(fGetActiveUniformName);
BEFORE_GL_CALL;
mSymbols.fGetActiveUniformName(program, uniformIndex, bufSize, length, uniformName);
AFTER_GL_CALL;
}
GLuint fGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) {
ASSERT_SYMBOL_PRESENT(fGetUniformBlockIndex);
BEFORE_GL_CALL;
@@ -3148,6 +3141,16 @@ public:
return ret;
}
// -----------------------------------------------------------------------------
// APPLE_framebuffer_multisample
void fResolveMultisampleFramebufferAPPLE() {
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE);
mSymbols.fResolveMultisampleFramebufferAPPLE();
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// Constructor
protected:
+17 -1
View File
@@ -547,6 +547,20 @@ static const FeatureInfo sFeatureInfoArr[] = {
GLContext::Extensions_End
}
},
{
// Do we have separate DRAW and READ framebuffer bind points?
"split_framebuffer",
GLVersion::GL3,
GLESVersion::ES3,
GLContext::ARB_framebuffer_object,
{
GLContext::ANGLE_framebuffer_blit,
GLContext::APPLE_framebuffer_multisample,
GLContext::EXT_framebuffer_blit,
GLContext::NV_framebuffer_blit,
GLContext::Extensions_End
}
},
{
"standard_derivatives",
GLVersion::GL2,
@@ -561,8 +575,10 @@ static const FeatureInfo sFeatureInfoArr[] = {
"sync",
GLVersion::GL3_2,
GLESVersion::ES3,
GLContext::ARB_sync,
GLContext::Extension_None,
{
GLContext::ARB_sync,
GLContext::APPLE_sync,
GLContext::Extensions_End
}
},
+15 -13
View File
@@ -614,8 +614,6 @@ struct GLContextSymbols
typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices,
GLenum pname, GLint* params);
PFNGLGETACTIVEUNIFORMSIVPROC fGetActiveUniformsiv;
typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIdex, GLsizei bufSize, GLsizei* length, GLchar* uniformName);
PFNGLGETACTIVEUNIFORMNAMEPROC fGetActiveUniformName;
typedef GLuint (GLAPIENTRY * PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar* uniformBlockName);
PFNGLGETUNIFORMBLOCKINDEXPROC fGetUniformBlockIndex;
typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
@@ -675,19 +673,23 @@ struct GLContextSymbols
GLint yoffset, GLint zoffset, GLint x,
GLint y, GLsizei width, GLsizei height);
PFNGLCOPYTEXSUBIMAGE3DPROC fCopyTexSubImage3D;
typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3D) (GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLsizei imageSize, const GLvoid* data);
PFNGLCOMPRESSEDTEXIMAGE3D fCompressedTexImage3D;
typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3D) (GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const GLvoid* data);
PFNGLCOMPRESSEDTEXSUBIMAGE3D fCompressedTexSubImage3D;
typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLsizei imageSize, const GLvoid* data);
PFNGLCOMPRESSEDTEXIMAGE3DPROC fCompressedTexImage3D;
typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const GLvoid* data);
PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC fCompressedTexSubImage3D;
// get_string_indexed
typedef const GLubyte* (GLAPIENTRY * pfnGLGetStringiT)(GLenum name, GLuint index);
pfnGLGetStringiT fGetStringi;
typedef const GLubyte* (GLAPIENTRY * PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
PFNGLGETSTRINGIPROC fGetStringi;
// APPLE_framebuffer_multisample
typedef void (GLAPIENTRY * PFNRESOLVEMULTISAMPLEFRAMEBUFFERAPPLE) (void);
PFNRESOLVEMULTISAMPLEFRAMEBUFFERAPPLE fResolveMultisampleFramebufferAPPLE;
};
} // namespace gl
+20 -20
View File
@@ -151,7 +151,7 @@ GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
GLuint drawFB = DrawFB();
GLuint readFB = ReadFB();
if (!gl->IsSupported(GLFeature::framebuffer_blit)) {
if (!gl->IsSupported(GLFeature::split_framebuffer)) {
MOZ_ASSERT(drawFB == readFB);
gl->raw_fBindFramebuffer(target, readFB);
return;
@@ -164,16 +164,10 @@ GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
break;
case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
if (!gl->IsSupported(GLFeature::framebuffer_blit))
NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable.");
gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
break;
case LOCAL_GL_READ_FRAMEBUFFER_EXT:
if (!gl->IsSupported(GLFeature::framebuffer_blit))
NS_WARNING("READ_FRAMEBUFFER requested but unavailable.");
gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
break;
@@ -196,7 +190,7 @@ GLScreenBuffer::BindFB(GLuint fb)
if (mInternalDrawFB == mInternalReadFB) {
mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
} else {
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
}
@@ -210,7 +204,7 @@ GLScreenBuffer::BindFB(GLuint fb)
void
GLScreenBuffer::BindDrawFB(GLuint fb)
{
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
GLuint drawFB = DrawFB();
mUserDrawFB = fb;
@@ -226,7 +220,7 @@ GLScreenBuffer::BindDrawFB(GLuint fb)
void
GLScreenBuffer::BindReadFB(GLuint fb)
{
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
GLuint readFB = ReadFB();
mUserReadFB = fb;
@@ -255,7 +249,7 @@ GLScreenBuffer::BindFB_Internal(GLuint fb)
void
GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
{
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
mInternalDrawFB = mUserDrawFB = fb;
mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
@@ -268,7 +262,7 @@ GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
void
GLScreenBuffer::BindReadFB_Internal(GLuint fb)
{
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
mInternalReadFB = mUserReadFB = fb;
mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
@@ -314,7 +308,7 @@ GLScreenBuffer::GetReadFB() const
// We use raw_ here because this is debug code and we need to see what
// the driver thinks.
GLuint actual = 0;
if (mGL->IsSupported(GLFeature::framebuffer_blit))
if (mGL->IsSupported(GLFeature::split_framebuffer))
mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
else
mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
@@ -429,7 +423,7 @@ GLScreenBuffer::AssureBlitted()
MOZ_ASSERT(drawFB != 0);
MOZ_ASSERT(drawFB != readFB);
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
MOZ_ASSERT(mDraw->mSize == mRead->Size());
ScopedBindFramebuffer boundFB(mGL);
@@ -438,13 +432,19 @@ GLScreenBuffer::AssureBlitted()
BindReadFB_Internal(drawFB);
BindDrawFB_Internal(readFB);
const gfx::IntSize& srcSize = mDraw->mSize;
const gfx::IntSize& destSize = mRead->Size();
if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
const gfx::IntSize& srcSize = mDraw->mSize;
const gfx::IntSize& destSize = mRead->Size();
mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
0, 0, destSize.width, destSize.height,
LOCAL_GL_COLOR_BUFFER_BIT,
LOCAL_GL_NEAREST);
mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
0, 0, destSize.width, destSize.height,
LOCAL_GL_COLOR_BUFFER_BIT,
LOCAL_GL_NEAREST);
} else if (mGL->IsExtensionSupported(GLContext::APPLE_framebuffer_multisample)) {
mGL->fResolveMultisampleFramebufferAPPLE();
} else {
MOZ_CRASH("No available blit methods.");
}
// Done!
}
+1 -1
View File
@@ -62,7 +62,7 @@ ScopedGLState::UnwrapImpl()
void
ScopedBindFramebuffer::Init()
{
if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
if (mGL->IsSupported(GLFeature::split_framebuffer)) {
mOldReadFB = mGL->GetReadFB();
mOldDrawFB = mGL->GetDrawFB();
} else {
+1 -1
View File
@@ -153,7 +153,7 @@ SharedSurface_GLTexture::ProducerReleaseImpl()
{
mGL->MakeCurrent();
if (mGL->IsExtensionSupported(GLContext::ARB_sync)) {
if (mGL->IsSupported(GLFeature::sync)) {
if (mSync) {
mGL->fDeleteSync(mSync);
mSync = 0;
+1 -17
View File
@@ -469,17 +469,6 @@ LinkModuleToHeap(JSContext* cx, AsmJSModule& module, Handle<ArrayBufferObjectMay
{
uint32_t heapLength = heap->byteLength();
if (IsDeprecatedAsmJSHeapLength(heapLength)) {
LinkFail(cx, "ArrayBuffer byteLengths smaller than 64KB are deprecated and "
"will cause a link-time failure in the future");
// The goal of deprecation is to give apps some time before linking
// fails. However, if warnings-as-errors is turned on (which happens as
// part of asm.js testing) an exception may be raised.
if (cx->isExceptionPending())
return false;
}
if (!IsValidAsmJSHeapLength(heapLength)) {
ScopedJSFreePtr<char> msg(
JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
@@ -631,7 +620,6 @@ ChangeHeap(JSContext* cx, AsmJSModule& module, const CallArgs& args)
}
MOZ_ASSERT(IsValidAsmJSHeapLength(heapLength));
MOZ_ASSERT(!IsDeprecatedAsmJSHeapLength(heapLength));
if (!ArrayBufferObject::prepareForAsmJS(cx, newBuffer, module.usesSignalHandlersForOOB()))
return false;
@@ -749,12 +737,8 @@ CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
// that the optimized asm.js-to-Ion FFI call path (which we want to be
// very fast) can avoid doing so. The JitActivation is marked as
// inactive so stack iteration will skip over it.
//
// We needn't provide an entry script pointer; that's only used for
// reporting entry points to performance-monitoring tools, and asm.js ->
// Ion calls will never be entry points.
AsmJSActivation activation(cx, module);
JitActivation jitActivation(cx, /* entryScript */ nullptr, /* active */ false);
JitActivation jitActivation(cx, /* active */ false);
// Call the per-exported-function trampoline created by GenerateEntry.
AsmJSModule::CodePtr enter = module.entryTrampoline(func);
-2
View File
@@ -326,8 +326,6 @@ AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembl
if (!callSites_.appendAll(callSites))
return false;
MOZ_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
// Absolute link metadata: absolute addresses that refer to some fixed
// address in the address space.
AbsoluteLinkArray& absoluteLinks = staticLinkData_.absoluteLinks;
+20 -21
View File
@@ -69,6 +69,7 @@ using mozilla::Maybe;
using mozilla::Move;
using mozilla::PositiveInfinity;
using mozilla::UniquePtr;
using JS::AsmJSOption;
using JS::GenericNaN;
/*****************************************************************************/
@@ -172,18 +173,22 @@ VarListHead(ParseNode* pn)
return ListHead(pn);
}
static inline bool
IsDefaultCase(ParseNode* pn)
{
return pn->as<CaseClause>().isDefault();
}
static inline ParseNode*
CaseExpr(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(PNK_CASE) || pn->isKind(PNK_DEFAULT));
return BinaryLeft(pn);
return pn->as<CaseClause>().caseExpression();
}
static inline ParseNode*
CaseBody(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(PNK_CASE) || pn->isKind(PNK_DEFAULT));
return BinaryRight(pn);
return pn->as<CaseClause>().statementList();
}
static inline ParseNode*
@@ -1596,17 +1601,9 @@ class MOZ_STACK_CLASS ModuleValidator
masm().patchCall(callerOffset, calleeOffset);
}
// When an interrupt is triggered, all function code is mprotected and,
// for sanity, stub code (particularly the interrupt stub) is not.
// Protection works at page granularity, so we need to ensure that no
// stub code gets into the function code pages.
// TODO; this is no longer true and could be removed, see also
// bug 1200609.
MOZ_ASSERT(!finishedFunctionBodies_);
masm().haltingAlign(AsmJSPageSize);
module_->finishFunctionBodies(masm().currentOffset());
finishedFunctionBodies_ = true;
return true;
}
@@ -5915,8 +5912,7 @@ static bool
CheckDefaultAtEnd(FunctionValidator& f, ParseNode* stmt)
{
for (; stmt; stmt = NextNode(stmt)) {
MOZ_ASSERT(stmt->isKind(PNK_CASE) || stmt->isKind(PNK_DEFAULT));
if (stmt->isKind(PNK_DEFAULT) && NextNode(stmt) != nullptr)
if (IsDefaultCase(stmt) && NextNode(stmt) != nullptr)
return f.fail(stmt, "default label must be at the end");
}
@@ -5927,7 +5923,7 @@ static bool
CheckSwitchRange(FunctionValidator& f, ParseNode* stmt, int32_t* low, int32_t* high,
int32_t* tableLength)
{
if (stmt->isKind(PNK_DEFAULT)) {
if (IsDefaultCase(stmt)) {
*low = 0;
*high = -1;
*tableLength = 0;
@@ -5941,7 +5937,7 @@ CheckSwitchRange(FunctionValidator& f, ParseNode* stmt, int32_t* low, int32_t* h
*low = *high = i;
ParseNode* initialStmt = stmt;
for (stmt = NextNode(stmt); stmt && stmt->isKind(PNK_CASE); stmt = NextNode(stmt)) {
for (stmt = NextNode(stmt); stmt && !IsDefaultCase(stmt); stmt = NextNode(stmt)) {
int32_t i = 0;
if (!CheckCaseExpr(f, CaseExpr(stmt), &i))
return false;
@@ -6016,7 +6012,7 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt)
return false;
uint32_t numCases = 0;
for (; stmt && stmt->isKind(PNK_CASE); stmt = NextNode(stmt)) {
for (; stmt && !IsDefaultCase(stmt); stmt = NextNode(stmt)) {
int32_t caseValue = ExtractNumericLiteral(f.m(), CaseExpr(stmt)).toInt32();
unsigned caseIndex = caseValue - low;
@@ -6033,7 +6029,7 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt)
}
bool hasDefault = false;
if (stmt && stmt->isKind(PNK_DEFAULT)) {
if (stmt && IsDefaultCase(stmt)) {
hasDefault = true;
if (!CheckStatement(f, CaseBody(stmt)))
return false;
@@ -8275,11 +8271,14 @@ EstablishPreconditions(ExclusiveContext* cx, AsmJSParser& parser)
if (cx->gcSystemPageSize() != AsmJSPageSize)
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by non 4KiB system page size");
if (!parser.options().asmJSOption)
switch (parser.options().asmJSOption) {
case AsmJSOption::Disabled:
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by javascript.options.asmjs in about:config");
if (cx->compartment()->debuggerObservesAsmJS())
case AsmJSOption::DisabledByDebugger:
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by debugger");
case AsmJSOption::Enabled:
break;
}
if (parser.pc->isGenerator())
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by generator context");
+12 -11
View File
@@ -51,8 +51,17 @@ extern bool
ValidateAsmJS(ExclusiveContext* cx, AsmJSParser& parser, frontend::ParseNode* stmtList,
bool* validated);
// The minimum heap length for asm.js.
const size_t AsmJSMinHeapLength = 64 * 1024;
// The assumed page size; dynamically checked in ValidateAsmJS.
#ifdef _MIPS_ARCH_LOONGSON3A
const size_t AsmJSPageSize = 16384;
#else
const size_t AsmJSPageSize = 4096;
#endif
static_assert(AsmJSMinHeapLength % AsmJSPageSize == 0, "Invalid page size");
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
@@ -86,8 +95,8 @@ static const size_t AsmJSMappedSize = 4 * 1024ULL * 1024ULL * 1024ULL +
inline uint32_t
RoundUpToNextValidAsmJSHeapLength(uint32_t length)
{
if (length <= 4 * 1024)
return 4 * 1024;
if (length <= AsmJSMinHeapLength)
return AsmJSMinHeapLength;
if (length <= 16 * 1024 * 1024)
return mozilla::RoundUpPow2(length);
@@ -99,7 +108,7 @@ RoundUpToNextValidAsmJSHeapLength(uint32_t length)
inline bool
IsValidAsmJSHeapLength(uint32_t length)
{
bool valid = length >= 4 * 1024 &&
bool valid = length >= AsmJSMinHeapLength &&
(IsPowerOfTwo(length) ||
(length & 0x00ffffff) == 0);
@@ -109,14 +118,6 @@ IsValidAsmJSHeapLength(uint32_t length)
return valid;
}
// For now, power-of-2 lengths in this range are accepted, but in the future
// we'll change this to cause link-time failure.
inline bool
IsDeprecatedAsmJSHeapLength(uint32_t length)
{
return length >= 4 * 1024 && length < 64 * 1024 && IsPowerOfTwo(length);
}
// Return whether asm.js optimization is inhibited by the platform or
// dynamically disabled:
extern bool
+1 -1
View File
@@ -771,7 +771,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
// See <https://bugs.ecmascript.org/show_bug.cgi?id=2883>.
while (true) {
// Steps 6.g.i-iii.
var next = iterator.next();
var next = callFunction(iterator.next, iterator);
if (!IsObject(next))
ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
+22 -16
View File
@@ -443,9 +443,9 @@ function CanonicalizeLanguageTag(locale) {
while (i < subtags.length && subtags[i].length > 1)
i++;
var extension = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, extensionStart, i), "-");
extensions.push(extension);
callFunction(std_Array_push, extensions, extension);
}
extensions.sort();
callFunction(std_Array_sort, extensions);
// Private use sequences are left as is. "x-private"
var privateUse = "";
@@ -455,7 +455,7 @@ function CanonicalizeLanguageTag(locale) {
// Put everything back together.
var canonical = normal;
if (extensions.length > 0)
canonical += "-" + extensions.join("-");
canonical += "-" + callFunction(std_Array_join, extensions, "-");
if (privateUse.length > 0) {
// Be careful of a Language-Tag that is entirely privateuse.
if (canonical.length > 0)
@@ -578,11 +578,14 @@ function DefaultLocale() {
// (perhaps via fallback). Otherwise use the last-ditch locale.
var candidate = DefaultLocaleIgnoringAvailableLocales();
var locale;
if (BestAvailableLocaleIgnoringDefault(collatorInternalProperties.availableLocales(),
if (BestAvailableLocaleIgnoringDefault(callFunction(collatorInternalProperties.availableLocales,
collatorInternalProperties),
candidate) &&
BestAvailableLocaleIgnoringDefault(numberFormatInternalProperties.availableLocales(),
BestAvailableLocaleIgnoringDefault(callFunction(numberFormatInternalProperties.availableLocales,
numberFormatInternalProperties),
candidate) &&
BestAvailableLocaleIgnoringDefault(dateTimeFormatInternalProperties.availableLocales(),
BestAvailableLocaleIgnoringDefault(callFunction(dateTimeFormatInternalProperties.availableLocales,
dateTimeFormatInternalProperties),
candidate))
{
locale = candidate;
@@ -675,8 +678,8 @@ function CanonicalizeLocaleList(locales) {
if (!IsStructurallyValidLanguageTag(tag))
ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, tag);
tag = CanonicalizeLanguageTag(tag);
if (seen.indexOf(tag) === -1)
seen.push(tag);
if (callFunction(std_Array_indexOf, seen, tag) === -1)
callFunction(std_Array_push, seen, tag);
}
k++;
}
@@ -968,14 +971,14 @@ function LookupSupportedLocales(availableLocales, requestedLocales) {
// Step 4.c-d.
var availableLocale = BestAvailableLocale(availableLocales, noExtensionsLocale);
if (availableLocale !== undefined)
subset.push(locale);
callFunction(std_Array_push, subset, locale);
// Step 4.e.
k++;
}
// Steps 5-6.
return subset.slice(0);
return callFunction(std_Array_slice, subset, 0);
}
@@ -1317,7 +1320,7 @@ function resolveCollatorInternals(lazyCollatorData)
var relevantExtensionKeys = Collator.relevantExtensionKeys;
// Step 15.
var r = ResolveLocale(Collator.availableLocales(),
var r = ResolveLocale(callFunction(Collator.availableLocales, Collator),
lazyCollatorData.requestedLocales,
lazyCollatorData.opt,
relevantExtensionKeys,
@@ -1507,7 +1510,8 @@ function InitializeCollator(collator, locales, options) {
function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
var options = arguments.length > 1 ? arguments[1] : undefined;
var availableLocales = collatorInternalProperties.availableLocales();
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
collatorInternalProperties);
var requestedLocales = CanonicalizeLocaleList(locales);
return SupportedLocales(availableLocales, requestedLocales, options);
}
@@ -1675,7 +1679,7 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
var localeData = NumberFormat.localeData;
// Step 11.
var r = ResolveLocale(NumberFormat.availableLocales(),
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
lazyNumberFormatData.requestedLocales,
lazyNumberFormatData.opt,
NumberFormat.relevantExtensionKeys,
@@ -1960,7 +1964,8 @@ function CurrencyDigits(currency) {
function Intl_NumberFormat_supportedLocalesOf(locales /*, options*/) {
var options = arguments.length > 1 ? arguments[1] : undefined;
var availableLocales = numberFormatInternalProperties.availableLocales();
var availableLocales = callFunction(numberFormatInternalProperties.availableLocales,
numberFormatInternalProperties);
var requestedLocales = CanonicalizeLocaleList(locales);
return SupportedLocales(availableLocales, requestedLocales, options);
}
@@ -2119,7 +2124,7 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
var localeData = DateTimeFormat.localeData;
// Step 10.
var r = ResolveLocale(DateTimeFormat.availableLocales(),
var r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
lazyDateTimeFormatData.requestedLocales,
lazyDateTimeFormatData.localeOpt,
DateTimeFormat.relevantExtensionKeys,
@@ -2660,7 +2665,8 @@ function BestFitFormatMatcher(options, formats) {
function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
var options = arguments.length > 1 ? arguments[1] : undefined;
var availableLocales = dateTimeFormatInternalProperties.availableLocales();
var availableLocales = callFunction(dateTimeFormatInternalProperties.availableLocales,
dateTimeFormatInternalProperties);
var requestedLocales = CanonicalizeLocaleList(locales);
return SupportedLocales(availableLocales, requestedLocales, options);
}
+2 -2
View File
@@ -11,7 +11,7 @@ var LegacyIteratorWrapperMap = new std_WeakMap();
function LegacyIteratorNext(arg) {
var iter = callFunction(std_WeakMap_get, LegacyIteratorWrapperMap, this);
try {
return { value: iter.next(arg), done: false };
return { value: callFunction(iter.next, iter, arg), done: false };
} catch (e) {
if (e instanceof std_StopIteration)
return { value: undefined, done: true };
@@ -22,7 +22,7 @@ function LegacyIteratorNext(arg) {
function LegacyIteratorThrow(exn) {
var iter = callFunction(std_WeakMap_get, LegacyIteratorWrapperMap, this);
try {
return { value: iter.throw(exn), done: false };
return { value: callFunction(iter.throw, iter, exn), done: false };
} catch (e) {
if (e instanceof std_StopIteration)
return { value: undefined, done: true };
+15 -13
View File
@@ -43,7 +43,8 @@ function ModuleGetExportedNames(exportStarSet = [])
for (let i = 0; i < starExportEntries.length; i++) {
let e = starExportEntries[i];
let requestedModule = HostResolveImportedModule(module, e.moduleRequest);
let starNames = requestedModule.getExportedNames(exportStarSet);
let starNames = callFunction(requestedModule.getExportedNames, requestedModule,
exportStarSet);
for (let j = 0; j < starNames.length; j++) {
let n = starNames[j];
if (n !== "default" && !(n in exportedNames))
@@ -89,9 +90,8 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = [])
let e = indirectExportEntries[i];
if (exportName === e.exportName) {
let importedModule = HostResolveImportedModule(module, e.moduleRequest);
let indirectResolution = importedModule.resolveExport(e.importName,
resolveSet,
exportStarSet);
let indirectResolution = callFunction(importedModule.resolveExport, importedModule,
e.importName, resolveSet, exportStarSet);
if (indirectResolution !== null)
return indirectResolution;
}
@@ -118,7 +118,8 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = [])
for (let i = 0; i < starExportEntries.length; i++) {
let e = starExportEntries[i];
let importedModule = HostResolveImportedModule(module, e.moduleRequest);
let resolution = importedModule.resolveExport(exportName, resolveSet, exportStarSet);
let resolution = callFunction(importedModule.resolveExport, importedModule,
exportName, resolveSet, exportStarSet);
if (resolution === "ambiguous")
return resolution;
@@ -146,11 +147,11 @@ function GetModuleNamespace(module)
// Step 3
if (typeof namespace === "undefined") {
let exportedNames = module.getExportedNames();
let exportedNames = callFunction(module.getExportedNames, module);
let unambiguousNames = [];
for (let i = 0; i < exportedNames.length; i++) {
let name = exportedNames[i];
let resolution = module.resolveExport(name);
let resolution = callFunction(module.resolveExport, module, name);
if (resolution === null)
ThrowSyntaxError(JSMSG_MISSING_NAMESPACE_EXPORT);
if (resolution !== "ambiguous")
@@ -166,7 +167,7 @@ function GetModuleNamespace(module)
// 9.4.6.13 ModuleNamespaceCreate(module, exports)
function ModuleNamespaceCreate(module, exports)
{
exports.sort();
callFunction(std_Array_sort, exports);
let ns = NewModuleNamespace(module, exports);
@@ -174,7 +175,7 @@ function ModuleNamespaceCreate(module, exports)
// access.
for (let i = 0; i < exports.length; i++) {
let name = exports[i];
let binding = module.resolveExport(name);
let binding = callFunction(module.resolveExport, module, name);
assert(binding !== null && binding !== "ambiguous", "Failed to resolve binding");
AddModuleNamespaceBinding(ns, name, binding.module, binding.bindingName);
}
@@ -204,14 +205,14 @@ function ModuleDeclarationInstantiation()
for (let i = 0; i < requestedModules.length; i++) {
let required = requestedModules[i];
let requiredModule = HostResolveImportedModule(module, required);
requiredModule.declarationInstantiation();
callFunction(requiredModule.declarationInstantiation, requiredModule);
}
// Step 9
let indirectExportEntries = module.indirectExportEntries;
for (let i = 0; i < indirectExportEntries.length; i++) {
let e = indirectExportEntries[i];
let resolution = module.resolveExport(e.exportName);
let resolution = callFunction(module.resolveExport, module, e.exportName);
if (resolution === null)
ThrowSyntaxError(JSMSG_MISSING_INDIRECT_EXPORT);
if (resolution === "ambiguous")
@@ -227,7 +228,8 @@ function ModuleDeclarationInstantiation()
let namespace = GetModuleNamespace(importedModule);
CreateNamespaceBinding(env, imp.localName, namespace);
} else {
let resolution = importedModule.resolveExport(imp.importName);
let resolution = callFunction(importedModule.resolveExport, importedModule,
imp.importName);
if (resolution === null)
ThrowSyntaxError(JSMSG_MISSING_IMPORT);
if (resolution === "ambiguous")
@@ -261,7 +263,7 @@ function ModuleEvaluation()
for (let i = 0; i < requestedModules.length; i++) {
let required = requestedModules[i];
let requiredModule = HostResolveImportedModule(module, required);
requiredModule.evaluation();
callFunction(requiredModule.evaluation, requiredModule);
}
return EvaluateModule(module);
+1 -1
View File
@@ -57,7 +57,7 @@ function Object_toLocaleString() {
var O = this;
// Step 2.
return O.toString();
return callFunction(O.toString, O);
}
function ObjectDefineSetter(name, setter) {
+2 -2
View File
@@ -2387,8 +2387,8 @@ ASTSerializer::switchCase(ParseNode* pn, MutableHandleValue dst)
RootedValue expr(cx);
return optExpression(pn->pn_left, &expr) &&
statements(pn->pn_right, stmts) &&
return optExpression(pn->as<CaseClause>().caseExpression(), &expr) &&
statements(pn->as<CaseClause>().statementList(), stmts) &&
builder.switchCase(expr, stmts, &pn->pn_pos, dst);
}
+3 -3
View File
@@ -292,12 +292,12 @@ function String_static_fromCodePoint(codePoints) {
// Step 5f.
// Inlined UTF-16 Encoding
if (nextCP <= 0xFFFF) {
elements.push(nextCP);
callFunction(std_Array_push, elements, nextCP);
continue;
}
elements.push((((nextCP - 0x10000) / 0x400) | 0) + 0xD800);
elements.push((nextCP - 0x10000) % 0x400 + 0xDC00);
callFunction(std_Array_push, elements, (((nextCP - 0x10000) / 0x400) | 0) + 0xD800);
callFunction(std_Array_push, elements, (nextCP - 0x10000) % 0x400 + 0xDC00);
}
// Step 6.
+3 -3
View File
@@ -216,7 +216,7 @@ function TypedArrayFilter(callbackfn, thisArg = undefined) {
// Step 13.f.
if (selected) {
// Step 13.f.i.
kept.push(kValue);
callFunction(std_Array_push, kept, kValue);
// Step 13.f.ii.
captured++;
}
@@ -1059,14 +1059,14 @@ function TypedArrayFrom(constructor, target, items, mapfn, thisArg) {
// Steps 10.d-e.
while (true) {
// Steps 10.e.i-ii.
var next = iterator.next();
var next = callFunction(iterator.next, iterator);
if (!IsObject(next))
ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
// Steps 10.e.iii-vi.
if (next.done)
break;
values.push(next.value);
callFunction(std_Array_push, values, next.value);
}
// Step 10.f.
+1 -10
View File
@@ -53,16 +53,7 @@ var std_Map_iterator_next = MapIteratorNext;
function List() {
this.length = 0;
}
{
let ListProto = std_Object_create(null);
ListProto.indexOf = std_Array_indexOf;
ListProto.join = std_Array_join;
ListProto.push = std_Array_push;
ListProto.slice = std_Array_slice;
ListProto.sort = std_Array_sort;
MakeConstructible(List, ListProto);
}
MakeConstructible(List, {__proto__: null});
/********** Record specification type **********/
+14 -6
View File
@@ -62,7 +62,7 @@ HEADER_TEMPLATE = """\
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace js {
namespace selfhosted {
namespace %(namespace)s {
static const %(sources_type)s data[] = { %(sources_data)s };
static const %(sources_type)s * const %(sources_name)s = reinterpret_cast<const %(sources_type)s *>(data);
@@ -78,7 +78,7 @@ namespace selfhosted {
} // js
"""
def embed(cxx, preprocessorOption, msgs, sources, c_out, js_out, env):
def embed(cxx, preprocessorOption, msgs, sources, c_out, js_out, namespace, env):
combinedSources = '\n'.join([msgs] + ['#include "%(s)s"' % { 's': source } for source in sources])
args = ['-D%(k)s=%(v)s' % { 'k': k, 'v': env[k] } for k in env]
preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args)
@@ -94,7 +94,8 @@ def embed(cxx, preprocessorOption, msgs, sources, c_out, js_out, env):
'sources_data': data,
'sources_name': 'compressedSources',
'compressed_total_length': len(compressed),
'raw_total_length': len(processed)
'raw_total_length': len(processed),
'namespace': namespace
})
def preprocess(cxx, preprocessorOption, source, args = []):
@@ -141,8 +142,7 @@ def get_config_defines(buildconfig):
env[pair[0]] = pair[1]
return env
def generate_selfhosted(c_out, msg_file, *inputs):
# Called from moz.build to embed selfhosted JS.
def process_inputs(namespace, c_out, msg_file, inputs):
deps = [path for path in inputs if path.endswith(".h")]
sources = [path for path in inputs if path.endswith(".js")]
assert len(deps) + len(sources) == len(inputs)
@@ -152,4 +152,12 @@ def generate_selfhosted(c_out, msg_file, *inputs):
js_path = re.sub(r"\.out\.h$", "", c_out.name) + ".js"
msgs = messages(msg_file)
with open(js_path, 'w') as js_out:
embed(cxx, cxx_option, msgs, sources, c_out, js_out, env)
embed(cxx, cxx_option, msgs, sources, c_out, js_out, namespace, env)
def generate_selfhosted(c_out, msg_file, *inputs):
# Called from moz.build to embed selfhosted JS.
process_inputs('selfhosted', c_out, msg_file, inputs)
def generate_shellmoduleloader(c_out, msg_file, *inputs):
# Called from moz.build to embed shell module loader JS.
process_inputs('moduleloader', c_out, msg_file, inputs)
+101 -104
View File
@@ -2147,7 +2147,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true;
return true;
case PNK_DEFAULT:
case PNK_COLON:
case PNK_CASE:
MOZ_ASSERT(pn->isArity(PN_BINARY));
@@ -2599,10 +2598,8 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
ParseNode* pndot = pn2;
ParseNode* pnup = nullptr;
ParseNode* pndown;
ptrdiff_t top = offset();
for (;;) {
/* Reverse pndot->pn_expr to point up, not down. */
pndot->pn_offset = top;
MOZ_ASSERT(!pndot->isUsed());
pndown = pndot->pn_expr;
pndot->pn_expr = pnup;
@@ -3068,7 +3065,7 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
ParseNode* cases = pn->pn_right;
MOZ_ASSERT(cases->isKind(PNK_LEXICALSCOPE) || cases->isKind(PNK_STATEMENTLIST));
/* Push the discriminant. */
// Emit code for the discriminant.
if (!emitTree(pn->pn_left))
return false;
@@ -3080,7 +3077,8 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
stmtInfo.type = StmtType::SWITCH;
stmtInfo.update = top = offset();
/* Advance |cases| to refer to the switch case list. */
// Advance |cases| to refer to the switch case list.
cases = cases->expr();
} else {
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
@@ -3088,21 +3086,22 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
pushStatement(&stmtInfo, StmtType::SWITCH, top);
}
/* Switch bytecodes run from here till end of final case. */
// Switch bytecodes run from here till end of final case.
uint32_t caseCount = cases->pn_count;
if (caseCount > JS_BIT(16)) {
parser->tokenStream.reportError(JSMSG_TOO_MANY_CASES);
return false;
}
/* Try for most optimal, fall back if not dense ints. */
// Try for most optimal, fall back if not dense ints.
JSOp switchOp = JSOP_TABLESWITCH;
uint32_t tableLength = 0;
int32_t low, high;
bool hasDefault = false;
CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
if (caseCount == 0 ||
(caseCount == 1 &&
(hasDefault = cases->pn_head->isKind(PNK_DEFAULT)))) {
(caseCount == 1 && (hasDefault = firstCase->isDefault())))
{
caseCount = 0;
low = 0;
high = -1;
@@ -3113,20 +3112,19 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
low = JSVAL_INT_MAX;
high = JSVAL_INT_MIN;
for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
if (caseNode->isKind(PNK_DEFAULT)) {
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
if (caseNode->isDefault()) {
hasDefault = true;
caseCount--; /* one of the "cases" was the default */
caseCount--; // one of the "cases" was the default
continue;
}
MOZ_ASSERT(caseNode->isKind(PNK_CASE));
if (switchOp == JSOP_CONDSWITCH)
continue;
MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
ParseNode* caseValue = caseNode->pn_left;
ParseNode* caseValue = caseNode->caseExpression();
if (caseValue->getKind() != PNK_NUMBER) {
switchOp = JSOP_CONDSWITCH;
@@ -3148,11 +3146,9 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
if (i > high)
high = i;
/*
* Check for duplicates, which require a JSOP_CONDSWITCH.
* We bias i by 65536 if it's negative, and hope that's a rare
* case (because it requires a malloc'd bitmap).
*/
// Check for duplicates, which require a JSOP_CONDSWITCH.
// We bias i by 65536 if it's negative, and hope that's a rare
// case (because it requires a malloc'd bitmap).
if (i < 0)
i += JS_BIT(16);
if (i >= intmapBitLength) {
@@ -3168,10 +3164,8 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
JS_SET_BIT(intmap, i);
}
/*
* Compute table length and select condswitch instead if overlarge or
* more than half-sparse.
*/
// Compute table length and select condswitch instead if overlarge or
// more than half-sparse.
if (switchOp == JSOP_TABLESWITCH) {
tableLength = uint32_t(high - low + 1);
if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
@@ -3179,31 +3173,29 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
}
}
/*
* The note has one or two offsets: first tells total switch code length;
* second (if condswitch) tells offset to first JSOP_CASE.
*/
// The note has one or two offsets: first tells total switch code length;
// second (if condswitch) tells offset to first JSOP_CASE.
unsigned noteIndex;
size_t switchSize;
if (switchOp == JSOP_CONDSWITCH) {
/* 0 bytes of immediate for unoptimized switch. */
// 0 bytes of immediate for unoptimized switch.
switchSize = 0;
if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, &noteIndex))
return false;
} else {
MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
/* 3 offsets (len, low, high) before the table, 1 per entry. */
switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength));
// 3 offsets (len, low, high) before the table, 1 per entry.
switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableLength));
if (!newSrcNote2(SRC_TABLESWITCH, 0, &noteIndex))
return false;
}
/* Emit switchOp followed by switchSize bytes of jump or lookup table. */
// Emit switchOp followed by switchSize bytes of jump or lookup table.
if (!emitN(switchOp, switchSize))
return false;
Vector<ParseNode*, 32, SystemAllocPolicy> table;
Vector<CaseClause*, 32, SystemAllocPolicy> table;
ptrdiff_t condSwitchDefaultOff = -1;
if (switchOp == JSOP_CONDSWITCH) {
@@ -3211,31 +3203,38 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
bool beforeCases = true;
ptrdiff_t prevCaseOffset;
/* Emit code for evaluating cases and jumping to case statements. */
for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
ParseNode* caseValue = caseNode->pn_left;
// If the expression is a literal, suppress line number
// emission so that debugging works more naturally.
if (caseValue &&
!emitTree(caseValue, caseValue->isLiteral() ? SUPPRESS_LINENOTE :
EMIT_LINENOTE))
return false;
// Emit code for evaluating cases and jumping to case statements.
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
ParseNode* caseValue = caseNode->caseExpression();
// If the expression is a literal, suppress line number emission so
// that debugging works more naturally.
if (caseValue) {
if (!emitTree(caseValue,
caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
{
return false;
}
}
if (!beforeCases) {
/* prevCaseOffset is the previous JSOP_CASE's bytecode offset. */
// prevCaseOffset is the previous JSOP_CASE's bytecode offset.
if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - prevCaseOffset))
return false;
}
if (!caseValue) {
MOZ_ASSERT(caseNode->isKind(PNK_DEFAULT));
// This is the default clause.
continue;
}
if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex))
return false;
if (!emitJump(JSOP_CASE, 0, &prevCaseOffset))
return false;
caseNode->pn_offset = prevCaseOffset;
caseNode->setOffset(prevCaseOffset);
if (beforeCases) {
/* Switch note's second offset is to first JSOP_CASE. */
// Switch note's second offset is to first JSOP_CASE.
unsigned noteCount = notes().length();
if (!setSrcNoteOffset(noteIndex, 1, prevCaseOffset - top))
return false;
@@ -3246,12 +3245,10 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
}
}
/*
* If we didn't have an explicit default (which could fall in between
* cases, preventing us from fusing this setSrcNoteOffset with the call
* in the loop above), link the last case to the implicit default for
* the benefit of IonBuilder.
*/
// If we didn't have an explicit default (which could fall in between
// cases, preventing us from fusing this setSrcNoteOffset with the call
// in the loop above), link the last case to the implicit default for
// the benefit of IonBuilder.
if (!hasDefault &&
!beforeCases &&
!setSrcNoteOffset(caseNoteIndex, 0, offset() - prevCaseOffset))
@@ -3259,14 +3256,14 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
return false;
}
/* Emit default even if no explicit default statement. */
// Emit default even if no explicit default statement.
if (!emitJump(JSOP_DEFAULT, 0, &condSwitchDefaultOff))
return false;
} else {
MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
jsbytecode* pc = code(top + JUMP_OFFSET_LEN);
/* Fill in switch bounds, which we know fit in 16-bit offsets. */
// Fill in switch bounds, which we know fit in 16-bit offsets.
SET_JUMP_OFFSET(pc, low);
pc += JUMP_OFFSET_LEN;
SET_JUMP_OFFSET(pc, high);
@@ -3276,49 +3273,49 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
if (!table.growBy(tableLength))
return false;
for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
if (caseNode->isKind(PNK_DEFAULT))
continue;
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
if (ParseNode* caseValue = caseNode->caseExpression()) {
MOZ_ASSERT(caseValue->isKind(PNK_NUMBER));
MOZ_ASSERT(caseNode->isKind(PNK_CASE));
int32_t i = int32_t(caseValue->pn_dval);
MOZ_ASSERT(double(i) == caseValue->pn_dval);
ParseNode* caseValue = caseNode->pn_left;
MOZ_ASSERT(caseValue->isKind(PNK_NUMBER));
int32_t i = int32_t(caseValue->pn_dval);
MOZ_ASSERT(double(i) == caseValue->pn_dval);
i -= low;
MOZ_ASSERT(uint32_t(i) < tableLength);
MOZ_ASSERT(!table[i]);
table[i] = caseNode;
i -= low;
MOZ_ASSERT(uint32_t(i) < tableLength);
MOZ_ASSERT(!table[i]);
table[i] = caseNode;
}
}
}
}
ptrdiff_t defaultOffset = -1;
/* Emit code for each case's statements, copying pn_offset up to caseNode. */
for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
if (switchOp == JSOP_CONDSWITCH && !caseNode->isKind(PNK_DEFAULT))
setJumpOffsetAt(caseNode->pn_offset);
ParseNode* caseValue = caseNode->pn_right;
if (!emitTree(caseValue))
// Emit code for each case's statements.
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
if (switchOp == JSOP_CONDSWITCH && !caseNode->isDefault())
setJumpOffsetAt(caseNode->offset());
// If this is emitted as a TABLESWITCH, we'll need to know this case's
// offset later when emitting the table. Store it in the node's
// pn_offset (giving the field a different meaning vs. how we used it
// on the immediately preceding line of code).
ptrdiff_t here = offset();
caseNode->setOffset(here);
if (caseNode->isDefault())
defaultOffset = here - top;
if (!emitTree(caseNode->statementList()))
return false;
caseNode->pn_offset = caseValue->pn_offset;
if (caseNode->isKind(PNK_DEFAULT))
defaultOffset = caseNode->pn_offset - top;
}
if (!hasDefault) {
/* If no default case, offset for default is to end of switch. */
// If no default case, offset for default is to end of switch.
defaultOffset = offset() - top;
}
/* We better have set "defaultOffset" by now. */
MOZ_ASSERT(defaultOffset != -1);
/* Set the default offset (to end of switch if no default). */
// Set the default offset (to end of switch if no default).
jsbytecode* pc;
if (switchOp == JSOP_CONDSWITCH) {
pc = nullptr;
@@ -3329,18 +3326,18 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
pc += JUMP_OFFSET_LEN;
}
/* Set the SRC_SWITCH note's offset operand to tell end of switch. */
// Set the SRC_SWITCH note's offset operand to tell end of switch.
if (!setSrcNoteOffset(noteIndex, 0, offset() - top))
return false;
if (switchOp == JSOP_TABLESWITCH) {
/* Skip over the already-initialized switch bounds. */
// Skip over the already-initialized switch bounds.
pc += 2 * JUMP_OFFSET_LEN;
/* Fill in the jump table, if there is one. */
// Fill in the jump table, if there is one.
for (uint32_t i = 0; i < tableLength; i++) {
ParseNode* caseNode = table[i];
ptrdiff_t off = caseNode ? caseNode->pn_offset - top : 0;
CaseClause* caseNode = table[i];
ptrdiff_t off = caseNode ? caseNode->offset() - top : 0;
SET_JUMP_OFFSET(pc, off);
pc += JUMP_OFFSET_LEN;
}
@@ -5354,12 +5351,13 @@ BytecodeEmitter::emitForInOrOfVariables(ParseNode* pn, bool* letDecl)
}
bool
BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn)
{
MOZ_ASSERT(type == StmtType::FOR_OF_LOOP || type == StmtType::SPREAD);
MOZ_ASSERT_IF(type == StmtType::FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
MOZ_ASSERT_IF(type == StmtType::SPREAD, !pn);
ptrdiff_t top = offset();
ParseNode* forHead = pn ? pn->pn_left : nullptr;
ParseNode* forHeadExpr = forHead ? forHead->pn_kid3 : nullptr;
ParseNode* forBody = pn ? pn->pn_right : nullptr;
@@ -5505,8 +5503,9 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top)
}
bool
BytecodeEmitter::emitForIn(ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitForIn(ParseNode* pn)
{
ptrdiff_t top = offset();
ParseNode* forHead = pn->pn_left;
ParseNode* forBody = pn->pn_right;
@@ -5627,10 +5626,10 @@ BytecodeEmitter::emitForIn(ParseNode* pn, ptrdiff_t top)
/* C-style `for (init; cond; update) ...` loop. */
bool
BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitCStyleFor(ParseNode* pn)
{
LoopStmtInfo stmtInfo(cx);
pushLoopStatement(&stmtInfo, StmtType::FOR_LOOP, top);
pushLoopStatement(&stmtInfo, StmtType::FOR_LOOP, offset());
ParseNode* forHead = pn->pn_left;
ParseNode* forBody = pn->pn_right;
@@ -5700,7 +5699,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top)
return false;
}
top = offset();
ptrdiff_t top = offset();
stmtInfo.setTop(top);
/* Emit code for the loop body. */
@@ -5802,19 +5801,19 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top)
}
bool
BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitFor(ParseNode* pn)
{
if (pn->pn_left->isKind(PNK_FORHEAD))
return emitCStyleFor(pn, top);
return emitCStyleFor(pn);
if (!updateLineNumberNotes(pn->pn_pos.begin))
return false;
if (pn->pn_left->isKind(PNK_FORIN))
return emitForIn(pn, top);
return emitForIn(pn);
MOZ_ASSERT(pn->pn_left->isKind(PNK_FOROF));
return emitForOf(StmtType::FOR_OF_LOOP, pn, top);
return emitForOf(StmtType::FOR_OF_LOOP, pn);
}
MOZ_NEVER_INLINE bool
@@ -6043,7 +6042,7 @@ BytecodeEmitter::emitDo(ParseNode* pn)
}
bool
BytecodeEmitter::emitWhile(ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitWhile(ParseNode* pn)
{
/*
* Minimize bytecodes issued for one or more iterations by jumping to
@@ -6073,7 +6072,7 @@ BytecodeEmitter::emitWhile(ParseNode* pn, ptrdiff_t top)
return false;
LoopStmtInfo stmtInfo(cx);
pushLoopStatement(&stmtInfo, StmtType::WHILE_LOOP, top);
pushLoopStatement(&stmtInfo, StmtType::WHILE_LOOP, offset());
unsigned noteIndex;
if (!newSrcNote(SRC_WHILE, &noteIndex))
@@ -6083,7 +6082,7 @@ BytecodeEmitter::emitWhile(ParseNode* pn, ptrdiff_t top)
if (!emitJump(JSOP_GOTO, 0, &jmp))
return false;
top = offset();
ptrdiff_t top = offset();
if (!emitLoopHead(pn->pn_right))
return false;
@@ -6406,7 +6405,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
}
bool
BytecodeEmitter::emitStatementList(ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitStatementList(ParseNode* pn)
{
MOZ_ASSERT(pn->isArity(PN_LIST));
for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
@@ -7286,7 +7285,7 @@ BytecodeEmitter::emitArrayComp(ParseNode* pn)
bool
BytecodeEmitter::emitSpread()
{
return emitForOf(StmtType::SPREAD, nullptr, -1);
return emitForOf(StmtType::SPREAD, nullptr);
}
bool
@@ -7610,8 +7609,6 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
EmitLevelManager elm(this);
bool ok = true;
ptrdiff_t top = offset();
pn->pn_offset = top;
/* Emit notes to tell the current bytecode's source line number.
However, a couple trees require special treatment; see the
@@ -7723,7 +7720,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_WHILE:
ok = emitWhile(pn, top);
ok = emitWhile(pn);
break;
case PNK_DOWHILE:
@@ -7731,7 +7728,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_FOR:
ok = emitFor(pn, top);
ok = emitFor(pn);
break;
case PNK_BREAK:
@@ -7779,7 +7776,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_STATEMENTLIST:
ok = emitStatementList(pn, top);
ok = emitStatementList(pn);
break;
case PNK_SEMI:
+6 -6
View File
@@ -566,7 +566,7 @@ struct BytecodeEmitter
bool emitReturn(ParseNode* pn);
bool emitStatement(ParseNode* pn);
bool emitStatementList(ParseNode* pn, ptrdiff_t top);
bool emitStatementList(ParseNode* pn);
bool emitDeleteName(ParseNode* pn);
bool emitDeleteProperty(ParseNode* pn);
@@ -589,11 +589,11 @@ struct BytecodeEmitter
bool emitSelfHostedForceInterpreter(ParseNode* pn);
bool emitDo(ParseNode* pn);
bool emitFor(ParseNode* pn, ptrdiff_t top);
bool emitForIn(ParseNode* pn, ptrdiff_t top);
bool emitFor(ParseNode* pn);
bool emitForIn(ParseNode* pn);
bool emitForInOrOfVariables(ParseNode* pn, bool* letDecl);
bool emitCStyleFor(ParseNode* pn, ptrdiff_t top);
bool emitWhile(ParseNode* pn, ptrdiff_t top);
bool emitCStyleFor(ParseNode* pn);
bool emitWhile(ParseNode* pn);
bool emitBreak(PropertyName* label);
bool emitContinue(PropertyName* label);
@@ -620,7 +620,7 @@ struct BytecodeEmitter
//
// Please refer the comment above emitSpread for additional information about
// stack convention.
bool emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top);
bool emitForOf(StmtType type, ParseNode* pn);
bool emitClass(ParseNode* pn);
bool emitSuperPropLHS(bool isCall = false);
+9 -10
View File
@@ -238,13 +238,8 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
MOZ_ASSERT(node->isArity(PN_BINARY));
return ContainsHoistedDeclaration(cx, node->pn_right, result);
// A case/default node's right half is its statements. A default node's
// left half is null; a case node's left half is its expression.
case PNK_DEFAULT:
MOZ_ASSERT(!node->pn_left);
case PNK_CASE:
MOZ_ASSERT(node->isArity(PN_BINARY));
return ContainsHoistedDeclaration(cx, node->pn_right, result);
return ContainsHoistedDeclaration(cx, node->as<CaseClause>().statementList(), result);
case PNK_FOR: {
MOZ_ASSERT(node->isArity(PN_BINARY));
@@ -1873,7 +1868,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return FoldCall(cx, pn, parser, inGenexpLambda);
case PNK_SWITCH:
case PNK_CASE:
case PNK_COLON:
case PNK_ASSIGN:
case PNK_ADDASSIGN:
@@ -1924,11 +1918,16 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return FoldCondition(cx, &pn->pn_left, parser, inGenexpLambda) &&
Fold(cx, &pn->pn_right, parser, inGenexpLambda);
case PNK_DEFAULT:
case PNK_CASE: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(!pn->pn_left);
MOZ_ASSERT(pn->pn_right->isKind(PNK_STATEMENTLIST));
// pn_left is null for DefaultClauses.
if (pn->pn_left) {
if (!Fold(cx, &pn->pn_left, parser, inGenexpLambda))
return false;
}
return Fold(cx, &pn->pn_right, parser, inGenexpLambda);
}
case PNK_WITH:
MOZ_ASSERT(pn->isArity(PN_BINARY_OBJ));
+1 -2
View File
@@ -577,8 +577,7 @@ class FullParseHandler
}
ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
TokenPos pos(begin, body->pn_pos.end);
return new_<BinaryNode>(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body);
return new_<CaseClause>(expr, body, begin);
}
ParseNode* newContinueStatement(PropertyName* label, const TokenPos& pos) {
+5 -3
View File
@@ -441,7 +441,6 @@ class NameResolver
case PNK_MODASSIGN:
case PNK_POWASSIGN:
case PNK_COLON:
case PNK_CASE:
case PNK_SHORTHAND:
case PNK_DOWHILE:
case PNK_WHILE:
@@ -472,9 +471,12 @@ class NameResolver
return false;
break;
case PNK_DEFAULT:
case PNK_CASE:
MOZ_ASSERT(cur->isArity(PN_BINARY));
MOZ_ASSERT(!cur->pn_left);
if (ParseNode* caseExpr = cur->pn_left) {
if (!resolve(caseExpr, prefix))
return false;
}
if (!resolve(cur->pn_right, prefix))
return false;
break;
+4 -12
View File
@@ -273,7 +273,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_IMPORT_SPEC:
case PNK_EXPORT_SPEC:
case PNK_COLON:
case PNK_CASE:
case PNK_SHORTHAND:
case PNK_DOWHILE:
case PNK_WHILE:
@@ -288,7 +287,10 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushResult::Recyclable;
}
// Named class expressions do not have outer binding nodes
// Default clauses are PNK_CASE but do not have case expressions.
// Named class expressions do not have outer binding nodes.
// So both are binary nodes with a possibly-null pn_left.
case PNK_CASE:
case PNK_CLASSNAMES: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
if (pn->pn_left)
@@ -308,16 +310,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushResult::Recyclable;
}
// Default nodes, for dumb reasons that we're not changing now (mostly
// structural semi-consistency with PNK_CASE nodes), have a null left
// node and a non-null right node.
case PNK_DEFAULT: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_left == nullptr);
stack->push(pn->pn_right);
return PushResult::Recyclable;
}
// The left half is the expression being yielded. The right half is
// internal goop: a name reference to the invisible '.generator' local
// variable, or an assignment of a PNK_GENERATOR node to the '.generator'
+38 -14
View File
@@ -123,7 +123,6 @@ class PackedScopeCoordinate
F(IF) \
F(SWITCH) \
F(CASE) \
F(DEFAULT) \
F(WHILE) \
F(DOWHILE) \
F(FOR) \
@@ -297,17 +296,15 @@ IsDeleteKind(ParseNodeKind kind)
* PNK_STATEMENTLIST.
* PNK_SWITCH binary pn_left: discriminant
* pn_right: list of PNK_CASE nodes, with at most one
* PNK_DEFAULT node, or if there are let bindings
* default node, or if there are let bindings
* in the top level of the switch body's cases, a
* PNK_LEXICALSCOPE node that contains the list of
* PNK_CASE nodes.
* PNK_CASE, binary pn_left: case expr
* PNK_CASE binary pn_left: case-expression if CaseClause, or
* null if DefaultClause
* pn_right: PNK_STATEMENTLIST node for this case's
* statements
* PNK_DEFAULT binary pn_left: null
* pn_right: PNK_STATEMENTLIST node for this default's
* statements
* pn_val: constant value if lookup or table switch
* pn_u.binary.offset: scratch space for the emitter
* PNK_WHILE binary pn_left: cond, pn_right: body
* PNK_DOWHILE binary pn_left: body, pn_right: cond
* PNK_FOR binary pn_left: either PNK_FORIN (for-in statement),
@@ -501,7 +498,6 @@ enum ParseNodeArity
struct Definition;
class LabeledStatement;
class LoopControlStatement;
class BreakStatement;
class ContinueStatement;
@@ -523,7 +519,7 @@ class ParseNode
public:
ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
: pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
pn_pos(0, 0), pn_offset(0), pn_next(nullptr), pn_link(nullptr)
pn_pos(0, 0), pn_next(nullptr), pn_link(nullptr)
{
MOZ_ASSERT(kind < PNK_LIMIT);
memset(&pn_u, 0, sizeof pn_u);
@@ -531,7 +527,7 @@ class ParseNode
ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity, const TokenPos& pos)
: pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
pn_pos(pos), pn_offset(0), pn_next(nullptr), pn_link(nullptr)
pn_pos(pos), pn_next(nullptr), pn_link(nullptr)
{
MOZ_ASSERT(kind < PNK_LIMIT);
memset(&pn_u, 0, sizeof pn_u);
@@ -583,8 +579,7 @@ class ParseNode
"This is supposed to fit in a single uint32_t");
TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
int32_t pn_offset; /* first generated bytecode offset */
ParseNode* pn_next; /* intrinsic link in parent PN_LIST */
ParseNode* pn_next; /* intrinsic link in parent PN_LIST */
/*
* Nodes that represent lexical bindings may, in addition to being
@@ -619,8 +614,9 @@ class ParseNode
ParseNode* right;
union {
unsigned iflags; /* JSITER_* flags for PNK_FOR node */
ObjectBox* objbox; /* Only for PN_BINARY_OBJ */
bool isStatic; /* Only for PNK_CLASSMETHOD */
ObjectBox* objbox; /* only for PN_BINARY_OBJ */
bool isStatic; /* only for PNK_CLASSMETHOD */
uint32_t offset; /* for the emitter's use on PNK_CASE nodes */
};
} binary;
struct { /* one kid if unary */
@@ -1152,6 +1148,34 @@ class LabeledStatement : public ParseNode
}
};
// Inside a switch statement, a CaseClause is a case-label and the subsequent
// statements. The same node type is used for DefaultClauses. The only
// difference is that their caseExpression() is null.
class CaseClause : public BinaryNode
{
public:
CaseClause(ParseNode* expr, ParseNode* stmts, uint32_t begin)
: BinaryNode(PNK_CASE, JSOP_NOP, TokenPos(begin, stmts->pn_pos.end), expr, stmts) {}
ParseNode* caseExpression() const { return pn_left; }
bool isDefault() const { return !caseExpression(); }
ParseNode* statementList() const { return pn_right; }
// The next CaseClause in the same switch statement.
CaseClause* next() const { return pn_next ? &pn_next->as<CaseClause>() : nullptr; }
// Scratch space used by the emitter.
uint32_t offset() const { return pn_u.binary.offset; }
void setOffset(uint32_t u) { pn_u.binary.offset = u; }
static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_CASE);
MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
return match;
}
};
class LoopControlStatement : public ParseNode
{
protected:
+5
View File
@@ -8644,6 +8644,11 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
return nextMember;
}
if (options().selfHostingMode && handler.isPropertyAccess(lhs)) {
report(ParseError, false, null(), JSMSG_SELFHOSTED_METHOD_CALL);
return null();
}
nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
if (!nextMember)
return null();
+4 -2
View File
@@ -2526,8 +2526,10 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
* The GC and CC are run independently. Consequently, the following sequence of
* events can occur:
* 1. GC runs and marks an object gray.
* 2. Some JS code runs that creates a pointer from a JS root to the gray
* object. If we re-ran a GC at this point, the object would now be black.
* 2. The mutator runs (specifically, some C++ code with access to gray
* objects) and creates a pointer from a JS root or other black object to
* the gray object. If we re-ran a GC at this point, the object would now be
* black.
* 3. Now we run the CC. It may think it can collect the gray object, even
* though it's reachable from the JS heap.
*
+1 -1
View File
@@ -24,7 +24,7 @@ FRAGMENT(asmjs, segfault) {
CompileOptions opts(cx);
opts.setFileAndLine(__FILE__, line0 + 1);
opts.asmJSOption = true;
opts.asmJSOption = JS::AsmJSOption::Enabled;
RootedValue rval(cx);
bool ok;
ok = false;
+9 -6
View File
@@ -17,7 +17,7 @@ def add_libdir_to_path():
add_libdir_to_path()
import jittests
from tests import get_jitflags
from tests import get_jitflags, get_environment_overlay, change_env
# Python 3.3 added shutil.which, but we can't use that yet.
def which(name):
@@ -149,8 +149,9 @@ def main(argv):
options, args = op.parse_args(argv)
if len(args) < 1:
op.error('missing JS_SHELL argument')
# We need to make sure we are using backslashes on Windows.
js_shell = which(args[0])
test_args = args[1:]
test_environment = get_environment_overlay(js_shell)
if jittests.stdio_might_be_broken():
# Prefer erring on the side of caution and not using stdio if
@@ -209,7 +210,7 @@ def main(argv):
file=sys.stderr)
sys.exit(0)
test_list = [jittests.Test.from_file(_, options) for _ in test_list]
test_list = [jittests.JitTest.from_file(_, options) for _ in test_list]
if not options.run_slow:
test_list = [_ for _ in test_list if not _.slow]
@@ -249,7 +250,7 @@ def main(argv):
else:
options.ignore_timeouts = set()
prefix = [which(args[0])] + shlex.split(options.shell_args)
prefix = [js_shell] + shlex.split(options.shell_args)
prologue = os.path.join(jittests.LIB_DIR, 'prologue.js')
if options.remote:
prologue = posixpath.join(options.remote_test_root,
@@ -277,7 +278,8 @@ def main(argv):
else:
debug_cmd = options.debugger.split()
subprocess.call(debug_cmd + tc.command(prefix, jittests.LIB_DIR))
with change_env(test_environment):
subprocess.call(debug_cmd + tc.command(prefix, jittests.LIB_DIR))
sys.exit()
try:
@@ -287,7 +289,8 @@ def main(argv):
elif options.max_jobs > 1 and jittests.HAVE_MULTIPROCESSING:
ok = jittests.run_tests_parallel(job_list, prefix, options)
else:
ok = jittests.run_tests(job_list, prefix, options)
with change_env(test_environment):
ok = jittests.run_tests(job_list, prefix, options)
if not ok:
sys.exit(2)
except OSError:
+1 -1
View File
@@ -9,7 +9,7 @@ function evalWithCache(code, ctx) {
// We create a new global ...
if (!("global" in ctx))
ctx.global = newGlobal();
ctx.global = newGlobal({ cloneSingletons: true });
if (!("isRunOnce" in ctx))
ctx.isRunOnce = true;
+2
View File
@@ -3,6 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// explicitly run on ECMA 5
version(185);
var appendToActual = function(s) {
actual += s + ',';
@@ -15,7 +15,7 @@ function f(stdlib, foreign, buffer)
if (isAsmJSCompilationAvailable())
assertEq(isAsmJSModule(f), true);
var i32 = new Int32Array(4096);
var i32 = new Int32Array(65536);
var buffer = i32.buffer;
var set = f(this, null, buffer);
if (isAsmJSCompilationAvailable())
@@ -8,6 +8,7 @@ test = (function () {
evalWithCache(test, {});
function evalWithCache(code, ctx) {
code = cacheEntry(code);
ctx.global = newGlobal({ cloneSingletons: true });
ctx.isRunOnce = true;
var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } }));
var res2 = evaluate(code, Object.create(ctx, {loadBytecode: { value: true }, saveBytecode: { value: true } }));
@@ -6,6 +6,7 @@ test = (function () {
evalWithCache(test, {});
function evalWithCache(code, ctx) {
code = cacheEntry(code);
ctx.global = newGlobal({ cloneSingletons: true });
var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } }));
}
if (typeof assertThrowsInstanceOf === 'undefined') {
@@ -0,0 +1,23 @@
// Debugger.allowUnobservedAsmJS with off-thread parsing.
load(libdir + "asm.js");
if (helperThreadCount() == 0)
quit();
var g = newGlobal();
g.parent = this;
g.eval("dbg = new Debugger(parent);");
assertEq(g.dbg.allowUnobservedAsmJS, false);
enableLastWarning();
var asmFunStr = USE_ASM + 'function f() {} return f';
offThreadCompileScript("(function() {" + asmFunStr + "})");
runOffThreadScript();
var msg = getLastWarning().message;
assertEq(msg === "asm.js type error: Disabled by debugger" ||
msg === "asm.js type error: Disabled by lack of floating point support",
true);
@@ -8,14 +8,38 @@ const root = newGlobal();
const dbg = new Debugger();
const wrappedRoot = dbg.addDebuggee(root);
// Out of range.
var mem = dbg.memory;
assertThrowsInstanceOf(() => dbg.memory.allocationSamplingProbability = -1,
// Out of range, negative
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -Number.MAX_VALUE,
TypeError);
assertThrowsInstanceOf(() => dbg.memory.allocationSamplingProbability = 2,
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -1,
TypeError);
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -Number.MIN_VALUE,
TypeError);
// In range
dbg.memory.allocationSamplingProbability = 0;
dbg.memory.allocationSamplingProbability = 1;
dbg.memory.allocationSamplingProbability = .5;
mem.allocationSamplingProbability = -0.0;
mem.allocationSamplingProbability = 0.0;
mem.allocationSamplingProbability = Number.MIN_VALUE;
mem.allocationSamplingProbability = 1 / 3;
mem.allocationSamplingProbability = .5;
mem.allocationSamplingProbability = 2 / 3;
mem.allocationSamplingProbability = 1 - Math.pow(2, -53);
mem.allocationSamplingProbability = 1;
// Out of range, positive
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = 1 + Number.EPSILON,
TypeError);
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = 2,
TypeError);
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = Number.MAX_VALUE,
TypeError);
// Out of range, non-finite
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -Infinity,
TypeError);
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = Infinity,
TypeError);
assertThrowsInstanceOf(() => mem.allocationSamplingProbability = NaN,
TypeError);
+1 -1
View File
@@ -5,7 +5,7 @@ gczeal(2);
(function() {
evaluate(cacheEntry((function() {
return "".toSource()
})()), Object.create({}, {
})()), Object.create({ global: newGlobal({ cloneSingletons: true }) }, {
saveBytecode: {
value: true
}
+9
View File
@@ -0,0 +1,9 @@
var caught = false;
try {
evaluate(cacheEntry(""), {saveBytecode: {value: true}, global: this});
[[0]];
} catch (err) {
caught = true;
assertEq(err.message, "compartment cannot save singleton anymore.");
}
assertEq(caught, true);
+15
View File
@@ -0,0 +1,15 @@
// |jit-test| error: cache does not have the same size
load(libdir + 'bytecode-cache.js');
var test = (function () {
function f(x) {
function ifTrue() {};
function ifFalse() {};
if (generation % 2 == 0)
return ifTrue();
return ifFalse();
}
return f.toSource() + "; f()";
})();
evalWithCache(test, { assertEqBytecode: true, assertEqResult : true });
+1 -1
View File
@@ -150,7 +150,7 @@ test = `
evalWithCache(test, { assertEqBytecode: true, assertEqResult: true });
// And more of the same, in a slightly different way
var g1 = newGlobal();
var g1 = newGlobal({ cloneSingletons: true });
var g2 = newGlobal();
var res = "function f(){}";
var code = cacheEntry(res + "; f();");
+2 -1
View File
@@ -117,7 +117,8 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
data.result.setInt32(data.numActualArgs);
{
AssertCompartmentUnchanged pcc(cx);
JitActivation activation(cx, data.calleeToken);
ActivationEntryMonitor entryMonitor(cx, data.calleeToken);
JitActivation activation(cx);
if (data.osrFrame)
data.osrFrame->setRunningInJit();
+4 -2
View File
@@ -2687,7 +2687,8 @@ EnterIon(JSContext* cx, EnterJitData& data)
data.result.setInt32(data.numActualArgs);
{
AssertCompartmentUnchanged pcc(cx);
JitActivation activation(cx, data.calleeToken);
ActivationEntryMonitor entryMonitor(cx, data.calleeToken);
JitActivation activation(cx);
CALL_GENERATED_CODE(enter, data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */nullptr, data.calleeToken,
/* scopeChain = */ nullptr, 0, data.result.address());
@@ -2816,7 +2817,8 @@ jit::FastInvoke(JSContext* cx, HandleFunction fun, CallArgs& args)
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT(!ion->bailoutExpected());
JitActivation activation(cx, CalleeToToken(script));
ActivationEntryMonitor entryMonitor(cx, CalleeToToken(script));
JitActivation activation(cx);
EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
void* calleeToken = CalleeToToken(fun, /* constructing = */ false);
+1
View File
@@ -314,6 +314,7 @@ MSG_DEF(JSMSG_RESERVED_ID, 1, JSEXN_SYNTAXERR, "{0} is a reserved id
MSG_DEF(JSMSG_REST_WITH_DEFAULT, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL, 1, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level {0} declarations")
MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL, 0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls")
MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 0, JSEXN_SYNTAXERR, "missing ; before statement")
+14 -1
View File
@@ -1220,6 +1220,14 @@ JS_GetErrorPrototype(JSContext* cx)
return GlobalObject::getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR);
}
JS_PUBLIC_API(JSObject*)
JS_GetIteratorPrototype(JSContext* cx)
{
CHECK_REQUEST(cx);
Rooted<GlobalObject*> global(cx, cx->global());
return GlobalObject::getOrCreateIteratorPrototype(cx, global);
}
JS_PUBLIC_API(JSObject*)
JS_GetGlobalForObject(JSContext* cx, JSObject* obj)
{
@@ -3983,7 +3991,12 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version)
strictOption = cx->runtime()->options().strictMode();
extraWarningsOption = cx->compartment()->options().extraWarnings(cx);
werrorOption = cx->runtime()->options().werror();
asmJSOption = cx->runtime()->options().asmJS();
if (!cx->runtime()->options().asmJS())
asmJSOption = AsmJSOption::Disabled;
else if (cx->compartment()->debuggerObservesAsmJS())
asmJSOption = AsmJSOption::DisabledByDebugger;
else
asmJSOption = AsmJSOption::Enabled;
throwOnAsmJSValidationFailureOption = cx->runtime()->options().throwOnAsmJSValidationFailure();
}
+11 -2
View File
@@ -1495,6 +1495,13 @@ JS_GetArrayPrototype(JSContext* cx, JS::HandleObject forObj);
extern JS_PUBLIC_API(JSObject*)
JS_GetErrorPrototype(JSContext* cx);
/**
* Returns the %IteratorPrototype% object that all built-in iterator prototype
* chains go through for the global object of the current compartment of cx.
*/
extern JS_PUBLIC_API(JSObject*)
JS_GetIteratorPrototype(JSContext* cx);
extern JS_PUBLIC_API(JSObject*)
JS_GetGlobalForObject(JSContext* cx, JSObject* obj);
@@ -3562,6 +3569,8 @@ namespace JS {
* derived from ReadOnlyCompileOptions, so the compiler accepts it.
*/
enum class AsmJSOption : uint8_t { Enabled, Disabled, DisabledByDebugger };
/**
* The common base class for the CompileOptions hierarchy.
*
@@ -3604,7 +3613,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
strictOption(false),
extraWarningsOption(false),
werrorOption(false),
asmJSOption(false),
asmJSOption(AsmJSOption::Disabled),
throwOnAsmJSValidationFailureOption(false),
forceAsync(false),
installedFile(false),
@@ -3639,7 +3648,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
bool strictOption;
bool extraWarningsOption;
bool werrorOption;
bool asmJSOption;
AsmJSOption asmJSOption;
bool throwOnAsmJSValidationFailureOption;
bool forceAsync;
bool installedFile; // 'true' iff pre-compiling js file in packaged app
+43
View File
@@ -0,0 +1,43 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// A basic synchronous module loader for testing the shell.
Reflect.Loader = new class {
constructor() {
this.registry = new Map();
this.loadPath = getModuleLoadPath();
}
resolve(name) {
if (os.path.isAbsolute(name))
return name;
return os.path.join(this.loadPath, name);
}
fetch(path) {
return os.file.readFile(path);
}
loadAndParse(name) {
let path = this.resolve(name);
if (this.registry.has(path))
return this.registry.get(path);
let source = this.fetch(path);
let module = parseModule(source, path);
this.registry.set(path, module);
return module;
}
["import"](name, referrer) {
let module = this.loadAndParse(name);
module.declarationInstantiation();
return module.evaluation();
}
};
setModuleResolveHook((module, requestName) => Reflect.Loader.loadAndParse(requestName));
+429 -179
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -34,3 +34,12 @@ OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
if not CONFIG['GNU_CXX']:
ALLOW_COMPILER_WARNINGS = True
# Prepare module loader JS code for embedding
GENERATED_FILES += ['shellmoduleloader.out.h']
shellmoduleloader = GENERATED_FILES['shellmoduleloader.out.h']
shellmoduleloader.script = '../builtin/embedjs.py:generate_shellmoduleloader'
shellmoduleloader.inputs = [
'../js.msg',
'ModuleLoader.js',
]
+14 -16
View File
@@ -13,7 +13,8 @@ from contextlib import contextmanager
from copy import copy
from subprocess import list2cmdline, call
from lib.tests import TestCase, get_jitflags
from lib.tests import RefTestCase, get_jitflags, get_environment_overlay, \
change_env
from lib.results import ResultsSink
from lib.progressbar import ProgressBar
@@ -211,8 +212,8 @@ def parse_args():
abspath(dirname(abspath(__file__))),
'..', '..', 'examples', 'jorendb.js'))
js_cmd_args.extend(['-d', '-f', debugger_path, '--'])
prefix = TestCase.build_js_cmd_prefix(options.js_shell, js_cmd_args,
debugger_prefix)
prefix = RefTestCase.build_js_cmd_prefix(options.js_shell, js_cmd_args,
debugger_prefix)
# If files with lists of tests to run were specified, add them to the
# requested tests set.
@@ -275,8 +276,8 @@ def load_tests(options, requested_paths, excluded_paths):
test_dir = dirname(abspath(__file__))
test_count = manifest.count_tests(test_dir, requested_paths, excluded_paths)
test_gen = manifest.load(test_dir, requested_paths, excluded_paths,
xul_tester)
test_gen = manifest.load_reftests(test_dir, requested_paths, excluded_paths,
xul_tester)
if options.make_manifests:
manifest.make_manifests(options.make_manifests, test_gen)
@@ -332,6 +333,7 @@ def main():
print('Could not find shell at given path.')
return 1
test_count, test_gen = load_tests(options, requested_paths, excluded_paths)
test_environment = get_environment_overlay(options.js_shell)
if test_count == 0:
print('no tests selected')
@@ -340,29 +342,25 @@ def main():
test_dir = dirname(abspath(__file__))
if options.debug:
if len(list(test_gen)) > 1:
tests = list(test_gen)
if len(tests) > 1:
print('Multiple tests match command line arguments,'
' debugger can only run one')
for tc in test_gen:
for tc in tests:
print(' {}'.format(tc.path))
return 2
cmd = test_gen[0].get_command(TestCase.js_cmd_prefix)
cmd = tests[0].get_command(prefix)
if options.show_cmd:
print(list2cmdline(cmd))
with changedir(test_dir):
with changedir(test_dir), change_env(test_environment):
call(cmd)
return 0
with changedir(test_dir):
# Force Pacific time zone to avoid failures in Date tests.
os.environ['TZ'] = 'PST8PDT'
# Force date strings to English.
os.environ['LC_TIME'] = 'en_US.UTF-8'
with changedir(test_dir), change_env(test_environment):
results = ResultsSink(options, test_count)
try:
for out in run_all_tests(test_gen, prefix, results, options):
for out in run_all_tests(test_gen, prefix, results.pb, options):
results.push(out)
results.finish(True)
except KeyboardInterrupt:
+5 -5
View File
@@ -78,7 +78,7 @@ def js_quote(quote, s):
os.path.relpath = _relpath
class Test:
class JitTest:
VALGRIND_CMD = []
paths = (d for d in os.environ['PATH'].split(os.pathsep))
@@ -122,7 +122,7 @@ class Test:
self.expect_status = 0 # Exit status to expect from shell
def copy(self):
t = Test(self.path)
t = JitTest(self.path)
t.jitflags = self.jitflags[:]
t.slow = self.slow
t.allow_oom = self.allow_oom
@@ -255,7 +255,7 @@ class Test:
# We may have specified '-a' or '-d' twice: once via --jitflags, once
# via the "|jit-test|" line. Remove dups because they are toggles.
cmd = prefix + ['--js-cache', Test.CacheDir]
cmd = prefix + ['--js-cache', JitTest.CacheDir]
cmd += list(set(self.jitflags)) + ['-e', expr, '-f', path]
if self.valgrind:
cmd = self.VALGRIND_CMD + cmd
@@ -831,8 +831,8 @@ def run_tests_remote(tests, prefix, options):
push_progs(options, dm, [prefix[0]])
dm.chmodDir(options.remote_test_root)
Test.CacheDir = posixpath.join(options.remote_test_root, '.js-cache')
dm.mkDir(Test.CacheDir)
JitTest.CacheDir = posixpath.join(options.remote_test_root, '.js-cache')
dm.mkDir(JitTest.CacheDir)
dm.pushDir(JS_TESTS_DIR, posixpath.join(jit_tests_dir, 'tests'),
timeout=600)
+11 -11
View File
@@ -7,7 +7,7 @@ from __future__ import print_function
import os, re, sys
from subprocess import Popen, PIPE
from tests import TestCase
from tests import RefTestCase
def split_path_into_dirs(path):
@@ -168,13 +168,13 @@ def _build_manifest_script_entry(script_name, test):
line.append(test.comment)
return ' '.join(line)
def _map_prefixes_left(test_list):
def _map_prefixes_left(test_gen):
"""
Splits tests into a dictionary keyed on the first component of the test
path, aggregating tests with a common base path into a list.
"""
byprefix = {}
for t in test_list:
for t in test_gen:
left, sep, remainder = t.path.partition(os.sep)
if left not in byprefix:
byprefix[left] = []
@@ -183,14 +183,14 @@ def _map_prefixes_left(test_list):
byprefix[left].append(t)
return byprefix
def _emit_manifest_at(location, relative, test_list, depth):
def _emit_manifest_at(location, relative, test_gen, depth):
"""
location - str: absolute path where we want to write the manifest
relative - str: relative path from topmost manifest directory to current
test_list - [str]: list of all test paths and directorys
test_gen - (str): generator of all test paths and directorys
depth - int: number of dirs we are below the topmost manifest dir
"""
manifests = _map_prefixes_left(test_list)
manifests = _map_prefixes_left(test_gen)
filename = os.path.join(location, 'jstests.list')
manifest = []
@@ -223,8 +223,8 @@ def _emit_manifest_at(location, relative, test_list, depth):
finally:
fp.close()
def make_manifests(location, test_list):
_emit_manifest_at(location, '', test_list, 0)
def make_manifests(location, test_gen):
_emit_manifest_at(location, '', test_gen, 0)
def _find_all_js_files(base, location):
for root, dirs, files in os.walk(location):
@@ -362,7 +362,7 @@ def count_tests(location, requested_paths, excluded_paths):
return count
def load(location, requested_paths, excluded_paths, xul_tester, reldir=''):
def load_reftests(location, requested_paths, excluded_paths, xul_tester, reldir=''):
"""
Locates all tests by walking the filesystem starting at |location|.
Uses xul_tester to evaluate any test conditions in the test header.
@@ -379,12 +379,12 @@ def load(location, requested_paths, excluded_paths, xul_tester, reldir=''):
filename = os.path.join(root, basename)
if not _is_test_file(root, basename, filename, requested_paths, excluded_paths):
continue
# Skip empty files.
fullpath = os.path.join(location, filename)
statbuf = os.stat(fullpath)
testcase = TestCase(os.path.join(reldir, filename))
testcase = RefTestCase(os.path.join(reldir, filename))
_apply_external_manifests(filename, testcase, externalManifestEntries,
xul_tester)
_parse_test_header(fullpath, testcase, xul_tester)
+11 -5
View File
@@ -137,10 +137,10 @@ def timed_out(task, timeout):
def reap_zombies(tasks, timeout):
"""
Search for children of this process that have finished. If they are tasks,
then this routine will clean up the child and send a TestOutput to the
results channel. This method returns a new task list that has had the ended
tasks removed.
Search for children of this process that have finished. If they are tasks,
then this routine will clean up the child. This method returns a new task
list that has had the ended tasks removed, followed by the list of finished
tasks.
"""
finished = []
while True:
@@ -182,7 +182,7 @@ def kill_undead(tasks, timeout):
if timed_out(task, timeout):
os.kill(task.pid, 9)
def run_all_tests(tests, prefix, results, options):
def run_all_tests(tests, prefix, pb, options):
# Copy and reverse for fast pop off end.
tests = list(tests)
tests = tests[:]
@@ -208,3 +208,9 @@ def run_all_tests(tests, prefix, results, options):
# With Python3.4+ we could use yield from to remove this loop.
for out in finished:
yield out
# If we did not finish any tasks, poke the progress bar to show that
# the test harness is at least not frozen.
if len(finished) == 0:
pb.poke()
+2 -2
View File
@@ -68,7 +68,7 @@ def _do_watch(qWatch, timeout):
assert fin is TaskFinishedMarker, "invalid finish marker"
def run_all_tests(tests, prefix, results, options):
def run_all_tests(tests, prefix, pb, options):
"""
Uses scatter-gather to a thread-pool to manage children.
"""
@@ -114,7 +114,7 @@ def run_all_tests(tests, prefix, results, options):
else:
yield result
except Empty:
results.pb.poke()
pb.poke()
# Cleanup and exit.
pusher.join()
+56 -5
View File
@@ -4,6 +4,7 @@
# metadata, and know how to run the tests and determine failures.
import datetime, os, sys, time
from contextlib import contextmanager
from subprocess import Popen, PIPE
from threading import Thread
@@ -45,7 +46,57 @@ def get_jitflags(variant, **kwargs):
return kwargs['none']
return JITFLAGS[variant]
class Test(object):
def get_environment_overlay(js_shell):
"""
Build a dict of additional environment variables that must be set to run
tests successfully.
"""
env = {
# Force Pacific time zone to avoid failures in Date tests.
'TZ': 'PST8PDT',
# Force date strings to English.
'LC_TIME': 'en_US.UTF-8',
# Tell the shell to disable crash dialogs on windows.
'XRE_NO_WINDOWS_CRASH_DIALOG': '1',
}
# Add the binary's directory to the library search path so that we find the
# nspr and icu we built, instead of the platform supplied ones (or none at
# all on windows).
if sys.platform.startswith('linux'):
env['LD_LIBRARY_PATH'] = os.path.dirname(js_shell)
elif sys.platform.startswith('darwin'):
env['DYLD_LIBRARY_PATH'] = os.path.dirname(js_shell)
elif sys.platform.startswith('win'):
env['PATH'] = os.path.dirname(js_shell)
return env
@contextmanager
def change_env(env_overlay):
# Apply the overlaid environment and record the current state.
prior_env = {}
for key, val in env_overlay.items():
prior_env[key] = os.environ.get(key, None)
if 'PATH' in key and key in os.environ:
os.environ[key] = '{}{}{}'.format(val, os.pathsep, os.environ[key])
else:
os.environ[key] = val
try:
# Execute with the new environment.
yield
finally:
# Restore the prior environment.
for key, val in prior_env.items():
if val is not None:
os.environ[key] = val
else:
del os.environ[key]
class RefTest(object):
"""A runnable test."""
def __init__(self, path):
self.path = path # str: path of JS file relative to tests root dir
@@ -59,19 +110,19 @@ class Test(object):
if path == '':
return ['-f', 'shell.js']
head, base = os.path.split(path)
return Test.prefix_command(head) \
return RefTest.prefix_command(head) \
+ ['-f', os.path.join(path, 'shell.js')]
def get_command(self, prefix):
dirname, filename = os.path.split(self.path)
cmd = prefix + self.jitflags + self.options \
+ Test.prefix_command(dirname) + ['-f', self.path]
+ RefTest.prefix_command(dirname) + ['-f', self.path]
return cmd
class TestCase(Test):
class RefTestCase(RefTest):
"""A test case consisting of a test and an expected result."""
def __init__(self, path):
Test.__init__(self, path)
RefTest.__init__(self, path)
self.enable = True # bool: True => run test, False => don't run
self.expect = True # bool: expected result, True => pass
self.random = False # bool: True => ignore output as 'random'
-7
View File
@@ -3,13 +3,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Explicitly set the default version.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=522760#c11
if (typeof version != 'undefined')
{
version(0);
}
var STATUS = "STATUS: ";
var VERBOSE = false;
var SECT_PREFIX = 'Section ';

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