From 205b93ba0946dd4a840b693b09549e4da2236b79 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Fri, 29 Aug 2014 14:47:30 -0400 Subject: [PATCH 001/120] Bug 1060165: Remove gfxPoint3D r=nical --- gfx/ipc/GfxMessageUtils.h | 21 -------- gfx/layers/LayerSorter.cpp | 9 ++-- gfx/layers/LayerTreeInvalidation.cpp | 1 - .../composite/AsyncCompositionManager.cpp | 15 +++--- gfx/layers/d3d10/ThebesLayerD3D10.cpp | 2 +- gfx/layers/ipc/LayerTransactionParent.cpp | 13 +++-- gfx/layers/ipc/LayersMessages.ipdlh | 6 +-- gfx/thebes/gfx3DMatrix.cpp | 30 +++++------ gfx/thebes/gfx3DMatrix.h | 14 ++--- gfx/thebes/gfxPoint3D.h | 19 ------- gfx/thebes/moz.build | 1 - layout/base/nsDisplayList.cpp | 52 +++++++++---------- layout/base/nsDisplayList.h | 19 +++---- layout/base/nsLayoutUtils.cpp | 1 - layout/style/StyleAnimationValue.cpp | 31 +++++------ layout/style/nsStyleTransformMatrix.cpp | 17 +++--- 16 files changed, 104 insertions(+), 147 deletions(-) delete mode 100644 gfx/thebes/gfxPoint3D.h diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index f672400013ac..865e93938935 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -17,7 +17,6 @@ #include "mozilla/gfx/Matrix.h" #include "GraphicsFilter.h" #include "gfxPoint.h" -#include "gfxPoint3D.h" #include "gfxRect.h" #include "nsRect.h" #include "nsRegion.h" @@ -154,26 +153,6 @@ struct ParamTraits } }; -template<> -struct ParamTraits -{ - typedef gfxPoint3D paramType; - - static void Write(Message* aMsg, const paramType& aParam) - { - WriteParam(aMsg, aParam.x); - WriteParam(aMsg, aParam.y); - WriteParam(aMsg, aParam.z); - } - - static bool Read(const Message* aMsg, void** aIter, paramType* aResult) - { - return (ReadParam(aMsg, aIter, &aResult->x) && - ReadParam(aMsg, aIter, &aResult->y) && - ReadParam(aMsg, aIter, &aResult->z)); - } -}; - template<> struct ParamTraits { diff --git a/gfx/layers/LayerSorter.cpp b/gfx/layers/LayerSorter.cpp index 213413df3668..e2841ca63b6c 100644 --- a/gfx/layers/LayerSorter.cpp +++ b/gfx/layers/LayerSorter.cpp @@ -13,7 +13,6 @@ #include "gfx3DMatrix.h" // for gfx3DMatrix #include "gfxLineSegment.h" // for gfxLineSegment #include "gfxPoint.h" // for gfxPoint -#include "gfxPoint3D.h" // for gfxPoint3D #include "gfxQuad.h" // for gfxQuad #include "gfxRect.h" // for gfxRect #include "gfxTypes.h" // for gfxFloat @@ -44,10 +43,10 @@ enum LayerSortOrder { */ static gfxFloat RecoverZDepth(const gfx3DMatrix& aTransform, const gfxPoint& aPoint) { - const gfxPoint3D l(0, 0, 1); - gfxPoint3D l0 = gfxPoint3D(aPoint.x, aPoint.y, 0); - gfxPoint3D p0 = aTransform.Transform3D(gfxPoint3D(0, 0, 0)); - gfxPoint3D normal = aTransform.GetNormalVector(); + const Point3D l(0, 0, 1); + Point3D l0 = Point3D(aPoint.x, aPoint.y, 0); + Point3D p0 = aTransform.Transform3D(Point3D(0, 0, 0)); + Point3D normal = aTransform.GetNormalVector(); gfxFloat n = normal.DotProduct(p0 - l0); gfxFloat d = normal.DotProduct(l); diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp index 0336e1824645..9f4bc2ffb5f8 100644 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ b/gfx/layers/LayerTreeInvalidation.cpp @@ -10,7 +10,6 @@ #include "Layers.h" // for Layer, ContainerLayer, etc #include "gfxColor.h" // for gfxRGBA #include "GraphicsFilter.h" // for GraphicsFilter -#include "gfxPoint3D.h" // for gfxPoint3D #include "gfxRect.h" // for gfxRect #include "gfxUtils.h" // for gfxUtils #include "mozilla/gfx/BaseSize.h" // for BaseSize diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index e8fd0d1320d4..32cb9d2d6860 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -11,7 +11,6 @@ #include "LayerManagerComposite.h" // for LayerManagerComposite, etc #include "Layers.h" // for Layer, ContainerLayer, etc #include "gfxPoint.h" // for gfxPoint, gfxSize -#include "gfxPoint3D.h" // for gfxPoint3D #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc #include "mozilla/WidgetUtils.h" // for ComputeTransformForRotation #include "mozilla/dom/AnimationPlayer.h" // for AnimationPlayer @@ -379,10 +378,10 @@ SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart, // adjust to dev pixels. double cssPerDev = double(nsDeviceContext::AppUnitsPerCSSPixel()) / double(data.appUnitsPerDevPixel()); - gfxPoint3D transformOrigin = data.transformOrigin(); + Point3D transformOrigin = data.transformOrigin(); transformOrigin.x = transformOrigin.x * cssPerDev; transformOrigin.y = transformOrigin.y * cssPerDev; - gfxPoint3D perspectiveOrigin = data.perspectiveOrigin(); + Point3D perspectiveOrigin = data.perspectiveOrigin(); perspectiveOrigin.x = perspectiveOrigin.x * cssPerDev; perspectiveOrigin.y = perspectiveOrigin.y * cssPerDev; nsDisplayTransform::FrameTransformProperties props(interpolatedList, @@ -393,10 +392,10 @@ SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart, nsDisplayTransform::GetResultingTransformMatrix(props, origin, data.appUnitsPerDevPixel(), &data.bounds()); - gfxPoint3D scaledOrigin = - gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(origin.x, data.appUnitsPerDevPixel())), - NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())), - 0.0f); + Point3D scaledOrigin = + Point3D(NS_round(NSAppUnitsToFloatPixels(origin.x, data.appUnitsPerDevPixel())), + NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())), + 0.0f); transform.Translate(scaledOrigin); @@ -882,7 +881,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) // in screen space when the compensatory transform is performed in // AlignFixedAndStickyLayers. ScreenRect contentScreenRect = mContentRect * userZoom; - gfxPoint3D overscrollTranslation; + Point3D overscrollTranslation; if (userScroll.x < contentScreenRect.x) { overscrollTranslation.x = contentScreenRect.x - userScroll.x; } else if (userScroll.x + metrics.mCompositionBounds.width > contentScreenRect.XMost()) { diff --git a/gfx/layers/d3d10/ThebesLayerD3D10.cpp b/gfx/layers/d3d10/ThebesLayerD3D10.cpp index 521c29729a0c..3b7b2578043d 100644 --- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp +++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp @@ -349,7 +349,7 @@ ThebesLayerD3D10::FillTexturesBlackWhite(const nsIntRegion& aRegion, const nsInt device()->OMSetRenderTargets(2, views, nullptr); gfx3DMatrix transform; - transform.Translate(gfxPoint3D(-aOffset.x, -aOffset.y, 0)); + transform.Translate(Point3D(-aOffset.x, -aOffset.y, 0)); void* raw = &const_cast(transform)._11; effect()->GetVariableByName("mLayerTransform")->SetRawValue(raw, 0, 64); diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 609f25f6795f..6ae7f85f8e53 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -11,7 +11,6 @@ #include "ImageLayers.h" // for ImageLayer #include "Layers.h" // for Layer, ContainerLayer, etc #include "ShadowLayerParent.h" // for ShadowLayerParent -#include "gfxPoint3D.h" // for gfxPoint3D #include "CompositableTransactionParent.h" // for EditReplyVector #include "ShadowLayersManager.h" // for ShadowLayersManager #include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D @@ -651,16 +650,16 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent, 1.0f); } float scale = 1; - gfxPoint3D scaledOrigin; - gfxPoint3D transformOrigin; + Point3D scaledOrigin; + Point3D transformOrigin; for (uint32_t i=0; i < layer->GetAnimations().Length(); i++) { if (layer->GetAnimations()[i].data().type() == AnimationData::TTransformData) { const TransformData& data = layer->GetAnimations()[i].data().get_TransformData(); scale = data.appUnitsPerDevPixel(); scaledOrigin = - gfxPoint3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)), - NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)), - 0.0f); + Point3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)), + NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)), + 0.0f); double cssPerDev = double(nsDeviceContext::AppUnitsPerCSSPixel()) / double(scale); transformOrigin = data.transformOrigin() * cssPerDev; @@ -674,7 +673,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent, // Undo the rebasing applied by // nsDisplayTransform::GetResultingTransformMatrixInternal - gfxPoint3D basis = -scaledOrigin - transformOrigin; + Point3D basis = -scaledOrigin - transformOrigin; transform.ChangeBasis(basis.x, basis.y, basis.z); // Convert to CSS pixels (this undoes the operations performed by diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 0ac7c4fa3244..4ba3cd8b72fb 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -18,7 +18,7 @@ include "ImageLayers.h"; using mozilla::GraphicsFilterType from "mozilla/GfxMessageUtils.h"; using struct gfxRGBA from "gfxColor.h"; -using struct gfxPoint3D from "gfxPoint3D.h"; +using struct mozilla::gfx::Point3D from "mozilla/gfx/Point.h"; using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h"; using nscoord from "nsCoord.h"; using struct nsIntPoint from "nsPoint.h"; @@ -156,9 +156,9 @@ struct TransformData { // the origin of the frame being transformed in app units nsPoint origin; // the transform-origin property for the transform in css pixels - gfxPoint3D transformOrigin; + Point3D transformOrigin; // the perspective-origin property for the transform in css pixels - gfxPoint3D perspectiveOrigin; + Point3D perspectiveOrigin; nsRect bounds; nscoord perspective; int32_t appUnitsPerDevPixel; diff --git a/gfx/thebes/gfx3DMatrix.cpp b/gfx/thebes/gfx3DMatrix.cpp index ad7937dc6163..711a44d2d855 100644 --- a/gfx/thebes/gfx3DMatrix.cpp +++ b/gfx/thebes/gfx3DMatrix.cpp @@ -181,7 +181,7 @@ gfx3DMatrix::IsIdentity() const } void -gfx3DMatrix::Translate(const gfxPoint3D& aPoint) +gfx3DMatrix::Translate(const Point3D& aPoint) { _41 += aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31; _42 += aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32; @@ -190,7 +190,7 @@ gfx3DMatrix::Translate(const gfxPoint3D& aPoint) } void -gfx3DMatrix::TranslatePost(const gfxPoint3D& aPoint) +gfx3DMatrix::TranslatePost(const Point3D& aPoint) { _11 += _14 * aPoint.x; _21 += _24 * aPoint.x; @@ -226,7 +226,7 @@ gfx3DMatrix::ScalePost(float aX, float aY, float aZ) } void -gfx3DMatrix::ChangeBasis(const gfxPoint3D& aOrigin) +gfx3DMatrix::ChangeBasis(const Point3D& aOrigin) { // Translate to the origin before applying this matrix. Translate(-aOrigin); @@ -411,7 +411,7 @@ gfx3DMatrix::Translation(float aX, float aY, float aZ) } gfx3DMatrix -gfx3DMatrix::Translation(const gfxPoint3D& aPoint) +gfx3DMatrix::Translation(const Point3D& aPoint) { gfx3DMatrix matrix; @@ -523,7 +523,7 @@ gfx3DMatrix::Inverse() const * the values. */ gfx3DMatrix matrix3 = Inverse3x3(); - matrix3.Translate(gfxPoint3D(-_41, -_42, -_43)); + matrix3.Translate(Point3D(-_41, -_42, -_43)); return matrix3; } @@ -618,13 +618,13 @@ gfx3DMatrix::Transposed() const gfxPoint gfx3DMatrix::Transform(const gfxPoint& point) const { - gfxPoint3D vec3d(point.x, point.y, 0); + Point3D vec3d(point.x, point.y, 0); vec3d = Transform3D(vec3d); return gfxPoint(vec3d.x, vec3d.y); } -gfxPoint3D -gfx3DMatrix::Transform3D(const gfxPoint3D& point) const +Point3D +gfx3DMatrix::Transform3D(const Point3D& point) const { gfxFloat x = point.x * _11 + point.y * _21 + point.z * _31 + _41; gfxFloat y = point.x * _12 + point.y * _22 + point.z * _32 + _42; @@ -635,7 +635,7 @@ gfx3DMatrix::Transform3D(const gfxPoint3D& point) const y /= w; z /= w; - return gfxPoint3D(x, y, z); + return Point3D(x, y, z); } gfxPointH3D @@ -777,17 +777,17 @@ gfxPointH3D gfx3DMatrix::ProjectPoint(const gfxPoint& aPoint) const return Transform4D(gfxPointH3D(aPoint.x, aPoint.y, z, 1)); } -gfxPoint3D gfx3DMatrix::GetNormalVector() const +Point3D gfx3DMatrix::GetNormalVector() const { // Define a plane in transformed space as the transformations // of 3 points on the z=0 screen plane. - gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0)); - gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0)); - gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0)); + Point3D a = Transform3D(Point3D(0, 0, 0)); + Point3D b = Transform3D(Point3D(0, 1, 0)); + Point3D c = Transform3D(Point3D(1, 0, 0)); // Convert to two vectors on the surface of the plane. - gfxPoint3D ab = b - a; - gfxPoint3D ac = c - a; + Point3D ab = b - a; + Point3D ac = c - a; return ac.CrossProduct(ab); } diff --git a/gfx/thebes/gfx3DMatrix.h b/gfx/thebes/gfx3DMatrix.h index 2002dbad1b53..3dc629cf34b8 100644 --- a/gfx/thebes/gfx3DMatrix.h +++ b/gfx/thebes/gfx3DMatrix.h @@ -7,7 +7,6 @@ #define GFX_3DMATRIX_H #include -#include #include #include @@ -30,6 +29,7 @@ class gfxMatrix; */ class gfx3DMatrix { + typedef mozilla::gfx::Point3D Point3D; public: /** * Create matrix. @@ -145,7 +145,7 @@ public: * | 0 0 1 0 | * | aPoint.x aPoint.y aPoint.z 1 | */ - void Translate(const gfxPoint3D& aPoint); + void Translate(const Point3D& aPoint); /** * Skew the matrix. @@ -244,7 +244,7 @@ public: * This is functionally equivalent to: * matrix * gfx3DMatrix::Translation(aPoint) */ - void TranslatePost(const gfxPoint3D& aPoint); + void TranslatePost(const Point3D& aPoint); void ScalePost(float aX, float aY, float aZ); @@ -258,7 +258,7 @@ public: * @param aOrigin The origin to translate to * @return The modified matrix */ - void ChangeBasis(const gfxPoint3D& aOrigin); + void ChangeBasis(const Point3D& aOrigin); /** * Transforms a point according to this matrix. @@ -276,7 +276,7 @@ public: /** * Transforms a 3D vector according to this matrix. */ - gfxPoint3D Transform3D(const gfxPoint3D& point) const; + Point3D Transform3D(const Point3D& point) const; gfxPointH3D Transform4D(const gfxPointH3D& aPoint) const; gfxPointH3D TransposeTransform4D(const gfxPointH3D& aPoint) const; @@ -322,7 +322,7 @@ public: * Returns a unit vector that is perpendicular to the plane formed * by transform the screen plane (z=0) by this matrix. */ - gfxPoint3D GetNormalVector() const; + Point3D GetNormalVector() const; /** * Returns true if a plane transformed by this matrix will @@ -343,7 +343,7 @@ public: * \param aZ Translation on Z-axis. */ static gfx3DMatrix Translation(float aX, float aY, float aZ); - static gfx3DMatrix Translation(const gfxPoint3D& aPoint); + static gfx3DMatrix Translation(const Point3D& aPoint); /** * Create a scale matrix. Scales uniformly along all axes. diff --git a/gfx/thebes/gfxPoint3D.h b/gfx/thebes/gfxPoint3D.h deleted file mode 100644 index 52bad1bb6c47..000000000000 --- a/gfx/thebes/gfxPoint3D.h +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GFX_POINT3D_H -#define GFX_POINT3D_H - -#include "mozilla/gfx/BasePoint3D.h" -#include "gfxTypes.h" - -struct gfxPoint3D : public mozilla::gfx::BasePoint3D { - typedef mozilla::gfx::BasePoint3D Super; - - gfxPoint3D() : Super() {} - gfxPoint3D(gfxFloat aX, gfxFloat aY, gfxFloat aZ) : Super(aX, aY, aZ) {} -}; - -#endif /* GFX_POINT3D_H */ diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index d5852fa2d8d4..902b30daa930 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -31,7 +31,6 @@ EXPORTS += [ 'gfxPattern.h', 'gfxPlatform.h', 'gfxPoint.h', - 'gfxPoint3D.h', 'gfxPointH3D.h', 'gfxPrefs.h', 'gfxQuad.h', diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index a632b5d2a864..991b5783b402 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -471,9 +471,9 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame); // all data passed directly to the compositor should be in css pixels float scale = nsDeviceContext::AppUnitsPerCSSPixel(); - gfxPoint3D offsetToTransformOrigin = + Point3D offsetToTransformOrigin = nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds); - gfxPoint3D offsetToPerspectiveOrigin = + Point3D offsetToPerspectiveOrigin = nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame, scale); nscoord perspective = 0.0; nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent(); @@ -4493,7 +4493,7 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, * to get from (0, 0) of the frame to the transform origin. This function is * called off the main thread. */ -/* static */ gfxPoint3D +/* static */ Point3D nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, float aAppUnitsPerPixel, const nsRect* aBoundsOverride) @@ -4503,7 +4503,7 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, "Shouldn't get a delta for an untransformed frame!"); if (!aFrame->IsTransformed()) { - return gfxPoint3D(); + return Point3D(); } /* For both of the coordinates, if the value of -moz-transform is a @@ -4555,7 +4555,7 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel); coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel); - return gfxPoint3D(coords[0], coords[1], coords[2]); + return Point3D(coords[0], coords[1], coords[2]); } /* Returns the delta specified by the -moz-perspective-origin property. @@ -4563,7 +4563,7 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, * to get from (0, 0) of the frame to the perspective origin. This function is * called off the main thread. */ -/* static */ gfxPoint3D +/* static */ Point3D nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, float aAppUnitsPerPixel) { @@ -4572,7 +4572,7 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, "Shouldn't get a delta for an untransformed frame!"); if (!aFrame->IsTransformed()) { - return gfxPoint3D(); + return Point3D(); } /* For both of the coordinates, if the value of -moz-perspective-origin is a @@ -4584,15 +4584,15 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, // How do we handle aBoundsOverride in the latter case? nsIFrame* parent = aFrame->GetParentStyleContextFrame(); if (!parent) { - return gfxPoint3D(); + return Point3D(); } const nsStyleDisplay* display = parent->StyleDisplay(); nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent); /* Allows us to access named variables by index. */ - gfxPoint3D result; + Point3D result; result.z = 0.0f; - gfxFloat* coords[2] = {&result.x, &result.y}; + gfx::Float* coords[2] = {&result.x, &result.y}; const nscoord* dimensions[2] = {&boundingRect.width, &boundingRect.height}; @@ -4619,10 +4619,10 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, } nsPoint parentOffset = aFrame->GetOffsetTo(parent); - gfxPoint3D gfxOffset( - NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel), - NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel), - 0.0f); + Point3D gfxOffset( + NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel), + NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel), + 0.0f); return result - gfxOffset; } @@ -4744,14 +4744,14 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp /* Account for the -moz-transform-origin property by translating the * coordinate space to the new origin. */ - gfxPoint3D newOrigin = - gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel), - NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel), - 0.0f); - gfxPoint3D roundedOrigin(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x), - hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y), - 0); - gfxPoint3D offsetBetweenOrigins = roundedOrigin + aProperties.mToTransformOrigin; + Point3D newOrigin = + Point3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel), + NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel), + 0.0f); + Point3D roundedOrigin(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x), + hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y), + 0); + Point3D offsetBetweenOrigins = roundedOrigin + aProperties.mToTransformOrigin; if (frame && frame->Preserves3D()) { // Include the transform set on our parent @@ -4892,10 +4892,10 @@ nsDisplayTransform::GetTransform() { if (mTransform.IsIdentity()) { float scale = mFrame->PresContext()->AppUnitsPerDevPixel(); - gfxPoint3D newOrigin = - gfxPoint3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale), - NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale), - 0.0f); + Point3D newOrigin = + Point3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale), + NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale), + 0.0f); if (mTransformGetter) { mTransform = mTransformGetter(mFrame, scale); mTransform.ChangeBasis(newOrigin.x, newOrigin.y, newOrigin.z); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 71828bbafdc8..73353c745a78 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3187,6 +3187,7 @@ private: class nsDisplayTransform: public nsDisplayItem { typedef mozilla::gfx::Matrix4x4 Matrix4x4; + typedef mozilla::gfx::Point3D Point3D; public: /** * Returns a matrix (in pixels) for the current frame. The matrix should be relative to @@ -3318,12 +3319,12 @@ public: bool UntransformVisibleRect(nsDisplayListBuilder* aBuilder, nsRect* aOutRect); - static gfxPoint3D GetDeltaToTransformOrigin(const nsIFrame* aFrame, - float aAppUnitsPerPixel, - const nsRect* aBoundsOverride); + static Point3D GetDeltaToTransformOrigin(const nsIFrame* aFrame, + float aAppUnitsPerPixel, + const nsRect* aBoundsOverride); - static gfxPoint3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, - float aAppUnitsPerPixel); + static Point3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, + float aAppUnitsPerPixel); /** * Returns the bounds of a frame as defined for resolving percentage @@ -3347,8 +3348,8 @@ public: float aAppUnitsPerPixel, const nsRect* aBoundsOverride); FrameTransformProperties(nsCSSValueSharedList* aTransformList, - const gfxPoint3D& aToTransformOrigin, - const gfxPoint3D& aToPerspectiveOrigin, + const Point3D& aToTransformOrigin, + const Point3D& aToPerspectiveOrigin, nscoord aChildPerspective) : mFrame(nullptr) , mTransformList(aTransformList) @@ -3359,8 +3360,8 @@ public: const nsIFrame* mFrame; nsRefPtr mTransformList; - const gfxPoint3D mToTransformOrigin; - const gfxPoint3D mToPerspectiveOrigin; + const Point3D mToTransformOrigin; + const Point3D mToPerspectiveOrigin; nscoord mChildPerspective; }; diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 828fe0ab0faf..791748b5e736 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -43,7 +43,6 @@ #include "nsIDocShell.h" #include "nsIWidget.h" #include "gfxMatrix.h" -#include "gfxPoint3D.h" #include "gfxPrefs.h" #include "gfxTypes.h" #include "nsTArray.h" diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index 39a346f47619..105b81558d40 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -27,6 +27,7 @@ #include "nsIDocument.h" using namespace mozilla; +using namespace mozilla::gfx; // HELPER METHODS // -------------- @@ -1338,9 +1339,9 @@ StyleAnimationValue::AppendTransformFunction(nsCSSKeyword aTransformFunction, #define YZSHEAR 2 static bool -Decompose2DMatrix(const gfxMatrix &aMatrix, gfxPoint3D &aScale, +Decompose2DMatrix(const gfxMatrix &aMatrix, Point3D &aScale, float aShear[3], gfxQuaternion &aRotate, - gfxPoint3D &aTranslate) + Point3D &aTranslate) { float A = aMatrix._11, B = aMatrix._12, @@ -1397,9 +1398,9 @@ Decompose2DMatrix(const gfxMatrix &aMatrix, gfxPoint3D &aScale, * in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz */ static bool -Decompose3DMatrix(const gfx3DMatrix &aMatrix, gfxPoint3D &aScale, +Decompose3DMatrix(const gfx3DMatrix &aMatrix, Point3D &aScale, float aShear[3], gfxQuaternion &aRotate, - gfxPoint3D &aTranslate, gfxPointH3D &aPerspective) + Point3D &aTranslate, gfxPointH3D &aPerspective) { gfx3DMatrix local = aMatrix; @@ -1508,12 +1509,12 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, // TODO: What do we do if one of these returns false (singular matrix) - gfxPoint3D scale1(1, 1, 1), translate1; + Point3D scale1(1, 1, 1), translate1; gfxPointH3D perspective1(0, 0, 0, 1); gfxQuaternion rotate1; float shear1[3] = { 0.0f, 0.0f, 0.0f}; - gfxPoint3D scale2(1, 1, 1), translate2; + Point3D scale2(1, 1, 1), translate2; gfxPointH3D perspective2(0, 0, 0, 1); gfxQuaternion rotate2; float shear2[3] = { 0.0f, 0.0f, 0.0f}; @@ -1536,7 +1537,7 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, InterpolateNumerically(perspective1, perspective2, aProgress); result.SetTransposedVector(3, perspective); - gfxPoint3D translate = + Point3D translate = InterpolateNumerically(translate1, translate2, aProgress); result.Translate(translate); @@ -1565,9 +1566,9 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, result.SkewXY(xyshear); } - gfxPoint3D scale = + Point3D scale = InterpolateNumerically(scale1, scale2, aProgress); - if (scale != gfxPoint3D(1.0, 1.0, 1.0)) { + if (scale != Point3D(1.0, 1.0, 1.0)) { result.Scale(scale.x, scale.y, scale.z); } @@ -1814,13 +1815,13 @@ AddTransformLists(double aCoeff1, const nsCSSValueList* aList1, break; } case eCSSKeyword_rotate3d: { - gfxPoint3D vector1(a1->Item(1).GetFloatValue(), - a1->Item(2).GetFloatValue(), - a1->Item(3).GetFloatValue()); + Point3D vector1(a1->Item(1).GetFloatValue(), + a1->Item(2).GetFloatValue(), + a1->Item(3).GetFloatValue()); vector1.Normalize(); - gfxPoint3D vector2(a2->Item(1).GetFloatValue(), - a2->Item(2).GetFloatValue(), - a2->Item(3).GetFloatValue()); + Point3D vector2(a2->Item(1).GetFloatValue(), + a2->Item(2).GetFloatValue(), + a2->Item(3).GetFloatValue()); vector2.Normalize(); // Handle rotate3d with matched (normalized) vectors, diff --git a/layout/style/nsStyleTransformMatrix.cpp b/layout/style/nsStyleTransformMatrix.cpp index a55e95dc43c6..fc1d03d8929b 100644 --- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -16,6 +16,7 @@ #include "gfxMatrix.h" using namespace mozilla; +using namespace mozilla::gfx; namespace nsStyleTransformMatrix { @@ -196,7 +197,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix, { NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); - gfxPoint3D temp; + Point3D temp; temp.x = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, @@ -215,7 +216,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix, { NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); - gfxPoint3D temp; + Point3D temp; temp.y = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, @@ -232,7 +233,7 @@ ProcessTranslateZ(gfx3DMatrix& aMatrix, { NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); - gfxPoint3D temp; + Point3D temp; temp.z = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, 0); @@ -250,7 +251,7 @@ ProcessTranslate(gfx3DMatrix& aMatrix, { NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!"); - gfxPoint3D temp; + Point3D temp; temp.x = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, @@ -275,7 +276,7 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix, { NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); - gfxPoint3D temp; + Point3D temp; temp.x = ProcessTranslatePart(aData->Item(1), aContext, aPresContext, aCanStoreInRuleTree, @@ -437,9 +438,9 @@ ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) float cosTheta = FlushToZero(cos(theta)); float sinTheta = FlushToZero(sin(theta)); - gfxPoint3D vector(aData->Item(1).GetFloatValue(), - aData->Item(2).GetFloatValue(), - aData->Item(3).GetFloatValue()); + Point3D vector(aData->Item(1).GetFloatValue(), + aData->Item(2).GetFloatValue(), + aData->Item(3).GetFloatValue()); if (!vector.Length()) { return; From 0b7ba4a9b82ef10d3b9539d049494cd728562665 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Fri, 29 Aug 2014 14:47:30 -0400 Subject: [PATCH 002/120] Bug 952977: Remove gfxPointH3D r=nical --- gfx/2d/Matrix.h | 60 ++++++++++++++++++++++ gfx/layers/apz/src/APZCTreeManager.cpp | 12 ++--- gfx/layers/apz/src/APZCTreeManager.h | 2 +- gfx/thebes/gfx3DMatrix.cpp | 70 +++----------------------- gfx/thebes/gfx3DMatrix.h | 40 +++------------ gfx/thebes/gfxPointH3D.h | 26 ---------- gfx/thebes/gfxQuaternion.h | 8 +-- gfx/thebes/moz.build | 1 - layout/base/nsDisplayList.cpp | 16 +++--- layout/style/StyleAnimationValue.cpp | 25 ++++----- 10 files changed, 108 insertions(+), 152 deletions(-) delete mode 100644 gfx/thebes/gfxPointH3D.h diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h index e378779f8615..9867df9c595e 100644 --- a/gfx/2d/Matrix.h +++ b/gfx/2d/Matrix.h @@ -311,6 +311,17 @@ public: Float _31, _32, _33, _34; Float _41, _42, _43, _44; + Point4D& operator[](int aIndex) + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + return *reinterpret_cast((&_11)+4*aIndex); + } + const Point4D& operator[](int aIndex) const + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + return *reinterpret_cast((&_11)+4*aIndex); + } + /** * Returns true if the matrix is isomorphic to a 2D affine transformation. */ @@ -404,6 +415,16 @@ public: return Is2D() && As2D().IsIntegerTranslation(); } + Point4D TransposeTransform4D(const Point4D& aPoint) const + { + Float x = aPoint.x * _11 + aPoint.y * _12 + aPoint.z * _13 + aPoint.w * _14; + Float y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24; + Float z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34; + Float w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44; + + return Point4D(x, y, z, w); + } + Point4D operator *(const Point4D& aPoint) const { Point4D retPoint; @@ -485,6 +506,21 @@ public: return *this; } + void SkewXY(Float aSkew) + { + (*this)[1] += (*this)[0] * aSkew; + } + + void SkewXZ(Float aSkew) + { + (*this)[2] += (*this)[0] * aSkew; + } + + void SkewYZ(Float aSkew) + { + (*this)[2] += (*this)[1] * aSkew; + } + Matrix4x4 &ChangeBasis(Float aX, Float aY, Float aZ) { // Translate to the origin before applying this matrix @@ -585,6 +621,15 @@ public: bool Invert(); + void Normalize() + { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + (*this)[i][j] /= (*this)[3][3]; + } + } + } + void ScalePost(Float aX, Float aY, Float aZ) { _11 *= aX; @@ -664,6 +709,21 @@ public: NudgeToInteger(&_44, error); } + Point4D TransposedVector(int aIndex) const + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + return Point4D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex)); + } + + void SetTransposedVector(int aIndex, Point4D &aVector) + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + *((&_11)+aIndex) = aVector.x; + *((&_21)+aIndex) = aVector.y; + *((&_31)+aIndex) = aVector.z; + *((&_41)+aIndex) = aVector.w; + } + // Set all the members of the matrix to NaN void SetNAN(); }; diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 2d8ca4991613..167d7ce4d23f 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -33,6 +33,7 @@ namespace mozilla { namespace layers { typedef mozilla::gfx::Point Point; +typedef mozilla::gfx::Point4D Point4D; typedef mozilla::gfx::Matrix4x4 Matrix4x4; float APZCTreeManager::sDPI = 160.0; @@ -996,10 +997,9 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, bool* aOutInOverscroll MonitorAutoLock lock(mTreeLock); nsRefPtr target; // The root may have siblings, so check those too - gfxPoint point(aPoint.x, aPoint.y); bool inOverscrolledApzc = false; for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) { - target = GetAPZCAtPoint(apzc, point, &inOverscrolledApzc); + target = GetAPZCAtPoint(apzc, aPoint.ToUnknownPoint(), &inOverscrolledApzc); // If we hit an overscrolled APZC, 'target' will be nullptr but it's still // a hit so we don't search further siblings. if (target || inOverscrolledApzc) { @@ -1129,7 +1129,7 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL AsyncPanZoomController* APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, - const gfxPoint& aHitTestPoint, + const Point& aHitTestPoint, bool* aOutInOverscrolledApzc) { mTreeLock.AssertCurrentThreadOwns(); @@ -1149,7 +1149,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, // Hit testing for this layer takes place in our parent layer coordinates, // since the composition bounds (used to initialize the visible rect against // which we hit test are in those coordinates). - gfxPointH3D hitTestPointForThisLayer = To3DMatrix(ancestorUntransform).ProjectPoint(aHitTestPoint); + Point4D hitTestPointForThisLayer = ancestorUntransform.ProjectPoint(aHitTestPoint); APZCTM_LOG("Untransformed %f %f to transient coordinates %f %f for hit-testing APZC %p\n", aHitTestPoint.x, aHitTestPoint.y, hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc); @@ -1161,7 +1161,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform(); asyncUntransform.Invert(); Matrix4x4 childUntransform = ancestorUntransform * asyncUntransform; - gfxPointH3D hitTestPointForChildLayers = To3DMatrix(childUntransform).ProjectPoint(aHitTestPoint); + Point4D hitTestPointForChildLayers = childUntransform.ProjectPoint(aHitTestPoint); APZCTM_LOG("Untransformed %f %f to layer coordinates %f %f for APZC %p\n", aHitTestPoint.x, aHitTestPoint.y, hitTestPointForChildLayers.x, hitTestPointForChildLayers.y, aApzc); @@ -1183,7 +1183,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, } } if (!result && hitTestPointForThisLayer.HasPositiveWCoord() && - aApzc->VisibleRegionContains(ViewAs(hitTestPointForThisLayer.As2DPoint()))) { + aApzc->VisibleRegionContains(ParentLayerPoint::FromUnknownPoint(hitTestPointForThisLayer.As2DPoint()))) { APZCTM_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n", hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc); result = aApzc; diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index 01d02410cd2c..7229daa6184f 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -366,7 +366,7 @@ private: AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId); AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid); AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, - const gfxPoint& aHitTestPoint, + const gfx::Point& aHitTestPoint, bool* aOutInOverscrolledApzc); already_AddRefed CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2); already_AddRefed RootAPZCForLayersId(AsyncPanZoomController* aApzc); diff --git a/gfx/thebes/gfx3DMatrix.cpp b/gfx/thebes/gfx3DMatrix.cpp index 711a44d2d855..bbb9ba09ae54 100644 --- a/gfx/thebes/gfx3DMatrix.cpp +++ b/gfx/thebes/gfx3DMatrix.cpp @@ -5,6 +5,7 @@ #include "gfxMatrix.h" #include "gfx3DMatrix.h" +#include "gfx2DGlue.h" #include "mozilla/gfx/Tools.h" #include #include @@ -235,24 +236,6 @@ gfx3DMatrix::ChangeBasis(const Point3D& aOrigin) TranslatePost(aOrigin); } -void -gfx3DMatrix::SkewXY(double aSkew) -{ - (*this)[1] += (*this)[0] * aSkew; -} - -void -gfx3DMatrix::SkewXZ(double aSkew) -{ - (*this)[2] += (*this)[0] * aSkew; -} - -void -gfx3DMatrix::SkewYZ(double aSkew) -{ - (*this)[2] += (*this)[1] * aSkew; -} - void gfx3DMatrix::Scale(float aX, float aY, float aZ) { @@ -511,7 +494,7 @@ gfx3DMatrix::IsSingular() const gfx3DMatrix gfx3DMatrix::Inverse() const { - if (TransposedVector(3) == gfxPointH3D(0, 0, 0, 1)) { + if (_14 == 0 && _24 == 0 && _34 == 0 && _44 == 1) { /** * When the matrix contains no perspective, the inverse * is the same as the 3x3 inverse of the rotation components @@ -587,34 +570,6 @@ gfx3DMatrix::Inverse() const return temp; } -gfx3DMatrix& -gfx3DMatrix::Normalize() -{ - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - (*this)[i][j] /= (*this)[3][3]; - } - } - return *this; -} - -gfx3DMatrix& -gfx3DMatrix::Transpose() -{ - *this = Transposed(); - return *this; -} - -gfx3DMatrix -gfx3DMatrix::Transposed() const -{ - gfx3DMatrix temp; - for (int i = 0; i < 4; i++) { - temp[i] = TransposedVector(i); - } - return temp; -} - gfxPoint gfx3DMatrix::Transform(const gfxPoint& point) const { @@ -638,26 +593,15 @@ gfx3DMatrix::Transform3D(const Point3D& point) const return Point3D(x, y, z); } -gfxPointH3D -gfx3DMatrix::Transform4D(const gfxPointH3D& aPoint) const +Point4D +gfx3DMatrix::Transform4D(const Point4D& aPoint) const { gfxFloat x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41; gfxFloat y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42; gfxFloat z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43; gfxFloat w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44; - return gfxPointH3D(x, y, z, w); -} - -gfxPointH3D -gfx3DMatrix::TransposeTransform4D(const gfxPointH3D& aPoint) const -{ - gfxFloat x = aPoint.x * _11 + aPoint.y * _12 + aPoint.z * _13 + aPoint.w * _14; - gfxFloat y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24; - gfxFloat z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34; - gfxFloat w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44; - - return gfxPointH3D(x, y, z, w); + return Point4D(x, y, z, w); } gfxRect @@ -763,7 +707,7 @@ gfx3DMatrix::ProjectTo2D() return *this; } -gfxPointH3D gfx3DMatrix::ProjectPoint(const gfxPoint& aPoint) const +Point4D gfx3DMatrix::ProjectPoint(const gfxPoint& aPoint) const { // Find a value for z that will transform to 0. @@ -774,7 +718,7 @@ gfxPointH3D gfx3DMatrix::ProjectPoint(const gfxPoint& aPoint) const float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33; // Compute the transformed point - return Transform4D(gfxPointH3D(aPoint.x, aPoint.y, z, 1)); + return Transform4D(Point4D(aPoint.x, aPoint.y, z, 1)); } Point3D gfx3DMatrix::GetNormalVector() const diff --git a/gfx/thebes/gfx3DMatrix.h b/gfx/thebes/gfx3DMatrix.h index 3dc629cf34b8..c25febda2237 100644 --- a/gfx/thebes/gfx3DMatrix.h +++ b/gfx/thebes/gfx3DMatrix.h @@ -7,7 +7,7 @@ #define GFX_3DMATRIX_H #include -#include +#include "mozilla/gfx/Point.h" #include class gfxMatrix; @@ -30,6 +30,7 @@ class gfxMatrix; class gfx3DMatrix { typedef mozilla::gfx::Point3D Point3D; + typedef mozilla::gfx::Point4D Point4D; public: /** * Create matrix. @@ -63,15 +64,15 @@ public: gfx3DMatrix operator*(const gfx3DMatrix &aMatrix) const; gfx3DMatrix& operator*=(const gfx3DMatrix &aMatrix); - gfxPointH3D& operator[](int aIndex) + Point4D& operator[](int aIndex) { NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); - return *reinterpret_cast((&_11)+4*aIndex); + return *reinterpret_cast((&_11)+4*aIndex); } - const gfxPointH3D& operator[](int aIndex) const + const Point4D& operator[](int aIndex) const { NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); - return *reinterpret_cast((&_11)+4*aIndex); + return *reinterpret_cast((&_11)+4*aIndex); } /** @@ -157,10 +158,6 @@ public: * | 0 0 0 1 | */ void SkewXY(double aXSkew, double aYSkew); - - void SkewXY(double aSkew); - void SkewXZ(double aSkew); - void SkewYZ(double aSkew); /** * Scale the matrix @@ -277,14 +274,13 @@ public: * Transforms a 3D vector according to this matrix. */ Point3D Transform3D(const Point3D& point) const; - gfxPointH3D Transform4D(const gfxPointH3D& aPoint) const; - gfxPointH3D TransposeTransform4D(const gfxPointH3D& aPoint) const; + Point4D Transform4D(const Point4D& aPoint) const; /** * Given a point (x,y) find a value for z such that (x,y,z,1) transforms * into (x',y',0,w') and returns the latter. */ - gfxPointH3D ProjectPoint(const gfxPoint& aPoint) const; + Point4D ProjectPoint(const gfxPoint& aPoint) const; /** * Inverts this matrix, if possible. Otherwise, the matrix is left @@ -298,26 +294,6 @@ public: return *this; } - gfx3DMatrix& Normalize(); - - gfxPointH3D TransposedVector(int aIndex) const - { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); - return gfxPointH3D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex)); - } - - void SetTransposedVector(int aIndex, gfxPointH3D &aVector) - { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); - *((&_11)+aIndex) = aVector.x; - *((&_21)+aIndex) = aVector.y; - *((&_31)+aIndex) = aVector.z; - *((&_41)+aIndex) = aVector.w; - } - - gfx3DMatrix& Transpose(); - gfx3DMatrix Transposed() const; - /** * Returns a unit vector that is perpendicular to the plane formed * by transform the screen plane (z=0) by this matrix. diff --git a/gfx/thebes/gfxPointH3D.h b/gfx/thebes/gfxPointH3D.h deleted file mode 100644 index c494e114c5d2..000000000000 --- a/gfx/thebes/gfxPointH3D.h +++ /dev/null @@ -1,26 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GFX_POINTH3D_H -#define GFX_POINTH3D_H - -#include "mozilla/gfx/BasePoint4D.h" -#include "gfxTypes.h" -#include "gfxPoint.h" - -struct gfxPointH3D : public mozilla::gfx::BasePoint4D { - typedef mozilla::gfx::BasePoint4D Super; - - gfxPointH3D() : Super() {} - gfxPointH3D(float aX, float aY, float aZ, float aW) : Super(aX, aY, aZ, aW) {} - - bool HasPositiveWCoord() { return w > 0; } - - gfxPoint As2DPoint() { - return gfxPoint(x / w, y / w); - } -}; - -#endif /* GFX_POINTH3D_H */ diff --git a/gfx/thebes/gfxQuaternion.h b/gfx/thebes/gfxQuaternion.h index c7b3f154178d..cc78e5cdf986 100644 --- a/gfx/thebes/gfxQuaternion.h +++ b/gfx/thebes/gfxQuaternion.h @@ -7,7 +7,7 @@ #define GFX_QUATERNION_H #include "mozilla/gfx/BasePoint4D.h" -#include "gfx3DMatrix.h" +#include "mozilla/gfx/Matrix.h" #include "nsAlgorithm.h" #include @@ -17,7 +17,7 @@ struct gfxQuaternion : public mozilla::gfx::BasePoint4D gfxQuaternion() : Super() {} gfxQuaternion(gfxFloat aX, gfxFloat aY, gfxFloat aZ, gfxFloat aW) : Super(aX, aY, aZ, aW) {} - gfxQuaternion(const gfx3DMatrix& aMatrix) { + gfxQuaternion(const mozilla::gfx::Matrix4x4& aMatrix) { w = 0.5 * sqrt(std::max(1 + aMatrix[0][0] + aMatrix[1][1] + aMatrix[2][2], 0.0f)); x = 0.5 * sqrt(std::max(1 + aMatrix[0][0] - aMatrix[1][1] - aMatrix[2][2], 0.0f)); y = 0.5 * sqrt(std::max(1 - aMatrix[0][0] + aMatrix[1][1] - aMatrix[2][2], 0.0f)); @@ -50,8 +50,8 @@ struct gfxQuaternion : public mozilla::gfx::BasePoint4D return left + right; } - gfx3DMatrix ToMatrix() { - gfx3DMatrix temp; + mozilla::gfx::Matrix4x4 ToMatrix() { + mozilla::gfx::Matrix4x4 temp; temp[0][0] = 1 - 2 * (y * y + z * z); temp[0][1] = 2 * (x * y + w * z); diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 902b30daa930..24d02a8503f5 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -31,7 +31,6 @@ EXPORTS += [ 'gfxPattern.h', 'gfxPlatform.h', 'gfxPoint.h', - 'gfxPointH3D.h', 'gfxPrefs.h', 'gfxQuad.h', 'gfxQuaternion.h', diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 991b5783b402..cc4d99c827cc 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -5051,16 +5051,17 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder, */ /* Now, apply the transform and pass it down the channel. */ + matrix.Invert(); nsRect resultingRect; if (aRect.width == 1 && aRect.height == 1) { // Magic width/height indicating we're hit testing a point, not a rect - gfxPointH3D point = To3DMatrix(matrix).Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor), - NSAppUnitsToFloatPixels(aRect.y, factor))); + Point4D point = matrix.ProjectPoint(Point(NSAppUnitsToFloatPixels(aRect.x, factor), + NSAppUnitsToFloatPixels(aRect.y, factor))); if (!point.HasPositiveWCoord()) { return; } - gfxPoint point2d = point.As2DPoint(); + Point point2d = point.As2DPoint(); resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point2d.x), factor), NSFloatPixelsToAppUnits(float(point2d.y), factor), @@ -5072,7 +5073,6 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder, NSAppUnitsToFloatPixels(aRect.width, factor), NSAppUnitsToFloatPixels(aRect.height, factor)); - matrix.Invert(); Rect rect = matrix.ProjectRectBounds(originalRect); bool snap; @@ -5120,11 +5120,13 @@ nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsP NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!"); - gfxPointH3D point = To3DMatrix(matrix).Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor), - NSAppUnitsToFloatPixels(aPoint.y, factor))); + Matrix4x4 inverse = matrix; + inverse.Invert(); + Point4D point = inverse.ProjectPoint(Point(NSAppUnitsToFloatPixels(aPoint.x, factor), + NSAppUnitsToFloatPixels(aPoint.y, factor))); NS_ASSERTION(point.HasPositiveWCoord(), "Why are we trying to get the depth for a point we didn't hit?"); - gfxPoint point2d = point.As2DPoint(); + Point point2d = point.As2DPoint(); Point3D transformed = matrix * Point3D(point2d.x, point2d.y, 0); return transformed.z; diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index 105b81558d40..d0f7d94ea2ad 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -25,6 +25,7 @@ #include "gfxMatrix.h" #include "gfxQuaternion.h" #include "nsIDocument.h" +#include "gfx2DGlue.h" using namespace mozilla; using namespace mozilla::gfx; @@ -1400,9 +1401,9 @@ Decompose2DMatrix(const gfxMatrix &aMatrix, Point3D &aScale, static bool Decompose3DMatrix(const gfx3DMatrix &aMatrix, Point3D &aScale, float aShear[3], gfxQuaternion &aRotate, - Point3D &aTranslate, gfxPointH3D &aPerspective) + Point3D &aTranslate, Point4D &aPerspective) { - gfx3DMatrix local = aMatrix; + Matrix4x4 local = ToMatrix4x4(aMatrix); if (local[3][3] == 0) { return false; @@ -1414,8 +1415,8 @@ Decompose3DMatrix(const gfx3DMatrix &aMatrix, Point3D &aScale, * perspective is used to solve for perspective, but it also provides * an easy way to test for singularity of the upper 3x3 component. */ - gfx3DMatrix perspective = local; - gfxPointH3D empty(0, 0, 0, 1); + Matrix4x4 perspective = local; + Point4D empty(0, 0, 0, 1); perspective.SetTransposedVector(3, empty); if (perspective.Determinant() == 0.0) { @@ -1438,7 +1439,7 @@ Decompose3DMatrix(const gfx3DMatrix &aMatrix, Point3D &aScale, /* Clear the perspective partition */ local.SetTransposedVector(3, empty); } else { - aPerspective = gfxPointH3D(0, 0, 0, 1); + aPerspective = Point4D(0, 0, 0, 1); } /* Next take care of translation */ @@ -1510,12 +1511,12 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, // TODO: What do we do if one of these returns false (singular matrix) Point3D scale1(1, 1, 1), translate1; - gfxPointH3D perspective1(0, 0, 0, 1); + Point4D perspective1(0, 0, 0, 1); gfxQuaternion rotate1; float shear1[3] = { 0.0f, 0.0f, 0.0f}; Point3D scale2(1, 1, 1), translate2; - gfxPointH3D perspective2(0, 0, 0, 1); + Point4D perspective2(0, 0, 0, 1); gfxQuaternion rotate2; float shear2[3] = { 0.0f, 0.0f, 0.0f}; @@ -1531,18 +1532,18 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, } // Interpolate each of the pieces - gfx3DMatrix result; + Matrix4x4 result; - gfxPointH3D perspective = + Point4D perspective = InterpolateNumerically(perspective1, perspective2, aProgress); result.SetTransposedVector(3, perspective); Point3D translate = InterpolateNumerically(translate1, translate2, aProgress); - result.Translate(translate); + result.Translate(translate.x, translate.y, translate.z); gfxQuaternion q3 = rotate1.Slerp(rotate2, aProgress); - gfx3DMatrix rotate = q3.ToMatrix(); + Matrix4x4 rotate = q3.ToMatrix(); if (!rotate.IsIdentity()) { result = rotate * result; } @@ -1572,7 +1573,7 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, result.Scale(scale.x, scale.y, scale.z); } - return result; + return To3DMatrix(result); } static nsCSSValueList* From c0631572bb3150ceca252005771f356de32b8660 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Fri, 29 Aug 2014 11:30:14 -0600 Subject: [PATCH 003/120] Bug 768802: Prevent plugins from setting the foreground window during NP_Initialize; r=bsmedberg --HG-- extra : rebase_source : 8628dba0eca82a12d2b9f999e55889c9a6c3ab18 --- dom/plugins/ipc/PluginModuleParent.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 0ff64570fe11..b2d667f293dd 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -34,6 +34,7 @@ #ifdef XP_WIN #include "PluginHangUIParent.h" +#include "mozilla/GuardObjects.h" #include "mozilla/widget/AudioSession.h" #endif @@ -1217,6 +1218,26 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs return NS_OK; } #else +#if defined(XP_WIN) +class MOZ_STACK_CLASS SetForegroundLocker +{ +public: + SetForegroundLocker(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + ::LockSetForegroundWindow(LSFW_LOCK); + } + + ~SetForegroundLocker() + { + ::LockSetForegroundWindow(LSFW_UNLOCK); + } + +private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; +#endif + nsresult PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) { @@ -1232,6 +1253,11 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) uint32_t flags = 0; #ifdef XP_WIN flags |= kAllowAsyncDrawing; + + // Bug 768802: We need to call LockSetForegroundWindow before calling + // NP_Initialize to prevent our window from losing focus when the + // plugin starts. + SetForegroundLocker fgLock; #endif if (!CallNP_Initialize(flags, error)) { From 324349ab013194714ce9535e25f3e80737a4f65d Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 29 Aug 2014 15:32:18 +0200 Subject: [PATCH 004/120] Bug 992267: Introduce the IsSimdAvailable testing function; r=luke --HG-- extra : rebase_source : 65975807c240817b7cc7dfb8bfca59f5d8f6d6a0 --- js/src/builtin/TestingFunctions.cpp | 17 +++++++++++++++++ js/src/jit/Ion.cpp | 6 ++++++ js/src/jit/Ion.h | 1 + js/src/jit/arm/Assembler-arm.h | 3 +++ js/src/jit/arm/MacroAssembler-arm.cpp | 4 ++-- js/src/jit/shared/Assembler-x86-shared.h | 1 + js/src/jscntxt.h | 1 + js/src/vm/Runtime.cpp | 2 ++ js/src/vm/Runtime.h | 1 + 9 files changed, 34 insertions(+), 2 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index acb17c74cac9..59ed58e40206 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1974,6 +1974,19 @@ EvalReturningScope(JSContext *cx, unsigned argc, jsval *vp) return true; } +static bool +IsSimdAvailable(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); +#ifdef JS_CODEGEN_NONE + bool available = false; +#else + bool available = cx->jitSupportsSimd(); +#endif + args.rval().set(BooleanValue(available)); + return true; +} + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'compartment')", @@ -2157,6 +2170,10 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " Returns whether asm.js compilation is currently available or whether it is disabled\n" " (e.g., by the debugger)."), + JS_FN_HELP("isSimdAvailable", IsSimdAvailable, 0, 0, +"isSimdAvailable", +" Returns true if SIMD extensions are supported on this platform."), + JS_FN_HELP("getJitCompilerOptions", GetJitCompilerOptions, 0, 0, "getCompilerOptions()", "Return an object describing some of the JIT compiler options.\n"), diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 29f5d9d2c04b..3c970273ff65 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -3214,3 +3214,9 @@ jit::JitSupportsFloatingPoint() { return js::jit::MacroAssembler::SupportsFloatingPoint(); } + +bool +jit::JitSupportsSimd() +{ + return js::jit::MacroAssembler::SupportsSimd(); +} diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 608afb936df6..285f41b31fb9 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -207,6 +207,7 @@ bool UpdateForDebugMode(JSContext *maybecx, JSCompartment *comp, AutoDebugModeInvalidation &invalidate); bool JitSupportsFloatingPoint(); +bool JitSupportsSimd(); } // namespace jit } // namespace js diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 91c8ca8b52b1..18c0daea319a 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1552,6 +1552,9 @@ class Assembler : public AssemblerShared static bool SupportsFloatingPoint() { return HasVFP(); } + static bool SupportsSimd() { + return js::jit::SupportsSimd; + } protected: void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index c9d840e1c293..14fcca88ae61 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1880,7 +1880,7 @@ MacroAssemblerARMCompat::freeStack(Register amount) void MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet) { - JS_ASSERT(!SupportsSimd && simdSet.size() == 0); + JS_ASSERT(!SupportsSimd() && simdSet.size() == 0); int32_t diffF = set.fpus().getPushSizeInBytes(); int32_t diffG = set.gprs().size() * sizeof(intptr_t); @@ -1909,7 +1909,7 @@ MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet) void MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore, FloatRegisterSet simdSet) { - JS_ASSERT(!SupportsSimd && simdSet.size() == 0); + JS_ASSERT(!SupportsSimd() && simdSet.size() == 0); int32_t diffG = set.gprs().size() * sizeof(intptr_t); int32_t diffF = set.fpus().getPushSizeInBytes(); const int32_t reservedG = diffG; diff --git a/js/src/jit/shared/Assembler-x86-shared.h b/js/src/jit/shared/Assembler-x86-shared.h index 9bb420ae30a1..7095e78c6c8d 100644 --- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -926,6 +926,7 @@ class AssemblerX86Shared : public AssemblerShared static bool HasSSE3() { return CPUInfo::IsSSE3Present(); } static bool HasSSE41() { return CPUInfo::IsSSE41Present(); } static bool SupportsFloatingPoint() { return CPUInfo::IsSSE2Present(); } + static bool SupportsSimd() { return CPUInfo::IsSSE2Present(); } // The below cmpl methods switch the lhs and rhs when it invokes the // macroassembler to conform with intel standard. When calling this diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 59b79a0e8253..1e27edc03731 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -295,6 +295,7 @@ struct ThreadSafeContext : ContextFriendFields, bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); } bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); } bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; } + bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; } // Thread local data that may be accessed freely. DtoaState *dtoaState() { diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 9371afaa7a1e..346e7c04c71f 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -211,6 +211,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) wrapObjectCallbacks(&DefaultWrapObjectCallbacks), preserveWrapperCallback(nullptr), jitSupportsFloatingPoint(false), + jitSupportsSimd(false), ionPcScriptCache(nullptr), threadPool(this), defaultJSContextCallback(nullptr), @@ -315,6 +316,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) nativeStackBase = GetNativeStackBase(); jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint(); + jitSupportsSimd = js::jit::JitSupportsSimd(); signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this); canUseSignalHandlers_ = signalHandlersInstalled_ && !SignalBasedTriggersDisabled(); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 7daa9bbaa25c..784e3b1d45ca 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1274,6 +1274,7 @@ struct JSRuntime : public JS::shadow::Runtime, } bool jitSupportsFloatingPoint; + bool jitSupportsSimd; // Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1) // has been noticed by Ion/Baseline. From 2914b2e38ae84ae7d0f19c200e9e219f008d7e2f Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Fri, 29 Aug 2014 15:34:20 +0200 Subject: [PATCH 005/120] Bug 992267: Ensure stack alignment requirements for asm.js code; r=bbouvier --HG-- extra : rebase_source : 5d5b45fc4418bf8898cdf0a735386140ebc8b230 --- js/src/asmjs/AsmJSFrameIterator.cpp | 6 +- js/src/asmjs/AsmJSFrameIterator.h | 1 - js/src/asmjs/AsmJSValidate.cpp | 116 ++++++++++-------- .../irregexp/NativeRegExpMacroAssembler.cpp | 2 +- js/src/jit/CodeGenerator.cpp | 11 +- js/src/jit/IonFrames.cpp | 2 +- js/src/jit/IonMacroAssembler.h | 10 +- js/src/jit/LIR.h | 8 +- js/src/jit/arm/Assembler-arm.h | 5 +- js/src/jit/arm/MacroAssembler-arm.cpp | 8 +- js/src/jit/arm/Simulator-arm.cpp | 4 +- js/src/jit/mips/Assembler-mips.h | 6 +- js/src/jit/mips/MacroAssembler-mips.cpp | 22 ++-- js/src/jit/mips/Simulator-mips.cpp | 4 +- js/src/jit/none/Architecture-none.h | 1 + js/src/jit/none/MacroAssembler-none.h | 3 +- js/src/jit/shared/Assembler-shared.h | 4 +- js/src/jit/shared/CodeGenerator-shared.cpp | 60 +++------ js/src/jit/shared/CodeGenerator-shared.h | 2 - js/src/jit/x64/Assembler-x64.h | 7 +- js/src/jit/x64/MacroAssembler-x64.cpp | 8 +- js/src/jit/x64/Trampoline-x64.cpp | 1 - js/src/jit/x86/Assembler-x86.h | 11 +- js/src/jit/x86/MacroAssembler-x86.cpp | 8 +- js/src/jit/x86/Trampoline-x86.cpp | 1 - js/src/vm/Stack.cpp | 4 +- js/src/vm/Stack.h | 4 +- 27 files changed, 149 insertions(+), 170 deletions(-) diff --git a/js/src/asmjs/AsmJSFrameIterator.cpp b/js/src/asmjs/AsmJSFrameIterator.cpp index 3b8e20cdb317..1d196e4c4a20 100644 --- a/js/src/asmjs/AsmJSFrameIterator.cpp +++ b/js/src/asmjs/AsmJSFrameIterator.cpp @@ -356,11 +356,11 @@ js::GenerateAsmJSStackOverflowExit(MacroAssembler &masm, Label *overflowExit, La masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfFP())); // Prepare the stack for calling C++. - if (unsigned stackDec = StackDecrementForCall(sizeof(AsmJSFrame), ShadowStackSpace)) - masm.subPtr(Imm32(stackDec), StackPointer); + if (uint32_t d = StackDecrementForCall(ABIStackAlignment, sizeof(AsmJSFrame), ShadowStackSpace)) + masm.subPtr(Imm32(d), StackPointer); // No need to restore the stack; the throw stub pops everything. - masm.assertStackAlignment(); + masm.assertStackAlignment(ABIStackAlignment); masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed)); masm.jump(throwLabel); } diff --git a/js/src/asmjs/AsmJSFrameIterator.h b/js/src/asmjs/AsmJSFrameIterator.h index 27ffd94c89ef..f8aaea2859a3 100644 --- a/js/src/asmjs/AsmJSFrameIterator.h +++ b/js/src/asmjs/AsmJSFrameIterator.h @@ -170,7 +170,6 @@ void GenerateAsmJSExitEpilogue(jit::MacroAssembler &masm, unsigned framePushed, AsmJSExit::Reason reason, jit::Label *profilingReturn); - } // namespace js #endif // asmjs_AsmJSFrameIterator_h diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 83e0985cad30..f8248c544c4e 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -2282,7 +2282,7 @@ class FunctionCompiler uint32_t parentStackBytes = call->abi_.stackBytesConsumedSoFar(); uint32_t newStackBytes; if (call->childClobbers_) { - call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, StackAlignment); + call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, AsmJSStackAlignment); for (unsigned i = 0; i < call->stackArgs_.length(); i++) call->stackArgs_[i]->incrementOffset(call->spIncrement_); newStackBytes = Max(call->prevMaxStackBytes_, @@ -5913,16 +5913,16 @@ CheckModuleReturn(ModuleCompiler &m) } static void -AssertStackAlignment(MacroAssembler &masm) +AssertStackAlignment(MacroAssembler &masm, uint32_t alignment) { - JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % StackAlignment == 0); - masm.assertStackAlignment(); + JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % alignment == 0); + masm.assertStackAlignment(alignment); } static unsigned -StackDecrementForCall(MacroAssembler &masm, unsigned bytesToPush) +StackDecrementForCall(MacroAssembler &masm, uint32_t alignment, unsigned bytesToPush) { - return StackDecrementForCall(sizeof(AsmJSFrame) + masm.framePushed(), bytesToPush); + return StackDecrementForCall(alignment, sizeof(AsmJSFrame) + masm.framePushed(), bytesToPush); } template @@ -5937,9 +5937,10 @@ StackArgBytes(const VectorT &argTypes) template static unsigned -StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0) +StackDecrementForCall(MacroAssembler &masm, uint32_t alignment, const VectorT &argTypes, + unsigned extraBytes = 0) { - return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes); + return StackDecrementForCall(masm, alignment, StackArgBytes(argTypes) + extraBytes); } #if defined(JS_CODEGEN_ARM) @@ -5965,6 +5966,7 @@ static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * siz static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) + NonVolatileRegs.fpus().getPushSizeInBytes(); #endif +static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void*); static bool GenerateEntry(ModuleCompiler &m, unsigned exportIndex) @@ -5975,17 +5977,18 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) masm.align(CodeAlignment); masm.bind(&begin); + // Save the return address if it wasn't already saved by the call insn. #if defined(JS_CODEGEN_ARM) masm.push(lr); #elif defined(JS_CODEGEN_MIPS) masm.push(ra); +#elif defined(JS_CODEGEN_X86) + static const unsigned EntryFrameSize = sizeof(void*); #endif - masm.subPtr(Imm32(AsmJSFrameBytesAfterReturnAddress), StackPointer); - masm.setFramePushed(0); - // In constrast to the system ABI, the Ion convention is that all registers - // are clobbered by calls. Thus, we must save the caller's non-volatile - // registers. + // Save all caller non-volatile registers before we clobber them here and in + // the asm.js callee (which does not preserve non-volatile registers). + masm.setFramePushed(0); masm.PushRegsInMask(NonVolatileRegs); JS_ASSERT(masm.framePushed() == FramePushedAfterSave); @@ -6003,29 +6006,36 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) masm.loadPtr(Address(IntArgReg1, AsmJSModule::heapGlobalDataOffset()), HeapReg); #endif - // Remember the stack pointer in the current AsmJSActivation. This will be - // used by error exit paths to set the stack pointer back to what it was - // right after the (C++) caller's non-volatile registers were saved so that - // they can be restored. - Register activation = ABIArgGenerator::NonArgReturnReg0; - masm.loadAsmJSActivation(activation); - masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP())); - - // Get 'argv' into a non-arg register and save it on the stack. + // Put the 'argv' argument into a non-argument/return register so that we + // can use 'argv' while we fill in the arguments for the asm.js callee. + // Also, save 'argv' on the stack so that we can recover it after the call. + // Use a second non-argument/return register as temporary scratch. Register argv = ABIArgGenerator::NonArgReturnReg0; Register scratch = ABIArgGenerator::NonArgReturnReg1; #if defined(JS_CODEGEN_X86) - masm.loadPtr(Address(StackPointer, sizeof(AsmJSFrame) + masm.framePushed()), argv); + masm.loadPtr(Address(StackPointer, EntryFrameSize + masm.framePushed()), argv); #else masm.movePtr(IntArgReg0, argv); #endif masm.Push(argv); + // Save the stack pointer to the saved non-volatile registers. We will use + // this on two paths: normal return and exceptional return. Since + // loadAsmJSActivation uses GlobalReg, we must do this after loading + // GlobalReg. + JS_ASSERT(masm.framePushed() == FramePushedForEntrySP); + masm.loadAsmJSActivation(scratch); + masm.storePtr(StackPointer, Address(scratch, AsmJSActivation::offsetOfEntrySP())); + + // Dynamically align the stack since ABIStackAlignment is not necessarily + // AsmJSStackAlignment. We'll use entrySP to recover the original stack + // pointer on return. + masm.andPtr(Imm32(~(AsmJSStackAlignment - 1)), StackPointer); + // Bump the stack for the call. PropertyName *funcName = m.module().exportedFunction(exportIndex).name(); const ModuleCompiler::Func &func = *m.lookupFunction(funcName); - unsigned stackDec = StackDecrementForCall(masm, func.sig().args()); - masm.reserveStack(stackDec); + masm.reserveStack(AlignBytes(StackArgBytes(func.sig().args()), AsmJSStackAlignment)); // Copy parameters out of argv and into the registers/stack-slots specified by // the system ABI. @@ -6061,12 +6071,15 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) } // Call into the real function. - AssertStackAlignment(masm); + masm.assertStackAlignment(AsmJSStackAlignment); masm.call(CallSiteDesc(CallSiteDesc::Relative), &func.entry()); - // Pop the stack and recover the original 'argv' argument passed to the - // trampoline (which was pushed on the stack). - masm.freeStack(stackDec); + // Recover the stack pointer value before dynamic alignment. + masm.loadAsmJSActivation(scratch); + masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfEntrySP()), StackPointer); + masm.setFramePushed(FramePushedForEntrySP); + + // Recover the 'argv' pointer which was saved before aligning the stack. masm.Pop(argv); // Store the return value in argv[0] @@ -6090,7 +6103,6 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) JS_ASSERT(masm.framePushed() == 0); masm.move32(Imm32(true), ReturnReg); - masm.addPtr(Imm32(AsmJSFrameBytesAfterReturnAddress), StackPointer); masm.ret(); return m.finishGeneratingEntry(exportIndex, &begin) && !masm.oom(); @@ -6154,7 +6166,7 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e // padding between argv and retaddr ensures that sp is aligned. unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes), sizeof(double)); unsigned argvBytes = Max(1, exit.sig().args().length()) * sizeof(Value); - unsigned framePushed = StackDecrementForCall(masm, offsetToArgv + argvBytes); + unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, offsetToArgv + argvBytes); Label begin; GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::SlowFFI, &begin); @@ -6194,7 +6206,7 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e JS_ASSERT(i.done()); // Make the call, test whether it succeeded, and extract the return value. - AssertStackAlignment(masm); + AssertStackAlignment(masm, ABIStackAlignment); switch (exit.sig().retType().which()) { case RetType::Void: masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore)); @@ -6256,7 +6268,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit unsigned offsetToIonArgs = MaybeRetAddr; unsigned ionArgBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value); unsigned totalIonBytes = offsetToIonArgs + ionArgBytes + savedRegBytes; - unsigned ionFrameSize = StackDecrementForCall(masm, totalIonBytes); + unsigned ionFrameSize = StackDecrementForCall(masm, AsmJSStackAlignment, totalIonBytes); // Coercion calls use the following stack layout (sp grows to the left): // | stack args | padding | Value argv[1] | ... @@ -6265,7 +6277,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit coerceArgTypes.infallibleAppend(MIRType_Pointer); // argv unsigned offsetToCoerceArgv = AlignBytes(StackArgBytes(coerceArgTypes), sizeof(double)); unsigned totalCoerceBytes = offsetToCoerceArgv + sizeof(Value) + savedRegBytes; - unsigned coerceFrameSize = StackDecrementForCall(masm, totalCoerceBytes); + unsigned coerceFrameSize = StackDecrementForCall(masm, AsmJSStackAlignment, totalCoerceBytes); unsigned framePushed = Max(ionFrameSize, coerceFrameSize); @@ -6366,9 +6378,9 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit } // 2. Call - AssertStackAlignment(masm); + AssertStackAlignment(masm, AsmJSStackAlignment); masm.callIonFromAsmJS(callee); - AssertStackAlignment(masm); + AssertStackAlignment(masm, AsmJSStackAlignment); { // Disable Activation. @@ -6451,7 +6463,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit JS_ASSERT(i.done()); // Call coercion function - AssertStackAlignment(masm); + AssertStackAlignment(masm, ABIStackAlignment); switch (exit.sig().retType().which()) { case RetType::Signed: masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32)); @@ -6546,7 +6558,7 @@ GenerateBuiltinThunk(ModuleCompiler &m, AsmJSExit::BuiltinKind builtin) MOZ_CRASH("Bad builtin"); } - uint32_t framePushed = StackDecrementForCall(masm, argTypes); + uint32_t framePushed = StackDecrementForCall(masm, ABIStackAlignment, argTypes); Label begin; GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::Builtin(builtin), &begin); @@ -6571,7 +6583,7 @@ GenerateBuiltinThunk(ModuleCompiler &m, AsmJSExit::BuiltinKind builtin) #endif } - AssertStackAlignment(masm); + AssertStackAlignment(masm, ABIStackAlignment); masm.call(BuiltinToImmKind(builtin)); Label profilingReturn; @@ -6626,11 +6638,11 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // We know that StackPointer is word-aligned, but not necessarily // stack-aligned, so we need to align it dynamically. masm.mov(StackPointer, ABIArgGenerator::NonVolatileReg); - masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer); + masm.andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); if (ShadowStackSpace) masm.subPtr(Imm32(ShadowStackSpace), StackPointer); - masm.assertStackAlignment(); + masm.assertStackAlignment(ABIStackAlignment); masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt)); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -6653,7 +6665,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // Save the stack pointer in a non-volatile register. masm.movePtr(StackPointer, s0); // Align the stack. - masm.ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1))); + masm.ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); // Store resumePC into the reserved space. masm.loadAsmJSActivation(IntArgReg0); @@ -6663,7 +6675,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // MIPS ABI requires rewserving stack for registes $a0 to $a3. masm.subPtr(Imm32(4 * sizeof(intptr_t)), StackPointer); - masm.assertStackAlignment(); + masm.assertStackAlignment(ABIStackAlignment); masm.call(AsmJSImm_HandleExecutionInterrupt); masm.addPtr(Imm32(4 * sizeof(intptr_t)), StackPointer); @@ -6700,7 +6712,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllDoubleMask))); // save all FP registers - masm.assertStackAlignment(); + masm.assertStackAlignment(ABIStackAlignment); masm.call(AsmJSImm_HandleExecutionInterrupt); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -6744,11 +6756,11 @@ GenerateSyncInterruptExit(ModuleCompiler &m, Label *throwLabel) MacroAssembler &masm = m.masm(); masm.setFramePushed(0); - unsigned framePushed = StackDecrementForCall(masm, ShadowStackSpace); + unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, ShadowStackSpace); GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::Interrupt, &m.syncInterruptLabel()); - AssertStackAlignment(masm); + AssertStackAlignment(masm, ABIStackAlignment); masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt)); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -6772,17 +6784,17 @@ GenerateThrowStub(ModuleCompiler &m, Label *throwLabel) // We are about to pop all frames in this AsmJSActivation. Set fp to null to // maintain the invariant that fp is either null or pointing to a valid // frame. - Register activation = ABIArgGenerator::NonArgReturnReg0; - masm.loadAsmJSActivation(activation); - masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfFP())); + Register scratch = ABIArgGenerator::NonArgReturnReg0; + masm.loadAsmJSActivation(scratch); + masm.storePtr(ImmWord(0), Address(scratch, AsmJSActivation::offsetOfFP())); - masm.setFramePushed(FramePushedAfterSave); - masm.loadPtr(Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()), StackPointer); + masm.setFramePushed(FramePushedForEntrySP); + masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfEntrySP()), StackPointer); + masm.Pop(scratch); masm.PopRegsInMask(NonVolatileRegs); JS_ASSERT(masm.framePushed() == 0); masm.mov(ImmWord(0), ReturnReg); - masm.addPtr(Imm32(AsmJSFrameBytesAfterReturnAddress), StackPointer); masm.ret(); return m.finishGeneratingInlineStub(throwLabel) && !masm.oom(); diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index 4600bc0847cd..fad374596758 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -144,7 +144,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx) #endif size_t frameSize = sizeof(FrameData) + num_registers_ * sizeof(void *); - frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), StackAlignment) - masm.framePushed(); + frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), ABIStackAlignment) - masm.framePushed(); // Actually emit code to start a new stack frame. masm.reserveStack(frameSize); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 38b7b754f92b..67b94bb0d150 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8769,12 +8769,15 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins) if (mir->spIncrement()) masm.freeStack(mir->spIncrement()); - JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % StackAlignment == 0); + JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % AsmJSStackAlignment == 0); #ifdef DEBUG + static_assert(AsmJSStackAlignment >= ABIStackAlignment, + "The asm.js stack alignment should subsume the ABI-required alignment"); + static_assert(AsmJSStackAlignment % ABIStackAlignment == 0, + "The asm.js stack alignment should subsume the ABI-required alignment"); Label ok; - JS_ASSERT(IsPowerOfTwo(StackAlignment)); - masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok); + masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(AsmJSStackAlignment - 1), &ok); masm.breakpoint(); masm.bind(&ok); #endif @@ -9013,7 +9016,7 @@ CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir) masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin); { uint32_t stackFixup = ComputeByteAlignment(masm.framePushed() + sizeof(AsmJSFrame), - StackAlignment); + ABIStackAlignment); masm.reserveStack(stackFixup); masm.call(lir->funcDesc(), lir->interruptExit()); masm.freeStack(stackFixup); diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index 6f628a11daac..88de264262d2 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -1075,7 +1075,7 @@ uint8_t * alignDoubleSpillWithOffset(uint8_t *pointer, int32_t offset) { uint32_t address = reinterpret_cast(pointer); - address = (address - offset) & ~(StackAlignment - 1); + address = (address - offset) & ~(ABIStackAlignment - 1); return reinterpret_cast(address); } diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 9066ef3f6ad8..c64baa3bb7ff 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -1426,11 +1426,11 @@ class MacroAssembler : public MacroAssemblerSpecific PopRegsInMask(liveRegs); } - void assertStackAlignment() { + void assertStackAlignment(uint32_t alignment) { #ifdef DEBUG Label ok; - JS_ASSERT(IsPowerOfTwo(StackAlignment)); - branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok); + JS_ASSERT(IsPowerOfTwo(alignment)); + branchTestPtr(Assembler::Zero, StackPointer, Imm32(alignment - 1), &ok); breakpoint(); bind(&ok); #endif @@ -1508,10 +1508,10 @@ JSOpToCondition(JSOp op, bool isSigned) } static inline size_t -StackDecrementForCall(size_t bytesAlreadyPushed, size_t bytesToPush) +StackDecrementForCall(uint32_t alignment, size_t bytesAlreadyPushed, size_t bytesToPush) { return bytesToPush + - ComputeByteAlignment(bytesAlreadyPushed + bytesToPush, StackAlignment); + ComputeByteAlignment(bytesAlreadyPushed + bytesToPush, alignment); } } // namespace jit diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index e9d96f6cd128..40498f2bddfd 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -1586,10 +1586,10 @@ class LIRGraph // platform stack alignment requirement, and so that it's a multiple of // the number of slots per Value. uint32_t paddedLocalSlotCount() const { - // Round to StackAlignment, but also round to at least sizeof(Value) in - // case that's greater, because StackOffsetOfPassedArg rounds argument - // slots to 8-byte boundaries. - size_t Alignment = Max(size_t(StackAlignment), sizeof(Value)); + // Round to ABIStackAlignment, but also round to at least sizeof(Value) + // in case that's greater, because StackOffsetOfPassedArg rounds + // argument slots to 8-byte boundaries. + size_t Alignment = Max(size_t(ABIStackAlignment), sizeof(Value)); return AlignBytes(localSlotCount(), Alignment); } size_t paddedLocalSlotsSize() const { diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 18c0daea319a..f2cedd5a3289 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -145,9 +145,8 @@ static MOZ_CONSTEXPR_VAR FloatRegister d15 = {FloatRegisters::d15, VFPRegister:: // load/store) operate in a single cycle when the address they are dealing with // is 8 byte aligned. Also, the ARM abi wants the stack to be 8 byte aligned at // function boundaries. I'm trying to make sure this is always true. -static const uint32_t StackAlignment = 8; +static const uint32_t ABIStackAlignment = 8; static const uint32_t CodeAlignment = 8; -static const bool StackKeptAligned = true; // This boolean indicates whether we support SIMD instructions flavoured for // this architecture or not. Rather than a method in the LIRGenerator, it is @@ -156,6 +155,8 @@ static const bool StackKeptAligned = true; static const bool SupportsSimd = false; static const uint32_t SimdStackAlignment = 8; +static const uint32_t AsmJSStackAlignment = SimdStackAlignment; + static const Scale ScalePointer = TimesFour; class Instruction; diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 14fcca88ae61..2b2ecf51d4fa 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -3778,7 +3778,7 @@ MacroAssemblerARMCompat::setupUnalignedABICall(uint32_t args, Register scratch) ma_mov(sp, scratch); // Force sp to be aligned. - ma_and(Imm32(~(StackAlignment - 1)), sp, sp); + ma_and(Imm32(~(ABIStackAlignment - 1)), sp, sp); ma_push(scratch); } @@ -3937,7 +3937,7 @@ MacroAssemblerARMCompat::passABIArg(FloatRegister freg, MoveOp::Type type) void MacroAssemblerARMCompat::checkStackAlignment() { #ifdef DEBUG - ma_tst(sp, Imm32(StackAlignment - 1)); + ma_tst(sp, Imm32(ABIStackAlignment - 1)); breakpoint(NonZero); #endif } @@ -3956,11 +3956,11 @@ MacroAssemblerARMCompat::callWithABIPre(uint32_t *stackAdjust, bool callFromAsmJ if (!dynamicAlignment_) { *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust + alignmentAtPrologue, - StackAlignment); + ABIStackAlignment); } else { // sizeof(intptr_t) accounts for the saved stack pointer pushed by // setupUnalignedABICall. - *stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), StackAlignment); + *stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), ABIStackAlignment); } reserveStack(*stackAdjust); diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp index 610b3fc27f84..ea4ec2d915b6 100644 --- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -2117,7 +2117,7 @@ Simulator::softwareInterrupt(SimInstruction *instr) int32_t saved_lr = get_register(lr); intptr_t external = reinterpret_cast(redirection->nativeFunction()); - bool stack_aligned = (get_register(sp) & (StackAlignment - 1)) == 0; + bool stack_aligned = (get_register(sp) & (ABIStackAlignment - 1)) == 0; if (!stack_aligned) { fprintf(stderr, "Runtime call with unaligned stack!\n"); MOZ_CRASH(); @@ -4258,7 +4258,7 @@ Simulator::call(uint8_t* entry, int argument_count, ...) if (argument_count >= 4) entry_stack -= (argument_count - 4) * sizeof(int32_t); - entry_stack &= ~StackAlignment; + entry_stack &= ~ABIStackAlignment; // Store remaining arguments on stack, from low to high memory. intptr_t *stack_argument = reinterpret_cast(entry_stack); diff --git a/js/src/jit/mips/Assembler-mips.h b/js/src/jit/mips/Assembler-mips.h index ee901094f427..094b715f9ad2 100644 --- a/js/src/jit/mips/Assembler-mips.h +++ b/js/src/jit/mips/Assembler-mips.h @@ -158,9 +158,8 @@ static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegiste // MIPS CPUs can only load multibyte data that is "naturally" // four-byte-aligned, sp register should be eight-byte-aligned. -static const uint32_t StackAlignment = 8; +static const uint32_t ABIStackAlignment = 8; static const uint32_t CodeAlignment = 4; -static const bool StackKeptAligned = true; // This boolean indicates whether we support SIMD instructions flavoured for // this architecture or not. Rather than a method in the LIRGenerator, it is @@ -171,6 +170,8 @@ static const bool SupportsSimd = false; // alignment requirements still need to be explored. static const uint32_t SimdStackAlignment = 8; +static const uint32_t AsmJSStackAlignment = SimdStackAlignment; + static const Scale ScalePointer = TimesFour; // MIPS instruction types @@ -238,7 +239,6 @@ static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; static const uint32_t RegMask = Registers::Total - 1; -static const uint32_t StackAlignmentMask = StackAlignment - 1; static const uint32_t MAX_BREAK_CODE = 1024 - 1; diff --git a/js/src/jit/mips/MacroAssembler-mips.cpp b/js/src/jit/mips/MacroAssembler-mips.cpp index 3bb1aa88e836..f7243ccd2644 100644 --- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -1574,7 +1574,7 @@ MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet) // Double values have to be aligned. We reserve extra space so that we can // start writing from the first aligned location. // We reserve a whole extra double so that the buffer has even size. - ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1))); + ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1))); reserveStack(diffF + sizeof(double)); for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) { @@ -1596,7 +1596,7 @@ MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore, FloatRe // Read the buffer form the first aligned location. ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double))); - ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1))); + ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1))); for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) { if (!ignore.has(*iter) && ((*iter).code() % 2 == 0)) @@ -3158,7 +3158,7 @@ MacroAssemblerMIPSCompat::setupUnalignedABICall(uint32_t args, Register scratch) // Force sp to be aligned ma_subu(StackPointer, StackPointer, Imm32(sizeof(uint32_t))); - ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1))); + ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); as_sw(scratch, StackPointer, 0); } @@ -3259,7 +3259,7 @@ MacroAssemblerMIPSCompat::checkStackAlignment() { #ifdef DEBUG Label aligned; - as_andi(ScratchRegister, sp, StackAlignment - 1); + as_andi(ScratchRegister, sp, ABIStackAlignment - 1); ma_b(ScratchRegister, zero, &aligned, Equal, ShortJump); as_break(MAX_BREAK_CODE); bind(&aligned); @@ -3271,7 +3271,7 @@ MacroAssemblerMIPSCompat::alignStackPointer() { movePtr(StackPointer, SecondScratchReg); subPtr(Imm32(sizeof(uintptr_t)), StackPointer); - andPtr(Imm32(~(StackAlignment - 1)), StackPointer); + andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); storePtr(SecondScratchReg, Address(StackPointer, 0)); } @@ -3284,13 +3284,13 @@ MacroAssemblerMIPSCompat::restoreStackPointer() void MacroAssembler::alignFrameForICArguments(AfterICSaveLive &aic) { - if (framePushed() % StackAlignment != 0) { - aic.alignmentPadding = StackAlignment - (framePushed() % StackAlignment); + if (framePushed() % ABIStackAlignment != 0) { + aic.alignmentPadding = ABIStackAlignment - (framePushed() % StackAlignment); reserveStack(aic.alignmentPadding); } else { aic.alignmentPadding = 0; } - MOZ_ASSERT(framePushed() % StackAlignment == 0); + MOZ_ASSERT(framePushed() % ABIStackAlignment == 0); checkStackAlignment(); } @@ -3316,10 +3316,10 @@ MacroAssemblerMIPSCompat::callWithABIPre(uint32_t *stackAdjust, bool callFromAsm uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0; if (dynamicAlignment_) { - *stackAdjust += ComputeByteAlignment(*stackAdjust, StackAlignment); + *stackAdjust += ComputeByteAlignment(*stackAdjust, ABIStackAlignment); } else { *stackAdjust += ComputeByteAlignment(framePushed_ + alignmentAtPrologue + *stackAdjust, - StackAlignment); + ABIStackAlignment); } reserveStack(*stackAdjust); @@ -3444,7 +3444,7 @@ void MacroAssemblerMIPSCompat::handleFailureWithHandler(void *handler) { // Reserve space for exception information. - int size = (sizeof(ResumeFromException) + StackAlignment) & ~(StackAlignment - 1); + int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1); ma_subu(StackPointer, StackPointer, Imm32(size)); ma_move(a0, StackPointer); // Use a0 since it is a first function argument diff --git a/js/src/jit/mips/Simulator-mips.cpp b/js/src/jit/mips/Simulator-mips.cpp index 25f39937a79a..b33c6cf7d0f3 100644 --- a/js/src/jit/mips/Simulator-mips.cpp +++ b/js/src/jit/mips/Simulator-mips.cpp @@ -1871,7 +1871,7 @@ Simulator::softwareInterrupt(SimInstruction *instr) intptr_t external = reinterpret_cast(redirection->nativeFunction()); - bool stack_aligned = (getRegister(sp) & (StackAlignment - 1)) == 0; + bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0; if (!stack_aligned) { fprintf(stderr, "Runtime call with unaligned stack!\n"); MOZ_CRASH(); @@ -3405,7 +3405,7 @@ Simulator::call(uint8_t *entry, int argument_count, ...) else entry_stack = entry_stack - kCArgsSlotsSize; - entry_stack &= ~StackAlignment; + entry_stack &= ~ABIStackAlignment; intptr_t *stack_argument = reinterpret_cast(entry_stack); diff --git a/js/src/jit/none/Architecture-none.h b/js/src/jit/none/Architecture-none.h index 40bf91e11480..e5dd5b5fce34 100644 --- a/js/src/jit/none/Architecture-none.h +++ b/js/src/jit/none/Architecture-none.h @@ -16,6 +16,7 @@ namespace jit { static const bool SupportsSimd = false; static const uint32_t SimdStackAlignment = 0; +static const uint32_t AsmJSStackAlignment = 0; class Registers { diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 9049f4497222..2582bb465e92 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -68,9 +68,8 @@ static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg); #error "Bad architecture" #endif -static const uint32_t StackAlignment = 8; +static const uint32_t ABIStackAlignment = 4; static const uint32_t CodeAlignment = 4; -static const bool StackKeptAligned = false; static const Scale ScalePointer = TimesOne; diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 038fd421b799..7df6f01900fa 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -640,9 +640,9 @@ class CallSite : public CallSiteDesc typedef Vector CallSiteVector; // As an invariant across architectures, within asm.js code: -// $sp % StackAlignment = (sizeof(AsmJSFrame) + masm.framePushed) % StackAlignment +// $sp % AsmJSStackAlignment = (sizeof(AsmJSFrame) + masm.framePushed) % AsmJSStackAlignment // Thus, AsmJSFrame represents the bytes pushed after the call (which occurred -// with a StackAlignment-aligned StackPointer) that are not included in +// with a AsmJSStackAlignment-aligned StackPointer) that are not included in // masm.framePushed. struct AsmJSFrame { diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index dc7546795005..568879f7f90c 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -69,26 +69,26 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac if (!gen->compilingAsmJS()) masm.setInstrumentation(&sps_); - // Since asm.js uses the system ABI which does not necessarily use a - // regular array where all slots are sizeof(Value), it maintains the max - // argument stack depth separately. if (gen->compilingAsmJS()) { + // Since asm.js uses the system ABI which does not necessarily use a + // regular array where all slots are sizeof(Value), it maintains the max + // argument stack depth separately. JS_ASSERT(graph->argumentSlotCount() == 0); frameDepth_ += gen->maxAsmJSStackArgBytes(); - // An MAsmJSCall does not align the stack pointer at calls sites but instead - // relies on the a priori stack adjustment (in the prologue) on platforms - // (like x64) which require the stack to be aligned. - if (StackKeptAligned || gen->performsCall() || gen->usesSimd()) { - unsigned alignmentAtCall = sizeof(AsmJSFrame) + frameDepth_; - unsigned firstFixup = 0; - if (unsigned rem = alignmentAtCall % StackAlignment) - frameDepth_ += (firstFixup = StackAlignment - rem); - - if (gen->usesSimd()) - setupSimdAlignment(firstFixup); + // If the function uses any SIMD, we may need to insert padding so that + // local slots are aligned for SIMD. + if (gen->usesSimd()) { + frameInitialAdjustment_ = ComputeByteAlignment(sizeof(AsmJSFrame), AsmJSStackAlignment); + frameDepth_ += frameInitialAdjustment_; } + // An MAsmJSCall does not align the stack pointer at calls sites but instead + // relies on the a priori stack adjustment. This must be the last + // adjustment of frameDepth_. + if (gen->performsCall()) + frameDepth_ += ComputeByteAlignment(sizeof(AsmJSFrame) + frameDepth_, AsmJSStackAlignment); + // FrameSizeClass is only used for bailing, which cannot happen in // asm.js code. frameClass_ = FrameSizeClass::None(); @@ -97,38 +97,6 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac } } -void -CodeGeneratorShared::setupSimdAlignment(unsigned fixup) -{ - JS_STATIC_ASSERT(SimdStackAlignment % StackAlignment == 0); - // At this point, we have: - // (frameDepth_ + sizeof(AsmJSFrame)) % StackAlignment == 0 - // which means we can add as many SimdStackAlignment as needed. - - // The next constraint is to have all stack slots - // aligned for SIMD. That's done by having the first stack slot - // aligned. We need an offset such that: - // (frameDepth_ - offset) % SimdStackAlignment == 0 - frameInitialAdjustment_ = frameDepth_ % SimdStackAlignment; - - // We need to ensure that the first stack slot is actually - // located in this frame and not beforehand, when taking this - // offset into account, i.e.: - // frameDepth_ - initial adjustment >= frameDepth_ - fixup - // <=> fixup >= initial adjustment - // - // For instance, on x86 with gcc, if the initial frameDepth - // % 16 is 8, then the fixup is 0, although the initial - // adjustment is 8. The first stack slot would be located at - // frameDepth - 8 in this case, which is obviously before - // frameDepth. - // - // If that's not the case, we add SimdStackAlignment to the - // fixup, which will keep on satisfying other constraints. - if (frameInitialAdjustment_ > int32_t(fixup)) - frameDepth_ += SimdStackAlignment; -} - bool CodeGeneratorShared::generateOutOfLineCode() { diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 35e6950b62f2..24899fb2164d 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -496,8 +496,6 @@ class CodeGeneratorShared : public LInstructionVisitor private: void generateInvalidateEpilogue(); - void setupSimdAlignment(unsigned fixup); - public: CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm); diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index 9d84a2492907..0567dbd26758 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -184,10 +184,7 @@ static MOZ_CONSTEXPR_VAR Register OsrFrameReg = IntArgReg3; static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx; -// GCC stack is aligned on 16 bytes, but we don't maintain the invariant in -// jitted code. -static const uint32_t StackAlignment = 16; -static const bool StackKeptAligned = false; +static const uint32_t ABIStackAlignment = 16; static const uint32_t CodeAlignment = 8; // This boolean indicates whether we support SIMD instructions flavoured for @@ -197,6 +194,8 @@ static const uint32_t CodeAlignment = 8; static const bool SupportsSimd = true; static const uint32_t SimdStackAlignment = 16; +static const uint32_t AsmJSStackAlignment = SimdStackAlignment; + static const Scale ScalePointer = TimesEight; } // namespace jit diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index c87136f9dff9..49986e8c1f86 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -200,7 +200,7 @@ MacroAssemblerX64::setupUnalignedABICall(uint32_t args, Register scratch) dynamicAlignment_ = true; movq(rsp, scratch); - andq(Imm32(~(StackAlignment - 1)), rsp); + andq(Imm32(~(ABIStackAlignment - 1)), rsp); push(scratch); } @@ -270,11 +270,11 @@ MacroAssemblerX64::callWithABIPre(uint32_t *stackAdjust) if (dynamicAlignment_) { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t), - StackAlignment); + ABIStackAlignment); } else { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + framePushed_, - StackAlignment); + ABIStackAlignment); } reserveStack(*stackAdjust); @@ -293,7 +293,7 @@ MacroAssemblerX64::callWithABIPre(uint32_t *stackAdjust) #ifdef DEBUG { Label good; - testq(rsp, Imm32(StackAlignment - 1)); + testq(rsp, Imm32(ABIStackAlignment - 1)); j(Equal, &good); breakpoint(); bind(&good); diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index 583b25f0cdd5..cacaa5025fb7 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -551,7 +551,6 @@ JitRuntime::generateBailoutHandler(JSContext *cx, ExecutionMode mode) JitCode * JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { - JS_ASSERT(!StackKeptAligned); JS_ASSERT(functionWrappers_); JS_ASSERT(functionWrappers_->initialized()); VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f); diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 3067607ae515..832a03389e9b 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -108,14 +108,13 @@ static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = edi; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = eax; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = esi; -// GCC stack is aligned on 16 bytes, but we don't maintain the invariant in -// jitted code. +// GCC stack is aligned on 16 bytes. Ion does not maintain this for internal +// calls. asm.js code does. #if defined(__GNUC__) -static const uint32_t StackAlignment = 16; +static const uint32_t ABIStackAlignment = 16; #else -static const uint32_t StackAlignment = 4; +static const uint32_t ABIStackAlignment = 4; #endif -static const bool StackKeptAligned = false; static const uint32_t CodeAlignment = 8; // This boolean indicates whether we support SIMD instructions flavoured for @@ -125,6 +124,8 @@ static const uint32_t CodeAlignment = 8; static const bool SupportsSimd = true; static const uint32_t SimdStackAlignment = 16; +static const uint32_t AsmJSStackAlignment = SimdStackAlignment; + struct ImmTag : public Imm32 { ImmTag(JSValueTag mask) diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 90e94db0844d..23d1224fa1e0 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -227,7 +227,7 @@ MacroAssemblerX86::setupUnalignedABICall(uint32_t args, Register scratch) dynamicAlignment_ = true; movl(esp, scratch); - andl(Imm32(~(StackAlignment - 1)), esp); + andl(Imm32(~(ABIStackAlignment - 1)), esp); push(scratch); } @@ -267,11 +267,11 @@ MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust) if (dynamicAlignment_) { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t), - StackAlignment); + ABIStackAlignment); } else { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + framePushed_, - StackAlignment); + ABIStackAlignment); } reserveStack(*stackAdjust); @@ -291,7 +291,7 @@ MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust) { // Check call alignment. Label good; - testl(esp, Imm32(StackAlignment - 1)); + testl(esp, Imm32(ABIStackAlignment - 1)); j(Equal, &good); breakpoint(); bind(&good); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 9ee84f2a476e..808fe7de0a2d 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -590,7 +590,6 @@ JitRuntime::generateBailoutHandler(JSContext *cx, ExecutionMode mode) JitCode * JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { - JS_ASSERT(!StackKeptAligned); JS_ASSERT(functionWrappers_); JS_ASSERT(functionWrappers_->initialized()); VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index b6de66540be9..2abd6a942f8e 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1550,7 +1550,7 @@ jit::JitActivation::markRematerializedFrames(JSTracer *trc) AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) : Activation(cx, AsmJS), module_(module), - errorRejoinSP_(nullptr), + entrySP_(nullptr), profiler_(nullptr), resumePC_(nullptr), fp_(nullptr), @@ -1573,7 +1573,7 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) JSRuntime::AutoLockForInterrupt lock(cx->runtime()); cx->mainThread().asmJSActivationStack_ = this; - (void) errorRejoinSP_; // squelch GCC warning + (void) entrySP_; // squelch GCC warning } AsmJSActivation::~AsmJSActivation() diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index d1bfab36d587..0f9b2b0bd676 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1482,7 +1482,7 @@ class AsmJSActivation : public Activation AsmJSModule &module_; AsmJSActivation *prevAsmJS_; AsmJSActivation *prevAsmJSForModule_; - void *errorRejoinSP_; + void *entrySP_; SPSProfiler *profiler_; void *resumePC_; uint8_t *fp_; @@ -1512,7 +1512,7 @@ class AsmJSActivation : public Activation static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); } // Written by JIT code: - static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); } + static unsigned offsetOfEntrySP() { return offsetof(AsmJSActivation, entrySP_); } static unsigned offsetOfFP() { return offsetof(AsmJSActivation, fp_); } static unsigned offsetOfExitReason() { return offsetof(AsmJSActivation, exitReason_); } From cb1711d02862fdb97c1d8e27207050fd3d716080 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 28 Aug 2014 10:01:44 +0200 Subject: [PATCH 006/120] Bug 992267: Odin basic SIMD support; r=luke * * * Bug 992267: Add SIMD globals support to Odin; r=luke --HG-- extra : rebase_source : 7a10c51e0e9be701b91e462caff2701a6c52c258 --- js/src/asmjs/AsmJSLink.cpp | 219 +++- js/src/asmjs/AsmJSModule.cpp | 8 +- js/src/asmjs/AsmJSModule.h | 209 +++- js/src/asmjs/AsmJSValidate.cpp | 969 ++++++++++++++++-- js/src/builtin/SIMD.cpp | 22 +- js/src/builtin/SIMD.h | 6 + js/src/jit-test/lib/asm.js | 4 +- js/src/jit-test/tests/asm.js/testSIMD.js | 657 ++++++++++++ js/src/jit/Lowering.cpp | 6 +- js/src/jit/MIR.cpp | 1 + js/src/jit/MIR.h | 2 +- js/src/jit/shared/BaseAssembler-x86-shared.h | 38 + .../jit/shared/CodeGenerator-x86-shared.cpp | 22 +- js/src/jit/shared/Lowering-shared-inl.h | 6 + js/src/jit/x64/Assembler-x64.cpp | 30 +- js/src/jit/x64/Assembler-x64.h | 18 + js/src/jit/x64/CodeGenerator-x64.cpp | 49 +- js/src/jit/x86/Assembler-x86.cpp | 12 +- js/src/jit/x86/Assembler-x86.h | 20 + js/src/jit/x86/CodeGenerator-x86.cpp | 46 +- js/src/js.msg | 1 + 21 files changed, 2137 insertions(+), 208 deletions(-) create mode 100644 js/src/jit-test/tests/asm.js/testSIMD.js diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 8e3c8815cc7e..de305fd257ee 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -30,6 +30,7 @@ #include "jswrapper.h" #include "asmjs/AsmJSModule.h" +#include "builtin/SIMD.h" #include "frontend/BytecodeCompiler.h" #include "jit/Ion.h" #include "jit/JitCommon.h" @@ -96,59 +97,75 @@ GetDataProperty(JSContext *cx, HandleValue objVal, HandlePropertyName field, Mut return true; } +static bool +HasPureCoercion(JSContext *cx, HandleValue v) +{ + if (IsVectorObject(v) || IsVectorObject(v)) + return true; + + // Ideally, we'd reject all non-SIMD non-primitives, but Emscripten has a + // bug that generates code that passes functions for some imports. To avoid + // breaking all the code that contains this bug, we make an exception for + // functions that don't have user-defined valueOf or toString, for their + // coercions are not observable and coercion via ToNumber/ToInt32 + // definitely produces NaN/0. We should remove this special case later once + // most apps have been built with newer Emscripten. + jsid toString = NameToId(cx->names().toString); + if (v.toObject().is() && + HasObjectValueOf(&v.toObject(), cx) && + ClassMethodIsNative(cx, &v.toObject(), &JSFunction::class_, toString, fun_toString)) + { + return true; + } + + return false; +} + static bool ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Global &global, HandleValue importVal) { JS_ASSERT(global.which() == AsmJSModule::Global::Variable); - void *datum = module.globalVarIndexToGlobalDatum(global.varIndex()); + void *datum = module.globalVarToGlobalDatum(global); switch (global.varInitKind()) { case AsmJSModule::Global::InitConstant: { const AsmJSNumLit &lit = global.varInitNumLit(); - const Value &v = lit.value(); switch (lit.which()) { case AsmJSNumLit::Fixnum: case AsmJSNumLit::NegativeInt: case AsmJSNumLit::BigUnsigned: - *(int32_t *)datum = v.toInt32(); + *(int32_t *)datum = lit.scalarValue().toInt32(); break; case AsmJSNumLit::Double: - *(double *)datum = v.toDouble(); + *(double *)datum = lit.scalarValue().toDouble(); break; case AsmJSNumLit::Float: - *(float *)datum = static_cast(v.toDouble()); + *(float *)datum = static_cast(lit.scalarValue().toDouble()); + break; + case AsmJSNumLit::Int32x4: + memcpy(datum, lit.simdValue().asInt32x4(), Simd128DataSize); + break; + case AsmJSNumLit::Float32x4: + memcpy(datum, lit.simdValue().asFloat32x4(), Simd128DataSize); break; case AsmJSNumLit::OutOfRangeInt: MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("OutOfRangeInt isn't valid in the first place"); } break; } + case AsmJSModule::Global::InitImport: { RootedPropertyName field(cx, global.varImportField()); RootedValue v(cx); if (!GetDataProperty(cx, importVal, field, &v)) return false; - if (!v.isPrimitive()) { - // Ideally, we'd reject all non-primitives, but Emscripten has a bug - // that generates code that passes functions for some imports. To - // avoid breaking all the code that contains this bug, we make an - // exception for functions that don't have user-defined valueOf or - // toString, for their coercions are not observable and coercion via - // ToNumber/ToInt32 definitely produces NaN/0. We should remove this - // special case later once most apps have been built with newer - // Emscripten. - jsid toString = NameToId(cx->names().toString); - if (!v.toObject().is() || - !HasObjectValueOf(&v.toObject(), cx) || - !ClassMethodIsNative(cx, &v.toObject(), &JSFunction::class_, toString, fun_toString)) - { - return LinkFail(cx, "Imported values must be primitives"); - } - } + if (!v.isPrimitive() && !HasPureCoercion(cx, v)) + return LinkFail(cx, "Imported values must be primitives"); + SimdConstant simdConstant; switch (global.varInitCoercion()) { case AsmJS_ToInt32: if (!ToInt32(cx, v, (int32_t *)datum)) @@ -162,6 +179,16 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl if (!RoundFloat32(cx, v, (float *)datum)) return false; break; + case AsmJS_ToInt32x4: + if (!ToSimdConstant(cx, v, &simdConstant)) + return false; + memcpy(datum, simdConstant.asInt32x4(), Simd128DataSize); + break; + case AsmJS_ToFloat32x4: + if (!ToSimdConstant(cx, v, &simdConstant)) + return false; + memcpy(datum, simdConstant.asFloat32x4(), Simd128DataSize); + break; } break; } @@ -240,6 +267,103 @@ ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleVa return true; } +static PropertyName * +SimdTypeToName(JSContext *cx, AsmJSSimdType type) +{ + switch (type) { + case AsmJSSimdType_int32x4: return cx->names().int32x4; + case AsmJSSimdType_float32x4: return cx->names().float32x4; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type"); +} + +static X4TypeDescr::Type +AsmJSSimdTypeToTypeDescrType(AsmJSSimdType type) +{ + switch (type) { + case AsmJSSimdType_int32x4: return Int32x4::type; + case AsmJSSimdType_float32x4: return Float32x4::type; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSSimdType"); +} + +static bool +ValidateSimdType(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal, + MutableHandleValue out) +{ + RootedValue v(cx); + if (!GetDataProperty(cx, globalVal, cx->names().SIMD, &v)) + return false; + + AsmJSSimdType type; + if (global.which() == AsmJSModule::Global::SimdCtor) + type = global.simdCtorType(); + else + type = global.simdOperationType(); + + RootedPropertyName simdTypeName(cx, SimdTypeToName(cx, type)); + if (!GetDataProperty(cx, v, simdTypeName, &v)) + return false; + + if (!v.isObject()) + return LinkFail(cx, "bad SIMD type"); + + RootedObject x4desc(cx, &v.toObject()); + if (!x4desc->is()) + return LinkFail(cx, "bad SIMD type"); + + if (AsmJSSimdTypeToTypeDescrType(type) != x4desc->as().type()) + return LinkFail(cx, "bad SIMD type"); + + out.set(v); + return true; +} + +static bool +ValidateSimdType(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal) +{ + RootedValue _(cx); + return ValidateSimdType(cx, global, globalVal, &_); +} + +static bool +ValidateSimdOperation(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal) +{ + // SIMD operations are loaded from the SIMD type, so the type must have been + // validated before the operation. + RootedValue v(cx); + JS_ALWAYS_TRUE(ValidateSimdType(cx, global, globalVal, &v)); + + RootedPropertyName opName(cx, global.simdOperationName()); + if (!GetDataProperty(cx, v, opName, &v)) + return false; + + Native native = nullptr; + switch (global.simdOperationType()) { + case AsmJSSimdType_int32x4: + switch (global.simdOperation()) { + case AsmJSSimdOperation_add: native = simd_int32x4_add; break; + case AsmJSSimdOperation_sub: native = simd_int32x4_sub; break; + case AsmJSSimdOperation_mul: + case AsmJSSimdOperation_div: + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Mul and div shouldn't have been validated in " + "the first place"); + } + break; + case AsmJSSimdType_float32x4: + switch (global.simdOperation()) { + case AsmJSSimdOperation_add: native = simd_float32x4_add; break; + case AsmJSSimdOperation_sub: native = simd_float32x4_sub; break; + case AsmJSSimdOperation_mul: native = simd_float32x4_mul; break; + case AsmJSSimdOperation_div: native = simd_float32x4_div; break; + } + break; + } + if (!native || !IsNativeFunction(v, native)) + return LinkFail(cx, "bad SIMD.type.* operation"); + return true; +} + static bool ValidateConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal) { @@ -376,6 +500,14 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module) if (!ValidateConstant(cx, global, globalVal)) return false; break; + case AsmJSModule::Global::SimdCtor: + if (!ValidateSimdType(cx, global, globalVal)) + return false; + break; + case AsmJSModule::Global::SimdOperation: + if (!ValidateSimdOperation(cx, global, globalVal)) + return false; + break; } } @@ -436,14 +568,14 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) const AsmJSModule::ExportedFunction &func = FunctionToExportedFunction(callee, module); // The calling convention for an external call into asm.js is to pass an - // array of 8-byte values where each value contains either a coerced int32 - // (in the low word) or double value, with the coercions specified by the - // asm.js signature. The external entry point unpacks this array into the - // system-ABI-specified registers and stack memory and then calls into the - // internal entry point. The return value is stored in the first element of - // the array (which, therefore, must have length >= 1). - - js::Vector coercedArgs(cx); + // array of 16-byte values where each value contains either a coerced int32 + // (in the low word), a double value (in the low dword) or a SIMD vector + // value, with the coercions specified by the asm.js signature. The + // external entry point unpacks this array into the system-ABI-specified + // registers and stack memory and then calls into the internal entry point. + // The return value is stored in the first element of the array (which, + // therefore, must have length >= 1). + js::Vector coercedArgs(cx); if (!coercedArgs.resize(Max(1, func.numArgs()))) return false; @@ -463,6 +595,20 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) if (!RoundFloat32(cx, v, (float *)&coercedArgs[i])) return false; break; + case AsmJS_ToInt32x4: { + SimdConstant simd; + if (!ToSimdConstant(cx, v, &simd)) + return false; + memcpy(&coercedArgs[i], simd.asInt32x4(), Simd128DataSize); + break; + } + case AsmJS_ToFloat32x4: { + SimdConstant simd; + if (!ToSimdConstant(cx, v, &simd)) + return false; + memcpy(&coercedArgs[i], simd.asFloat32x4(), Simd128DataSize); + break; + } } } @@ -500,6 +646,7 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) return true; } + JSObject *x4obj; switch (func.returnType()) { case AsmJSModule::Return_Void: callArgs.rval().set(UndefinedValue()); @@ -510,6 +657,18 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) case AsmJSModule::Return_Double: callArgs.rval().set(NumberValue(*(double*)&coercedArgs[0])); break; + case AsmJSModule::Return_Int32x4: + x4obj = CreateSimd(cx, (int32_t*)&coercedArgs[0]); + if (!x4obj) + return false; + callArgs.rval().set(ObjectValue(*x4obj)); + break; + case AsmJSModule::Return_Float32x4: + x4obj = CreateSimd(cx, (float*)&coercedArgs[0]); + if (!x4obj) + return false; + callArgs.rval().set(ObjectValue(*x4obj)); + break; } return true; diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index 32645f0f9746..3b6b38f39f0c 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -303,8 +303,8 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl // The global data section sits immediately after the executable (and // other) data allocated by the MacroAssembler, so ensure it is - // double-aligned. - pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), sizeof(double)); + // SIMD-aligned. + pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), SimdStackAlignment); // The entire region is allocated via mmap/VirtualAlloc which requires // units of pages. @@ -518,11 +518,11 @@ TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t if (fun->nargs() > size_t(argc)) return true; - // Normally the types should corresond, since we just ran with those types, + // Normally the types should correspond, since we just ran with those types, // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only. if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType())) return true; - for(uint32_t i = 0; i < fun->nargs(); i++) { + for (uint32_t i = 0; i < fun->nargs(); i++) { types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i); types::Type type = types::Type::DoubleType(); if (!argv[i].isDouble()) diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index d4bcf940f202..7f2bca6cce72 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -27,8 +27,10 @@ #include "asmjs/AsmJSFrameIterator.h" #include "asmjs/AsmJSValidate.h" +#include "builtin/SIMD.h" #include "gc/Marking.h" #include "jit/IonMacroAssembler.h" +#include "jit/IonTypes.h" #ifdef JS_ION_PERF # include "jit/PerfSpewer.h" #endif @@ -47,7 +49,9 @@ enum AsmJSCoercion { AsmJS_ToInt32, AsmJS_ToNumber, - AsmJS_FRound + AsmJS_FRound, + AsmJS_ToInt32x4, + AsmJS_ToFloat32x4 }; // The asm.js spec recognizes this set of builtin Math functions. @@ -61,6 +65,22 @@ enum AsmJSMathBuiltinFunction AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max }; +// Set of known global object SIMD's attributes, i.e. types +enum AsmJSSimdType +{ + AsmJSSimdType_int32x4, + AsmJSSimdType_float32x4 +}; + +// Set of known operations, for a given SIMD type (int32x4, float32x4,...) +enum AsmJSSimdOperation +{ + AsmJSSimdOperation_add, + AsmJSSimdOperation_sub, + AsmJSSimdOperation_mul, + AsmJSSimdOperation_div +}; + // These labels describe positions in the prologue/epilogue of functions while // compiling an AsmJSModule. struct AsmJSFunctionLabels @@ -97,18 +117,32 @@ class AsmJSNumLit BigUnsigned, Double, Float, + Int32x4, + Float32x4, OutOfRangeInt = -1 }; private: Which which_; - Value value_; + union { + Value scalar_; + jit::SimdConstant simd_; + } value; public: static AsmJSNumLit Create(Which w, Value v) { AsmJSNumLit lit; lit.which_ = w; - lit.value_ = v; + lit.value.scalar_ = v; + JS_ASSERT(!lit.isSimd()); + return lit; + } + + static AsmJSNumLit Create(Which w, jit::SimdConstant c) { + AsmJSNumLit lit; + lit.which_ = w; + lit.value.simd_ = c; + JS_ASSERT(lit.isSimd()); return lit; } @@ -118,22 +152,31 @@ class AsmJSNumLit int32_t toInt32() const { JS_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned); - return value_.toInt32(); + return value.scalar_.toInt32(); } double toDouble() const { JS_ASSERT(which_ == Double); - return value_.toDouble(); + return value.scalar_.toDouble(); } float toFloat() const { JS_ASSERT(which_ == Float); - return float(value_.toDouble()); + return float(value.scalar_.toDouble()); } - Value value() const { + Value scalarValue() const { JS_ASSERT(which_ != OutOfRangeInt); - return value_; + return value.scalar_; + } + + bool isSimd() const { + return which_ == Int32x4 || which_ == Float32x4; + } + + const jit::SimdConstant &simdValue() const { + JS_ASSERT(isSimd()); + return value.simd_; } bool hasType() const { @@ -157,7 +200,8 @@ class AsmJSModule class Global { public: - enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant }; + enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant, + SimdCtor, SimdOperation}; enum VarInitKind { InitConstant, InitImport }; enum ConstantKind { GlobalConstant, MathConstant }; @@ -176,6 +220,11 @@ class AsmJSModule uint32_t ffiIndex_; Scalar::Type viewType_; AsmJSMathBuiltinFunction mathBuiltinFunc_; + AsmJSSimdType simdCtorType_; + struct { + AsmJSSimdType type_; + AsmJSSimdOperation which_; + } simdOp; struct { ConstantKind kind_; double value_; @@ -196,7 +245,7 @@ class AsmJSModule if (name_) MarkStringUnbarriered(trc, &name_, "asm.js global name"); JS_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant, - !pod.u.var.u.numLit_.value().isMarkable()); + !pod.u.var.u.numLit_.scalarValue().isMarkable()); } public: @@ -251,6 +300,26 @@ class AsmJSModule JS_ASSERT(pod.which_ == MathBuiltinFunction); return pod.u.mathBuiltinFunc_; } + AsmJSSimdType simdCtorType() const { + JS_ASSERT(pod.which_ == SimdCtor); + return pod.u.simdCtorType_; + } + PropertyName *simdCtorName() const { + JS_ASSERT(pod.which_ == SimdCtor); + return name_; + } + PropertyName *simdOperationName() const { + JS_ASSERT(pod.which_ == SimdOperation); + return name_; + } + AsmJSSimdOperation simdOperation() const { + JS_ASSERT(pod.which_ == SimdOperation); + return pod.u.simdOp.which_; + } + AsmJSSimdType simdOperationType() const { + JS_ASSERT(pod.which_ == SimdOperation); + return pod.u.simdOp.type_; + } PropertyName *constantName() const { JS_ASSERT(pod.which_ == Constant); return name_; @@ -309,7 +378,13 @@ class AsmJSModule const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); bool clone(ExclusiveContext *cx, Exit *out) const; }; - typedef int32_t (*CodePtr)(uint64_t *args, uint8_t *global); + + struct EntryArg { + uint64_t lo; + uint64_t hi; + }; + JS_STATIC_ASSERT(sizeof(EntryArg) >= jit::Simd128DataSize); + typedef int32_t (*CodePtr)(EntryArg *args, uint8_t *global); // An Exit holds bookkeeping information about an exit; the ExitDatum // struct overlays the actual runtime data stored in the global data @@ -322,7 +397,7 @@ class AsmJSModule typedef Vector ArgCoercionVector; - enum ReturnType { Return_Int32, Return_Double, Return_Void }; + enum ReturnType { Return_Int32, Return_Double, Return_Int32x4, Return_Float32x4, Return_Void }; class ExportedFunction { @@ -672,7 +747,8 @@ class AsmJSModule size_t codeBytes_; // function bodies and stubs size_t totalBytes_; // function bodies, stubs, and global data uint32_t minHeapLength_; - uint32_t numGlobalVars_; + uint32_t numGlobalScalarVars_; + uint32_t numGlobalSimdVars_; uint32_t numFFIs_; uint32_t srcLength_; uint32_t srcLengthWithRightBrace_; @@ -819,20 +895,43 @@ class AsmJSModule } bool addGlobalVarInit(const AsmJSNumLit &lit, uint32_t *globalIndex) { JS_ASSERT(!isFinishedWithModulePrologue()); - if (pod.numGlobalVars_ == UINT32_MAX) - return false; Global g(Global::Variable, nullptr); g.pod.u.var.initKind_ = Global::InitConstant; g.pod.u.var.u.numLit_ = lit; - g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++; + + if (lit.isSimd()) { + if (pod.numGlobalSimdVars_ == UINT32_MAX) + return false; + *globalIndex = pod.numGlobalSimdVars_++; + } else { + if (pod.numGlobalScalarVars_ == UINT32_MAX) + return false; + *globalIndex = pod.numGlobalScalarVars_++; + } + + g.pod.u.var.index_ = *globalIndex; return globals_.append(g); } + static bool IsSimdCoercion(AsmJSCoercion c) { + switch (c) { + case AsmJS_ToInt32: + case AsmJS_ToNumber: + case AsmJS_FRound: + return false; + case AsmJS_ToInt32x4: + case AsmJS_ToFloat32x4: + return true; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSCoercion"); + } bool addGlobalVarImport(PropertyName *name, AsmJSCoercion coercion, uint32_t *globalIndex) { JS_ASSERT(!isFinishedWithModulePrologue()); Global g(Global::Variable, name); g.pod.u.var.initKind_ = Global::InitImport; g.pod.u.var.u.coercion_ = coercion; - g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++; + *globalIndex = IsSimdCoercion(coercion) ? pod.numGlobalSimdVars_++ + : pod.numGlobalScalarVars_++; + g.pod.u.var.index_ = *globalIndex; return globals_.append(g); } bool addFFI(PropertyName *field, uint32_t *ffiIndex) { @@ -863,6 +962,17 @@ class AsmJSModule g.pod.u.constant.kind_ = Global::MathConstant; return globals_.append(g); } + bool addSimdCtor(AsmJSSimdType type, PropertyName *field) { + Global g(Global::SimdCtor, field); + g.pod.u.simdCtorType_ = type; + return globals_.append(g); + } + bool addSimdOperation(AsmJSSimdType type, AsmJSSimdOperation op, PropertyName *field) { + Global g(Global::SimdOperation, field); + g.pod.u.simdOp.type_ = type; + g.pod.u.simdOp.which_ = op; + return globals_.append(g); + } bool addGlobalConstant(double value, PropertyName *name) { JS_ASSERT(!isFinishedWithModulePrologue()); Global g(Global::Constant, name); @@ -1109,10 +1219,11 @@ class AsmJSModule // are laid out in this order: // 0. a pointer to the current AsmJSActivation // 1. a pointer to the heap that was linked to the module - // 2. the double float constant NaN. - // 3. the float32 constant NaN, padded to sizeof(double). - // 4. global variable state (elements are sizeof(uint64_t)) - // 5. interleaved function-pointer tables and exits. These are allocated + // 2. the double float constant NaN + // 3. the float32 constant NaN, padded to Simd128DataSize + // 4. global SIMD variable state (elements are Simd128DataSize) + // 5. global variable state (elements are sizeof(uint64_t)) + // 6. interleaved function-pointer tables and exits. These are allocated // while type checking function bodies (as exits and uses of // function-pointer tables are encountered). size_t offsetOfGlobalData() const { @@ -1123,13 +1234,18 @@ class AsmJSModule JS_ASSERT(isFinished()); return code_ + offsetOfGlobalData(); } + size_t globalSimdVarsOffset() const { + return AlignBytes(/* 0 */ sizeof(void*) + + /* 1 */ sizeof(void*) + + /* 2 */ sizeof(double) + + /* 3 */ sizeof(float), + jit::Simd128DataSize); + } size_t globalDataBytes() const { - return sizeof(void*) + - sizeof(void*) + - sizeof(double) + - sizeof(double) + - pod.numGlobalVars_ * sizeof(uint64_t) + - pod.funcPtrTableAndExitBytes_; + return globalSimdVarsOffset() + + /* 4 */ pod.numGlobalSimdVars_ * jit::Simd128DataSize + + /* 5 */ pod.numGlobalScalarVars_ * sizeof(uint64_t) + + /* 6 */ pod.funcPtrTableAndExitBytes_; } static unsigned activationGlobalDataOffset() { JS_STATIC_ASSERT(jit::AsmJSActivationGlobalDataOffset == 0); @@ -1164,20 +1280,39 @@ class AsmJSModule *(double *)(globalData() + nan64GlobalDataOffset()) = GenericNaN(); *(float *)(globalData() + nan32GlobalDataOffset()) = GenericNaN(); } - unsigned globalVariableOffset() const { - static_assert((2 * sizeof(void*) + 2 * sizeof(double)) % sizeof(double) == 0, - "Global data should be aligned"); - return 2 * sizeof(void*) + 2 * sizeof(double); - } - unsigned globalVarIndexToGlobalDataOffset(unsigned i) const { + unsigned globalSimdVarIndexToGlobalDataOffset(unsigned i) const { JS_ASSERT(isFinishedWithModulePrologue()); - JS_ASSERT(i < pod.numGlobalVars_); - return globalVariableOffset() + + JS_ASSERT(i < pod.numGlobalSimdVars_); + return globalSimdVarsOffset() + + i * jit::Simd128DataSize; + } + unsigned globalScalarVarIndexToGlobalDataOffset(unsigned i) const { + JS_ASSERT(isFinishedWithModulePrologue()); + JS_ASSERT(i < pod.numGlobalScalarVars_); + return globalSimdVarsOffset() + + pod.numGlobalSimdVars_ * jit::Simd128DataSize + i * sizeof(uint64_t); } - void *globalVarIndexToGlobalDatum(unsigned i) const { + void *globalScalarVarIndexToGlobalDatum(unsigned i) const { JS_ASSERT(isFinished()); - return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i)); + return (void *)(globalData() + globalScalarVarIndexToGlobalDataOffset(i)); + } + void *globalSimdVarIndexToGlobalDatum(unsigned i) const { + JS_ASSERT(isFinished()); + return (void *)(globalData() + globalSimdVarIndexToGlobalDataOffset(i)); + } + void *globalVarToGlobalDatum(const Global &g) const { + unsigned index = g.varIndex(); + if (g.varInitKind() == Global::VarInitKind::InitConstant) { + return g.varInitNumLit().isSimd() + ? globalSimdVarIndexToGlobalDatum(index) + : globalScalarVarIndexToGlobalDatum(index); + } + + JS_ASSERT(g.varInitKind() == Global::VarInitKind::InitImport); + return IsSimdCoercion(g.varInitCoercion()) + ? globalSimdVarIndexToGlobalDatum(index) + : globalScalarVarIndexToGlobalDatum(index); } uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const { JS_ASSERT(isFinished()); diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index f8248c544c4e..e648cc64d025 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -32,6 +32,7 @@ #include "asmjs/AsmJSLink.h" #include "asmjs/AsmJSModule.h" #include "asmjs/AsmJSSignalHandlers.h" +#include "builtin/SIMD.h" #include "frontend/Parser.h" #include "jit/CodeGenerator.h" #include "jit/CompileWrappers.h" @@ -387,6 +388,8 @@ class Type Unsigned = AsmJSNumLit::BigUnsigned, Double = AsmJSNumLit::Double, Float = AsmJSNumLit::Float, + Int32x4 = AsmJSNumLit::Int32x4, + Float32x4 = AsmJSNumLit::Float32x4, MaybeDouble, MaybeFloat, Floatish, @@ -402,12 +405,23 @@ class Type Type() : which_(Which(-1)) {} static Type Of(const AsmJSNumLit &lit) { JS_ASSERT(lit.hasType()); - JS_ASSERT(Type::Which(lit.which()) >= Fixnum && Type::Which(lit.which()) <= Float); + JS_ASSERT(Type::Which(lit.which()) >= Fixnum && Type::Which(lit.which()) <= Float32x4); Type t; t.which_ = Type::Which(lit.which()); return t; } MOZ_IMPLICIT Type(Which w) : which_(w) {} + MOZ_IMPLICIT Type(AsmJSSimdType type) { + switch (type) { + case AsmJSSimdType_int32x4: + which_ = Int32x4; + return; + case AsmJSSimdType_float32x4: + which_ = Float32x4; + return; + } + MOZ_CRASH("unexpected AsmJSSimdType"); + } bool operator==(Type rhs) const { return which_ == rhs.which_; } bool operator!=(Type rhs) const { return which_ != rhs.which_; } @@ -456,8 +470,20 @@ class Type return isDouble() || isSigned(); } + bool isInt32x4() const { + return which_ == Int32x4; + } + + bool isFloat32x4() const { + return which_ == Float32x4; + } + + bool isSimd() const { + return isInt32x4() || isFloat32x4(); + } + bool isVarType() const { - return isInt() || isDouble() || isFloat(); + return isInt() || isDouble() || isFloat() || isSimd(); } MIRType toMIRType() const { @@ -475,12 +501,64 @@ class Type case Unsigned: case Intish: return MIRType_Int32; + case Int32x4: + return MIRType_Int32x4; + case Float32x4: + return MIRType_Float32x4; case Void: return MIRType_None; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid Type"); } + Type simdToScalarType() const { + JS_ASSERT(isSimd()); + switch (which_) { + case Int32x4: + return Int; + case Float32x4: + return Float; + // Scalar types + case Double: + case MaybeDouble: + case Float: + case MaybeFloat: + case Floatish: + case Fixnum: + case Int: + case Signed: + case Unsigned: + case Intish: + case Void: + break; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid SIMD Type"); + } + + AsmJSSimdType simdToSimdType() const { + JS_ASSERT(isSimd()); + switch (which_) { + case Int32x4: + return AsmJSSimdType_int32x4; + case Float32x4: + return AsmJSSimdType_float32x4; + // Scalar types + case Double: + case MaybeDouble: + case Float: + case MaybeFloat: + case Floatish: + case Fixnum: + case Int: + case Signed: + case Unsigned: + case Intish: + case Void: + break; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid SIMD Type"); + } + const char *toChars() const { switch (which_) { case Double: return "double"; @@ -493,6 +571,8 @@ class Type case Signed: return "signed"; case Unsigned: return "unsigned"; case Intish: return "intish"; + case Int32x4: return "int32x4"; + case Float32x4: return "float32x4"; case Void: return "void"; } MOZ_CRASH("Invalid Type"); @@ -510,7 +590,9 @@ class RetType Void = Type::Void, Signed = Type::Signed, Double = Type::Double, - Float = Type::Float + Float = Type::Float, + Int32x4 = Type::Int32x4, + Float32x4 = Type::Float32x4 }; private: @@ -524,6 +606,8 @@ class RetType case AsmJS_ToInt32: which_ = Signed; break; case AsmJS_ToNumber: which_ = Double; break; case AsmJS_FRound: which_ = Float; break; + case AsmJS_ToInt32x4: which_ = Int32x4; break; + case AsmJS_ToFloat32x4: which_ = Float32x4; break; } } Which which() const { @@ -538,6 +622,8 @@ class RetType case Signed: return AsmJSModule::Return_Int32; case Float: // will be converted to a Double case Double: return AsmJSModule::Return_Double; + case Int32x4: return AsmJSModule::Return_Int32x4; + case Float32x4: return AsmJSModule::Return_Float32x4; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected return type"); } @@ -547,6 +633,8 @@ class RetType case Signed: return MIRType_Int32; case Double: return MIRType_Double; case Float: return MIRType_Float32; + case Int32x4: return MIRType_Int32x4; + case Float32x4: return MIRType_Float32x4; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected return type"); } @@ -612,7 +700,9 @@ class VarType enum Which { Int = Type::Int, Double = Type::Double, - Float = Type::Float + Float = Type::Float, + Int32x4 = Type::Int32x4, + Float32x4 = Type::Float32x4 }; private: @@ -628,6 +718,8 @@ class VarType case AsmJS_ToInt32: which_ = Int; break; case AsmJS_ToNumber: which_ = Double; break; case AsmJS_FRound: which_ = Float; break; + case AsmJS_ToInt32x4: which_ = Int32x4; break; + case AsmJS_ToFloat32x4: which_ = Float32x4; break; } } static VarType Of(const AsmJSNumLit &lit) { @@ -645,6 +737,12 @@ class VarType case AsmJSNumLit::Float: v.which_ = Float; return v; + case AsmJSNumLit::Int32x4: + v.which_ = Int32x4; + return v; + case AsmJSNumLit::Float32x4: + v.which_ = Float32x4; + return v; case AsmJSNumLit::OutOfRangeInt: MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("can't be out of range int"); } @@ -659,28 +757,37 @@ class VarType } MIRType toMIRType() const { switch(which_) { - case Int: return MIRType_Int32; - case Double: return MIRType_Double; - case Float: return MIRType_Float32; + case Int: return MIRType_Int32; + case Double: return MIRType_Double; + case Float: return MIRType_Float32; + case Int32x4: return MIRType_Int32x4; + case Float32x4: return MIRType_Float32x4; } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, Double or Float"); + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, SIMD, Double or Float"); } AsmJSCoercion toCoercion() const { switch(which_) { - case Int: return AsmJS_ToInt32; - case Double: return AsmJS_ToNumber; - case Float: return AsmJS_FRound; + case Int: return AsmJS_ToInt32; + case Double: return AsmJS_ToNumber; + case Float: return AsmJS_FRound; + case Int32x4: return AsmJS_ToInt32x4; + case Float32x4: return AsmJS_ToFloat32x4; } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, Double or Float"); + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, SIMD, Double or Float"); } static VarType FromCheckedType(Type type) { - JS_ASSERT(type.isInt() || type.isMaybeDouble() || type.isFloatish()); + JS_ASSERT(type.isInt() || type.isMaybeDouble() || type.isFloatish() || type.isSimd()); if (type.isMaybeDouble()) return Double; else if (type.isFloatish()) return Float; - else + else if (type.isInt()) return Int; + else if (type.isInt32x4()) + return Int32x4; + else if (type.isFloat32x4()) + return Float32x4; + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unknown type in FromCheckedType"); } bool operator==(VarType rhs) const { return which_ == rhs.which_; } bool operator!=(VarType rhs) const { return which_ != rhs.which_; } @@ -693,9 +800,11 @@ static inline bool operator<=(Type lhs, VarType rhs) { switch (rhs.which()) { - case VarType::Int: return lhs.isInt(); - case VarType::Double: return lhs.isDouble(); - case VarType::Float: return lhs.isFloat(); + case VarType::Int: return lhs.isInt(); + case VarType::Double: return lhs.isDouble(); + case VarType::Float: return lhs.isFloat(); + case VarType::Int32x4: return lhs.isInt32x4(); + case VarType::Float32x4: return lhs.isFloat32x4(); } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected rhs type"); } @@ -935,7 +1044,9 @@ class MOZ_STACK_CLASS ModuleCompiler FuncPtrTable, FFI, ArrayView, - MathBuiltinFunction + MathBuiltinFunction, + SimdCtor, + SimdOperation }; private: @@ -951,6 +1062,11 @@ class MOZ_STACK_CLASS ModuleCompiler uint32_t ffiIndex_; Scalar::Type viewType_; AsmJSMathBuiltinFunction mathBuiltinFunc_; + AsmJSSimdType simdCtorType_; + struct { + AsmJSSimdType type_; + AsmJSSimdOperation which_; + } simdOp; } u; friend class ModuleCompiler; @@ -1000,6 +1116,24 @@ class MOZ_STACK_CLASS ModuleCompiler JS_ASSERT(which_ == MathBuiltinFunction); return u.mathBuiltinFunc_; } + bool isSimdCtor() const { + return which_ == SimdCtor; + } + AsmJSSimdType simdCtorType() const { + JS_ASSERT(which_ == SimdCtor); + return u.simdCtorType_; + } + bool isSimdOperation() const { + return which_ == SimdOperation; + } + AsmJSSimdOperation simdOperation() const { + JS_ASSERT(which_ == SimdOperation); + return u.simdOp.which_; + } + AsmJSSimdType simdOperationType() const { + JS_ASSERT(which_ == SimdOperation); + return u.simdOp.type_; + } }; typedef Vector FuncPtrVector; @@ -1101,6 +1235,7 @@ class MOZ_STACK_CLASS ModuleCompiler }; typedef HashMap MathNameMap; + typedef HashMap SimdOperationNameMap; typedef HashMap GlobalMap; typedef Vector FuncVector; typedef Vector GlobalAccessVector; @@ -1121,6 +1256,7 @@ class MOZ_STACK_CLASS ModuleCompiler FuncPtrTableVector funcPtrTables_; ExitMap exits_; MathNameMap standardLibraryMathNames_; + SimdOperationNameMap standardLibrarySimdOpNames_; NonAssertingLabel stackOverflowLabel_; NonAssertingLabel asyncInterruptLabel_; NonAssertingLabel syncInterruptLabel_; @@ -1133,6 +1269,7 @@ class MOZ_STACK_CLASS ModuleCompiler SlowFunctionVector slowFunctions_; DebugOnly finishedFunctionBodies_; + bool supportsSimd_; bool addStandardLibraryMathName(const char *name, AsmJSMathBuiltinFunction func) { JSAtom *atom = Atomize(cx_, name, strlen(name)); @@ -1148,6 +1285,12 @@ class MOZ_STACK_CLASS ModuleCompiler MathBuiltin builtin(cst); return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin); } + bool addStandardLibrarySimdOpName(const char *name, AsmJSSimdOperation op) { + JSAtom *atom = Atomize(cx_, name, strlen(name)); + if (!atom) + return false; + return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op); + } public: ModuleCompiler(ExclusiveContext *cx, AsmJSParser &parser) @@ -1162,12 +1305,14 @@ class MOZ_STACK_CLASS ModuleCompiler funcPtrTables_(cx), exits_(cx), standardLibraryMathNames_(cx), + standardLibrarySimdOpNames_(cx), errorString_(nullptr), errorOffset_(UINT32_MAX), errorOverRecursed_(false), usecBefore_(PRMJ_Now()), slowFunctions_(cx), - finishedFunctionBodies_(false) + finishedFunctionBodies_(false), + supportsSimd_(cx->jitSupportsSimd()) { JS_ASSERT(moduleFunctionNode_->pn_funbox == parser.pc->sc->asFunctionBox()); } @@ -1218,6 +1363,15 @@ class MOZ_STACK_CLASS ModuleCompiler return false; } + if (!standardLibrarySimdOpNames_.init() || + !addStandardLibrarySimdOpName("add", AsmJSSimdOperation_add) || + !addStandardLibrarySimdOpName("sub", AsmJSSimdOperation_sub) || + !addStandardLibrarySimdOpName("mul", AsmJSSimdOperation_mul) || + !addStandardLibrarySimdOpName("div", AsmJSSimdOperation_div)) + { + return false; + } + uint32_t srcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin; uint32_t srcBodyStart = tokenStream().currentToken().pos.end; @@ -1299,6 +1453,7 @@ class MOZ_STACK_CLASS ModuleCompiler uint32_t srcStart() const { return module_->srcStart(); } bool usesSignalHandlersForInterrupt() const { return module_->usesSignalHandlersForInterrupt(); } bool usesSignalHandlersForOOB() const { return module_->usesSignalHandlersForOOB(); } + bool supportsSimd() const { return supportsSimd_; } ParseNode *moduleFunctionNode() const { return moduleFunctionNode_; } PropertyName *moduleFunctionName() const { return moduleFunctionName_; } @@ -1335,6 +1490,13 @@ class MOZ_STACK_CLASS ModuleCompiler } return false; } + bool lookupStandardSimdOpName(PropertyName *name, AsmJSSimdOperation *op) const { + if (SimdOperationNameMap::Ptr p = standardLibrarySimdOpNames_.lookup(name)) { + *op = p->value(); + return true; + } + return false; + } ExitMap::Range allExits() const { return exits_.all(); } @@ -1438,6 +1600,27 @@ class MOZ_STACK_CLASS ModuleCompiler global->u.mathBuiltinFunc_ = func; return globals_.putNew(varName, global); } + bool addSimdCtor(PropertyName *varName, AsmJSSimdType type, PropertyName *fieldName) { + if (!module_->addSimdCtor(type, fieldName)) + return false; + Global *global = moduleLifo_.new_(Global::SimdCtor); + if (!global) + return false; + global->u.simdCtorType_ = type; + return globals_.putNew(varName, global); + } + bool addSimdOperation(PropertyName *varName, AsmJSSimdType type, AsmJSSimdOperation op, + PropertyName *typeVarName, PropertyName *opName) + { + if (!module_->addSimdOperation(type, op, opName)) + return false; + Global *global = moduleLifo_.new_(Global::SimdOperation); + if (!global) + return false; + global->u.simdOp.type_ = type; + global->u.simdOp.which_ = op; + return globals_.putNew(varName, global); + } private: bool addGlobalDoubleConstant(PropertyName *varName, double constant) { Global *global = moduleLifo_.new_(Global::ConstantLiteral); @@ -1671,39 +1854,118 @@ IsCallToGlobal(ModuleCompiler &m, ParseNode *pn, const ModuleCompiler::Global ** } static bool -IsFloatCoercion(ModuleCompiler &m, ParseNode *pn, ParseNode **coercedExpr) +IsCoercionCall(ModuleCompiler &m, ParseNode *pn, AsmJSCoercion *coercion, ParseNode **coercedExpr) { const ModuleCompiler::Global *global; if (!IsCallToGlobal(m, pn, &global)) return false; - if (!global->isMathFunction() || global->mathBuiltinFunction() != AsmJSMathBuiltin_fround) - return false; - if (CallArgListLength(pn) != 1) return false; if (coercedExpr) *coercedExpr = CallArgList(pn); + if (global->isMathFunction() && global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) { + *coercion = AsmJS_FRound; + return true; + } + + if (global->isSimdCtor()) { + switch (global->simdCtorType()) { + case AsmJSSimdType_int32x4: + *coercion = AsmJS_ToInt32x4; + return true; + case AsmJSSimdType_float32x4: + *coercion = AsmJS_ToFloat32x4; + return true; + } + } + + return false; +} + +static bool +IsFloatLiteral(ModuleCompiler &m, ParseNode *pn) +{ + ParseNode *coercedExpr; + AsmJSCoercion coercion; + if (!IsCoercionCall(m, pn, &coercion, &coercedExpr) || coercion != AsmJS_FRound) + return false; + return IsNumericNonFloatLiteral(coercedExpr); +} + +static unsigned +SimdTypeToLength(AsmJSSimdType type) +{ + switch (type) { + case AsmJSSimdType_float32x4: + case AsmJSSimdType_int32x4: + return 4; + } + MOZ_CRASH("unexpected SIMD type"); +} + +static bool +IsSimdTuple(ModuleCompiler &m, ParseNode *pn, AsmJSSimdType *type) +{ + const ModuleCompiler::Global *global; + if (!IsCallToGlobal(m, pn, &global)) + return false; + + if (!global->isSimdCtor()) + return false; + + if (CallArgListLength(pn) != SimdTypeToLength(global->simdCtorType())) + return false; + + *type = global->simdCtorType(); return true; } static bool -IsNumericFloatLiteral(ModuleCompiler &m, ParseNode *pn) +IsNumericLiteral(ModuleCompiler &m, ParseNode *pn); +static AsmJSNumLit +ExtractNumericLiteral(ModuleCompiler &m, ParseNode *pn); +static inline bool +IsLiteralInt(ModuleCompiler &m, ParseNode *pn, uint32_t *u32); + +static bool +IsSimdLiteral(ModuleCompiler &m, ParseNode *pn) { - ParseNode *coercedExpr; - if (!IsFloatCoercion(m, pn, &coercedExpr)) + AsmJSSimdType type; + if (!IsSimdTuple(m, pn, &type)) return false; - return IsNumericNonFloatLiteral(coercedExpr); + ParseNode *arg = CallArgList(pn); + unsigned length = SimdTypeToLength(type); + for (unsigned i = 0; i < length; i++) { + if (!IsNumericLiteral(m, arg)) + return false; + + uint32_t _; + switch (type) { + case AsmJSSimdType_int32x4: + if (!IsLiteralInt(m, arg, &_)) + return false; + case AsmJSSimdType_float32x4: + if (!IsNumericNonFloatLiteral(arg)) + return false; + } + + arg = NextNode(arg); + } + + JS_ASSERT(arg == nullptr); + return true; } static bool IsNumericLiteral(ModuleCompiler &m, ParseNode *pn) { return IsNumericNonFloatLiteral(pn) || - IsNumericFloatLiteral(m, pn); + IsFloatLiteral(m, pn) || + IsSimdLiteral(m, pn); } // The JS grammar treats -42 as -(42) (i.e., with separate grammar @@ -1711,16 +1973,53 @@ IsNumericLiteral(ModuleCompiler &m, ParseNode *pn) // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal // so fold the two potential parse nodes into a single double value. static double -ExtractNumericNonFloatValue(ParseNode **pn) +ExtractNumericNonFloatValue(ParseNode *pn, ParseNode **out = nullptr) { - JS_ASSERT(IsNumericNonFloatLiteral(*pn)); + JS_ASSERT(IsNumericNonFloatLiteral(pn)); - if ((*pn)->isKind(PNK_NEG)) { - *pn = UnaryKid(*pn); - return -NumberNodeValue(*pn); + if (pn->isKind(PNK_NEG)) { + pn = UnaryKid(pn); + if (out) + *out = pn; + return -NumberNodeValue(pn); } - return NumberNodeValue(*pn); + return NumberNodeValue(pn); +} + +static AsmJSNumLit +ExtractSimdValue(ModuleCompiler &m, ParseNode *pn) +{ + JS_ASSERT(IsSimdLiteral(m, pn)); + + AsmJSSimdType type; + JS_ALWAYS_TRUE(IsSimdTuple(m, pn, &type)); + + ParseNode *arg = CallArgList(pn); + unsigned length = SimdTypeToLength(type); + switch (type) { + case AsmJSSimdType_int32x4: { + JS_ASSERT(length == 4); + int32_t val[4]; + for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) { + uint32_t u32; + JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); + val[i] = int32_t(u32); + } + JS_ASSERT(arg== nullptr); + return AsmJSNumLit::Create(AsmJSNumLit::Int32x4, SimdConstant::CreateX4(val)); + } + case AsmJSSimdType_float32x4: { + JS_ASSERT(length == 4); + float val[4]; + for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) + val[i] = float(ExtractNumericNonFloatValue(arg)); + JS_ASSERT(arg == nullptr); + return AsmJSNumLit::Create(AsmJSNumLit::Float32x4, SimdConstant::CreateX4(val)); + } + } + + MOZ_CRASH("Unexpected SIMD type."); } static AsmJSNumLit @@ -1728,15 +2027,20 @@ ExtractNumericLiteral(ModuleCompiler &m, ParseNode *pn) { JS_ASSERT(IsNumericLiteral(m, pn)); - // Float literals are explicitly coerced and thus the coerced literal may be - // any valid (non-float) numeric literal. if (pn->isKind(PNK_CALL)) { - pn = CallArgList(pn); - double d = ExtractNumericNonFloatValue(&pn); - return AsmJSNumLit::Create(AsmJSNumLit::Float, DoubleValue(d)); + // Float literals are explicitly coerced and thus the coerced literal may be + // any valid (non-float) numeric literal. + if (CallArgListLength(pn) == 1) { + pn = CallArgList(pn); + double d = ExtractNumericNonFloatValue(pn); + return AsmJSNumLit::Create(AsmJSNumLit::Float, DoubleValue(d)); + } + + JS_ASSERT(CallArgListLength(pn) == 4); + return ExtractSimdValue(m, pn); } - double d = ExtractNumericNonFloatValue(&pn); + double d = ExtractNumericNonFloatValue(pn, &pn); // The asm.js spec syntactically distinguishes any literal containing a // decimal point or the literal -0 as having double type. @@ -1783,6 +2087,8 @@ IsLiteralInt(ModuleCompiler &m, ParseNode *pn, uint32_t *u32) case AsmJSNumLit::Double: case AsmJSNumLit::Float: case AsmJSNumLit::OutOfRangeInt: + case AsmJSNumLit::Int32x4: + case AsmJSNumLit::Float32x4: return false; } @@ -1953,7 +2259,14 @@ class FunctionCompiler unsigned firstLocalSlot = argTypes.length(); for (unsigned i = 0; i < varInitializers_.length(); i++) { AsmJSNumLit &lit = varInitializers_[i]; - MConstant *ins = MConstant::NewAsmJS(alloc(), lit.value(), Type::Of(lit).toMIRType()); + MIRType type = Type::Of(lit).toMIRType(); + + MInstruction *ins; + if (lit.isSimd()) + ins = MSimdConstant::New(alloc(), lit.simdValue(), type); + else + ins = MConstant::NewAsmJS(alloc(), lit.scalarValue(), type); + curBlock_->add(ins); curBlock_->initSlot(info().localSlot(firstLocalSlot + i), ins); if (!mirGen_->ensureBallast()) @@ -2004,13 +2317,23 @@ class FunctionCompiler return m_.lookupGlobal(name); } + bool supportsSimd() const { + return m_.supportsSimd(); + } + /***************************** Code generation (after local scope setup) */ MDefinition *constant(const AsmJSNumLit &lit) { if (inDeadCode()) return nullptr; - MConstant *constant = MConstant::NewAsmJS(alloc(), lit.value(), Type::Of(lit).toMIRType()); + + MInstruction *constant; + if (lit.isSimd()) + constant = MSimdConstant::New(alloc(), lit.simdValue(), Type::Of(lit).toMIRType()); + else + constant = MConstant::NewAsmJS(alloc(), lit.scalarValue(), Type::Of(lit).toMIRType()); + curBlock_->add(constant); return constant; } @@ -2064,6 +2387,19 @@ class FunctionCompiler return ins; } + MDefinition *binarySimd(MDefinition *lhs, MDefinition *rhs, MSimdBinaryArith::Operation op, + MIRType type) + { + if (inDeadCode()) + return nullptr; + + JS_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); + JS_ASSERT(lhs->type() == type); + MSimdBinaryArith *ins = MSimdBinaryArith::NewAsmJS(alloc(), lhs, rhs, op, type); + curBlock_->add(ins); + return ins; + } + MDefinition *minMax(MDefinition *lhs, MDefinition *rhs, MIRType type, bool isMax) { if (inDeadCode()) return nullptr; @@ -2161,9 +2497,14 @@ class FunctionCompiler if (inDeadCode()) return nullptr; - uint32_t index = global.varOrConstIndex(); - unsigned globalDataOffset = module().globalVarIndexToGlobalDataOffset(index); MIRType type = global.varOrConstType().toMIRType(); + + unsigned globalDataOffset; + if (IsSimdType(type)) + globalDataOffset = module().globalSimdVarIndexToGlobalDataOffset(global.varOrConstIndex()); + else + globalDataOffset = module().globalScalarVarIndexToGlobalDataOffset(global.varOrConstIndex()); + MAsmJSLoadGlobalVar *load = MAsmJSLoadGlobalVar::New(alloc(), type, globalDataOffset, global.isConst()); curBlock_->add(load); @@ -2175,7 +2516,13 @@ class FunctionCompiler if (inDeadCode()) return; JS_ASSERT(!global.isConst()); - unsigned globalDataOffset = module().globalVarIndexToGlobalDataOffset(global.varOrConstIndex()); + + unsigned globalDataOffset; + if (IsSimdType(v->type())) + globalDataOffset = module().globalSimdVarIndexToGlobalDataOffset(global.varOrConstIndex()); + else + globalDataOffset = module().globalScalarVarIndexToGlobalDataOffset(global.varOrConstIndex()); + curBlock_->add(MAsmJSStoreGlobalVar::New(alloc(), globalDataOffset, v)); } @@ -2193,6 +2540,31 @@ class FunctionCompiler curBlock_->add(MAsmJSInterruptCheck::New(alloc(), &m().syncInterruptLabel(), callDesc)); } + MDefinition *extractSimdElement(SimdLane lane, MDefinition *base, MIRType type) + { + if (inDeadCode()) + return nullptr; + + JS_ASSERT(IsSimdType(base->type())); + JS_ASSERT(!IsSimdType(type)); + MSimdExtractElement *ins = MSimdExtractElement::NewAsmJS(alloc(), base, type, lane); + curBlock_->add(ins); + return ins; + } + + template + MDefinition *constructSimd(MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w, + MIRType type) + { + if (inDeadCode()) + return nullptr; + + JS_ASSERT(IsSimdType(type)); + T *ins = T::New(alloc(), type, x, y, z, w); + curBlock_->add(ins); + return ins; + } + /***************************************************************** Calls */ // The IonMonkey backend maintains a single stack offset (from the stack @@ -2963,15 +3335,13 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c return true; } case PNK_CALL: { - *coercion = AsmJS_FRound; - if (!IsFloatCoercion(m, coercionNode, coercedExpr)) - return m.fail(coercionNode, "call must be to fround coercion"); - return true; + if (IsCoercionCall(m, coercionNode, coercion, coercedExpr)) + return true; } default:; } - return m.fail(coercionNode, "must be of the form +x, fround(x) or x|0"); + return m.fail(coercionNode, "must be of the form +x, fround(x), simdType(x) or x|0"); } static bool @@ -3054,6 +3424,82 @@ CheckNewArrayView(ModuleCompiler &m, PropertyName *varName, ParseNode *newExpr) return m.addArrayView(varName, type, field); } +static bool +IsSimdTypeName(ModuleCompiler &m, PropertyName *name, AsmJSSimdType *type) +{ + if (name == m.cx()->names().int32x4) { + *type = AsmJSSimdType_int32x4; + return true; + } + if (name == m.cx()->names().float32x4) { + *type = AsmJSSimdType_float32x4; + return true; + } + return false; +} + +static bool +IsSimdValidOperationType(AsmJSSimdType type, AsmJSSimdOperation op) +{ + switch (op) { + case AsmJSSimdOperation_add: + case AsmJSSimdOperation_sub: + return true; + case AsmJSSimdOperation_mul: + case AsmJSSimdOperation_div: + return type == AsmJSSimdType_float32x4; + } + return false; +} + +static bool +CheckGlobalMathImport(ModuleCompiler &m, ParseNode *initNode, PropertyName *varName, + PropertyName *field) +{ + // Math builtin, with the form glob.Math.[[builtin]] + ModuleCompiler::MathBuiltin mathBuiltin; + if (!m.lookupStandardLibraryMathName(field, &mathBuiltin)) + return m.failName(initNode, "'%s' is not a standard Math builtin", field); + + switch (mathBuiltin.kind) { + case ModuleCompiler::MathBuiltin::Function: + return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field); + case ModuleCompiler::MathBuiltin::Constant: + return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field); + default: + break; + } + MOZ_CRASH("unexpected or uninitialized math builtin type"); +} + +static bool +CheckGlobalSimdImport(ModuleCompiler &m, ParseNode *initNode, PropertyName *varName, + PropertyName *field) +{ + if (!m.supportsSimd()) + return m.fail(initNode, "SIMD is not supported on this platform"); + + // SIMD constructor, with the form glob.SIMD.[[type]] + AsmJSSimdType simdType; + if (!IsSimdTypeName(m, field, &simdType)) + return m.failName(initNode, "'%s' is not a standard SIMD type", field); + return m.addSimdCtor(varName, simdType, field); +} + +static bool +CheckGlobalSimdOperationImport(ModuleCompiler &m, const ModuleCompiler::Global *global, + ParseNode *initNode, PropertyName *varName, PropertyName *ctorVarName, + PropertyName *opName) +{ + AsmJSSimdType simdType = global->simdCtorType(); + AsmJSSimdOperation simdOp; + if (!m.lookupStandardSimdOpName(opName, &simdOp)) + return m.failName(initNode, "'%s' is not a standard SIMD operation", opName); + if (!IsSimdValidOperationType(simdType, simdOp)) + return m.failName(initNode, "'%s' is not an operation supported by the SIMD type", opName); + return m.addSimdOperation(varName, simdType, simdOp, ctorVarName, opName); +} + static bool CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode) { @@ -3062,26 +3508,22 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo if (base->isKind(PNK_DOT)) { ParseNode *global = DotBase(base); - PropertyName *math = DotMember(base); - if (!IsUseOfName(global, m.module().globalArgumentName()) || math != m.cx()->names().Math) - return m.fail(base, "expecting global.Math"); + PropertyName *mathOrSimd = DotMember(base); - ModuleCompiler::MathBuiltin mathBuiltin; - if (!m.lookupStandardLibraryMathName(field, &mathBuiltin)) - return m.failName(initNode, "'%s' is not a standard Math builtin", field); + if (!IsUseOfName(global, m.module().globalArgumentName())) + return m.failf(base, "expecting %s.*", m.module().globalArgumentName()); - switch (mathBuiltin.kind) { - case ModuleCompiler::MathBuiltin::Function: - return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field); - case ModuleCompiler::MathBuiltin::Constant: - return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field); - default: - break; - } - MOZ_CRASH("unexpected or uninitialized math builtin type"); + if (mathOrSimd == m.cx()->names().Math) + return CheckGlobalMathImport(m, initNode, varName, field); + if (mathOrSimd == m.cx()->names().SIMD) + return CheckGlobalSimdImport(m, initNode, varName, field); + return m.failf(base, "expecting %s.{Math|SIMD}", m.module().globalArgumentName()); } - if (IsUseOfName(base, m.module().globalArgumentName())) { + if (!base->isKind(PNK_NAME)) + return m.fail(base, "expected name of variable or parameter"); + + if (base->name() == m.module().globalArgumentName()) { if (field == m.cx()->names().NaN) return m.addGlobalConstant(varName, GenericNaN(), field); if (field == m.cx()->names().Infinity) @@ -3089,10 +3531,17 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo return m.failName(initNode, "'%s' is not a standard global constant", field); } - if (IsUseOfName(base, m.module().importArgumentName())) + if (base->name() == m.module().importArgumentName()) return m.addFFI(varName, field); - return m.fail(initNode, "expecting c.y where c is either the global or foreign parameter"); + const ModuleCompiler::Global *global = m.lookupGlobal(base->name()); + if (!global) + return m.failName(initNode, "%s not found in module global scope", base->name()); + + if (!global->isSimdCtor()) + return m.failName(base, "expecting SIMD constructor name, got %s", field); + + return CheckGlobalSimdOperationImport(m, global, initNode, varName, base->name(), field); } static bool @@ -3224,6 +3673,12 @@ CheckFinalReturn(FunctionCompiler &f, ParseNode *stmt, RetType *retType) case AsmJSNumLit::Float: *retType = RetType::Float; break; + case AsmJSNumLit::Int32x4: + *retType = RetType::Int32x4; + break; + case AsmJSNumLit::Float32x4: + *retType = RetType::Float32x4; + break; } return true; } @@ -3339,6 +3794,8 @@ CheckVarRef(FunctionCompiler &f, ParseNode *varRef, MDefinition **def, Type *typ case ModuleCompiler::Global::MathBuiltinFunction: case ModuleCompiler::Global::FuncPtrTable: case ModuleCompiler::Global::ArrayView: + case ModuleCompiler::Global::SimdCtor: + case ModuleCompiler::Global::SimdOperation: return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name); } return true; @@ -3361,7 +3818,7 @@ IsLiteralOrConstInt(FunctionCompiler &f, ParseNode *pn, uint32_t *u32) if (!global || global->which() != ModuleCompiler::Global::ConstantLiteral) return false; - const Value &v = global->constLiteralValue().value(); + const Value &v = global->constLiteralValue().scalarValue(); if (!v.isInt32()) return false; @@ -3497,6 +3954,40 @@ CheckLoadArray(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *ty return true; } +static bool +CheckDotAccess(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type) +{ + JS_ASSERT(elem->isKind(PNK_DOT)); + + ParseNode *base = DotBase(elem); + MDefinition *baseDef; + Type baseType; + if (!CheckExpr(f, base, &baseDef, &baseType)) + return false; + if (!baseType.isSimd()) + return f.failf(base, "expected SIMD type, got %s", baseType.toChars()); + + ModuleCompiler &m = f.m(); + PropertyName *field = DotMember(elem); + + SimdLane lane; + JSAtomState &names = m.cx()->names(); + if (field == names.x) + lane = LaneX; + else if (field == names.y) + lane = LaneY; + else if (field == names.z) + lane = LaneZ; + else if (field == names.w) + lane = LaneW; + else + return f.fail(base, "dot access field must be a lane name (x, y, z, w)"); + + *type = baseType.simdToScalarType(); + *def = f.extractSimdElement(lane, baseDef, type->toMIRType()); + return true; +} + static bool CheckStoreArray(FunctionCompiler &f, ParseNode *lhs, ParseNode *rhs, MDefinition **def, Type *type) { @@ -3914,6 +4405,8 @@ CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetTyp if (retType == RetType::Float) return f.fail(callNode, "FFI calls can't return float"); + if (retType.toType().isSimd()) + return f.fail(callNode, "FFI calls can't return SIMD values"); FunctionCompiler::Call call(f, callNode, retType); if (!CheckCallArgs(f, callNode, CheckIsExternType, &call)) @@ -3930,37 +4423,82 @@ CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetTyp return true; } +static bool +CheckFloatCoercionArg(FunctionCompiler &f, ParseNode *inputNode, Type inputType, + MDefinition *inputDef, MDefinition **def) +{ + if (inputType.isMaybeDouble() || inputType.isSigned()) { + *def = f.unary(inputDef); + return true; + } + if (inputType.isUnsigned()) { + *def = f.unary(inputDef); + return true; + } + if (inputType.isFloatish()) { + *def = inputDef; + return true; + } + + return f.failf(inputNode, "%s is not a subtype of signed, unsigned, double? or floatish", + inputType.toChars()); +} + static bool CheckCoercedCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type); +static bool +CheckCoercionArg(FunctionCompiler &f, ParseNode *arg, AsmJSCoercion expected, MDefinition **def, + Type *type) +{ + RetType retType(expected); + if (arg->isKind(PNK_CALL)) + return CheckCoercedCall(f, arg, retType, def, type); + + MDefinition *argDef; + Type argType; + if (!CheckExpr(f, arg, &argDef, &argType)) + return false; + + switch (expected) { + case AsmJS_FRound: + if (!CheckFloatCoercionArg(f, arg, argType, argDef, def)) + return false; + break; + case AsmJS_ToInt32x4: + if (!argType.isInt32x4()) + return f.fail(arg, "argument to SIMD int32x4 coercion isn't int32x4"); + *def = argDef; + break; + case AsmJS_ToFloat32x4: + if (!argType.isFloat32x4()) + return f.fail(arg, "argument to SIMD float32x4 coercion isn't float32x4"); + *def = argDef; + break; + case AsmJS_ToInt32: + case AsmJS_ToNumber: + MOZ_CRASH("not call coercions"); + } + + *type = retType.toType(); + return true; +} + static bool CheckMathFRound(FunctionCompiler &f, ParseNode *callNode, MDefinition **def, MathRetType *type) { - ParseNode *argNode = nullptr; - if (!IsFloatCoercion(f.m(), callNode, &argNode)) - return f.fail(callNode, "invalid call to fround"); - - // Make sure to do this before calling CheckCoercedCall - *type = MathRetType::Float; - - Type _; - if (argNode->isKind(PNK_CALL)) - return CheckCoercedCall(f, argNode, RetType::Float, def, &_); + if (CallArgListLength(callNode) != 1) + return f.fail(callNode, "Math.fround must be passed 1 argument"); + ParseNode *argNode = CallArgList(callNode); MDefinition *argDef; Type argType; - if (!CheckExpr(f, argNode, &argDef, &argType)) + if (!CheckCoercionArg(f, argNode, AsmJS_FRound, &argDef, &argType)) return false; - if (argType.isMaybeDouble() || argType.isSigned()) - *def = f.unary(argDef); - else if (argType.isUnsigned()) - *def = f.unary(argDef); - else if (argType.isFloatish()) - *def = argDef; - else - return f.failf(argNode, "%s is not a subtype of signed, unsigned, double? or floatish", argType.toChars()); - + JS_ASSERT(argType == Type::Float); + *def = argDef; + *type = MathRetType::Float; return true; } @@ -4042,19 +4580,120 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltinF return true; } +static bool +CheckBinarySimd(FunctionCompiler &f, ParseNode *call, AsmJSSimdType simdType, + MSimdBinaryArith::Operation op, MDefinition **def, Type *type) +{ + unsigned numArgs = CallArgListLength(call); + if (numArgs != 2) + return f.failf(call, "expected 2 arguments to binary arithmetic SIMD operation, got %u", numArgs); + + ParseNode *lhs = CallArgList(call); + ParseNode *rhs = NextNode(lhs); + + MDefinition *lhsDef, *rhsDef; + Type lhsType, rhsType; + if (!CheckExpr(f, lhs, &lhsDef, &lhsType)) + return false; + if (!CheckExpr(f, rhs, &rhsDef, &rhsType)) + return false; + + Type retType = simdType; + JS_ASSERT_IF(retType.isInt32x4(), op != MSimdBinaryArith::Mul && op != MSimdBinaryArith::Div); + if (lhsType != retType || rhsType != retType) + return f.failf(lhs, "arguments to SIMD binary op should both be %s", retType.toChars()); + + *type = retType; + *def = f.binarySimd(lhsDef, rhsDef, op, retType.toMIRType()); + return true; +} + +static bool +CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, + MDefinition **def, Type *type) +{ + JS_ASSERT(global->isSimdOperation()); + switch (global->simdOperation()) { + case AsmJSSimdOperation_add: + return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Add, def, type); + case AsmJSSimdOperation_sub: + return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Sub, def, type); + case AsmJSSimdOperation_mul: + return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Mul, def, type); + case AsmJSSimdOperation_div: + return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Div, def, type); + } + MOZ_CRASH("unexpected simd operation in CheckSimdOperationCall"); +} + +static bool +CheckSimdCtorCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, + MDefinition **def, Type *type) +{ + JS_ASSERT(call->isKind(PNK_CALL)); + + AsmJSCoercion coercion; + ParseNode *argNode; + if (IsCoercionCall(f.m(), call, &coercion, &argNode)) + return CheckCoercionArg(f, argNode, coercion, def, type); + + AsmJSSimdType simdType = global->simdCtorType(); + unsigned numArgs = CallArgListLength(call); + unsigned length = SimdTypeToLength(simdType); + if (numArgs != length) + return f.failName(call, "invalid number of arguments in call to '%s'", CallCallee(call)->name()); + + Vector defs; + if (!defs.resize(length)) + return false; + + argNode = CallArgList(call); + size_t i = 0; + for (; argNode; argNode = NextNode(argNode), ++i) + { + JS_ASSERT(i < length); + + Type argType; + if (!CheckExpr(f, argNode, &defs[i], &argType)) + return false; + + switch (simdType) { + case AsmJSSimdType_int32x4: + if (!argType.isIntish()) + return f.failf(argNode, "argument %d of Int32x4 ctor isn't a subtype of intish", i); + break; + case AsmJSSimdType_float32x4: + if (!CheckFloatCoercionArg(f, argNode, argType, defs[i], &defs[i])) + return false; + break; + } + } + JS_ASSERT(i == length); + + *type = simdType; + *def = f.constructSimd(defs[0], defs[1], defs[2], defs[3], type->toMIRType()); + return true; +} + static bool CheckUncoercedCall(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) { JS_ASSERT(expr->isKind(PNK_CALL)); const ModuleCompiler::Global *global; - if (IsCallToGlobal(f.m(), expr, &global) && global->isMathFunction()) - { - MathRetType mathRetType; - if (!CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), def, &mathRetType)) - return false; - *type = mathRetType.toType(); - return true; + if (IsCallToGlobal(f.m(), expr, &global)) { + if (global->isMathFunction()) { + MathRetType mathRetType; + if (!CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), def, &mathRetType)) + return false; + *type = mathRetType.toType(); + return true; + } + + if (global->isSimdCtor()) + return CheckSimdCtorCall(f, expr, global, def, type); + if (global->isSimdOperation()) + return CheckSimdOperationCall(f, expr, global, def, type); } return f.fail(expr, "all function calls must either be calls to standard lib math functions, " @@ -4072,6 +4711,10 @@ CheckCoercedMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathB return false; switch (retType.which()) { + case RetType::Int32x4: + case RetType::Float32x4: + return f.failf(callNode, "%s is not a vector type", actualRetType.toType().toChars()); + case RetType::Double: switch (actualRetType.which()) { case MathRetType::Double: @@ -4132,6 +4775,46 @@ CheckCoercedMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathB return true; } +static bool +CheckCoercedSimdCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, + RetType retType, MDefinition **def, Type *type) +{ + if (global->isSimdCtor()) { + if (!CheckSimdCtorCall(f, call, global, def, type)) + return false; + } else { + JS_ASSERT(global->isSimdOperation()); + if (!CheckSimdOperationCall(f, call, global, def, type)) + return false; + } + + JS_ASSERT(type->isSimd()); + switch (retType.which()) { + case RetType::Signed: + case RetType::Double: + case RetType::Float: + return f.failf(call, "SIMD call returns %s, used as scalar", type->toChars()); + + case RetType::Int32x4: + if (!type->isInt32x4()) + return f.failf(call, "SIMD call returns %s, used as int32x4", type->toChars()); + break; + + case RetType::Float32x4: + if (!type->isFloat32x4()) + return f.failf(call, "SIMD call returns %s, used as float32x4", type->toChars()); + break; + + case RetType::Void: + *def = nullptr; + break; + } + + JS_ASSERT_IF(retType == RetType::Void || f.inDeadCode(), !*def); + JS_ASSERT_IF(retType != RetType::Void && !f.inDeadCode(), !!*def); + return true; +} + static bool CheckCoercedCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type) { @@ -4159,6 +4842,9 @@ CheckCoercedCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinit case ModuleCompiler::Global::FuncPtrTable: case ModuleCompiler::Global::ArrayView: return f.failName(callee, "'%s' is not callable function", callee->name()); + case ModuleCompiler::Global::SimdCtor: + case ModuleCompiler::Global::SimdOperation: + return CheckCoercedSimdCall(f, call, global, retType, def, type); case ModuleCompiler::Global::Function: break; } @@ -4391,6 +5077,8 @@ IsValidIntMultiplyConstant(ModuleCompiler &m, ParseNode *expr) case AsmJSNumLit::Double: case AsmJSNumLit::Float: case AsmJSNumLit::OutOfRangeInt: + case AsmJSNumLit::Int32x4: + case AsmJSNumLit::Float32x4: return false; } @@ -4677,6 +5365,7 @@ CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) switch (expr->getKind()) { case PNK_NAME: return CheckVarRef(f, expr, def, type); case PNK_ELEM: return CheckLoadArray(f, expr, def, type); + case PNK_DOT: return CheckDotAccess(f, expr, def, type); case PNK_ASSIGN: return CheckAssign(f, expr, def, type); case PNK_POS: return CheckPos(f, expr, def, type); case PNK_NOT: return CheckNot(f, expr, def, type); @@ -5086,6 +5775,8 @@ CheckCaseExpr(FunctionCompiler &f, ParseNode *caseExpr, int32_t *value) return f.fail(caseExpr, "switch case expression out of integer range"); case AsmJSNumLit::Double: case AsmJSNumLit::Float: + case AsmJSNumLit::Int32x4: + case AsmJSNumLit::Float32x4: return f.fail(caseExpr, "switch case expression must be an integer literal"); } @@ -5244,6 +5935,10 @@ CheckReturn(FunctionCompiler &f, ParseNode *returnStmt) retType = RetType::Double; else if (type.isFloat()) retType = RetType::Float; + else if (type.isInt32x4()) + retType = RetType::Int32x4; + else if (type.isFloat32x4()) + retType = RetType::Float32x4; else if (type.isVoid()) retType = RetType::Void; else @@ -5955,6 +6650,8 @@ static const RegisterSet NonVolatileRegs = RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask), FloatRegisterSet(FloatRegisters::NonVolatileMask)); #endif +static const FloatRegisterSet NonVolatileSimdRegs = SupportsSimd ? NonVolatileRegs.fpus() + : FloatRegisterSet(); #if defined(JS_CODEGEN_MIPS) // Mips is using one more double slot due to stack alignment for double values. @@ -5963,8 +6660,11 @@ static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * siz NonVolatileRegs.fpus().getPushSizeInBytes() + sizeof(double); #else -static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) + - NonVolatileRegs.fpus().getPushSizeInBytes(); +static const unsigned FramePushedAfterSave = + SupportsSimd ? NonVolatileRegs.gprs().size() * sizeof(intptr_t) + + NonVolatileRegs.fpus().size() * Simd128DataSize + : NonVolatileRegs.gprs().size() * sizeof(intptr_t) + + NonVolatileRegs.fpus().getPushSizeInBytes(); #endif static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void*); @@ -5989,7 +6689,7 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) // Save all caller non-volatile registers before we clobber them here and in // the asm.js callee (which does not preserve non-volatile registers). masm.setFramePushed(0); - masm.PushRegsInMask(NonVolatileRegs); + masm.PushRegsInMask(NonVolatileRegs, NonVolatileSimdRegs); JS_ASSERT(masm.framePushed() == FramePushedAfterSave); // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative @@ -6040,31 +6740,58 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) // Copy parameters out of argv and into the registers/stack-slots specified by // the system ABI. for (ABIArgTypeIter iter(func.sig().args()); !iter.done(); iter++) { - unsigned argOffset = iter.index() * sizeof(uint64_t); + unsigned argOffset = iter.index() * sizeof(AsmJSModule::EntryArg); Address src(argv, argOffset); + MIRType type = iter.mirType(); switch (iter->kind()) { case ABIArg::GPR: masm.load32(src, iter->gpr()); break; case ABIArg::FPU: - if (iter.mirType() == MIRType_Double) { + switch (type) { + case MIRType_Int32x4: + masm.loadUnalignedInt32x4(src, iter->fpu()); + break; + case MIRType_Float32x4: + masm.loadUnalignedFloat32x4(src, iter->fpu()); + break; + case MIRType_Double: masm.loadDouble(src, iter->fpu()); - } else { - JS_ASSERT(iter.mirType() == MIRType_Float32); + break; + case MIRType_Float32: masm.loadFloat32(src, iter->fpu()); + break; + default: + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected FPU type"); + break; } break; case ABIArg::Stack: - if (iter.mirType() == MIRType_Int32) { + switch (type) { + case MIRType_Int32: masm.load32(src, scratch); masm.storePtr(scratch, Address(StackPointer, iter->offsetFromArgBase())); - } else if (iter.mirType() == MIRType_Double) { + break; + case MIRType_Double: masm.loadDouble(src, ScratchDoubleReg); masm.storeDouble(ScratchDoubleReg, Address(StackPointer, iter->offsetFromArgBase())); - } else { - JS_ASSERT(iter.mirType() == MIRType_Float32); + break; + case MIRType_Float32: masm.loadFloat32(src, ScratchFloat32Reg); masm.storeFloat32(ScratchFloat32Reg, Address(StackPointer, iter->offsetFromArgBase())); + break; + case MIRType_Int32x4: + masm.loadUnalignedInt32x4(src, ScratchSimdReg); + masm.storeAlignedInt32x4(ScratchSimdReg, + Address(StackPointer, iter->offsetFromArgBase())); + break; + case MIRType_Float32x4: + masm.loadUnalignedFloat32x4(src, ScratchSimdReg); + masm.storeAlignedFloat32x4(ScratchSimdReg, + Address(StackPointer, iter->offsetFromArgBase())); + break; + default: + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected stack arg type"); } break; } @@ -6096,10 +6823,18 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) masm.canonicalizeDouble(ReturnDoubleReg); masm.storeDouble(ReturnDoubleReg, Address(argv, 0)); break; + case RetType::Int32x4: + // We don't have control on argv alignment, do an unaligned access. + masm.storeUnalignedInt32x4(ReturnSimdReg, Address(argv, 0)); + break; + case RetType::Float32x4: + // We don't have control on argv alignment, do an unaligned access. + masm.storeUnalignedFloat32x4(ReturnSimdReg, Address(argv, 0)); + break; } // Restore clobbered non-volatile registers of the caller. - masm.PopRegsInMask(NonVolatileRegs); + masm.PopRegsInMask(NonVolatileRegs, NonVolatileSimdRegs); JS_ASSERT(masm.framePushed() == 0); masm.move32(Imm32(true), ReturnReg); @@ -6224,6 +6959,9 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e break; case RetType::Float: MOZ_CRASH("Float32 shouldn't be returned from a FFI"); + case RetType::Int32x4: + case RetType::Float32x4: + MOZ_CRASH("SIMD types shouldn't be returned from a FFI"); } Label profilingReturn; @@ -6435,6 +7173,9 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit break; case RetType::Float: MOZ_CRASH("Float shouldn't be returned from a FFI"); + case RetType::Int32x4: + case RetType::Float32x4: + MOZ_CRASH("SIMD types shouldn't be returned from a FFI"); } Label done; @@ -6626,7 +7367,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.push(Imm32(0)); // space for resumePC masm.pushFlags(); // after this we are safe to use sub masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below - masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP) + masm.PushRegsInMask(AllRegsExceptSP, AllRegsExceptSP.fpus()); // save all GP/FP registers (except SP) Register scratch = ABIArgGenerator::NonArgReturnReg0; @@ -6651,7 +7392,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.mov(ABIArgGenerator::NonVolatileReg, StackPointer); // Restore the machine state to before the interrupt. - masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP) + masm.PopRegsInMask(AllRegsExceptSP, AllRegsExceptSP.fpus()); // restore all GP/FP registers (except SP) masm.popFlags(); // after this, nothing that sets conditions masm.ret(); // pop resumePC into PC #elif defined(JS_CODEGEN_MIPS) @@ -6659,6 +7400,9 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.subPtr(Imm32(sizeof(intptr_t)), StackPointer); // set to zero so we can use masm.framePushed() below. masm.setFramePushed(0); + // When this platform supports SIMD extensions, we'll need to push high lanes + // of SIMD registers as well. + JS_STATIC_ASSERT(!SupportsSimd); // save all registers,except sp. After this stack is alligned. masm.PushRegsInMask(AllRegsExceptSP); @@ -6710,6 +7454,9 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1); masm.storePtr(IntArgReg1, Address(r6, 14 * sizeof(uint32_t*))); + // When this platform supports SIMD extensions, we'll need to push and pop + // high lanes of SIMD registers as well. + JS_STATIC_ASSERT(!SupportsSimd); masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllDoubleMask))); // save all FP registers masm.assertStackAlignment(ABIStackAlignment); @@ -6791,7 +7538,7 @@ GenerateThrowStub(ModuleCompiler &m, Label *throwLabel) masm.setFramePushed(FramePushedForEntrySP); masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfEntrySP()), StackPointer); masm.Pop(scratch); - masm.PopRegsInMask(NonVolatileRegs); + masm.PopRegsInMask(NonVolatileRegs, NonVolatileSimdRegs); JS_ASSERT(masm.framePushed() == 0); masm.mov(ImmWord(0), ReturnReg); diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 438f23031511..dabbf39c2831 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -39,8 +39,8 @@ extern const JSFunctionSpec Int32x4Methods[]; static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"}; template -static bool -IsVectorObject(HandleValue v) +bool +js::IsVectorObject(HandleValue v) { if (!v.isObject()) return false; @@ -56,6 +56,24 @@ IsVectorObject(HandleValue v) return typeRepr.as().type() == V::type; } +template +bool +js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out) +{ + typedef typename V::Elem Elem; + if (!IsVectorObject(v)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR); + return false; + } + + Elem *mem = reinterpret_cast(v.toObject().as().typedMem()); + *out = jit::SimdConstant::CreateX4(mem); + return true; +} + +template bool js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out); +template bool js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out); + template static Elem TypedObjectMemory(HandleValue v) diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h index b3c84f08477a..ea7d83244471 100644 --- a/js/src/builtin/SIMD.h +++ b/js/src/builtin/SIMD.h @@ -166,6 +166,12 @@ struct Int32x4 { template JSObject *CreateSimd(JSContext *cx, typename V::Elem *data); +template +bool IsVectorObject(HandleValue v); + +template +bool ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out); + #define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags) \ extern bool \ simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/jit-test/lib/asm.js b/js/src/jit-test/lib/asm.js index fe7ec5a171c0..c38420317660 100644 --- a/js/src/jit-test/lib/asm.js +++ b/js/src/jit-test/lib/asm.js @@ -108,8 +108,8 @@ function assertAsmLinkFail(f) assertEq(isAsmJSFunction(ret), false); if (typeof ret === 'object') - for (f of ret) - assertEq(isAsmJSFunction(f), false); + for (var i in ret) + assertEq(isAsmJSFunction(ret[i]), false); // Turn on warnings-as-errors var oldOpts = options("werror"); diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js new file mode 100644 index 000000000000..ce9bac08d2b9 --- /dev/null +++ b/js/src/jit-test/tests/asm.js/testSIMD.js @@ -0,0 +1,657 @@ +load(libdir + "asm.js"); +var heap = new ArrayBuffer(4096); + +// Set to true to see more JS debugging spew +const DEBUG = false; + +if (!isSimdAvailable() || typeof SIMD === 'undefined') { + DEBUG && print("won't run tests as simd extensions aren't activated yet"); + quit(0); +} + +const I32 = 'var i4 = glob.SIMD.int32x4;' +const I32A = 'var i4a = i4.add;' +const I32S = 'var i4s = i4.sub;' +const F32 = 'var f4 = glob.SIMD.float32x4;' +const F32A = 'var f4a = f4.add;' +const F32S = 'var f4s = f4.sub;' +const F32M = 'var f4m = f4.mul;' +const F32D = 'var f4d = f4.div;' +const FROUND = 'var f32=glob.Math.fround;' + +const INT32_MAX = Math.pow(2, 31) - 1; +const INT32_MIN = INT32_MAX + 1 | 0; + +const assertEqFFI = {assertEq:assertEq}; + +function assertEqX4(real, expected) { + assertEq(real.x, expected[0]); + assertEq(real.y, expected[1]); + assertEq(real.z, expected[2]); + assertEq(real.w, expected[3]); +} + +function CheckI4(header, code, expected) { + // code needs to contain a local called x + header = USE_ASM + I32 + header; + var lanes = ['x', 'y', 'z', 'w']; + for (var i = 0; i < 4; ++i) { + var lane = lanes[i]; + assertEq(asmLink(asmCompile('glob', header + ';function f() {' + code + ';return x.' + lane + '|0} return f'), this)(), expected[i]); + } +} + +function CheckF4(header, code, expected) { + // code needs to contain a local called x + var lanes = ['x', 'y', 'z', 'w']; + header = USE_ASM + F32 + header; + for (var i = 0; i < 4; ++i) { + var lane = lanes[i]; + assertEq(asmLink(asmCompile('glob', header + ';function f() {' + code + ';return +x.' + lane + '} return f'), this)(), Math.fround(expected[i])); + } +} + +try { + +// 1. Constructors + +// 1.1 Compilation +assertAsmTypeFail('glob', USE_ASM + "var i4 = int32x4 ; return {}") ; +assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.int32x4 ; return {}") ; +assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.globglob.int32x4 ; return {}") ; +assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Math.int32x4 ; return {}") ; +assertAsmTypeFail('glob', USE_ASM + "var herd = glob.SIMD.ponyX4 ; return {}") ; + +// 1.2 Linking +assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: 42}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: Math.fround}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: 42}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: Math.fround}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: new Array}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: SIMD.float32x4}}); + +[Type, int32] = [TypedObject.StructType, TypedObject.int32]; +var MyStruct = new Type({'x': int32, 'y': int32, 'z': int32, 'w': int32}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: MyStruct}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: new MyStruct}}); + +assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {} return f"), {SIMD:{int32x4: SIMD.int32x4}})(), undefined); + +assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: 42}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: Math.fround}}); +assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: new Array}}); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {} return f"), {SIMD:{float32x4: SIMD.float32x4}})(), undefined); + +// 1.3 Correctness +// 1.3.1 Local variables declarations +assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Int32x4(1,2,3,4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4();} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2, 3);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2, 3, 4.0);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2.0, 3, 4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4a(1,2,3,4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,2+2|0);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3," + (INT32_MIN - 1) + ");} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(i4(1,2,3,4));} return f"); +assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4);} return f"), this)(), undefined); +assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3," + (INT32_MAX + 1) + ");} return f"), this)(), undefined); + +assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4();} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3);} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,3.);} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,f32(3.),4.);} return f"); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,3.,4.);} return f"), this)(), undefined); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4);} return f"), this)(), undefined); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3," + (INT32_MIN - 1) + ");} return f"), this)(), undefined); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3," + (INT32_MAX + 1) + ");} return f"), this)(), undefined); + +// Places where NumLit can creep in +assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {i=i|0; var z=0; switch(i|0) {case i4(1,2,3,4): z=1; break; default: z=2; break;}} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {i=i|0; var z=0; return i * i4(1,2,3,4) | 0;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {var x=i4(1,2,3,i4(4,5,6,7))} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=i4(1,2,3,f4(4,5,6,7))} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=f4(1,2,3,i4(4,5,6,7))} return f"); + +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(i4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(f4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]); + +// Int32x4 ctor should accept int? +assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return i4(i4(i32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [0, 2, 3, 4]); +// Float32x4 ctor should accept floatish, i.e. float || float? || floatish +assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Float32Array(heap); function f(i) {i=i|0; return f4(f4(f32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [NaN, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "var f32=glob.Math.fround; function f(i) {i=i|0; return f4(f4(f32(1) + f32(2), 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]); + +// 1.3.2 Reading values out of lanes +assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1; return x.y | 0;} return f"); +assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1; return (x + x).y | 0;} return f"); +assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1.; return x.y | 0;} return f"); +assertAsmTypeFail('glob', USE_ASM + "var f32=glob.Math.fround;" + I32 + "function f() {var x=f32(1); return x.y | 0;} return f"); + +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return x.length|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4).y; return x|0;} return f"); + +CheckI4('', 'var x=i4(0,0,0,0)', [0,0,0,0]); +CheckI4('', 'var x=i4(1,2,3,4)', [1,2,3,4]); +CheckI4('', 'var x=i4(' + INT32_MIN + ',2,3,' + INT32_MAX + ')', [INT32_MIN,2,3,INT32_MAX]); +CheckI4('', 'var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); +CheckI4('', 'var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); +CheckI4('', 'var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]); + +CheckF4('', 'var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]); +CheckF4('', 'var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]); +CheckF4('', 'var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]); +CheckF4('', 'var x=f4(13.37, 2., 3., -0)', [13.37, 2, 3, -0]); + +// 1.3.3. Variable assignments +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4();} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1.0, 2, 3, 4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2.0, 3, 4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3.0, 4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3, 4.0);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3, x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var c=4.0; x=i4(1, 2, 3, +c);} return f"); + +assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f() {var x=i4(1,2,3,4); i32[0] = x;} return f"); +assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f() {var x=i4(1,2,3,4); x = i32[0];} return f"); +assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Float32Array(heap); function f() {var x=f4(1,2,3,4); f32[0] = x;} return f"); +assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Int32Array(heap); function f() {var x=f4(1,2,3,4); x = f32[0];} return f"); + +CheckI4('', 'var x=i4(1,2,3,4); x=i4(5,6,7,8)', [5, 6, 7, 8]); +CheckI4('', 'var x=i4(1,2,3,4); var c=6; x=i4(5,c|0,7,8)', [5, 6, 7, 8]); +CheckI4('', 'var x=i4(8,7,6,5); x=i4(x.w|0,x.z|0,x.y|0,x.x|0)', [5, 6, 7, 8]); + +CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(7.); x=f4(5,6,y,8)', [5, 6, 7, 8]); +CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5.),6.,7.,8.)', [5, 6, 7, 8]); +CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5),6,7,8)', [5, 6, 7, 8]); +CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5.),f32(6.),f32(7.),f32(8.))', [5, 6, 7, 8]); +CheckF4('', 'var x=f4(1.,2.,3.,4.); x=f4(5.,6.,7.,8.)', [5, 6, 7, 8]); +CheckF4('', 'var x=f4(1.,2.,3.,4.); x=f4(1,2,3,4)', [1, 2, 3, 4]); +CheckF4(FROUND, 'var x=f4(1.,2.,3.,4.); var y=f32(7.); x=f4(9, 4, 2, 1)', [9, 4, 2, 1]); +CheckF4('', 'var x=f4(8.,7.,6.,5.); x=f4(x.w, x.z, x.y, x.x)', [5, 6, 7, 8]); + +// 1.3.4 Return values +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x)} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x + x)} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1.; return i4(x)} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=f32(1.); return i4(x)} return f"); + +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return i4(x)} return f"), this)(), [1,2,3,4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); return f4(x)} return f"), this)(), [1,2,3,4]); + +// 1.3.5 Coerce and pass arguments +assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4();} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(1,2,3,4);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x,y) {x=i4(y);y=+y} return f"); + +var i32x4 = SIMD.int32x4(1, 3, 3, 7); +assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x)} return f"), this)(i32x4), undefined); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x); return i4(x);} return f"), this)(i32x4), [1,3,3,7]); + +var f32x4 = SIMD.float32x4(13.37, 42.42, -0, NaN); +assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x)} return f"), this)(f32x4), undefined); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x); return f4(x);} return f"), this)(f32x4), + [Math.fround(13.37), Math.fround(42.42), -0, NaN]); + +function assertCaught(f) { + var caught = false; + try { + f.apply(null, Array.prototype.slice.call(arguments, 1)); + } catch (e) { + DEBUG && print('Assert caught: ', e, '\n', e.stack); + assertEq(e instanceof TypeError, true); + caught = true; + } + assertEq(caught, true); +} + +var f = asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x); return f4(x);} return f"), this); +assertCaught(f); +assertCaught(f, 1); +assertCaught(f, {}); +assertCaught(f, "I sincerely am a SIMD typed object."); +assertCaught(f, SIMD.int32x4(1,2,3,4)); + +var f = asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x); return i4(x);} return f"), this); +assertCaught(f); +assertCaught(f, 1); +assertCaught(f, {}); +assertCaught(f, "I sincerely am a SIMD typed object."); +assertCaught(f, SIMD.float32x4(4,3,2,1)); + +// 1.3.6 Globals +// 1.3.6.1 Local globals +// Read +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; x=g|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; x=+g;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f"); + +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4; x=g|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; x=+g;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f"); + +assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); x=i4(g);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); x=f4(g);} return f"); + +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0; function f() {var x=i4(1,2,3,4); x=g|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0.; function f() {var x=i4(1,2,3,4); x=+g;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=i4(1,2,3,4); x=f32(g);} return f"); + +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0; function f() {var x=f4(0.,0.,0.,0.); x=g|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0.; function f() {var x=f4(0.,0.,0.,0.); x=+g;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=f4(0.,0.,0.,0.); x=f32(g);} return f"); + +CheckI4('var x=i4(1,2,3,4)', '', [1, 2, 3, 4]); +CheckI4('var _=42; var h=i4(5,5,5,5); var __=13.37; var x=i4(4,7,9,2);', '', [4,7,9,2]); + +CheckF4('var x=f4(1.,2.,3.,4.)', '', [1, 2, 3, 4]); +CheckF4('var _=42; var h=f4(5.,5.,5.,5.); var __=13.37; var x=f4(4.,13.37,9.,-0.);', '', [4, 13.37, 9, -0]); +CheckF4('var x=f4(1,2,3,4)', '', [1, 2, 3, 4]); + +// Write +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; g=x|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; g=+x;} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f"); + +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4; g=x|0;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; g=+x;} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f"); + +assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=i4(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=f4(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=f4(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=i4(x);} return f"); + +CheckI4('var x=i4(0,0,0,0);', 'x=i4(1,2,3,4)', [1,2,3,4]); +CheckF4('var x=f4(0.,0.,0.,0.);', 'x=f4(5.,3.,4.,2.)', [5,3,4,2]); + +CheckI4('var x=i4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=i4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]); +CheckF4('var x=f4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=f4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]); + +// 1.3.6.2 Imported globals +// Read +var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {return i4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})(); +assertEq(int32x4.x, 1); +assertEq(int32x4.y, 2); +assertEq(int32x4.z, 3); +assertEq(int32x4.w, 4); + +for (var v of [1, {}, "totally legit SIMD variable", SIMD.float32x4(1,2,3,4)]) + assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {return i4(g)} return f"), this, {g: v}); + +var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {return f4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})(); +assertEq(float32x4.x, 1); +assertEq(float32x4.y, 2); +assertEq(float32x4.z, 3); +assertEq(float32x4.w, 4); + +for (var v of [1, {}, "totally legit SIMD variable", SIMD.int32x4(1,2,3,4)]) + assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {return f4(g)} return f"), this, {g: v}); + +// Write +var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {g=i4(4,5,6,7); return i4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})(); +assertEq(int32x4.x, 4); +assertEq(int32x4.y, 5); +assertEq(int32x4.z, 6); +assertEq(int32x4.w, 7); + +var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return f4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})(); +assertEq(float32x4.x, 4); +assertEq(float32x4.y, 5); +assertEq(float32x4.z, 6); +assertEq(float32x4.w, 7); + +// 2. SIMD operations +// 2.1 Compilation +assertAsmTypeFail('glob', USE_ASM + "var add = int32x4.add; return {}"); +assertAsmTypeFail('glob', USE_ASM + I32A + I32 + "return {}"); +assertAsmTypeFail('glob', USE_ASM + "var g = 3; var add = g.add; return {}"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.doTheHarlemShake; return {}"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var div = i4.div; return {}"); +assertAsmTypeFail('glob', USE_ASM + "var f32 = glob.Math.fround; var i4a = f32.add; return {}"); + +// 2.2 Linking +assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {}); +assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: Math.fround}); + +var oldInt32x4Add = SIMD.int32x4.add; +var code = asmCompile('glob', USE_ASM + I32 + I32A + "return {}"); +for (var v of [42, Math.fround, SIMD.float32x4.add, function(){}, SIMD.int32x4.mul]) { + SIMD.int32x4.add = v; + assertAsmLinkFail(code, {SIMD: {int32x4: SIMD.int32x4}}); +} +SIMD.int32x4.add = oldInt32x4Add; // finally replace the add function with the original one +assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: {int32x4: SIMD.int32x4}})(), undefined); + +// 2.3. Binary arithmetic operations +// 2.3.1 Additions +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a();} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, x, x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(13, 37);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(23.10, 19.89);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, 42);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, 13.37);} return f"); + +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var y=4; x=i4a(x, y);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; x=i4a(y, y);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; y=i4a(x, x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=i4a(x, y);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, y);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, y);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=f4a(y, y);} return f"); + +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0; y=i4(x,x)|0} return f'); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0.; y=+i4(x,x)} return f'); + +CheckI4(I32A, 'var z=i4(1,2,3,4); var y=i4(0,1,0,3); var x=i4(0,0,0,0); x=i4a(z,y)', [1,3,3,7]); +CheckI4(I32A, 'var x=i4(2,3,4,5); var y=i4(0,1,0,3); x=i4a(x,y)', [2,4,4,8]); +CheckI4(I32A, 'var x=i4(1,2,3,4); x=i4a(x,x)', [2,4,6,8]); +CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4a(x,y)', [INT32_MIN,3,3,7]); +CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4(i4a(x,y))', [INT32_MIN,3,3,7]); + +CheckF4(F32A, 'var x=f4(1,2,3,4); x=f4a(x,x)', [2,4,6,8]); +CheckF4(F32A, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [5,5,8,6]); +CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [Math.fround(13.37) + 4,5,8,6]); +CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4a(x,y))', [Math.fround(13.37) + 4,5,8,6]); + +// 2.3.2. Subtracts +CheckI4(I32S, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=i4s(x,y)', [2,1,3,2]); +CheckI4(I32S, 'var x=i4(5,4,3,2); var y=i4(1,2,3,4); x=i4s(x,y)', [4,2,0,-2]); +CheckI4(I32S, 'var x=i4(1,2,3,4); x=i4s(x,x)', [0,0,0,0]); +CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4s(x,y)', [INT32_MAX,1,3,1]); +CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4(i4s(x,y))', [INT32_MAX,1,3,1]); + +CheckF4(F32S, 'var x=f4(1,2,3,4); x=f4s(x,x)', [0,0,0,0]); +CheckF4(F32S, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [-3,-1,-2,2]); +CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [Math.fround(13.37) - 4,-1,-2,2]); +CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4s(x,y))', [Math.fround(13.37) - 4,-1,-2,2]); + +// 2.3.3. Multiplications / Divisions +assertAsmTypeFail('glob', USE_ASM + I32 + "var f4m=i4.mul; function f() {} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var f4d=i4.div; function f() {} return f"); + +CheckF4(F32M, 'var x=f4(1,2,3,4); x=f4m(x,x)', [1,4,9,16]); +CheckF4(F32M, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [4,6,15,8]); +CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [Math.fround(13.37) * 4,6,15,8]); +CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]); + +// Test NaN +var f32x4 = SIMD.float32x4(0, NaN, -0, NaN); +var another = SIMD.float32x4(NaN, -1, -0, NaN); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32M + "function f(x, y) {x=f4(x); y=f4(y); x=f4m(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, 0, NaN]); + +CheckF4(F32D, 'var x=f4(1,2,3,4); x=f4d(x,x)', [1,1,1,1]); +CheckF4(F32D, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4d(x,y)', [1/4,2/3,3/5,2]); +CheckF4(F32D, 'var x=f4(13.37,1,1,4); var y=f4(4,0,-0.,2); x=f4d(x,y)', [Math.fround(13.37) / 4,+Infinity,-Infinity,2]); + +// Test NaN +var f32x4 = SIMD.float32x4(0, 0, -0, NaN); +var another = SIMD.float32x4(0, -0, 0, 0); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + "function f(x,y) {x=f4(x); y=f4(y); x=f4d(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]); + +// Dead code +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); return i4(x); x=i4(5,6,7,8); return i4(x);} return f'), this)(), [1, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); c=x.x|0; return i4(x);} return f'), this)(), [1, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4a(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]); +assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32S + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4s(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]); + +// 3. Function calls +// 3.1. No math builtins +assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); return +fround(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var sin=glob.Math.sin; function f() {var x=i4(1,2,3,4); return +sin(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var ceil=glob.Math.ceil; function f() {var x=i4(1,2,3,4); return +ceil(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {var x=i4(1,2,3,4); return +pow(1.0, x);} return f"); + +assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); x=i4(fround(3));} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var sin=glob.Math.sin; function f() {var x=i4(1,2,3,4); x=i4(sin(3.0));} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var ceil=glob.Math.sin; function f() {var x=i4(1,2,3,4); x=i4(ceil(3.0));} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {var x=i4(1,2,3,4); x=i4(pow(1.0, 2.0));} return f"); + +// 3.2. FFI calls +// Can't pass SIMD arguments to FFI +assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); func(x);} return f"); +assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); func(x);} return f"); + +// Can't have FFI return SIMD values +assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); x=i4(func());} return f"); +assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); x=f4(func());} return f"); + +// 3.3 Internal calls +// asm.js -> asm.js +// Retrieving values from asm.js +var code = USE_ASM + I32 + I32A + ` + var check = ffi.check; + + function g() { + var i = 0; + var y = i4(0,0,0,0); + var tmp = i4(0,0,0,0); var z = i4(1,1,1,1); + var w = i4(5,5,5,5); + for (; (i|0) < 30; i = i + 1 |0) + y = i4a(z, y); + y = i4a(w, y); + check(y.x | 0, y.y | 0, y.z | 0, y.w | 0); + return i4(y); + } + + function f(x) { + x = i4(x); + var y = i4(0,0,0,0); + y = i4(g()); + check(y.x | 0, y.y | 0, y.z | 0, y.w | 0); + return i4(x); + } + return f; +`; + +var v4 = SIMD.int32x4(1,2,3,4); +function check(x, y, z, w) { + assertEq(x, 35); + assertEq(y, 35); + assertEq(z, 35); + assertEq(w, 35); +} +var ffi = {check}; +assertEqX4(asmLink(asmCompile('glob', 'ffi', code), this, ffi)(v4), [1,2,3,4]); + +// Passing arguments from asm.js to asm.js +// TODO make this code look better with templatized strings +var code = USE_ASM + I32 + I32A + ` + var assertEq = ffi.assertEq; + + function internal([args]) { + [coerc] + assertEq([last].x | 0, [i] | 0); + assertEq([last].y | 0, [i] + 1 |0); + assertEq([last].z | 0, [i] + 2 |0); + assertEq([last].w | 0, [i] + 3 |0); + } + + function external() { + [decls] + internal([args]); + } + return external; +`; + +var ffi = {assertEq}; +var args = ''; +var decls = ''; +var coerc = ''; +for (var i = 1; i < 10; ++i) { + var j = i; + args += ((i > 1) ? ', ':'') + 'x' + i; + decls += 'var x' + i + ' = i4(' + j++ + ', ' + j++ + ', ' + j++ + ', ' + j++ + ');\n'; + coerc += 'x' + i + ' = i4(x' + i + ');\n'; + last = 'x' + i; + var c = code.replace(/\[args\]/g, args) + .replace(/\[last\]/g, last) + .replace(/\[decls\]/i, decls) + .replace(/\[coerc\]/i, coerc) + .replace(/\[i\]/g, i); + asmLink(asmCompile('glob', 'ffi', c), this, ffi)(); +} + +// Stress-test for register spilling code and stack depth checks +var code = ` + "use asm"; + var i4 = glob.SIMD.int32x4; + var i4a = i4.add; + var assertEq = ffi.assertEq; + function g() { + var x = i4(1,2,3,4); + var y = i4(2,3,4,5); + var z = i4(0,0,0,0); + z = i4a(x, y); + assertEq(z.x | 0, 3); + assertEq(z.y | 0, 5); + assertEq(z.z | 0, 7); + assertEq(z.w | 0, 9); + } + return g +` +asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)(); + +(function() { + var code = ` + "use asm"; + var i4 = glob.SIMD.int32x4; + var i4a = i4.add; + var assertEq = ffi.assertEq; + var one = ffi.one; + + // Function call with arguments on the stack (1 on x64, 3 on x86) + function h(x1, x2, x3, x4, x5, x6, x7) { + x1=x1|0 + x2=x2|0 + x3=x3|0 + x4=x4|0 + x5=x5|0 + x6=x6|0 + x7=x7|0 + return x1 + x2 |0 + } + + function g() { + var x = i4(1,2,3,4); + var y = i4(2,3,4,5); + var z = i4(0,0,0,0); + var w = 1; + z = i4a(x, y); + w = w + (one() | 0) | 0; + assertEq(z.x | 0, 3); + assertEq(z.y | 0, 5); + assertEq(z.z | 0, 7); + assertEq(z.w | 0, 9); + h(1, 2, 3, 4, 42, 42, 42)|0 + return w | 0; + } + return g + `; + + asmLink(asmCompile('glob', 'ffi', code), this, {assertEq: assertEq, one: () => 1})(); +})(); + +// Function calls with mixed arguments on the stack (SIMD and scalar). In the +// worst case (x64), we have 6 int arg registers and 8 float registers. +(function() { + var code = ` + "use asm"; + var i4 = glob.SIMD.int32x4; + function h( + // In registers: + gpr1, gpr2, gpr3, gpr4, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, + // On the stack: + sint1, ssimd1, sdouble1, ssimd2, sint2, sint3, sint4, ssimd3, sdouble2 + ) + { + gpr1=gpr1|0; + gpr2=gpr2|0; + gpr3=gpr3|0; + gpr4=gpr4|0; + + xmm1=+xmm1; + xmm2=+xmm2; + xmm3=+xmm3; + xmm4=+xmm4; + xmm5=+xmm5; + xmm6=+xmm6; + xmm7=+xmm7; + xmm8=+xmm8; + + sint1=sint1|0; + ssimd1=i4(ssimd1); + sdouble1=+sdouble1; + ssimd2=i4(ssimd2); + sint2=sint2|0; + sint3=sint3|0; + sint4=sint4|0; + ssimd3=i4(ssimd3); + sdouble2=+sdouble2; + + return (ssimd1.x|0) + (ssimd2.y|0) + (ssimd3.z|0) + sint2 + gpr3 | 0; + } + + function g() { + var simd1 = i4(1,2,3,4); + var simd2 = i4(5,6,7,8); + var simd3 = i4(9,10,11,12); + return h(1, 2, 3, 4, + 1., 2., 3., 4., 5., 6., 7., 8., + 5, simd1, 9., simd2, 6, 7, 8, simd3, 10.) | 0; + } + return g + `; + + assertEq(asmLink(asmCompile('glob', 'ffi', code), this)(), 1 + 6 + 11 + 6 + 3); +})(); + +// Check that the interrupt callback doesn't erase high components of simd +// registers: + +// WARNING: must be the last test in this file +(function() { + var iters = 2000000; + var code = ` + "use asm"; + var i4 = glob.SIMD.int32x4; + var i4a = i4.add; + function _() { + var i = 0; + var n = i4(0,0,0,0); + var one = i4(1,1,1,1); + for (; (i>>>0) < ` + iters + `; i=(i+1)>>>0) { + n = i4a(n, one); + } + return i4(n); + } + return _;`; + // This test relies on the fact that setting the timeout will call the + // interrupt callback at fixed intervals, even before the timeout. + timeout(1000); + var x4 = asmLink(asmCompile('glob', code), this)(); + assertEq(x4.x, iters); + assertEq(x4.y, iters); + assertEq(x4.z, iters); + assertEq(x4.w, iters); +})(); + +} catch(e) { + print('Stack:', e.stack) + print('Error:', e) + throw e; +} + diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index f3af7ff088eb..9fa0419cbe97 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3553,7 +3553,7 @@ LIRGenerator::visitAsmJSParameter(MAsmJSParameter *ins) if (abi.argInRegister()) return defineFixed(new(alloc()) LAsmJSParameter, ins, LAllocation(abi.reg())); - JS_ASSERT(IsNumberType(ins->type())); + JS_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type())); return defineFixed(new(alloc()) LAsmJSParameter, ins, LArgument(abi.offsetFromArgBase())); } @@ -3566,6 +3566,8 @@ LIRGenerator::visitAsmJSReturn(MAsmJSReturn *ins) lir->setOperand(0, useFixed(rval, ReturnFloat32Reg)); else if (rval->type() == MIRType_Double) lir->setOperand(0, useFixed(rval, ReturnDoubleReg)); + else if (IsSimdType(rval->type())) + lir->setOperand(0, useFixed(rval, ReturnSimdReg)); else if (rval->type() == MIRType_Int32) lir->setOperand(0, useFixed(rval, ReturnReg)); else @@ -3582,7 +3584,7 @@ LIRGenerator::visitAsmJSVoidReturn(MAsmJSVoidReturn *ins) bool LIRGenerator::visitAsmJSPassStackArg(MAsmJSPassStackArg *ins) { - if (IsFloatingPointType(ins->arg()->type())) { + if (IsFloatingPointType(ins->arg()->type()) || IsSimdType(ins->arg()->type())) { JS_ASSERT(!ins->arg()->isEmittedAtUses()); return add(new(alloc()) LAsmJSPassStackArg(useRegisterAtStart(ins->arg())), ins); } diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index bada2ff1638e..e41794f18e42 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -493,6 +493,7 @@ MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintLi MConstant * MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type) { + JS_ASSERT(!IsSimdType(type)); MConstant *constant = new(alloc) MConstant(v, nullptr); constant->setResultType(type); return constant; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index fdf078252445..e6523780b621 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -11184,7 +11184,7 @@ class MAsmJSLoadGlobalVar : public MNullaryInstruction MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant) : globalDataOffset_(globalDataOffset), isConstant_(isConstant) { - JS_ASSERT(IsNumberType(type)); + JS_ASSERT(IsNumberType(type) || IsSimdType(type)); setResultType(type); setMovable(); } diff --git a/js/src/jit/shared/BaseAssembler-x86-shared.h b/js/src/jit/shared/BaseAssembler-x86-shared.h index 76ae77fb7d4a..a93a71e3e220 100644 --- a/js/src/jit/shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/shared/BaseAssembler-x86-shared.h @@ -2978,6 +2978,21 @@ public: m_formatter.prefix(PRE_SSE_F3); m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, address); } + + void movdqa_rm(XMMRegisterID src, const void* address) + { + spew("movdqa %s, %p", + nameFPReg(src), address); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_MOVDQ_WdqVdq, (RegisterID)src, address); + } + + void movaps_rm(XMMRegisterID src, const void* address) + { + spew("movaps %s, %p", + nameFPReg(src), address); + m_formatter.twoByteOp(OP2_MOVPS_WpsVps, (RegisterID)src, address); + } #else JmpSrc movsd_ripr(XMMRegisterID dst) { @@ -3003,6 +3018,29 @@ public: m_formatter.twoByteRipOp(OP2_MOVSD_WsdVsd, (RegisterID)src, 0); return JmpSrc(m_formatter.size()); } + JmpSrc movss_rrip(XMMRegisterID src) + { + spew("movss %s, ?(%%rip)", + nameFPReg(src)); + m_formatter.prefix(PRE_SSE_F3); + m_formatter.twoByteRipOp(OP2_MOVSD_WsdVsd, (RegisterID)src, 0); + return JmpSrc(m_formatter.size()); + } + JmpSrc movdqa_rrip(XMMRegisterID src) + { + spew("movdqa %s, ?(%%rip)", + nameFPReg(src)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteRipOp(OP2_MOVDQ_WdqVdq, (RegisterID)src, 0); + return JmpSrc(m_formatter.size()); + } + JmpSrc movaps_rrip(XMMRegisterID src) + { + spew("movaps %s, ?(%%rip)", + nameFPReg(src)); + m_formatter.twoByteRipOp(OP2_MOVPS_WpsVps, (RegisterID)src, 0); + return JmpSrc(m_formatter.size()); + } #endif void movaps_rr(XMMRegisterID src, XMMRegisterID dst) diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 92c7bc8d0986..1bb23233f948 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -319,10 +319,26 @@ CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins) if (ins->arg()->isConstant()) { masm.storePtr(ImmWord(ToInt32(ins->arg())), dst); } else { - if (ins->arg()->isGeneralReg()) + if (ins->arg()->isGeneralReg()) { masm.storePtr(ToRegister(ins->arg()), dst); - else - masm.storeDouble(ToFloatRegister(ins->arg()), dst); + } else { + switch (mir->input()->type()) { + case MIRType_Double: + case MIRType_Float32: + masm.storeDouble(ToFloatRegister(ins->arg()), dst); + return true; + // StackPointer is SimdStackAlignment-aligned and ABIArgGenerator guarantees stack + // offsets are SimdStackAlignment-aligned. + case MIRType_Int32x4: + masm.storeAlignedInt32x4(ToFloatRegister(ins->arg()), dst); + return true; + case MIRType_Float32x4: + masm.storeAlignedFloat32x4(ToFloatRegister(ins->arg()), dst); + return true; + default: break; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected mir type in AsmJSPassStackArg"); + } } return true; } diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index f2280705c8de..c2868db3dccd 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -154,6 +154,12 @@ LIRGeneratorShared::defineReturn(LInstruction *lir, MDefinition *mir) case MIRType_Double: lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg))); break; + case MIRType_Int32x4: + lir->setDef(0, LDefinition(vreg, LDefinition::INT32X4, LFloatReg(ReturnSimdReg))); + break; + case MIRType_Float32x4: + lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32X4, LFloatReg(ReturnSimdReg))); + break; default: LDefinition::Type type = LDefinition::TypeFrom(mir->type()); JS_ASSERT(type != LDefinition::DOUBLE && type != LDefinition::FLOAT32); diff --git a/js/src/jit/x64/Assembler-x64.cpp b/js/src/jit/x64/Assembler-x64.cpp index c55d9dc66dd8..2970870eca54 100644 --- a/js/src/jit/x64/Assembler-x64.cpp +++ b/js/src/jit/x64/Assembler-x64.cpp @@ -30,8 +30,17 @@ ABIArgGenerator::next(MIRType type) #if defined(XP_WIN) JS_STATIC_ASSERT(NumIntArgRegs == NumFloatArgRegs); if (regIndex_ == NumIntArgRegs) { - current_ = ABIArg(stackOffset_); - stackOffset_ += sizeof(uint64_t); + if (IsSimdType(type)) { + // On Win64, >64 bit args need to be passed by reference, but asm.js + // doesn't allow passing SIMD values to FFIs. The only way to reach + // here is asm to asm calls, so we can break the ABI here. + stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment); + current_ = ABIArg(stackOffset_); + stackOffset_ += Simd128DataSize; + } else { + stackOffset_ += sizeof(uint64_t); + current_ = ABIArg(stackOffset_); + } return current_; } switch (type) { @@ -43,6 +52,13 @@ ABIArgGenerator::next(MIRType type) case MIRType_Double: current_ = ABIArg(FloatArgRegs[regIndex_++]); break; + case MIRType_Int32x4: + case MIRType_Float32x4: + // On Win64, >64 bit args need to be passed by reference, but asm.js + // doesn't allow passing SIMD values to FFIs. The only way to reach + // here is asm to asm calls, so we can break the ABI here. + current_ = ABIArg(FloatArgRegs[regIndex_++]); + break; default: MOZ_CRASH("Unexpected argument type"); } @@ -67,6 +83,16 @@ ABIArgGenerator::next(MIRType type) } current_ = ABIArg(FloatArgRegs[floatRegIndex_++]); break; + case MIRType_Int32x4: + case MIRType_Float32x4: + if (floatRegIndex_ == NumFloatArgRegs) { + stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment); + current_ = ABIArg(stackOffset_); + stackOffset_ += Simd128DataSize; + break; + } + current_ = ABIArg(FloatArgRegs[floatRegIndex_++]); + break; default: MOZ_CRASH("Unexpected argument type"); } diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index 0567dbd26758..bd633ada45f0 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -602,12 +602,30 @@ class Assembler : public AssemblerX86Shared CodeOffsetLabel loadRipRelativeDouble(FloatRegister dest) { return CodeOffsetLabel(masm.movsd_ripr(dest.code()).offset()); } + CodeOffsetLabel loadRipRelativeFloat32(FloatRegister dest) { + return CodeOffsetLabel(masm.movss_ripr(dest.code()).offset()); + } + CodeOffsetLabel loadRipRelativeInt32x4(FloatRegister dest) { + return CodeOffsetLabel(masm.movdqa_ripr(dest.code()).offset()); + } + CodeOffsetLabel loadRipRelativeFloat32x4(FloatRegister dest) { + return CodeOffsetLabel(masm.movaps_ripr(dest.code()).offset()); + } CodeOffsetLabel storeRipRelativeInt32(Register dest) { return CodeOffsetLabel(masm.movl_rrip(dest.code()).offset()); } CodeOffsetLabel storeRipRelativeDouble(FloatRegister dest) { return CodeOffsetLabel(masm.movsd_rrip(dest.code()).offset()); } + CodeOffsetLabel storeRipRelativeFloat32(FloatRegister dest) { + return CodeOffsetLabel(masm.movss_rrip(dest.code()).offset()); + } + CodeOffsetLabel storeRipRelativeInt32x4(FloatRegister dest) { + return CodeOffsetLabel(masm.movdqa_rrip(dest.code()).offset()); + } + CodeOffsetLabel storeRipRelativeFloat32x4(FloatRegister dest) { + return CodeOffsetLabel(masm.movaps_rrip(dest.code()).offset()); + } CodeOffsetLabel leaRipRelative(Register dest) { return CodeOffsetLabel(masm.leaq_rip(dest.code()).offset()); } diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index 048d7ee1fddb..bb68322c99d6 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -349,11 +349,32 @@ CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins) { MAsmJSLoadGlobalVar *mir = ins->mir(); + MIRType type = mir->type(); + JS_ASSERT(IsNumberType(type) || IsSimdType(type)); + CodeOffsetLabel label; - if (mir->type() == MIRType_Int32) + switch (type) { + case MIRType_Int32: label = masm.loadRipRelativeInt32(ToRegister(ins->output())); - else + break; + case MIRType_Float32: + label = masm.loadRipRelativeFloat32(ToFloatRegister(ins->output())); + break; + case MIRType_Double: label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output())); + break; + // Aligned access: code is aligned on PageSize + there is padding + // before the global data section. + case MIRType_Int32x4: + label = masm.loadRipRelativeInt32x4(ToFloatRegister(ins->output())); + break; + case MIRType_Float32x4: + label = masm.loadRipRelativeFloat32x4(ToFloatRegister(ins->output())); + break; + default: + MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSLoadGlobalVar"); + } + masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } @@ -364,13 +385,31 @@ CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins) MAsmJSStoreGlobalVar *mir = ins->mir(); MIRType type = mir->value()->type(); - JS_ASSERT(IsNumberType(type)); + JS_ASSERT(IsNumberType(type) || IsSimdType(type)); CodeOffsetLabel label; - if (type == MIRType_Int32) + switch (type) { + case MIRType_Int32: label = masm.storeRipRelativeInt32(ToRegister(ins->value())); - else + break; + case MIRType_Float32: + label = masm.storeRipRelativeFloat32(ToFloatRegister(ins->value())); + break; + case MIRType_Double: label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value())); + break; + // Aligned access: code is aligned on PageSize + there is padding + // before the global data section. + case MIRType_Int32x4: + label = masm.storeRipRelativeInt32x4(ToFloatRegister(ins->value())); + break; + case MIRType_Float32x4: + label = masm.storeRipRelativeFloat32x4(ToFloatRegister(ins->value())); + break; + default: + MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSStoreGlobalVar"); + } + masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } diff --git a/js/src/jit/x86/Assembler-x86.cpp b/js/src/jit/x86/Assembler-x86.cpp index bcdac920f180..15aba0dea5b3 100644 --- a/js/src/jit/x86/Assembler-x86.cpp +++ b/js/src/jit/x86/Assembler-x86.cpp @@ -19,16 +19,26 @@ ABIArgGenerator::ABIArgGenerator() ABIArg ABIArgGenerator::next(MIRType type) { - current_ = ABIArg(stackOffset_); switch (type) { case MIRType_Int32: case MIRType_Pointer: + current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); break; case MIRType_Float32: // Float32 moves are actually double moves case MIRType_Double: + current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); break; + case MIRType_Int32x4: + case MIRType_Float32x4: + // SIMD values aren't passed in or out of C++, so we can make up + // whatever internal ABI we like. visitAsmJSPassArg assumes + // SimdStackAlignment. + stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment); + current_ = ABIArg(stackOffset_); + stackOffset_ += Simd128DataSize; + break; default: MOZ_CRASH("Unexpected argument type"); } diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 832a03389e9b..fe1b329fa5ea 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -523,6 +523,16 @@ class Assembler : public AssemblerX86Shared masm.movsd_mr(src.addr, dest.code()); return CodeOffsetLabel(masm.currentOffset()); } + CodeOffsetLabel movdqaWithPatch(PatchedAbsoluteAddress src, FloatRegister dest) { + JS_ASSERT(HasSSE2()); + masm.movdqa_mr(src.addr, dest.code()); + return CodeOffsetLabel(masm.currentOffset()); + } + CodeOffsetLabel movapsWithPatch(PatchedAbsoluteAddress src, FloatRegister dest) { + JS_ASSERT(HasSSE2()); + masm.movaps_mr(src.addr, dest.code()); + return CodeOffsetLabel(masm.currentOffset()); + } // Store to *dest where dest can be patched. CodeOffsetLabel movbWithPatch(Register src, PatchedAbsoluteAddress dest) { @@ -547,6 +557,16 @@ class Assembler : public AssemblerX86Shared masm.movsd_rm(src.code(), dest.addr); return CodeOffsetLabel(masm.currentOffset()); } + CodeOffsetLabel movdqaWithPatch(FloatRegister src, PatchedAbsoluteAddress dest) { + JS_ASSERT(HasSSE2()); + masm.movdqa_rm(src.code(), dest.addr); + return CodeOffsetLabel(masm.currentOffset()); + } + CodeOffsetLabel movapsWithPatch(FloatRegister src, PatchedAbsoluteAddress dest) { + JS_ASSERT(HasSSE2()); + masm.movaps_rm(src.code(), dest.addr); + return CodeOffsetLabel(masm.currentOffset()); + } void loadAsmJSActivation(Register dest) { CodeOffsetLabel label = movlWithPatch(PatchedAbsoluteAddress(), dest); diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index adfd2ae2370b..8a5d303defe9 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -462,15 +462,30 @@ CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins) { MAsmJSLoadGlobalVar *mir = ins->mir(); MIRType type = mir->type(); - JS_ASSERT(IsNumberType(type)); + JS_ASSERT(IsNumberType(type) || IsSimdType(type)); CodeOffsetLabel label; - if (type == MIRType_Int32) + switch (type) { + case MIRType_Int32: label = masm.movlWithPatch(PatchedAbsoluteAddress(), ToRegister(ins->output())); - else if (type == MIRType_Float32) + break; + case MIRType_Float32: label = masm.movssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); - else + break; + case MIRType_Double: label = masm.movsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); + break; + // Aligned access: code is aligned on PageSize + there is padding + // before the global data section. + case MIRType_Int32x4: + label = masm.movdqaWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); + break; + case MIRType_Float32x4: + label = masm.movapsWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); + break; + default: + MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSLoadGlobalVar"); + } masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } @@ -481,15 +496,30 @@ CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins) MAsmJSStoreGlobalVar *mir = ins->mir(); MIRType type = mir->value()->type(); - JS_ASSERT(IsNumberType(type)); + JS_ASSERT(IsNumberType(type) || IsSimdType(type)); CodeOffsetLabel label; - if (type == MIRType_Int32) + switch (type) { + case MIRType_Int32: label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress()); - else if (type == MIRType_Float32) + break; + case MIRType_Float32: label = masm.movssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); - else + break; + case MIRType_Double: label = masm.movsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); + break; + // Aligned access: code is aligned on PageSize + there is padding + // before the global data section. + case MIRType_Int32x4: + label = masm.movdqaWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); + break; + case MIRType_Float32x4: + label = masm.movapsWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); + break; + default: + MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSStoreGlobalVar"); + } masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } diff --git a/js/src/js.msg b/js/src/js.msg index ab6a265feb3f..3a1cbc16f7f1 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -291,6 +291,7 @@ MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function") MSG_DEF(JSMSG_SYNTAX_ERROR, 0, JSEXN_SYNTAXERR, "syntax error") MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string") +MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 0, JSEXN_TYPEERR, "value isn't a SIMD value object") MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases") MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables") MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments") From 797ab33dab0dd4be02242bb131f26c718b77c365 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 29 Aug 2014 14:56:41 -0400 Subject: [PATCH 007/120] Bug 1058136 - Refactor GeckoEditable; r=cpeterson --- mobile/android/base/GeckoEditable.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index a15fc28599f2..4df6b530ebc9 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -229,6 +229,7 @@ final class GeckoEditable mActionsActive.tryAcquire(); mActions.offer(action); } + switch (action.mType) { case Action.TYPE_EVENT: case Action.TYPE_SET_SELECTION: @@ -238,17 +239,23 @@ final class GeckoEditable GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent( GeckoEvent.ImeAction.IME_SYNCHRONIZE)); break; + case Action.TYPE_REPLACE_TEXT: // try key events first sendCharKeyEvents(action); GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEReplaceEvent( action.mStart, action.mEnd, action.mSequence.toString())); break; + case Action.TYPE_ACKNOWLEDGE_FOCUS: GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent( GeckoEvent.ImeAction.IME_ACKNOWLEDGE_FOCUS)); break; + + default: + throw new IllegalStateException("Action not processed"); } + ++mIcUpdateSeqno; } @@ -307,12 +314,10 @@ final class GeckoEditable throw new IllegalStateException("empty actions queue"); } mActions.poll(); - // Don't bother locking if queue is not empty yet - if (mActions.isEmpty()) { - synchronized(this) { - if (mActions.isEmpty()) { - mActionsActive.release(); - } + + synchronized(this) { + if (mActions.isEmpty()) { + mActionsActive.release(); } } } From 9f915d3e8117f09fad52a16d762496443dc5d25e Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 29 Aug 2014 14:56:42 -0400 Subject: [PATCH 008/120] Bug 1058136 - Fix debug logging crash; r=cpeterson --- mobile/android/base/GeckoEditable.java | 12 ++++---- mobile/android/base/GeckoInputConnection.java | 30 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 4df6b530ebc9..38572e113b46 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -1039,11 +1039,13 @@ final class GeckoEditable if (DEBUG) { StringBuilder log = new StringBuilder(method.getName()); log.append("("); - for (Object arg : args) { - debugAppend(log, arg).append(", "); - } - if (args.length > 0) { - log.setLength(log.length() - 2); + if (args != null) { + for (Object arg : args) { + debugAppend(log, arg).append(", "); + } + if (args.length > 0) { + log.setLength(log.length() - 2); + } } if (method.getReturnType().equals(Void.TYPE)) { log.append(")"); diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index 272fbb081349..3a434ba31b99 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -1024,21 +1024,23 @@ final class DebugGeckoInputConnection StringBuilder log = new StringBuilder(mCallLevel); log.append("> ").append(method.getName()).append("("); - for (Object arg : args) { - // translate argument values to constant names - if ("notifyIME".equals(method.getName()) && arg == args[0]) { - log.append(GeckoEditable.getConstantName( - GeckoEditableListener.class, "NOTIFY_IME_", arg)); - } else if ("notifyIMEContext".equals(method.getName()) && arg == args[0]) { - log.append(GeckoEditable.getConstantName( - GeckoEditableListener.class, "IME_STATE_", arg)); - } else { - GeckoEditable.debugAppend(log, arg); + if (args != null) { + for (Object arg : args) { + // translate argument values to constant names + if ("notifyIME".equals(method.getName()) && arg == args[0]) { + log.append(GeckoEditable.getConstantName( + GeckoEditableListener.class, "NOTIFY_IME_", arg)); + } else if ("notifyIMEContext".equals(method.getName()) && arg == args[0]) { + log.append(GeckoEditable.getConstantName( + GeckoEditableListener.class, "IME_STATE_", arg)); + } else { + GeckoEditable.debugAppend(log, arg); + } + log.append(", "); + } + if (args.length > 0) { + log.setLength(log.length() - 2); } - log.append(", "); - } - if (args.length > 0) { - log.setLength(log.length() - 2); } log.append(")"); Log.d(LOGTAG, log.toString()); From 6fb43f76304cebd2c44b676c60362aaabd15786d Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 29 Aug 2014 14:56:42 -0400 Subject: [PATCH 009/120] Bug 1058136 - Don't notify null text changes; r=cpeterson --- widget/android/nsWindow.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 9ef305188d47..4b2d2c38e3e3 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2134,18 +2134,25 @@ nsWindow::FlushIMEChanges() for (uint32_t i = 0; i < mIMETextChanges.Length(); i++) { IMEChange &change = mIMETextChanges[i]; - WidgetQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this); - InitEvent(event, nullptr); - event.InitForQueryTextContent(change.mStart, - change.mNewEnd - change.mStart); - DispatchEvent(&event); - if (!event.mSucceeded) - return; + if (change.mStart == change.mOldEnd && + change.mStart == change.mNewEnd) { + continue; + } - mozilla::widget::android::GeckoAppShell::NotifyIMEChange(event.mReply.mString, - change.mStart, - change.mOldEnd, - change.mNewEnd); + WidgetQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this); + + if (change.mNewEnd != change.mStart) { + InitEvent(event, nullptr); + event.InitForQueryTextContent(change.mStart, + change.mNewEnd - change.mStart); + DispatchEvent(&event); + if (!event.mSucceeded) + return; + } + + mozilla::widget::android::GeckoAppShell::NotifyIMEChange( + event.mReply.mString, change.mStart, + change.mOldEnd, change.mNewEnd); } mIMETextChanges.Clear(); From bb770dd68493039261a8863075580475a947dbf0 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 29 Aug 2014 14:56:42 -0400 Subject: [PATCH 010/120] Bug 1058136 - Send separate compose event for composing text; r=cpeterson --- mobile/android/base/GeckoEditable.java | 35 +++++++++++++++++-- mobile/android/base/GeckoEvent.java | 16 ++++++--- mobile/android/base/GeckoInputConnection.java | 2 +- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 38572e113b46..8f0a304d137f 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -67,7 +67,7 @@ interface GeckoEditableListener { void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint); void onSelectionChange(int start, int end); - void onTextChange(String text, int start, int oldEnd, int newEnd); + void onTextChange(CharSequence text, int start, int oldEnd, int newEnd); } /* @@ -131,6 +131,8 @@ final class GeckoEditable static final int TYPE_ACKNOWLEDGE_FOCUS = 5; // For switching handler; use with IME_SYNCHRONIZE static final int TYPE_SET_HANDLER = 6; + // For Editable.replace() call involving compositions; use with IME_COMPOSE_TEXT + static final int TYPE_COMPOSE_TEXT = 7; final int mType; int mStart; @@ -150,7 +152,22 @@ final class GeckoEditable throw new IllegalArgumentException( "invalid replace text offsets: " + start + " to " + end); } - final Action action = new Action(TYPE_REPLACE_TEXT); + + int actionType = TYPE_REPLACE_TEXT; + + if (text instanceof Spanned) { + final Spanned spanned = (Spanned) text; + final Object[] spans = spanned.getSpans(0, spanned.length(), Object.class); + + for (Object span : spans) { + if ((spanned.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) { + actionType = TYPE_COMPOSE_TEXT; + break; + } + } + } + + final Action action = new Action(actionType); action.mSequence = text; action.mStart = start; action.mEnd = end; @@ -240,6 +257,12 @@ final class GeckoEditable GeckoEvent.ImeAction.IME_SYNCHRONIZE)); break; + case Action.TYPE_COMPOSE_TEXT: + // Send different event for composing text. + GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEComposeEvent( + action.mStart, action.mEnd, action.mSequence.toString())); + return; + case Action.TYPE_REPLACE_TEXT: // try key events first sendCharKeyEvents(action); @@ -685,6 +708,12 @@ final class GeckoEditable getConstantName(Action.class, "TYPE_", action.mType) + ")"); } switch (action.mType) { + case Action.TYPE_COMPOSE_TEXT: + // Compositions don't trigger text change notification, so notify manually. + onTextChange(action.mSequence, action.mStart, action.mEnd, + action.mStart + action.mSequence.length()); + break; + case Action.TYPE_SET_SELECTION: final int len = mText.length(); final int curStart = Selection.getSelectionStart(mText); @@ -872,7 +901,7 @@ final class GeckoEditable } @Override - public void onTextChange(final String text, final int start, + public void onTextChange(final CharSequence text, final int start, final int unboundedOldEnd, final int unboundedNewEnd) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index e2c897230248..1ac15c391d86 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -147,7 +147,8 @@ public class GeckoEvent { IME_ADD_COMPOSITION_RANGE(3), IME_UPDATE_COMPOSITION(4), IME_REMOVE_COMPOSITION(5), - IME_ACKNOWLEDGE_FOCUS(6); + IME_ACKNOWLEDGE_FOCUS(6), + IME_COMPOSE_TEXT(7); public final int value; @@ -600,10 +601,17 @@ public class GeckoEvent { return event; } - public static GeckoEvent createIMEReplaceEvent(int start, int end, - String text) { + public static GeckoEvent createIMEReplaceEvent(int start, int end, String text) { + return createIMETextEvent(false, start, end, text); + } + + public static GeckoEvent createIMEComposeEvent(int start, int end, String text) { + return createIMETextEvent(true, start, end, text); + } + + private static GeckoEvent createIMETextEvent(boolean compose, int start, int end, String text) { GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); - event.mAction = ImeAction.IME_REPLACE_TEXT.value; + event.mAction = (compose ? ImeAction.IME_COMPOSE_TEXT : ImeAction.IME_REPLACE_TEXT).value; event.mStart = start; event.mEnd = end; event.mCharacters = text; diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index 3a434ba31b99..a6e56d4e854b 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -430,7 +430,7 @@ class GeckoInputConnection } @Override - public void onTextChange(String text, int start, int oldEnd, int newEnd) { + public void onTextChange(CharSequence text, int start, int oldEnd, int newEnd) { if (mUpdateRequest == null) { // Android always expects selection updates when not in extracted mode; From bb5ea3c2379d4f250ec269e3f4f6c9f93ce70afb Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 29 Aug 2014 14:56:43 -0400 Subject: [PATCH 011/120] Bug 1058136 - Handle compose event to optimize composition usage; r=cpeterson --- widget/android/AndroidJavaWrappers.cpp | 3 +- widget/android/AndroidJavaWrappers.h | 1 + widget/android/nsWindow.cpp | 151 +++++++++++++++++-------- widget/android/nsWindow.h | 3 +- 4 files changed, 108 insertions(+), 50 deletions(-) diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 688262ff11f9..244f24fce389 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -471,7 +471,8 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) mStart = jenv->GetIntField(jobj, jStartField); mEnd = jenv->GetIntField(jobj, jEndField); - if (mAction == IME_REPLACE_TEXT) { + if (mAction == IME_REPLACE_TEXT || + mAction == IME_COMPOSE_TEXT) { ReadCharactersField(jenv); } else if (mAction == IME_UPDATE_COMPOSITION || mAction == IME_ADD_COMPOSITION_RANGE) { diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index 63bb99fe9bf6..b1b9760cff15 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -744,6 +744,7 @@ public: IME_UPDATE_COMPOSITION = 4, IME_REMOVE_COMPOSITION = 5, IME_ACKNOWLEDGE_FOCUS = 6, + IME_COMPOSE_TEXT = 7, dummy_ime_enum_list_end }; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 4b2d2c38e3e3..e41546df7f1c 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -177,6 +177,7 @@ nsWindow::nsWindow() : mParent(nullptr), mFocus(nullptr), mIMEComposing(false), + mIMEComposingStart(-1), mIMEMaskSelectionUpdate(false), mIMEMaskTextUpdate(false), mIMEMaskEventsCount(1), // Mask IME events since there's no focus yet @@ -679,6 +680,7 @@ nsWindow::DispatchEvent(WidgetGUIEvent* aEvent) case NS_COMPOSITION_END: MOZ_ASSERT(mIMEComposing); mIMEComposing = false; + mIMEComposingStart = -1; mIMEComposingText.Truncate(); break; case NS_TEXT_TEXT: @@ -1710,6 +1712,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); return; + } else if (ae->Action() == AndroidGeckoEvent::IME_UPDATE_CONTEXT) { mozilla::widget::android::GeckoAppShell::NotifyIMEContext(mInputContext.mIMEState.mEnabled, mInputContext.mHTMLInputType, @@ -1718,27 +1721,33 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) mIMEUpdatingContext = false; return; } + if (mIMEMaskEventsCount > 0) { // Still reply to events, but don't do anything else if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE || + ae->Action() == AndroidGeckoEvent::IME_COMPOSE_TEXT || ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } return; } + switch (ae->Action()) { case AndroidGeckoEvent::IME_FLUSH_CHANGES: { FlushIMEChanges(); } break; + case AndroidGeckoEvent::IME_SYNCHRONIZE: { FlushIMEChanges(); mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } break; + case AndroidGeckoEvent::IME_REPLACE_TEXT: + case AndroidGeckoEvent::IME_COMPOSE_TEXT: { /* Replace text in Gecko thread from ae->Start() to ae->End() @@ -1751,31 +1760,48 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) Gecko text */ AutoIMEMask selMask(mIMEMaskSelectionUpdate); - RemoveIMEComposition(); - { - WidgetSelectionEvent event(true, NS_SELECTION_SET, this); - InitEvent(event, nullptr); - event.mOffset = uint32_t(ae->Start()); - event.mLength = uint32_t(ae->End() - ae->Start()); - event.mExpandToClusterBoundary = false; - DispatchEvent(&event); - } - if (!mIMEKeyEvents.IsEmpty()) { - for (uint32_t i = 0; i < mIMEKeyEvents.Length(); i++) { - OnKeyEvent(&mIMEKeyEvents[i]); + if (!mIMEKeyEvents.IsEmpty() || + mIMEComposingStart < 0 || + ae->Start() != mIMEComposingStart || + ae->End() != mIMEComposingStart + + int32_t(mIMEComposingText.Length())) { + + // Only start a new composition if we have key events, + // if we don't have an existing composition, or + // the replaced text does not match our composition. + RemoveIMEComposition(); + + { + WidgetSelectionEvent event(true, NS_SELECTION_SET, this); + InitEvent(event, nullptr); + event.mOffset = uint32_t(ae->Start()); + event.mLength = uint32_t(ae->End() - ae->Start()); + event.mExpandToClusterBoundary = false; + DispatchEvent(&event); + } + + if (!mIMEKeyEvents.IsEmpty()) { + for (uint32_t i = 0; i < mIMEKeyEvents.Length(); i++) { + OnKeyEvent(&mIMEKeyEvents[i]); + } + mIMEKeyEvents.Clear(); + FlushIMEChanges(); + mozilla::widget::android::GeckoAppShell::NotifyIME( + AndroidBridge::NOTIFY_IME_REPLY_EVENT); + // Break out of the switch block + break; + } + + { + WidgetCompositionEvent event( + true, NS_COMPOSITION_START, this); + InitEvent(event, nullptr); + DispatchEvent(&event); + mIMEComposingStart = ae->Start(); } - mIMEKeyEvents.Clear(); - FlushIMEChanges(); - mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); - break; } - { - WidgetCompositionEvent event(true, NS_COMPOSITION_START, this); - InitEvent(event, nullptr); - DispatchEvent(&event); - } { WidgetCompositionEvent event(true, NS_COMPOSITION_UPDATE, this); InitEvent(event, nullptr); @@ -1788,16 +1814,23 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) event.theText = ae->Characters(); DispatchEvent(&event); } + + // Don't end composition when composing text. + if (ae->Action() != AndroidGeckoEvent::IME_COMPOSE_TEXT) { WidgetCompositionEvent event(true, NS_COMPOSITION_END, this); InitEvent(event, nullptr); event.data = ae->Characters(); DispatchEvent(&event); + + FlushIMEChanges(); } - FlushIMEChanges(); - mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + + mozilla::widget::android::GeckoAppShell::NotifyIME( + AndroidBridge::NOTIFY_IME_REPLY_EVENT); } break; + case AndroidGeckoEvent::IME_SET_SELECTION: { /* @@ -1874,7 +1907,6 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) */ AutoIMEMask selMask(mIMEMaskSelectionUpdate); AutoIMEMask textMask(mIMEMaskTextUpdate); - RemoveIMEComposition(); WidgetTextEvent event(true, NS_TEXT_TEXT, this); InitEvent(event, nullptr); @@ -1882,28 +1914,49 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) event.mRanges = new TextRangeArray(); mIMERanges.swap(event.mRanges); - { - WidgetSelectionEvent event(true, NS_SELECTION_SET, this); - InitEvent(event, nullptr); - event.mOffset = uint32_t(ae->Start()); - event.mLength = uint32_t(ae->End() - ae->Start()); - event.mExpandToClusterBoundary = false; - DispatchEvent(&event); - } - { - WidgetQueryContentEvent queryEvent(true, - NS_QUERY_SELECTED_TEXT, - this); - InitEvent(queryEvent, nullptr); - DispatchEvent(&queryEvent); - MOZ_ASSERT(queryEvent.mSucceeded && !queryEvent.mWasAsync); - event.theText = queryEvent.mReply.mString; - } - { - WidgetCompositionEvent event(true, NS_COMPOSITION_START, this); - InitEvent(event, nullptr); - DispatchEvent(&event); + if (mIMEComposingStart < 0 || + ae->Start() != mIMEComposingStart || + ae->End() != mIMEComposingStart + + int32_t(mIMEComposingText.Length())) { + + // Only start new composition if we don't have an existing one, + // or if the existing composition doesn't match the new one. + RemoveIMEComposition(); + + { + WidgetSelectionEvent event(true, NS_SELECTION_SET, this); + InitEvent(event, nullptr); + event.mOffset = uint32_t(ae->Start()); + event.mLength = uint32_t(ae->End() - ae->Start()); + event.mExpandToClusterBoundary = false; + DispatchEvent(&event); + } + + { + WidgetQueryContentEvent queryEvent(true, + NS_QUERY_SELECTED_TEXT, + this); + InitEvent(queryEvent, nullptr); + DispatchEvent(&queryEvent); + MOZ_ASSERT(queryEvent.mSucceeded && !queryEvent.mWasAsync); + event.theText = queryEvent.mReply.mString; + + mIMEComposingStart = queryEvent.mReply.mOffset; + } + + { + WidgetCompositionEvent event( + true, NS_COMPOSITION_START, this); + InitEvent(event, nullptr); + DispatchEvent(&event); + } + + } else { + // If the new composition matches the existing composition, + // reuse the old composition. + event.theText = mIMEComposingText; } + { WidgetCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, @@ -1924,12 +1977,14 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) // Notify SelectionHandler of final caret position // Required in cases of keyboards providing autoCorrections - AndroidGeckoEvent* broadcastEvent = AndroidGeckoEvent::MakeBroadcastEvent( - NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"), - NS_LITERAL_CSTRING("")); + AndroidGeckoEvent* broadcastEvent = + AndroidGeckoEvent::MakeBroadcastEvent( + NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"), + NS_LITERAL_CSTRING("")); nsAppShell::gAppShell->PostEvent(broadcastEvent); } break; + case AndroidGeckoEvent::IME_REMOVE_COMPOSITION: { /* diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 7c80ddd29344..f5325973965c 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -188,9 +188,10 @@ protected: nsCOMPtr mIdleService; bool mIMEComposing; + int32_t mIMEComposingStart; + nsString mIMEComposingText; bool mIMEMaskSelectionUpdate, mIMEMaskTextUpdate; int32_t mIMEMaskEventsCount; // Mask events when > 0 - nsString mIMEComposingText; nsRefPtr mIMERanges; bool mIMEUpdatingContext; nsAutoTArray mIMEKeyEvents; From 552a1eafab82e37fe396b716995e989872de2c89 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Fri, 29 Aug 2014 12:09:51 -0700 Subject: [PATCH 012/120] Backout c5aae1b3dc3f (bug 1002632) for breaking animations in SVG-in-opentype fonts. --- image/src/SVGDocumentWrapper.cpp | 13 ------------- image/src/SVGDocumentWrapper.h | 1 - image/src/VectorImage.cpp | 3 +-- layout/base/nsRefreshDriver.cpp | 7 ------- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/image/src/SVGDocumentWrapper.cpp b/image/src/SVGDocumentWrapper.cpp index b7d086b243a8..b4c04e7ce506 100644 --- a/image/src/SVGDocumentWrapper.cpp +++ b/image/src/SVGDocumentWrapper.cpp @@ -218,19 +218,6 @@ SVGDocumentWrapper::SetCurrentTime(float aTime) } } -void -SVGDocumentWrapper::TickRefreshDriver() -{ - nsCOMPtr presShell; - mViewer->GetPresShell(getter_AddRefs(presShell)); - if (presShell) { - nsPresContext* presContext = presShell->GetPresContext(); - if (presContext) { - presContext->RefreshDriver()->DoTick(); - } - } -} - /** nsIStreamListener methods **/ /* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, diff --git a/image/src/SVGDocumentWrapper.h b/image/src/SVGDocumentWrapper.h index 4904592b0eed..425036b1ccaa 100644 --- a/image/src/SVGDocumentWrapper.h +++ b/image/src/SVGDocumentWrapper.h @@ -137,7 +137,6 @@ public: void ResetAnimation(); float GetCurrentTime(); void SetCurrentTime(float aTime); - void TickRefreshDriver(); /** * Force a layout flush of the underlying SVG document. diff --git a/image/src/VectorImage.cpp b/image/src/VectorImage.cpp index 45cf49f310dd..d36252bdb39a 100644 --- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -540,10 +540,9 @@ VectorImage::RequestRefresh(const TimeStamp& aTime) return; } + // TODO: Implement for b666446. EvaluateAnimation(); - mSVGDocumentWrapper->TickRefreshDriver(); - if (mHasPendingInvalidation) { SendInvalidationNotifications(); mHasPendingInvalidation = false; diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 3bf8b02d718a..18ecc5085f80 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -856,13 +856,6 @@ nsRefreshDriver::EnsureTimerStarted(bool aAdjustingTimer) return; } - if (mPresContext->Document()->IsBeingUsedAsImage()) { - // Image documents receive ticks from clients' refresh drivers. - MOZ_ASSERT(!mActiveTimer, - "image document refresh driver should never have its own timer"); - return; - } - // We got here because we're either adjusting the time *or* we're // starting it for the first time. Add to the right timer, // prehaps removing it from a previously-set one. From bbf77ff477a6ccebd644614a41cbbe4b3077fbcd Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Fri, 29 Aug 2014 11:23:31 -0700 Subject: [PATCH 013/120] Bug 1052740 - Cancel LazyIdleThread timer before shutting down its thread, r=bsmedberg. --- xpcom/threads/LazyIdleThread.cpp | 37 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index b1aba02c7d46..518bf0b6ea3a 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -229,14 +229,16 @@ LazyIdleThread::ScheduleTimer() shouldSchedule = !mIdleNotificationCount && !mPendingEventCount; } - if (NS_FAILED(mIdleTimer->Cancel())) { - NS_WARNING("Failed to cancel timer!"); - } + if (mIdleTimer) { + if (NS_FAILED(mIdleTimer->Cancel())) { + NS_WARNING("Failed to cancel timer!"); + } - if (shouldSchedule && - NS_FAILED(mIdleTimer->InitWithCallback(this, mIdleTimeoutMS, - nsITimer::TYPE_ONE_SHOT))) { - NS_WARNING("Failed to schedule timer!"); + if (shouldSchedule && + NS_FAILED(mIdleTimer->InitWithCallback(this, mIdleTimeoutMS, + nsITimer::TYPE_ONE_SHOT))) { + NS_WARNING("Failed to schedule timer!"); + } } } @@ -252,6 +254,18 @@ LazyIdleThread::ShutdownThread() nsresult rv; + // Make sure to cancel the shutdown timer before spinning the event loop + // during |mThread->Shutdown()| below. Otherwise the timer might fire and we + // could reenter here. + if (mIdleTimer) { + rv = mIdleTimer->Cancel(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mIdleTimer = nullptr; + } + if (mThread) { if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) { nsCOMPtr obs = @@ -311,15 +325,6 @@ LazyIdleThread::ShutdownThread() } } - if (mIdleTimer) { - rv = mIdleTimer->Cancel(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - mIdleTimer = nullptr; - } - // If our temporary queue has any runnables then we need to dispatch them. if (queuedRunnables.Length()) { // If the thread manager has gone away then these runnables will never run. From 1c56da8a408a04e77e4048ac0b9045f295a62c99 Mon Sep 17 00:00:00 2001 From: Neil Rashbrook Date: Fri, 29 Aug 2014 20:33:16 +0100 Subject: [PATCH 014/120] Bug 1059707 Don't print a deprecation warning for theme XBL binding documents r=smaug --- content/xul/content/src/nsXULElement.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index c2cf661dc331..7511f1a0bda1 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -828,6 +828,7 @@ nsXULElement::BindToTree(nsIDocument* aDocument, { if (!aBindingParent && aDocument && + !aDocument->IsLoadedAsInteractiveData() && !aDocument->AllowXULXBL() && !aDocument->HasWarnedAbout(nsIDocument::eImportXULIntoContent)) { nsContentUtils::AddScriptRunner(new XULInContentErrorReporter(aDocument)); From a0446d2a55b261e15f90c73e2b664f1f1500921b Mon Sep 17 00:00:00 2001 From: Neil Rashbrook Date: Fri, 29 Aug 2014 20:34:35 +0100 Subject: [PATCH 015/120] Bug 1054289 Scroll to the current ref, not the original one r=smaug --- content/base/src/nsContentSink.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index c71773177bc2..56094da2fe3f 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -1177,7 +1177,7 @@ nsContentSink::StartLayout(bool aIgnorePendingSheets) // If the document we are loading has a reference or it is a // frameset document, disable the scroll bars on the views. - mDocument->SetScrollToRef(mDocumentURI); + mDocument->SetScrollToRef(mDocument->GetDocumentURI()); } void From 516c8a2d2a7c46e0ea7b6fe98d0bf57eff9dd28b Mon Sep 17 00:00:00 2001 From: Neil Rashbrook Date: Fri, 29 Aug 2014 20:35:00 +0100 Subject: [PATCH 016/120] Test for bug 1054289 r=smaug --HG-- rename : layout/reftests/scrolling/deferred-anchor-ref.xhtml => layout/reftests/scrolling/iframe-deferred-anchor.xhtml --- layout/reftests/scrolling/deferred-anchor2.xhtml | 8 ++++++++ .../reftests/scrolling/iframe-deferred-anchor.xhtml | 13 +++++++++++++ layout/reftests/scrolling/reftest.list | 1 + 3 files changed, 22 insertions(+) create mode 100644 layout/reftests/scrolling/deferred-anchor2.xhtml create mode 100644 layout/reftests/scrolling/iframe-deferred-anchor.xhtml diff --git a/layout/reftests/scrolling/deferred-anchor2.xhtml b/layout/reftests/scrolling/deferred-anchor2.xhtml new file mode 100644 index 000000000000..77e9bbedc2c8 --- /dev/null +++ b/layout/reftests/scrolling/deferred-anchor2.xhtml @@ -0,0 +1,8 @@ + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/mochi-wrapper.css b/dom/canvas/test/webgl-conformance/mochi-wrapper.css new file mode 100644 index 000000000000..8bad5495ddd5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/mochi-wrapper.css @@ -0,0 +1,8 @@ +iframe { + position:fixed; + top:0px; left:0px; bottom:0px; right:0px; + width:100%; height:100%; + border:none; margin:0; padding:0; + overflow:hidden; + z-index:999999; +} diff --git a/dom/canvas/test/webgl-conformance/mochi-wrapper.html.template b/dom/canvas/test/webgl-conformance/mochi-wrapper.html.template new file mode 100644 index 000000000000..16266d593d3c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/mochi-wrapper.html.template @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/mochitest.ini.template b/dom/canvas/test/webgl-conformance/mochitest.ini.template new file mode 100644 index 000000000000..c6d478aba0d8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/mochitest.ini.template @@ -0,0 +1,7 @@ +[DEFAULT] +skip-if = e10s +support-files = mochi-single.html + mochi-wrapper.css + %%SUPPORT_FILES%% + +%%MANIFEST_TESTS%% diff --git a/dom/canvas/test/webgl-conformance/moz.build b/dom/canvas/test/webgl-conformance/moz.build index fbe0963eb577..f08dc12c2a21 100644 --- a/dom/canvas/test/webgl-conformance/moz.build +++ b/dom/canvas/test/webgl-conformance/moz.build @@ -5,6 +5,5 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. MOCHITEST_MANIFESTS += [ - 'mochitest-conformance-files.ini', - 'mochitest.ini', + '_mochitest.ini', ] From 921593d77045220d1881fae98329b57f558b1e9f Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 17:31:39 -0700 Subject: [PATCH 050/120] Bug 1052240 - Generate mochi-wrapper files. - r=kamidphish --- .../test/webgl-conformance/_mochitest.ini | 816 ++++++++++++++++++ ...nce__attribs__gl-enable-vertex-attrib.html | 16 + ...attribs__gl-vertex-attrib-zero-issues.html | 16 + ...onformance__attribs__gl-vertex-attrib.html | 16 + ...tribs__gl-vertexattribpointer-offsets.html | 16 + ...ance__attribs__gl-vertexattribpointer.html | 16 + ...onformance__buffers__buffer-bind-test.html | 16 + ...ce__buffers__buffer-data-array-buffer.html | 16 + ...fers__index-validation-copies-indices.html | 16 + ...validation-crash-with-buffer-sub-data.html | 16 + ...-validation-verifies-too-many-indices.html | 16 + ..._index-validation-with-resized-buffer.html | 16 + ...onformance__buffers__index-validation.html | 16 + ...rmance__canvas__buffer-offscreen-test.html | 16 + ...ormance__canvas__buffer-preserve-test.html | 16 + ...test_conformance__canvas__canvas-test.html | 16 + ...conformance__canvas__canvas-zero-size.html | 16 + ...vas__drawingbuffer-static-canvas-test.html | 16 + ...nformance__canvas__drawingbuffer-test.html | 16 + ...anvas__viewport-unchanged-upon-resize.html | 16 + .../test_conformance__context__constants.html | 16 + ...ributes-alpha-depth-stencil-antialias.html | 16 + ...mance__context__context-lost-restored.html | 16 + ...st_conformance__context__context-lost.html | 16 + ...nformance__context__context-type-test.html | 16 + ...t__incorrect-context-object-behaviour.html | 16 + .../test_conformance__context__methods.html | 16 + ...mance__context__premultiplyalpha-test.html | 16 + ...mance__context__resource-sharing-test.html | 16 + ...est_conformance__extensions__ext-sRGB.html | 16 + ...e__extensions__ext-shader-texture-lod.html | 16 + ...sions__ext-texture-filter-anisotropic.html | 16 + ..._extensions__oes-standard-derivatives.html | 16 + ...rmance__extensions__oes-texture-float.html | 16 + ...__extensions__oes-vertex-array-object.html | 16 + ...nsions__webgl-compressed-texture-etc1.html | 16 + ...nsions__webgl-compressed-texture-s3tc.html | 16 + ...extensions__webgl-debug-renderer-info.html | 16 + ...ance__extensions__webgl-debug-shaders.html | 16 + ...e__glsl__functions__glsl-function-abs.html | 16 + ...__glsl__functions__glsl-function-acos.html | 16 + ...__glsl__functions__glsl-function-asin.html | 16 + ...lsl__functions__glsl-function-atan-xy.html | 16 + ...__glsl__functions__glsl-function-atan.html | 16 + ...__glsl__functions__glsl-function-ceil.html | 16 + ..._functions__glsl-function-clamp-float.html | 16 + ...unctions__glsl-function-clamp-gentype.html | 16 + ...e__glsl__functions__glsl-function-cos.html | 16 + ..._glsl__functions__glsl-function-cross.html | 16 + ...sl__functions__glsl-function-distance.html | 16 + ...e__glsl__functions__glsl-function-dot.html | 16 + ..._functions__glsl-function-faceforward.html | 16 + ..._glsl__functions__glsl-function-floor.html | 16 + ..._glsl__functions__glsl-function-fract.html | 16 + ...glsl__functions__glsl-function-length.html | 16 + ...l__functions__glsl-function-max-float.html | 16 + ..._functions__glsl-function-max-gentype.html | 16 + ...l__functions__glsl-function-min-float.html | 16 + ..._functions__glsl-function-min-gentype.html | 16 + ...l__functions__glsl-function-mix-float.html | 16 + ..._functions__glsl-function-mix-gentype.html | 16 + ...l__functions__glsl-function-mod-float.html | 16 + ..._functions__glsl-function-mod-gentype.html | 16 + ...l__functions__glsl-function-normalize.html | 16 + ...lsl__functions__glsl-function-reflect.html | 16 + ...__glsl__functions__glsl-function-sign.html | 16 + ...e__glsl__functions__glsl-function-sin.html | 16 + ...tions__glsl-function-smoothstep-float.html | 16 + ...ons__glsl-function-smoothstep-gentype.html | 16 + ...__functions__glsl-function-step-float.html | 16 + ...functions__glsl-function-step-gentype.html | 16 + ...mance__glsl__functions__glsl-function.html | 16 + ...e__glsl__implicit__add_int_float.vert.html | 16 + ...ce__glsl__implicit__add_int_mat2.vert.html | 16 + ...ce__glsl__implicit__add_int_mat3.vert.html | 16 + ...ce__glsl__implicit__add_int_mat4.vert.html | 16 + ...ce__glsl__implicit__add_int_vec2.vert.html | 16 + ...ce__glsl__implicit__add_int_vec3.vert.html | 16 + ...ce__glsl__implicit__add_int_vec4.vert.html | 16 + ...__glsl__implicit__add_ivec2_vec2.vert.html | 16 + ...__glsl__implicit__add_ivec3_vec3.vert.html | 16 + ...__glsl__implicit__add_ivec4_vec4.vert.html | 16 + ...l__implicit__assign_int_to_float.vert.html | 16 + ...__implicit__assign_ivec2_to_vec2.vert.html | 16 + ...__implicit__assign_ivec3_to_vec3.vert.html | 16 + ...__implicit__assign_ivec4_to_vec4.vert.html | 16 + ...glsl__implicit__construct_struct.vert.html | 16 + ...glsl__implicit__divide_int_float.vert.html | 16 + ..._glsl__implicit__divide_int_mat2.vert.html | 16 + ..._glsl__implicit__divide_int_mat3.vert.html | 16 + ..._glsl__implicit__divide_int_mat4.vert.html | 16 + ..._glsl__implicit__divide_int_vec2.vert.html | 16 + ..._glsl__implicit__divide_int_vec3.vert.html | 16 + ..._glsl__implicit__divide_int_vec4.vert.html | 16 + ...lsl__implicit__divide_ivec2_vec2.vert.html | 16 + ...lsl__implicit__divide_ivec3_vec3.vert.html | 16 + ...lsl__implicit__divide_ivec4_vec4.vert.html | 16 + ..._glsl__implicit__equal_int_float.vert.html | 16 + ...glsl__implicit__equal_ivec2_vec2.vert.html | 16 + ...glsl__implicit__equal_ivec3_vec3.vert.html | 16 + ...glsl__implicit__equal_ivec4_vec4.vert.html | 16 + ...sl__implicit__function_int_float.vert.html | 16 + ...l__implicit__function_ivec2_vec2.vert.html | 16 + ...l__implicit__function_ivec3_vec3.vert.html | 16 + ...l__implicit__function_ivec4_vec4.vert.html | 16 + ...ce__glsl__implicit__greater_than.vert.html | 16 + ...sl__implicit__greater_than_equal.vert.html | 16 + ...mance__glsl__implicit__less_than.vert.html | 16 + ..._glsl__implicit__less_than_equal.vert.html | 16 + ...sl__implicit__multiply_int_float.vert.html | 16 + ...lsl__implicit__multiply_int_mat2.vert.html | 16 + ...lsl__implicit__multiply_int_mat3.vert.html | 16 + ...lsl__implicit__multiply_int_mat4.vert.html | 16 + ...lsl__implicit__multiply_int_vec2.vert.html | 16 + ...lsl__implicit__multiply_int_vec3.vert.html | 16 + ...lsl__implicit__multiply_int_vec4.vert.html | 16 + ...l__implicit__multiply_ivec2_vec2.vert.html | 16 + ...l__implicit__multiply_ivec3_vec3.vert.html | 16 + ...l__implicit__multiply_ivec4_vec4.vert.html | 16 + ...l__implicit__not_equal_int_float.vert.html | 16 + ...__implicit__not_equal_ivec2_vec2.vert.html | 16 + ...__implicit__not_equal_ivec3_vec3.vert.html | 16 + ...__implicit__not_equal_ivec4_vec4.vert.html | 16 + ...sl__implicit__subtract_int_float.vert.html | 16 + ...lsl__implicit__subtract_int_mat2.vert.html | 16 + ...lsl__implicit__subtract_int_mat3.vert.html | 16 + ...lsl__implicit__subtract_int_mat4.vert.html | 16 + ...lsl__implicit__subtract_int_vec2.vert.html | 16 + ...lsl__implicit__subtract_int_vec3.vert.html | 16 + ...lsl__implicit__subtract_int_vec4.vert.html | 16 + ...l__implicit__subtract_ivec2_vec2.vert.html | 16 + ...l__implicit__subtract_ivec3_vec3.vert.html | 16 + ...l__implicit__subtract_ivec4_vec4.vert.html | 16 + ...lsl__implicit__ternary_int_float.vert.html | 16 + ...sl__implicit__ternary_ivec2_vec2.vert.html | 16 + ...sl__implicit__ternary_ivec3_vec3.vert.html | 16 + ...sl__implicit__ternary_ivec4_vec4.vert.html | 16 + ...__misc__attrib-location-length-limits.html | 16 + ...embedded-struct-definitions-forbidden.html | 16 + ...ance__glsl__misc__glsl-function-nodes.html | 16 + ..._glsl__misc__glsl-long-variable-names.html | 16 + ...__glsl__misc__non-ascii-comments.vert.html | 16 + ...nformance__glsl__misc__non-ascii.vert.html | 16 + ...er-with-256-character-identifier.frag.html | 16 + ...er-with-257-character-identifier.frag.html | 16 + ...c__shader-with-_webgl-identifier.vert.html | 16 + ...__shader-with-arbitrary-indexing.frag.html | 16 + ...__shader-with-arbitrary-indexing.vert.html | 16 + ...__misc__shader-with-attrib-array.vert.html | 16 + ..._misc__shader-with-attrib-struct.vert.html | 16 + ...sl__misc__shader-with-clipvertex.vert.html | 16 + ...c__shader-with-default-precision.frag.html | 16 + ...c__shader-with-default-precision.vert.html | 16 + ...er-with-define-line-continuation.frag.html | 16 + ...l__misc__shader-with-dfdx-no-ext.frag.html | 16 + ...ce__glsl__misc__shader-with-dfdx.frag.html | 16 + ...sl__misc__shader-with-error-directive.html | 16 + ...c__shader-with-explicit-int-cast.vert.html | 16 + ...__shader-with-float-return-value.frag.html | 16 + ...sl__misc__shader-with-frag-depth.frag.html | 16 + ...__shader-with-function-recursion.frag.html | 16 + ..._glsl__misc__shader-with-glcolor.vert.html | 16 + ...__glsl__misc__shader-with-gles-1.frag.html | 16 + ...l__misc__shader-with-gles-symbol.frag.html | 16 + ...__shader-with-glprojectionmatrix.vert.html | 16 + ...-with-implicit-vec3-to-vec4-cast.vert.html | 16 + ..._glsl__misc__shader-with-include.vert.html | 16 + ...sc__shader-with-int-return-value.frag.html | 16 + ...__shader-with-invalid-identifier.frag.html | 16 + ...__shader-with-ivec2-return-value.frag.html | 16 + ...__shader-with-ivec3-return-value.frag.html | 16 + ...__shader-with-ivec4-return-value.frag.html | 16 + ...sc__shader-with-limited-indexing.frag.html | 16 + ...ce__glsl__misc__shader-with-long-line.html | 16 + ...isc__shader-with-non-ascii-error.frag.html | 16 + ...lsl__misc__shader-with-precision.frag.html | 16 + ...__misc__shader-with-quoted-error.frag.html | 16 + ...th-undefined-preprocessor-symbol.frag.html | 16 + ...r-with-uniform-in-loop-condition.vert.html | 16 + ...c__shader-with-vec2-return-value.frag.html | 16 + ...c__shader-with-vec3-return-value.frag.html | 16 + ...c__shader-with-vec4-return-value.frag.html | 16 + ...l__misc__shader-with-version-100.frag.html | 16 + ...l__misc__shader-with-version-100.vert.html | 16 + ...l__misc__shader-with-version-120.vert.html | 16 + ...l__misc__shader-with-version-130.vert.html | 16 + ...sc__shader-with-webgl-identifier.vert.html | 16 + ...__misc__shader-without-precision.frag.html | 16 + .../test_conformance__glsl__misc__shared.html | 16 + ..._misc__struct-nesting-exceeds-maximum.html | 16 + ...l__misc__struct-nesting-under-maximum.html | 16 + ..._misc__uniform-location-length-limits.html | 16 + ...ce__glsl__reserved___webgl_field.vert.html | 16 + ..._glsl__reserved___webgl_function.vert.html | 16 + ...e__glsl__reserved___webgl_struct.vert.html | 16 + ..._glsl__reserved___webgl_variable.vert.html | 16 + ...nce__glsl__reserved__webgl_field.vert.html | 16 + ...__glsl__reserved__webgl_function.vert.html | 16 + ...ce__glsl__reserved__webgl_struct.vert.html | 16 + ...__glsl__reserved__webgl_variable.vert.html | 16 + ...rmance__glsl__variables__gl-fragcoord.html | 16 + ...ance__glsl__variables__gl-frontfacing.html | 16 + ...mance__glsl__variables__gl-pointcoord.html | 16 + ...ce__limits__gl-max-texture-dimensions.html | 16 + ...t_conformance__limits__gl-min-attribs.html | 16 + ..._conformance__limits__gl-min-textures.html | 16 + ..._conformance__limits__gl-min-uniforms.html | 16 + ...conformance__misc__bad-arguments-test.html | 16 + ...st_conformance__misc__error-reporting.html | 16 + ...ce__misc__functions-returning-strings.html | 16 + ...st_conformance__misc__instanceof-test.html | 16 + ...formance__misc__invalid-passed-params.html | 16 + .../test_conformance__misc__is-object.html | 16 + ...formance__misc__null-object-behaviour.html | 16 + ...ance__misc__object-deletion-behaviour.html | 16 + ...rmance__misc__shader-precision-format.html | 16 + ...nformance__misc__type-conversion-test.html | 16 + ...conformance__misc__uninitialized-test.html | 16 + ...est_conformance__misc__webgl-specific.html | 16 + ...ormance__more__conformance__constants.html | 16 + ...rmance__more__conformance__getContext.html | 16 + ...nformance__more__conformance__methods.html | 16 + ...e__more__conformance__quickCheckAPI-A.html | 16 + ...__more__conformance__quickCheckAPI-B1.html | 16 + ...__more__conformance__quickCheckAPI-B2.html | 16 + ...__more__conformance__quickCheckAPI-B3.html | 16 + ...__more__conformance__quickCheckAPI-B4.html | 16 + ...e__more__conformance__quickCheckAPI-C.html | 16 + ..._more__conformance__quickCheckAPI-D_G.html | 16 + ..._more__conformance__quickCheckAPI-G_I.html | 16 + ..._more__conformance__quickCheckAPI-L_S.html | 16 + ..._more__conformance__quickCheckAPI-S_V.html | 16 + ...mance__more__conformance__webGLArrays.html | 16 + ...formance__more__functions__bindBuffer.html | 16 + ...e__more__functions__bindBufferBadArgs.html | 16 + ...unctions__bindFramebufferLeaveNonZero.html | 16 + ...formance__more__functions__bufferData.html | 16 + ...e__more__functions__bufferDataBadArgs.html | 16 + ...mance__more__functions__bufferSubData.html | 16 + ...more__functions__bufferSubDataBadArgs.html | 16 + ...ance__more__functions__copyTexImage2D.html | 16 + ...ore__functions__copyTexImage2DBadArgs.html | 16 + ...e__more__functions__copyTexSubImage2D.html | 16 + ...__functions__copyTexSubImage2DBadArgs.html | 16 + ..._more__functions__deleteBufferBadArgs.html | 16 + ...formance__more__functions__drawArrays.html | 16 + ...ore__functions__drawArraysOutOfBounds.html | 16 + ...rmance__more__functions__drawElements.html | 16 + ..._more__functions__drawElementsBadArgs.html | 16 + ...conformance__more__functions__isTests.html | 16 + ...formance__more__functions__readPixels.html | 16 + ...e__more__functions__readPixelsBadArgs.html | 16 + ...formance__more__functions__texImage2D.html | 16 + ...e__more__functions__texImage2DBadArgs.html | 16 + ...ance__more__functions__texImage2DHTML.html | 16 + ...ore__functions__texImage2DHTMLBadArgs.html | 16 + ...mance__more__functions__texSubImage2D.html | 16 + ...more__functions__texSubImage2DBadArgs.html | 16 + ...e__more__functions__texSubImage2DHTML.html | 16 + ...__functions__texSubImage2DHTMLBadArgs.html | 16 + ...mance__more__functions__uniformMatrix.html | 16 + ...more__functions__uniformMatrixBadArgs.html | 16 + ...onformance__more__functions__uniformf.html | 16 + ...e__more__functions__uniformfArrayLen1.html | 16 + ...nce__more__functions__uniformfBadArgs.html | 16 + ...onformance__more__functions__uniformi.html | 16 + ...nce__more__functions__uniformiBadArgs.html | 16 + ...rmance__more__functions__vertexAttrib.html | 16 + ..._more__functions__vertexAttribBadArgs.html | 16 + ..._more__functions__vertexAttribPointer.html | 16 + ...functions__vertexAttribPointerBadArgs.html | 16 + ...ormance__more__glsl__arrayOutOfBounds.html | 16 + ...mance__more__glsl__uniformOutOfBounds.html | 16 + ...onformance__programs__get-active-test.html | 16 + ...rograms__gl-bind-attrib-location-test.html | 16 + ...ce__programs__gl-get-active-attribute.html | 16 + ...ance__programs__gl-get-active-uniform.html | 16 + ...ormance__programs__gl-getshadersource.html | 16 + ...conformance__programs__gl-shader-test.html | 16 + ...conformance__programs__invalid-UTF-16.html | 16 + ...t_conformance__programs__program-test.html | 16 + ...__reading__read-pixels-pack-alignment.html | 16 + ...onformance__reading__read-pixels-test.html | 16 + ...uffers__framebuffer-object-attachment.html | 16 + ...ance__renderbuffers__framebuffer-test.html | 16 + ...rbuffers__renderbuffer-initialization.html | 16 + ..._rendering__draw-arrays-out-of-bounds.html | 16 + ...endering__draw-elements-out-of-bounds.html | 16 + ...test_conformance__rendering__gl-clear.html | 16 + ...nformance__rendering__gl-drawelements.html | 16 + ...nformance__rendering__gl-scissor-test.html | 16 + ...ormance__rendering__line-loop-tri-fan.html | 16 + ...e__rendering__more-than-65536-indices.html | 16 + ...st_conformance__rendering__point-size.html | 16 + ...test_conformance__rendering__triangle.html | 16 + ...nformance__state__gl-enable-enum-test.html | 16 + ...est_conformance__state__gl-enum-tests.html | 16 + ...test_conformance__state__gl-get-calls.html | 16 + .../test_conformance__state__gl-geterror.html | 16 + ...test_conformance__state__gl-getstring.html | 16 + ...nformance__state__gl-object-get-calls.html | 16 + ...mance__textures__compressed-tex-image.html | 16 + ...ures__copy-tex-image-and-sub-image-2d.html | 16 + ...conformance__textures__gl-pixelstorei.html | 16 + ...st_conformance__textures__gl-teximage.html | 16 + ...e__textures__origin-clean-conformance.html | 16 + ...d-sub-image-2d-with-array-buffer-view.html | 16 + ...ex-image-and-sub-image-2d-with-canvas.html | 16 + ...mage-and-sub-image-2d-with-image-data.html | 16 + ...tex-image-and-sub-image-2d-with-image.html | 16 + ...tex-image-and-sub-image-2d-with-video.html | 16 + ...s__tex-image-and-uniform-binding-bugs.html | 16 + ...tures__tex-image-with-format-and-type.html | 16 + ...textures__tex-image-with-invalid-data.html | 16 + ...mance__textures__tex-input-validation.html | 16 + ...__textures__tex-sub-image-2d-bad-args.html | 16 + ...nformance__textures__tex-sub-image-2d.html | 16 + ...formance__textures__texparameter-test.html | 16 + ...ance__textures__texture-active-bind-2.html | 16 + ...rmance__textures__texture-active-bind.html | 16 + ...nformance__textures__texture-complete.html | 16 + ...mance__textures__texture-formats-test.html | 16 + ...t_conformance__textures__texture-mips.html | 16 + ...ormance__textures__texture-npot-video.html | 16 + ...t_conformance__textures__texture-npot.html | 16 + ...nce__textures__texture-size-cube-maps.html | 16 + ...t_conformance__textures__texture-size.html | 16 + ...exture-transparent-pixels-initialized.html | 16 + ...ance__typedarrays__array-buffer-crash.html | 16 + ..._typedarrays__array-buffer-view-crash.html | 16 + ...rmance__typedarrays__array-unit-tests.html | 16 + ...formance__uniforms__gl-uniform-arrays.html | 16 + ...onformance__uniforms__gl-uniform-bool.html | 16 + ...rmance__uniforms__gl-uniformmatrix4fv.html | 16 + ...ormance__uniforms__gl-unknown-uniform.html | 16 + ...ance__uniforms__null-uniform-location.html | 16 + ...nformance__uniforms__uniform-location.html | 16 + ...ance__uniforms__uniform-samplers-test.html | 16 + 338 files changed, 6208 insertions(+) create mode 100644 dom/canvas/test/webgl-conformance/_mochitest.ini create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer-offsets.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-bind-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-data-array-buffer.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-copies-indices.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-offscreen-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-preserve-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-zero-size.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__constants.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost-restored.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-type-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__incorrect-context-object-behaviour.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__methods.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__premultiplyalpha-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__resource-sharing-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-standard-derivatives.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-texture-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-vertex-array-object.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-abs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-acos.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-asin.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan-xy.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-ceil.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cos.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cross.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-distance.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-dot.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-faceforward.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-floor.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-fract.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-length.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-normalize.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-reflect.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sign.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sin.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-float.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-gentype.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_int_to_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec2_to_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec3_to_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec4_to_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__construct_struct.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than_equal.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than_equal.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_int_float.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec2_vec2.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec3_vec3.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec4_vec4.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__attrib-location-length-limits.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__embedded-struct-definitions-forbidden.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-function-nodes.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-long-variable-names.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii-comments.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-array.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-struct.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-clipvertex.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-define-line-continuation.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx-no-ext.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-error-directive.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-explicit-int-cast.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-float-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-frag-depth.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-function-recursion.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glcolor.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-1.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-symbol.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glprojectionmatrix.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-implicit-vec3-to-vec4-cast.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-include.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-int-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-invalid-identifier.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec2-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec3-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec4-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-limited-indexing.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-long-line.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-non-ascii-error.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-precision.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-quoted-error.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-undefined-preprocessor-symbol.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-uniform-in-loop-condition.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec2-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec3-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec4-return-value.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-120.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-130.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-without-precision.frag.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shared.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-under-maximum.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__uniform-location-length-limits.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_field.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_function.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_struct.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_variable.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_field.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_function.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_struct.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_variable.vert.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-fragcoord.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-frontfacing.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-pointcoord.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-max-texture-dimensions.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-attribs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-textures.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-uniforms.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__bad-arguments-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__error-reporting.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__functions-returning-strings.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__instanceof-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__invalid-passed-params.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__is-object.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__null-object-behaviour.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__object-deletion-behaviour.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__shader-precision-format.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__type-conversion-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__uninitialized-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__webgl-specific.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__constants.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__getContext.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__methods.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-A.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B1.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B2.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B3.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B4.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-C.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-D_G.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-G_I.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-L_S.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-S_V.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__webGLArrays.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBuffer.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBufferBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindFramebufferLeaveNonZero.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferData.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferDataBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubData.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubDataBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2D.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2DBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2D.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2DBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__deleteBufferBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArrays.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArraysOutOfBounds.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElements.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElementsBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__isTests.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixels.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixelsBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2D.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTML.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTMLBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2D.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTML.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTMLBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrix.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrixBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformf.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfArrayLen1.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformi.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformiBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttrib.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointer.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointerBadArgs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__arrayOutOfBounds.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__uniformOutOfBounds.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__get-active-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-attribute.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-uniform.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-getshadersource.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-shader-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__invalid-UTF-16.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__program-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-pack-alignment.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-clear.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-drawelements.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-scissor-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__line-loop-tri-fan.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__more-than-65536-indices.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__point-size.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__triangle.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enable-enum-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enum-tests.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-get-calls.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-geterror.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-getstring.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-object-get-calls.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__compressed-tex-image.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-pixelstorei.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-teximage.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__origin-clean-conformance.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-format-and-type.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-invalid-data.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-input-validation.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texparameter-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind-2.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-complete.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size-cube-maps.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-crash.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-unit-tests.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-arrays.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-bool.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniformmatrix4fv.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-unknown-uniform.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__null-uniform-location.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-location.html create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-samplers-test.html diff --git a/dom/canvas/test/webgl-conformance/_mochitest.ini b/dom/canvas/test/webgl-conformance/_mochitest.ini new file mode 100644 index 000000000000..5029548bb667 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_mochitest.ini @@ -0,0 +1,816 @@ +[DEFAULT] +skip-if = e10s +support-files = mochi-single.html + mochi-wrapper.css + conformance/00_readme.txt + conformance/00_test_list.txt + conformance/LICENSE_CHROMIUM + conformance/attribs/00_test_list.txt + conformance/attribs/gl-enable-vertex-attrib.html + conformance/attribs/gl-vertex-attrib-zero-issues.html + conformance/attribs/gl-vertex-attrib.html + conformance/attribs/gl-vertexattribpointer-offsets.html + conformance/attribs/gl-vertexattribpointer.html + conformance/buffers/00_test_list.txt + conformance/buffers/buffer-bind-test.html + conformance/buffers/buffer-data-array-buffer.html + conformance/buffers/index-validation-copies-indices.html + conformance/buffers/index-validation-crash-with-buffer-sub-data.html + conformance/buffers/index-validation-verifies-too-many-indices.html + conformance/buffers/index-validation-with-resized-buffer.html + conformance/buffers/index-validation.html + conformance/canvas/00_test_list.txt + conformance/canvas/buffer-offscreen-test.html + conformance/canvas/buffer-preserve-test.html + conformance/canvas/canvas-test.html + conformance/canvas/canvas-zero-size.html + conformance/canvas/drawingbuffer-static-canvas-test.html + conformance/canvas/drawingbuffer-test.html + conformance/canvas/viewport-unchanged-upon-resize.html + conformance/context/00_test_list.txt + conformance/context/constants.html + conformance/context/context-attribute-preserve-drawing-buffer.html + conformance/context/context-attributes-alpha-depth-stencil-antialias.html + conformance/context/context-lost-restored.html + conformance/context/context-lost.html + conformance/context/context-type-test.html + conformance/context/incorrect-context-object-behaviour.html + conformance/context/methods.html + conformance/context/premultiplyalpha-test.html + conformance/context/resource-sharing-test.html + conformance/extensions/00_test_list.txt + conformance/extensions/ext-sRGB.html + conformance/extensions/ext-shader-texture-lod.html + conformance/extensions/ext-texture-filter-anisotropic.html + conformance/extensions/oes-standard-derivatives.html + conformance/extensions/oes-texture-float.html + conformance/extensions/oes-vertex-array-object.html + conformance/extensions/webgl-compressed-texture-etc1.html + conformance/extensions/webgl-compressed-texture-s3tc.html + conformance/extensions/webgl-debug-renderer-info.html + conformance/extensions/webgl-debug-shaders.html + conformance/extensions/webgl-depth-texture.html + conformance/glsl/00_test_list.txt + conformance/glsl/functions/00_test_list.txt + conformance/glsl/functions/glsl-function-abs.html + conformance/glsl/functions/glsl-function-acos.html + conformance/glsl/functions/glsl-function-asin.html + conformance/glsl/functions/glsl-function-atan-xy.html + conformance/glsl/functions/glsl-function-atan.html + conformance/glsl/functions/glsl-function-ceil.html + conformance/glsl/functions/glsl-function-clamp-float.html + conformance/glsl/functions/glsl-function-clamp-gentype.html + conformance/glsl/functions/glsl-function-cos.html + conformance/glsl/functions/glsl-function-cross.html + conformance/glsl/functions/glsl-function-distance.html + conformance/glsl/functions/glsl-function-dot.html + conformance/glsl/functions/glsl-function-faceforward.html + conformance/glsl/functions/glsl-function-floor.html + conformance/glsl/functions/glsl-function-fract.html + conformance/glsl/functions/glsl-function-length.html + conformance/glsl/functions/glsl-function-lessThan.html + conformance/glsl/functions/glsl-function-max-float.html + conformance/glsl/functions/glsl-function-max-gentype.html + conformance/glsl/functions/glsl-function-min-float.html + conformance/glsl/functions/glsl-function-min-gentype.html + conformance/glsl/functions/glsl-function-mix-float.html + conformance/glsl/functions/glsl-function-mix-gentype.html + conformance/glsl/functions/glsl-function-mod-float.html + conformance/glsl/functions/glsl-function-mod-gentype.html + conformance/glsl/functions/glsl-function-normalize.html + conformance/glsl/functions/glsl-function-reflect.html + conformance/glsl/functions/glsl-function-refract.html + conformance/glsl/functions/glsl-function-sign.html + conformance/glsl/functions/glsl-function-sin.html + conformance/glsl/functions/glsl-function-smoothstep-float.html + conformance/glsl/functions/glsl-function-smoothstep-gentype.html + conformance/glsl/functions/glsl-function-step-float.html + conformance/glsl/functions/glsl-function-step-gentype.html + conformance/glsl/functions/glsl-function.html + conformance/glsl/implicit/00_test_list.txt + conformance/glsl/implicit/add_int_float.vert.html + conformance/glsl/implicit/add_int_mat2.vert.html + conformance/glsl/implicit/add_int_mat3.vert.html + conformance/glsl/implicit/add_int_mat4.vert.html + conformance/glsl/implicit/add_int_vec2.vert.html + conformance/glsl/implicit/add_int_vec3.vert.html + conformance/glsl/implicit/add_int_vec4.vert.html + conformance/glsl/implicit/add_ivec2_vec2.vert.html + conformance/glsl/implicit/add_ivec3_vec3.vert.html + conformance/glsl/implicit/add_ivec4_vec4.vert.html + conformance/glsl/implicit/assign_int_to_float.vert.html + conformance/glsl/implicit/assign_ivec2_to_vec2.vert.html + conformance/glsl/implicit/assign_ivec3_to_vec3.vert.html + conformance/glsl/implicit/assign_ivec4_to_vec4.vert.html + conformance/glsl/implicit/construct_struct.vert.html + conformance/glsl/implicit/divide_int_float.vert.html + conformance/glsl/implicit/divide_int_mat2.vert.html + conformance/glsl/implicit/divide_int_mat3.vert.html + conformance/glsl/implicit/divide_int_mat4.vert.html + conformance/glsl/implicit/divide_int_vec2.vert.html + conformance/glsl/implicit/divide_int_vec3.vert.html + conformance/glsl/implicit/divide_int_vec4.vert.html + conformance/glsl/implicit/divide_ivec2_vec2.vert.html + conformance/glsl/implicit/divide_ivec3_vec3.vert.html + conformance/glsl/implicit/divide_ivec4_vec4.vert.html + conformance/glsl/implicit/equal_int_float.vert.html + conformance/glsl/implicit/equal_ivec2_vec2.vert.html + conformance/glsl/implicit/equal_ivec3_vec3.vert.html + conformance/glsl/implicit/equal_ivec4_vec4.vert.html + conformance/glsl/implicit/function_int_float.vert.html + conformance/glsl/implicit/function_ivec2_vec2.vert.html + conformance/glsl/implicit/function_ivec3_vec3.vert.html + conformance/glsl/implicit/function_ivec4_vec4.vert.html + conformance/glsl/implicit/greater_than.vert.html + conformance/glsl/implicit/greater_than_equal.vert.html + conformance/glsl/implicit/less_than.vert.html + conformance/glsl/implicit/less_than_equal.vert.html + conformance/glsl/implicit/multiply_int_float.vert.html + conformance/glsl/implicit/multiply_int_mat2.vert.html + conformance/glsl/implicit/multiply_int_mat3.vert.html + conformance/glsl/implicit/multiply_int_mat4.vert.html + conformance/glsl/implicit/multiply_int_vec2.vert.html + conformance/glsl/implicit/multiply_int_vec3.vert.html + conformance/glsl/implicit/multiply_int_vec4.vert.html + conformance/glsl/implicit/multiply_ivec2_vec2.vert.html + conformance/glsl/implicit/multiply_ivec3_vec3.vert.html + conformance/glsl/implicit/multiply_ivec4_vec4.vert.html + conformance/glsl/implicit/not_equal_int_float.vert.html + conformance/glsl/implicit/not_equal_ivec2_vec2.vert.html + conformance/glsl/implicit/not_equal_ivec3_vec3.vert.html + conformance/glsl/implicit/not_equal_ivec4_vec4.vert.html + conformance/glsl/implicit/subtract_int_float.vert.html + conformance/glsl/implicit/subtract_int_mat2.vert.html + conformance/glsl/implicit/subtract_int_mat3.vert.html + conformance/glsl/implicit/subtract_int_mat4.vert.html + conformance/glsl/implicit/subtract_int_vec2.vert.html + conformance/glsl/implicit/subtract_int_vec3.vert.html + conformance/glsl/implicit/subtract_int_vec4.vert.html + conformance/glsl/implicit/subtract_ivec2_vec2.vert.html + conformance/glsl/implicit/subtract_ivec3_vec3.vert.html + conformance/glsl/implicit/subtract_ivec4_vec4.vert.html + conformance/glsl/implicit/ternary_int_float.vert.html + conformance/glsl/implicit/ternary_ivec2_vec2.vert.html + conformance/glsl/implicit/ternary_ivec3_vec3.vert.html + conformance/glsl/implicit/ternary_ivec4_vec4.vert.html + conformance/glsl/matrices/00_test_list.txt + conformance/glsl/matrices/glsl-mat4-to-mat3.html + conformance/glsl/misc/00_test_list.txt + conformance/glsl/misc/attrib-location-length-limits.html + conformance/glsl/misc/embedded-struct-definitions-forbidden.html + conformance/glsl/misc/glsl-2types-of-textures-on-same-unit.html + conformance/glsl/misc/glsl-function-nodes.html + conformance/glsl/misc/glsl-long-variable-names.html + conformance/glsl/misc/glsl-vertex-branch.html + conformance/glsl/misc/include.vs + conformance/glsl/misc/non-ascii-comments.vert.html + conformance/glsl/misc/non-ascii.vert.html + conformance/glsl/misc/re-compile-re-link.html + conformance/glsl/misc/shader-with-256-character-identifier.frag.html + conformance/glsl/misc/shader-with-257-character-identifier.frag.html + conformance/glsl/misc/shader-with-_webgl-identifier.vert.html + conformance/glsl/misc/shader-with-arbitrary-indexing.frag.html + conformance/glsl/misc/shader-with-arbitrary-indexing.vert.html + conformance/glsl/misc/shader-with-attrib-array.vert.html + conformance/glsl/misc/shader-with-attrib-struct.vert.html + conformance/glsl/misc/shader-with-clipvertex.vert.html + conformance/glsl/misc/shader-with-comma-assignment.html + conformance/glsl/misc/shader-with-comma-conditional-assignment.html + conformance/glsl/misc/shader-with-conditional-scoping.html + conformance/glsl/misc/shader-with-default-precision.frag.html + conformance/glsl/misc/shader-with-default-precision.vert.html + conformance/glsl/misc/shader-with-define-line-continuation.frag.html + conformance/glsl/misc/shader-with-dfdx-no-ext.frag.html + conformance/glsl/misc/shader-with-dfdx.frag.html + conformance/glsl/misc/shader-with-do-scoping.html + conformance/glsl/misc/shader-with-error-directive.html + conformance/glsl/misc/shader-with-explicit-int-cast.vert.html + conformance/glsl/misc/shader-with-float-return-value.frag.html + conformance/glsl/misc/shader-with-for-loop.html + conformance/glsl/misc/shader-with-for-scoping.html + conformance/glsl/misc/shader-with-frag-depth.frag.html + conformance/glsl/misc/shader-with-function-recursion.frag.html + conformance/glsl/misc/shader-with-function-scoped-struct.html + conformance/glsl/misc/shader-with-functional-scoping.html + conformance/glsl/misc/shader-with-glcolor.vert.html + conformance/glsl/misc/shader-with-gles-1.frag.html + conformance/glsl/misc/shader-with-gles-symbol.frag.html + conformance/glsl/misc/shader-with-glprojectionmatrix.vert.html + conformance/glsl/misc/shader-with-hex-int-constant-macro.html + conformance/glsl/misc/shader-with-implicit-vec3-to-vec4-cast.vert.html + conformance/glsl/misc/shader-with-include.vert.html + conformance/glsl/misc/shader-with-int-return-value.frag.html + conformance/glsl/misc/shader-with-invalid-identifier.frag.html + conformance/glsl/misc/shader-with-ivec2-return-value.frag.html + conformance/glsl/misc/shader-with-ivec3-return-value.frag.html + conformance/glsl/misc/shader-with-ivec4-return-value.frag.html + conformance/glsl/misc/shader-with-limited-indexing.frag.html + conformance/glsl/misc/shader-with-line-directive.html + conformance/glsl/misc/shader-with-long-line.html + conformance/glsl/misc/shader-with-non-ascii-error.frag.html + conformance/glsl/misc/shader-with-precision.frag.html + conformance/glsl/misc/shader-with-quoted-error.frag.html + conformance/glsl/misc/shader-with-undefined-preprocessor-symbol.frag.html + conformance/glsl/misc/shader-with-uniform-in-loop-condition.vert.html + conformance/glsl/misc/shader-with-vec2-return-value.frag.html + conformance/glsl/misc/shader-with-vec3-return-value.frag.html + conformance/glsl/misc/shader-with-vec4-return-value.frag.html + conformance/glsl/misc/shader-with-vec4-vec3-vec4-conditional.html + conformance/glsl/misc/shader-with-version-100.frag.html + conformance/glsl/misc/shader-with-version-100.vert.html + conformance/glsl/misc/shader-with-version-120.vert.html + conformance/glsl/misc/shader-with-version-130.vert.html + conformance/glsl/misc/shader-with-webgl-identifier.vert.html + conformance/glsl/misc/shader-without-precision.frag.html + conformance/glsl/misc/shared.html + conformance/glsl/misc/struct-nesting-exceeds-maximum.html + conformance/glsl/misc/struct-nesting-under-maximum.html + conformance/glsl/misc/uniform-location-length-limits.html + conformance/glsl/reserved/00_test_list.txt + conformance/glsl/reserved/_webgl_field.vert.html + conformance/glsl/reserved/_webgl_function.vert.html + conformance/glsl/reserved/_webgl_struct.vert.html + conformance/glsl/reserved/_webgl_variable.vert.html + conformance/glsl/reserved/webgl_field.vert.html + conformance/glsl/reserved/webgl_function.vert.html + conformance/glsl/reserved/webgl_struct.vert.html + conformance/glsl/reserved/webgl_variable.vert.html + conformance/glsl/samplers/00_test_list.txt + conformance/glsl/samplers/glsl-function-texture2d-bias.html + conformance/glsl/samplers/glsl-function-texture2dlod.html + conformance/glsl/samplers/glsl-function-texture2dproj.html + conformance/glsl/variables/00_test_list.txt + conformance/glsl/variables/gl-fragcoord.html + conformance/glsl/variables/gl-frontfacing.html + conformance/glsl/variables/gl-pointcoord.html + conformance/limits/00_test_list.txt + conformance/limits/gl-max-texture-dimensions.html + conformance/limits/gl-min-attribs.html + conformance/limits/gl-min-textures.html + conformance/limits/gl-min-uniforms.html + conformance/misc/00_test_list.txt + conformance/misc/bad-arguments-test.html + conformance/misc/delayed-drawing.html + conformance/misc/error-reporting.html + conformance/misc/functions-returning-strings.html + conformance/misc/instanceof-test.html + conformance/misc/invalid-passed-params.html + conformance/misc/is-object.html + conformance/misc/null-object-behaviour.html + conformance/misc/object-deletion-behaviour.html + conformance/misc/shader-precision-format.html + conformance/misc/type-conversion-test.html + conformance/misc/uninitialized-test.html + conformance/misc/webgl-specific.html + conformance/more/00_test_list.txt + conformance/more/README.md + conformance/more/all_tests.html + conformance/more/all_tests_linkonly.html + conformance/more/all_tests_sequential.html + conformance/more/conformance/argGenerators-A.js + conformance/more/conformance/argGenerators-B1.js + conformance/more/conformance/argGenerators-B2.js + conformance/more/conformance/argGenerators-B3.js + conformance/more/conformance/argGenerators-B4.js + conformance/more/conformance/argGenerators-C.js + conformance/more/conformance/argGenerators-D_G.js + conformance/more/conformance/argGenerators-G_I.js + conformance/more/conformance/argGenerators-L_S.js + conformance/more/conformance/argGenerators-S_V.js + conformance/more/conformance/badArgsArityLessThanArgc.html + conformance/more/conformance/constants.html + conformance/more/conformance/fuzzTheAPI.html + conformance/more/conformance/getContext.html + conformance/more/conformance/methods.html + conformance/more/conformance/quickCheckAPI-A.html + conformance/more/conformance/quickCheckAPI-B1.html + conformance/more/conformance/quickCheckAPI-B2.html + conformance/more/conformance/quickCheckAPI-B3.html + conformance/more/conformance/quickCheckAPI-B4.html + conformance/more/conformance/quickCheckAPI-C.html + conformance/more/conformance/quickCheckAPI-D_G.html + conformance/more/conformance/quickCheckAPI-G_I.html + conformance/more/conformance/quickCheckAPI-L_S.html + conformance/more/conformance/quickCheckAPI-S_V.html + conformance/more/conformance/quickCheckAPI.js + conformance/more/conformance/quickCheckAPIBadArgs.html + conformance/more/conformance/webGLArrays.html + conformance/more/demos/opengl_web.html + conformance/more/demos/video.html + conformance/more/functions/bindBuffer.html + conformance/more/functions/bindBufferBadArgs.html + conformance/more/functions/bindFramebufferLeaveNonZero.html + conformance/more/functions/bufferData.html + conformance/more/functions/bufferDataBadArgs.html + conformance/more/functions/bufferSubData.html + conformance/more/functions/bufferSubDataBadArgs.html + conformance/more/functions/copyTexImage2D.html + conformance/more/functions/copyTexImage2DBadArgs.html + conformance/more/functions/copyTexSubImage2D.html + conformance/more/functions/copyTexSubImage2DBadArgs.html + conformance/more/functions/deleteBufferBadArgs.html + conformance/more/functions/drawArrays.html + conformance/more/functions/drawArraysOutOfBounds.html + conformance/more/functions/drawElements.html + conformance/more/functions/drawElementsBadArgs.html + conformance/more/functions/isTests.html + conformance/more/functions/readPixels.html + conformance/more/functions/readPixelsBadArgs.html + conformance/more/functions/texImage2D.html + conformance/more/functions/texImage2DBadArgs.html + conformance/more/functions/texImage2DHTML.html + conformance/more/functions/texImage2DHTMLBadArgs.html + conformance/more/functions/texSubImage2D.html + conformance/more/functions/texSubImage2DBadArgs.html + conformance/more/functions/texSubImage2DHTML.html + conformance/more/functions/texSubImage2DHTMLBadArgs.html + conformance/more/functions/uniformMatrix.html + conformance/more/functions/uniformMatrixBadArgs.html + conformance/more/functions/uniformf.html + conformance/more/functions/uniformfArrayLen1.html + conformance/more/functions/uniformfBadArgs.html + conformance/more/functions/uniformi.html + conformance/more/functions/uniformiBadArgs.html + conformance/more/functions/vertexAttrib.html + conformance/more/functions/vertexAttribBadArgs.html + conformance/more/functions/vertexAttribPointer.html + conformance/more/functions/vertexAttribPointerBadArgs.html + conformance/more/glsl/arrayOutOfBounds.html + conformance/more/glsl/longLoops.html + conformance/more/glsl/uniformOutOfBounds.html + conformance/more/glsl/unusedAttribsUniforms.html + conformance/more/index.html + conformance/more/performance/CPUvsGPU.html + conformance/more/performance/bandwidth.html + conformance/more/performance/jsGCPause.html + conformance/more/performance/jsMatrixMult.html + conformance/more/performance/jsToGLOverhead.html + conformance/more/unit.css + conformance/more/unit.js + conformance/more/util.js + conformance/programs/00_test_list.txt + conformance/programs/get-active-test.html + conformance/programs/gl-bind-attrib-location-test.html + conformance/programs/gl-get-active-attribute.html + conformance/programs/gl-get-active-uniform.html + conformance/programs/gl-getshadersource.html + conformance/programs/gl-shader-test.html + conformance/programs/invalid-UTF-16.html + conformance/programs/program-test.html + conformance/reading/00_test_list.txt + conformance/reading/read-pixels-pack-alignment.html + conformance/reading/read-pixels-test.html + conformance/renderbuffers/00_test_list.txt + conformance/renderbuffers/framebuffer-object-attachment.html + conformance/renderbuffers/framebuffer-test.html + conformance/renderbuffers/renderbuffer-initialization.html + conformance/rendering/00_test_list.txt + conformance/rendering/draw-arrays-out-of-bounds.html + conformance/rendering/draw-elements-out-of-bounds.html + conformance/rendering/gl-clear.html + conformance/rendering/gl-drawelements.html + conformance/rendering/gl-scissor-test.html + conformance/rendering/line-loop-tri-fan.html + conformance/rendering/more-than-65536-indices.html + conformance/rendering/point-size.html + conformance/rendering/triangle.html + conformance/resources/3x3.png + conformance/resources/blue-1x1.jpg + conformance/resources/boolUniformShader.vert + conformance/resources/bug-32888-texture.png + conformance/resources/floatUniformShader.vert + conformance/resources/fragmentShader.frag + conformance/resources/glsl-conformance-test.js + conformance/resources/glsl-feature-tests.css + conformance/resources/glsl-generator.js + conformance/resources/gray-ramp-256-with-128-alpha.png + conformance/resources/gray-ramp-256.png + conformance/resources/gray-ramp-default-gamma.png + conformance/resources/gray-ramp-gamma0.1.png + conformance/resources/gray-ramp-gamma1.0.png + conformance/resources/gray-ramp-gamma2.0.png + conformance/resources/gray-ramp-gamma4.0.png + conformance/resources/gray-ramp-gamma9.0.png + conformance/resources/gray-ramp.png + conformance/resources/green-2x2-16bit.png + conformance/resources/intArrayUniformShader.vert + conformance/resources/intUniformShader.vert + conformance/resources/matUniformShader.vert + conformance/resources/noopUniformShader.frag + conformance/resources/noopUniformShader.vert + conformance/resources/npot-video.mp4 + conformance/resources/npot-video.theora.ogv + conformance/resources/npot-video.webmvp8.webm + conformance/resources/pnglib.js + conformance/resources/red-green.mp4 + conformance/resources/red-green.png + conformance/resources/red-green.theora.ogv + conformance/resources/red-green.webmvp8.webm + conformance/resources/red-indexed.png + conformance/resources/samplerUniformShader.frag + conformance/resources/small-square-with-cie-rgb-profile.png + conformance/resources/small-square-with-colormatch-profile.png + conformance/resources/small-square-with-colorspin-profile.jpg + conformance/resources/small-square-with-colorspin-profile.png + conformance/resources/small-square-with-e-srgb-profile.png + conformance/resources/small-square-with-smpte-c-profile.png + conformance/resources/small-square-with-srgb-iec61966-2.1-profile.png + conformance/resources/structUniformShader.vert + conformance/resources/vertexShader.vert + conformance/resources/webgl-test-utils.js + conformance/resources/webgl-test.js + conformance/resources/zero-alpha.png + conformance/state/00_test_list.txt + conformance/state/gl-enable-enum-test.html + conformance/state/gl-enum-tests.html + conformance/state/gl-get-calls.html + conformance/state/gl-geterror.html + conformance/state/gl-getstring.html + conformance/state/gl-object-get-calls.html + conformance/textures/00_test_list.txt + conformance/textures/compressed-tex-image.html + conformance/textures/copy-tex-image-and-sub-image-2d.html + conformance/textures/gl-pixelstorei.html + conformance/textures/gl-teximage.html + conformance/textures/origin-clean-conformance.html + conformance/textures/tex-image-and-sub-image-2d-with-array-buffer-view.html + conformance/textures/tex-image-and-sub-image-2d-with-canvas.html + conformance/textures/tex-image-and-sub-image-2d-with-image-data.html + conformance/textures/tex-image-and-sub-image-2d-with-image.html + conformance/textures/tex-image-and-sub-image-2d-with-video.html + conformance/textures/tex-image-and-uniform-binding-bugs.html + conformance/textures/tex-image-with-format-and-type.html + conformance/textures/tex-image-with-invalid-data.html + conformance/textures/tex-input-validation.html + conformance/textures/tex-sub-image-2d-bad-args.html + conformance/textures/tex-sub-image-2d.html + conformance/textures/texparameter-test.html + conformance/textures/texture-active-bind-2.html + conformance/textures/texture-active-bind.html + conformance/textures/texture-clear.html + conformance/textures/texture-complete.html + conformance/textures/texture-formats-test.html + conformance/textures/texture-mips.html + conformance/textures/texture-npot-video.html + conformance/textures/texture-npot.html + conformance/textures/texture-size-cube-maps.html + conformance/textures/texture-size.html + conformance/textures/texture-transparent-pixels-initialized.html + conformance/typedarrays/00_test_list.txt + conformance/typedarrays/array-buffer-crash.html + conformance/typedarrays/array-buffer-view-crash.html + conformance/typedarrays/array-unit-tests.html + conformance/uniforms/00_test_list.txt + conformance/uniforms/gl-uniform-arrays.html + conformance/uniforms/gl-uniform-bool.html + conformance/uniforms/gl-uniformmatrix4fv.html + conformance/uniforms/gl-unknown-uniform.html + conformance/uniforms/null-uniform-location.html + conformance/uniforms/uniform-location.html + conformance/uniforms/uniform-samplers-test.html + resources/cors-util.js + resources/desktop-gl-constants.js + resources/js-test-pre.js + resources/js-test-style.css + resources/opengl_logo.jpg + resources/thunderbird-logo-64x64.png + resources/webgl-logo.png + resources/webgl-test-harness.js + +[_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html] +[_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html] +[_wrappers/test_conformance__attribs__gl-vertex-attrib.html] +[_wrappers/test_conformance__attribs__gl-vertexattribpointer-offsets.html] +[_wrappers/test_conformance__attribs__gl-vertexattribpointer.html] +[_wrappers/test_conformance__buffers__buffer-bind-test.html] +[_wrappers/test_conformance__buffers__buffer-data-array-buffer.html] +[_wrappers/test_conformance__buffers__index-validation-copies-indices.html] +[_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html] +[_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html] +[_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html] +[_wrappers/test_conformance__buffers__index-validation.html] +[_wrappers/test_conformance__canvas__buffer-offscreen-test.html] +[_wrappers/test_conformance__canvas__buffer-preserve-test.html] +[_wrappers/test_conformance__canvas__canvas-test.html] +[_wrappers/test_conformance__canvas__canvas-zero-size.html] +[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html] +[_wrappers/test_conformance__canvas__drawingbuffer-test.html] +[_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html] +[_wrappers/test_conformance__context__constants.html] +[_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html] +[_wrappers/test_conformance__context__context-lost-restored.html] +[_wrappers/test_conformance__context__context-lost.html] +[_wrappers/test_conformance__context__context-type-test.html] +[_wrappers/test_conformance__context__incorrect-context-object-behaviour.html] +[_wrappers/test_conformance__context__methods.html] +[_wrappers/test_conformance__context__premultiplyalpha-test.html] +[_wrappers/test_conformance__context__resource-sharing-test.html] +[_wrappers/test_conformance__extensions__oes-standard-derivatives.html] +[_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html] +[_wrappers/test_conformance__extensions__oes-texture-float.html] +[_wrappers/test_conformance__extensions__oes-vertex-array-object.html] +[_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html] +[_wrappers/test_conformance__extensions__webgl-debug-shaders.html] +[_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html] +[_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html] +[_wrappers/test_conformance__extensions__ext-sRGB.html] +[_wrappers/test_conformance__extensions__ext-shader-texture-lod.html] +[_wrappers/test_conformance__glsl__functions__glsl-function.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-abs.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-acos.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-asin.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-atan.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-atan-xy.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-ceil.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-clamp-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-clamp-gentype.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-cos.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-cross.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-distance.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-dot.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-faceforward.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-floor.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-fract.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-length.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-max-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-max-gentype.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-min-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-min-gentype.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-mix-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-mix-gentype.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-mod-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-mod-gentype.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-normalize.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-reflect.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-sign.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-sin.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-step-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-step-gentype.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-float.html] +[_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html] +[_wrappers/test_conformance__glsl__implicit__add_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_int_mat2.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_int_mat3.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_int_mat4.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_int_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_int_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_int_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__add_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__assign_int_to_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__assign_ivec2_to_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__assign_ivec3_to_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__assign_ivec4_to_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__construct_struct.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_mat2.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_mat3.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_mat4.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_int_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__divide_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__equal_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__equal_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__equal_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__equal_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__function_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__function_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__function_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__function_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__greater_than.vert.html] +[_wrappers/test_conformance__glsl__implicit__greater_than_equal.vert.html] +[_wrappers/test_conformance__glsl__implicit__less_than.vert.html] +[_wrappers/test_conformance__glsl__implicit__less_than_equal.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_mat2.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_mat3.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_mat4.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_int_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__multiply_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__not_equal_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__not_equal_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__not_equal_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__not_equal_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_mat2.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_mat3.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_mat4.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_int_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__subtract_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__implicit__ternary_int_float.vert.html] +[_wrappers/test_conformance__glsl__implicit__ternary_ivec2_vec2.vert.html] +[_wrappers/test_conformance__glsl__implicit__ternary_ivec3_vec3.vert.html] +[_wrappers/test_conformance__glsl__implicit__ternary_ivec4_vec4.vert.html] +[_wrappers/test_conformance__glsl__misc__attrib-location-length-limits.html] +[_wrappers/test_conformance__glsl__misc__embedded-struct-definitions-forbidden.html] +[_wrappers/test_conformance__glsl__misc__glsl-function-nodes.html] +[_wrappers/test_conformance__glsl__misc__glsl-long-variable-names.html] +[_wrappers/test_conformance__glsl__misc__non-ascii-comments.vert.html] +[_wrappers/test_conformance__glsl__misc__non-ascii.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-attrib-array.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-attrib-struct.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-clipvertex.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-default-precision.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-default-precision.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-define-line-continuation.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-dfdx-no-ext.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-dfdx.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-error-directive.html] +[_wrappers/test_conformance__glsl__misc__shader-with-explicit-int-cast.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-float-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-frag-depth.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-function-recursion.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-glcolor.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-gles-1.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-gles-symbol.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-glprojectionmatrix.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-implicit-vec3-to-vec4-cast.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-include.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-int-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-invalid-identifier.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-ivec2-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-ivec3-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-ivec4-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-limited-indexing.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-long-line.html] +[_wrappers/test_conformance__glsl__misc__shader-with-non-ascii-error.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-precision.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-quoted-error.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-undefined-preprocessor-symbol.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-uniform-in-loop-condition.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-vec2-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-vec3-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-vec4-return-value.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-version-100.frag.html] +[_wrappers/test_conformance__glsl__misc__shader-with-version-100.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-version-120.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-version-130.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html] +[_wrappers/test_conformance__glsl__misc__shader-without-precision.frag.html] +[_wrappers/test_conformance__glsl__misc__shared.html] +[_wrappers/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html] +[_wrappers/test_conformance__glsl__misc__struct-nesting-under-maximum.html] +[_wrappers/test_conformance__glsl__misc__uniform-location-length-limits.html] +[_wrappers/test_conformance__glsl__reserved___webgl_field.vert.html] +[_wrappers/test_conformance__glsl__reserved___webgl_function.vert.html] +[_wrappers/test_conformance__glsl__reserved___webgl_struct.vert.html] +[_wrappers/test_conformance__glsl__reserved___webgl_variable.vert.html] +[_wrappers/test_conformance__glsl__reserved__webgl_field.vert.html] +[_wrappers/test_conformance__glsl__reserved__webgl_function.vert.html] +[_wrappers/test_conformance__glsl__reserved__webgl_struct.vert.html] +[_wrappers/test_conformance__glsl__reserved__webgl_variable.vert.html] +[_wrappers/test_conformance__glsl__variables__gl-fragcoord.html] +[_wrappers/test_conformance__glsl__variables__gl-frontfacing.html] +[_wrappers/test_conformance__glsl__variables__gl-pointcoord.html] +[_wrappers/test_conformance__limits__gl-min-attribs.html] +[_wrappers/test_conformance__limits__gl-max-texture-dimensions.html] +[_wrappers/test_conformance__limits__gl-min-textures.html] +[_wrappers/test_conformance__limits__gl-min-uniforms.html] +[_wrappers/test_conformance__misc__bad-arguments-test.html] +[_wrappers/test_conformance__misc__error-reporting.html] +[_wrappers/test_conformance__misc__instanceof-test.html] +[_wrappers/test_conformance__misc__invalid-passed-params.html] +[_wrappers/test_conformance__misc__is-object.html] +[_wrappers/test_conformance__misc__null-object-behaviour.html] +[_wrappers/test_conformance__misc__functions-returning-strings.html] +[_wrappers/test_conformance__misc__object-deletion-behaviour.html] +[_wrappers/test_conformance__misc__shader-precision-format.html] +[_wrappers/test_conformance__misc__type-conversion-test.html] +[_wrappers/test_conformance__misc__uninitialized-test.html] +[_wrappers/test_conformance__misc__webgl-specific.html] +[_wrappers/test_conformance__programs__get-active-test.html] +[_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html] +[_wrappers/test_conformance__programs__gl-get-active-attribute.html] +[_wrappers/test_conformance__programs__gl-get-active-uniform.html] +[_wrappers/test_conformance__programs__gl-getshadersource.html] +[_wrappers/test_conformance__programs__gl-shader-test.html] +[_wrappers/test_conformance__programs__invalid-UTF-16.html] +[_wrappers/test_conformance__programs__program-test.html] +[_wrappers/test_conformance__reading__read-pixels-pack-alignment.html] +[_wrappers/test_conformance__reading__read-pixels-test.html] +[_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html] +[_wrappers/test_conformance__renderbuffers__framebuffer-test.html] +[_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html] +[_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html] +[_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html] +[_wrappers/test_conformance__rendering__gl-clear.html] +[_wrappers/test_conformance__rendering__gl-drawelements.html] +[_wrappers/test_conformance__rendering__gl-scissor-test.html] +[_wrappers/test_conformance__rendering__more-than-65536-indices.html] +[_wrappers/test_conformance__rendering__point-size.html] +[_wrappers/test_conformance__rendering__triangle.html] +[_wrappers/test_conformance__rendering__line-loop-tri-fan.html] +[_wrappers/test_conformance__state__gl-enable-enum-test.html] +[_wrappers/test_conformance__state__gl-enum-tests.html] +[_wrappers/test_conformance__state__gl-get-calls.html] +[_wrappers/test_conformance__state__gl-geterror.html] +[_wrappers/test_conformance__state__gl-getstring.html] +[_wrappers/test_conformance__state__gl-object-get-calls.html] +[_wrappers/test_conformance__textures__compressed-tex-image.html] +[_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html] +[_wrappers/test_conformance__textures__gl-pixelstorei.html] +[_wrappers/test_conformance__textures__gl-teximage.html] +[_wrappers/test_conformance__textures__origin-clean-conformance.html] +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html] +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html] +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html] +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html] +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html] +[_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html] +[_wrappers/test_conformance__textures__tex-image-with-format-and-type.html] +[_wrappers/test_conformance__textures__tex-image-with-invalid-data.html] +[_wrappers/test_conformance__textures__tex-input-validation.html] +[_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html] +[_wrappers/test_conformance__textures__tex-sub-image-2d.html] +[_wrappers/test_conformance__textures__texparameter-test.html] +[_wrappers/test_conformance__textures__texture-active-bind-2.html] +[_wrappers/test_conformance__textures__texture-active-bind.html] +[_wrappers/test_conformance__textures__texture-complete.html] +[_wrappers/test_conformance__textures__texture-formats-test.html] +[_wrappers/test_conformance__textures__texture-mips.html] +[_wrappers/test_conformance__textures__texture-npot-video.html] +[_wrappers/test_conformance__textures__texture-npot.html] +[_wrappers/test_conformance__textures__texture-size.html] +[_wrappers/test_conformance__textures__texture-size-cube-maps.html] +[_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html] +[_wrappers/test_conformance__typedarrays__array-buffer-crash.html] +[_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html] +[_wrappers/test_conformance__typedarrays__array-unit-tests.html] +[_wrappers/test_conformance__uniforms__gl-uniform-arrays.html] +[_wrappers/test_conformance__uniforms__gl-uniform-bool.html] +[_wrappers/test_conformance__uniforms__gl-uniformmatrix4fv.html] +[_wrappers/test_conformance__uniforms__gl-unknown-uniform.html] +[_wrappers/test_conformance__uniforms__null-uniform-location.html] +[_wrappers/test_conformance__uniforms__uniform-location.html] +[_wrappers/test_conformance__uniforms__uniform-samplers-test.html] +[_wrappers/test_conformance__more__conformance__constants.html] +[_wrappers/test_conformance__more__conformance__getContext.html] +[_wrappers/test_conformance__more__conformance__methods.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-A.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-B1.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-B2.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-B3.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-B4.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-C.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-D_G.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-G_I.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-L_S.html] +[_wrappers/test_conformance__more__conformance__quickCheckAPI-S_V.html] +[_wrappers/test_conformance__more__conformance__webGLArrays.html] +[_wrappers/test_conformance__more__functions__bindBuffer.html] +[_wrappers/test_conformance__more__functions__bindBufferBadArgs.html] +[_wrappers/test_conformance__more__functions__bindFramebufferLeaveNonZero.html] +[_wrappers/test_conformance__more__functions__bufferData.html] +[_wrappers/test_conformance__more__functions__bufferDataBadArgs.html] +[_wrappers/test_conformance__more__functions__bufferSubData.html] +[_wrappers/test_conformance__more__functions__bufferSubDataBadArgs.html] +[_wrappers/test_conformance__more__functions__copyTexImage2D.html] +[_wrappers/test_conformance__more__functions__copyTexImage2DBadArgs.html] +[_wrappers/test_conformance__more__functions__copyTexSubImage2D.html] +[_wrappers/test_conformance__more__functions__copyTexSubImage2DBadArgs.html] +[_wrappers/test_conformance__more__functions__deleteBufferBadArgs.html] +[_wrappers/test_conformance__more__functions__drawArrays.html] +[_wrappers/test_conformance__more__functions__drawArraysOutOfBounds.html] +[_wrappers/test_conformance__more__functions__drawElements.html] +[_wrappers/test_conformance__more__functions__drawElementsBadArgs.html] +[_wrappers/test_conformance__more__functions__isTests.html] +[_wrappers/test_conformance__more__functions__readPixels.html] +[_wrappers/test_conformance__more__functions__readPixelsBadArgs.html] +[_wrappers/test_conformance__more__functions__texImage2D.html] +[_wrappers/test_conformance__more__functions__texImage2DBadArgs.html] +[_wrappers/test_conformance__more__functions__texImage2DHTML.html] +[_wrappers/test_conformance__more__functions__texImage2DHTMLBadArgs.html] +[_wrappers/test_conformance__more__functions__texSubImage2D.html] +[_wrappers/test_conformance__more__functions__texSubImage2DBadArgs.html] +[_wrappers/test_conformance__more__functions__texSubImage2DHTML.html] +[_wrappers/test_conformance__more__functions__texSubImage2DHTMLBadArgs.html] +[_wrappers/test_conformance__more__functions__uniformf.html] +[_wrappers/test_conformance__more__functions__uniformfBadArgs.html] +[_wrappers/test_conformance__more__functions__uniformfArrayLen1.html] +[_wrappers/test_conformance__more__functions__uniformi.html] +[_wrappers/test_conformance__more__functions__uniformiBadArgs.html] +[_wrappers/test_conformance__more__functions__uniformMatrix.html] +[_wrappers/test_conformance__more__functions__uniformMatrixBadArgs.html] +[_wrappers/test_conformance__more__functions__vertexAttrib.html] +[_wrappers/test_conformance__more__functions__vertexAttribBadArgs.html] +[_wrappers/test_conformance__more__functions__vertexAttribPointer.html] +[_wrappers/test_conformance__more__functions__vertexAttribPointerBadArgs.html] +[_wrappers/test_conformance__more__glsl__arrayOutOfBounds.html] +[_wrappers/test_conformance__more__glsl__uniformOutOfBounds.html] diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html new file mode 100644 index 000000000000..8686011e3a21 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html new file mode 100644 index 000000000000..9a636f0ba946 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib.html new file mode 100644 index 000000000000..da9770f776d9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertex-attrib.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer-offsets.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer-offsets.html new file mode 100644 index 000000000000..d17b89e85232 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer-offsets.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer.html new file mode 100644 index 000000000000..9162abac8c0d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__attribs__gl-vertexattribpointer.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-bind-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-bind-test.html new file mode 100644 index 000000000000..f35702e1b276 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-bind-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-data-array-buffer.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-data-array-buffer.html new file mode 100644 index 000000000000..93753bf32a42 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__buffer-data-array-buffer.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-copies-indices.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-copies-indices.html new file mode 100644 index 000000000000..5ed01b31590a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-copies-indices.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html new file mode 100644 index 000000000000..3899f1c41567 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html new file mode 100644 index 000000000000..8552508b1d70 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html new file mode 100644 index 000000000000..cc752c6da377 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation.html new file mode 100644 index 000000000000..054c07ececc0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__buffers__index-validation.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-offscreen-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-offscreen-test.html new file mode 100644 index 000000000000..46761ab50111 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-offscreen-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-preserve-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-preserve-test.html new file mode 100644 index 000000000000..ff8a06e1f5ab --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__buffer-preserve-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-test.html new file mode 100644 index 000000000000..b9eac40db9e5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-zero-size.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-zero-size.html new file mode 100644 index 000000000000..58db6af780c7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__canvas-zero-size.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html new file mode 100644 index 000000000000..e7b74fb01720 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html new file mode 100644 index 000000000000..71d4cadf8c2c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html new file mode 100644 index 000000000000..a1d43287203f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__constants.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__constants.html new file mode 100644 index 000000000000..b71abc1f9fd5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__constants.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html new file mode 100644 index 000000000000..2c85eef3ac0e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost-restored.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost-restored.html new file mode 100644 index 000000000000..1ab90df95654 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost-restored.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost.html new file mode 100644 index 000000000000..f5f7962af3f9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-lost.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-type-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-type-test.html new file mode 100644 index 000000000000..38a4ab14972e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__context-type-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__incorrect-context-object-behaviour.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__incorrect-context-object-behaviour.html new file mode 100644 index 000000000000..695f9ab7424f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__incorrect-context-object-behaviour.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__methods.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__methods.html new file mode 100644 index 000000000000..d2e8f2e317f7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__methods.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__premultiplyalpha-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__premultiplyalpha-test.html new file mode 100644 index 000000000000..ed9a45fa2de7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__premultiplyalpha-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__resource-sharing-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__resource-sharing-test.html new file mode 100644 index 000000000000..e842d3376612 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__context__resource-sharing-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html new file mode 100644 index 000000000000..b386a37258b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html new file mode 100644 index 000000000000..a034919bff5f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html new file mode 100644 index 000000000000..4d1ee0757927 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-standard-derivatives.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-standard-derivatives.html new file mode 100644 index 000000000000..16923446c3c8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-standard-derivatives.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-texture-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-texture-float.html new file mode 100644 index 000000000000..9ad88fe9ce34 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-texture-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-vertex-array-object.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-vertex-array-object.html new file mode 100644 index 000000000000..c170f0f851ff --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__oes-vertex-array-object.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html new file mode 100644 index 000000000000..2c3a9d953a33 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html new file mode 100644 index 000000000000..244b721255a1 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html new file mode 100644 index 000000000000..c902c8d01eaa --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html new file mode 100644 index 000000000000..796afe23c286 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-abs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-abs.html new file mode 100644 index 000000000000..58f55bc6ad8b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-abs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-acos.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-acos.html new file mode 100644 index 000000000000..6024daba1f0f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-acos.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-asin.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-asin.html new file mode 100644 index 000000000000..461b55d1d0a8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-asin.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan-xy.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan-xy.html new file mode 100644 index 000000000000..c4f7d7e74b23 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan-xy.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan.html new file mode 100644 index 000000000000..bf6d63121997 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-atan.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-ceil.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-ceil.html new file mode 100644 index 000000000000..cc1c1914af58 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-ceil.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-float.html new file mode 100644 index 000000000000..f27b7a8d6a34 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-gentype.html new file mode 100644 index 000000000000..860ec18fa1e3 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-clamp-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cos.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cos.html new file mode 100644 index 000000000000..d3ec0764f6a4 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cos.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cross.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cross.html new file mode 100644 index 000000000000..a30bc6be18b2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-cross.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-distance.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-distance.html new file mode 100644 index 000000000000..e375ffbcc284 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-distance.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-dot.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-dot.html new file mode 100644 index 000000000000..e59ed7fa23fa --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-dot.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-faceforward.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-faceforward.html new file mode 100644 index 000000000000..a90cd0afa4d7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-faceforward.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-floor.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-floor.html new file mode 100644 index 000000000000..19d124913fde --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-floor.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-fract.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-fract.html new file mode 100644 index 000000000000..8227f2310a23 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-fract.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-length.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-length.html new file mode 100644 index 000000000000..628d6db6d5d8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-length.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-float.html new file mode 100644 index 000000000000..a37ea66f4887 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-gentype.html new file mode 100644 index 000000000000..ddc5d5ef418a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-max-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-float.html new file mode 100644 index 000000000000..1b098716667d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-gentype.html new file mode 100644 index 000000000000..f8ebc13ef85a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-min-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-float.html new file mode 100644 index 000000000000..998a8508ca14 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-gentype.html new file mode 100644 index 000000000000..45548e435156 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mix-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-float.html new file mode 100644 index 000000000000..52cf618e9a4b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-gentype.html new file mode 100644 index 000000000000..1d452439ddbc --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-mod-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-normalize.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-normalize.html new file mode 100644 index 000000000000..e5445eaa3d10 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-normalize.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-reflect.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-reflect.html new file mode 100644 index 000000000000..baf95cc604e2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-reflect.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sign.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sign.html new file mode 100644 index 000000000000..a6a352b53014 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sign.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sin.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sin.html new file mode 100644 index 000000000000..53eaad09d45b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-sin.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-float.html new file mode 100644 index 000000000000..e87bbc044013 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html new file mode 100644 index 000000000000..ce97351deb99 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-float.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-float.html new file mode 100644 index 000000000000..161f1a2af95f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-float.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-gentype.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-gentype.html new file mode 100644 index 000000000000..9d1701d159ad --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function-step-gentype.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html new file mode 100644 index 000000000000..7441256b7601 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_float.vert.html new file mode 100644 index 000000000000..c04011eaf18a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat2.vert.html new file mode 100644 index 000000000000..6da4cfca746b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat3.vert.html new file mode 100644 index 000000000000..81987ae515b7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat4.vert.html new file mode 100644 index 000000000000..a47c2b5c31c9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_mat4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec2.vert.html new file mode 100644 index 000000000000..cf76ff7e671b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec3.vert.html new file mode 100644 index 000000000000..c2a36aaffc0c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec4.vert.html new file mode 100644 index 000000000000..bd1cb179dfa1 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_int_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec2_vec2.vert.html new file mode 100644 index 000000000000..14dd5bb38d92 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec3_vec3.vert.html new file mode 100644 index 000000000000..4ec31c5857de --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec4_vec4.vert.html new file mode 100644 index 000000000000..11d0d4280e71 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__add_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_int_to_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_int_to_float.vert.html new file mode 100644 index 000000000000..39d5440be625 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_int_to_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec2_to_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec2_to_vec2.vert.html new file mode 100644 index 000000000000..441abb536f57 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec2_to_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec3_to_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec3_to_vec3.vert.html new file mode 100644 index 000000000000..b3e5712c498d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec3_to_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec4_to_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec4_to_vec4.vert.html new file mode 100644 index 000000000000..696099fe8462 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__assign_ivec4_to_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__construct_struct.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__construct_struct.vert.html new file mode 100644 index 000000000000..ba82d0280216 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__construct_struct.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_float.vert.html new file mode 100644 index 000000000000..2cee54381ca1 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat2.vert.html new file mode 100644 index 000000000000..a2dfde21f39b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat3.vert.html new file mode 100644 index 000000000000..4558ff67f320 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat4.vert.html new file mode 100644 index 000000000000..5379d7270c3c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_mat4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec2.vert.html new file mode 100644 index 000000000000..0b2e31d28be7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec3.vert.html new file mode 100644 index 000000000000..a02e11f52906 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec4.vert.html new file mode 100644 index 000000000000..975a6f324b06 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_int_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec2_vec2.vert.html new file mode 100644 index 000000000000..2f19edafe25d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec3_vec3.vert.html new file mode 100644 index 000000000000..2db1d6a1a2bb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec4_vec4.vert.html new file mode 100644 index 000000000000..b04547e09c6a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__divide_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_int_float.vert.html new file mode 100644 index 000000000000..209db36e8f3f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec2_vec2.vert.html new file mode 100644 index 000000000000..59ddb8303cf4 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec3_vec3.vert.html new file mode 100644 index 000000000000..f55fb3805366 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec4_vec4.vert.html new file mode 100644 index 000000000000..f6e7f532ef29 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__equal_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_int_float.vert.html new file mode 100644 index 000000000000..a85624d53d4a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec2_vec2.vert.html new file mode 100644 index 000000000000..287f15fb32d5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec3_vec3.vert.html new file mode 100644 index 000000000000..dc4e2eca9a33 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec4_vec4.vert.html new file mode 100644 index 000000000000..f71e469a51bb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__function_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than.vert.html new file mode 100644 index 000000000000..a96682c348dc --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than_equal.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than_equal.vert.html new file mode 100644 index 000000000000..282cca9a0d4c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__greater_than_equal.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than.vert.html new file mode 100644 index 000000000000..ae59c2425e30 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than_equal.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than_equal.vert.html new file mode 100644 index 000000000000..79ca4dc22feb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__less_than_equal.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_float.vert.html new file mode 100644 index 000000000000..cd4399ff0083 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat2.vert.html new file mode 100644 index 000000000000..e0ca05f0b899 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat3.vert.html new file mode 100644 index 000000000000..f51684495485 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat4.vert.html new file mode 100644 index 000000000000..848ddef8897d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_mat4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec2.vert.html new file mode 100644 index 000000000000..d5dda986a70d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec3.vert.html new file mode 100644 index 000000000000..e1a5d32760d2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec4.vert.html new file mode 100644 index 000000000000..b61773b15c7f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_int_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec2_vec2.vert.html new file mode 100644 index 000000000000..33d1fe7206db --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec3_vec3.vert.html new file mode 100644 index 000000000000..c12237fa8866 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec4_vec4.vert.html new file mode 100644 index 000000000000..08a39164bf29 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__multiply_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_int_float.vert.html new file mode 100644 index 000000000000..42fe94f95981 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec2_vec2.vert.html new file mode 100644 index 000000000000..b2aa7c21e5f5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec3_vec3.vert.html new file mode 100644 index 000000000000..ce6cdc427a5d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec4_vec4.vert.html new file mode 100644 index 000000000000..c59fe1ce5d87 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__not_equal_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_float.vert.html new file mode 100644 index 000000000000..f90f8c5cf22b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat2.vert.html new file mode 100644 index 000000000000..2afcdf3e86b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat3.vert.html new file mode 100644 index 000000000000..1a171775a1b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat4.vert.html new file mode 100644 index 000000000000..8c2993a33352 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_mat4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec2.vert.html new file mode 100644 index 000000000000..d52b9fea558d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec3.vert.html new file mode 100644 index 000000000000..8d6945162666 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec4.vert.html new file mode 100644 index 000000000000..9359ef830019 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_int_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec2_vec2.vert.html new file mode 100644 index 000000000000..670b464c9633 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec3_vec3.vert.html new file mode 100644 index 000000000000..37b00818b4e7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec4_vec4.vert.html new file mode 100644 index 000000000000..633b3064d498 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__subtract_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_int_float.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_int_float.vert.html new file mode 100644 index 000000000000..db8753bb571f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_int_float.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec2_vec2.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec2_vec2.vert.html new file mode 100644 index 000000000000..eb1b3badda92 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec2_vec2.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec3_vec3.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec3_vec3.vert.html new file mode 100644 index 000000000000..ac0b515665b7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec3_vec3.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec4_vec4.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec4_vec4.vert.html new file mode 100644 index 000000000000..5bdafc2ee481 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__implicit__ternary_ivec4_vec4.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__attrib-location-length-limits.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__attrib-location-length-limits.html new file mode 100644 index 000000000000..e3666bc9c13f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__attrib-location-length-limits.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__embedded-struct-definitions-forbidden.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__embedded-struct-definitions-forbidden.html new file mode 100644 index 000000000000..bec04b7c6b22 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__embedded-struct-definitions-forbidden.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-function-nodes.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-function-nodes.html new file mode 100644 index 000000000000..424ef4dc7dad --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-function-nodes.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-long-variable-names.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-long-variable-names.html new file mode 100644 index 000000000000..3002cb29a44b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__glsl-long-variable-names.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii-comments.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii-comments.vert.html new file mode 100644 index 000000000000..b96cf0e9db26 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii-comments.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii.vert.html new file mode 100644 index 000000000000..cb7d788f8b02 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__non-ascii.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html new file mode 100644 index 000000000000..1e36b4a194cc --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html new file mode 100644 index 000000000000..e5a74480cb0a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html new file mode 100644 index 000000000000..f6346ef64348 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.frag.html new file mode 100644 index 000000000000..e9eb947628cb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.vert.html new file mode 100644 index 000000000000..96f487732417 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-array.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-array.vert.html new file mode 100644 index 000000000000..8a2c96f3c4c0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-array.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-struct.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-struct.vert.html new file mode 100644 index 000000000000..68acc94dbf7e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-attrib-struct.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-clipvertex.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-clipvertex.vert.html new file mode 100644 index 000000000000..de59dbca6f4d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-clipvertex.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.frag.html new file mode 100644 index 000000000000..95c0221b2c03 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.vert.html new file mode 100644 index 000000000000..6806536b53b1 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-default-precision.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-define-line-continuation.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-define-line-continuation.frag.html new file mode 100644 index 000000000000..ebed4ba81a8c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-define-line-continuation.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx-no-ext.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx-no-ext.frag.html new file mode 100644 index 000000000000..70b608feffa0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx-no-ext.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx.frag.html new file mode 100644 index 000000000000..2595ecb19105 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-dfdx.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-error-directive.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-error-directive.html new file mode 100644 index 000000000000..65ce329cfd61 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-error-directive.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-explicit-int-cast.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-explicit-int-cast.vert.html new file mode 100644 index 000000000000..3ee9233586de --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-explicit-int-cast.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-float-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-float-return-value.frag.html new file mode 100644 index 000000000000..69e0c97be92d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-float-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-frag-depth.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-frag-depth.frag.html new file mode 100644 index 000000000000..bc6f92d584e3 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-frag-depth.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-function-recursion.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-function-recursion.frag.html new file mode 100644 index 000000000000..1d9baca2d2a9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-function-recursion.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glcolor.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glcolor.vert.html new file mode 100644 index 000000000000..f31c1e23e0b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glcolor.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-1.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-1.frag.html new file mode 100644 index 000000000000..579ac7858d24 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-1.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-symbol.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-symbol.frag.html new file mode 100644 index 000000000000..73efccdb492c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-gles-symbol.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glprojectionmatrix.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glprojectionmatrix.vert.html new file mode 100644 index 000000000000..7103b1a20d8d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-glprojectionmatrix.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-implicit-vec3-to-vec4-cast.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-implicit-vec3-to-vec4-cast.vert.html new file mode 100644 index 000000000000..5c20c59eed30 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-implicit-vec3-to-vec4-cast.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-include.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-include.vert.html new file mode 100644 index 000000000000..006b113eb763 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-include.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-int-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-int-return-value.frag.html new file mode 100644 index 000000000000..a36c0751d22f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-int-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-invalid-identifier.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-invalid-identifier.frag.html new file mode 100644 index 000000000000..a956ba78aa5c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-invalid-identifier.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec2-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec2-return-value.frag.html new file mode 100644 index 000000000000..df9180e66685 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec2-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec3-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec3-return-value.frag.html new file mode 100644 index 000000000000..262152576e52 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec3-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec4-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec4-return-value.frag.html new file mode 100644 index 000000000000..4182be0a40c6 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-ivec4-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-limited-indexing.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-limited-indexing.frag.html new file mode 100644 index 000000000000..2501216a7fd4 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-limited-indexing.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-long-line.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-long-line.html new file mode 100644 index 000000000000..2b164b18d330 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-long-line.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-non-ascii-error.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-non-ascii-error.frag.html new file mode 100644 index 000000000000..195c94de2736 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-non-ascii-error.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-precision.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-precision.frag.html new file mode 100644 index 000000000000..5bf3ef3947dc --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-precision.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-quoted-error.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-quoted-error.frag.html new file mode 100644 index 000000000000..6a305cc82649 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-quoted-error.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-undefined-preprocessor-symbol.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-undefined-preprocessor-symbol.frag.html new file mode 100644 index 000000000000..d7a62c0d1abf --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-undefined-preprocessor-symbol.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-uniform-in-loop-condition.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-uniform-in-loop-condition.vert.html new file mode 100644 index 000000000000..41a738f36abf --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-uniform-in-loop-condition.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec2-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec2-return-value.frag.html new file mode 100644 index 000000000000..40c724072465 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec2-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec3-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec3-return-value.frag.html new file mode 100644 index 000000000000..97c8f4b56fab --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec3-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec4-return-value.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec4-return-value.frag.html new file mode 100644 index 000000000000..d451d727be0f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-vec4-return-value.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.frag.html new file mode 100644 index 000000000000..51eb16e291db --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.vert.html new file mode 100644 index 000000000000..a5d1cfd7a1f5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-100.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-120.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-120.vert.html new file mode 100644 index 000000000000..3028e6d863d8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-120.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-130.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-130.vert.html new file mode 100644 index 000000000000..babfea4770dd --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-version-130.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html new file mode 100644 index 000000000000..682e56edf8e0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-without-precision.frag.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-without-precision.frag.html new file mode 100644 index 000000000000..c7b722581b99 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shader-without-precision.frag.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shared.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shared.html new file mode 100644 index 000000000000..93f5ad3b9c59 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__shared.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html new file mode 100644 index 000000000000..99a6e437b411 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-under-maximum.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-under-maximum.html new file mode 100644 index 000000000000..879a70b4142d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__struct-nesting-under-maximum.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__uniform-location-length-limits.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__uniform-location-length-limits.html new file mode 100644 index 000000000000..d72b7ab2375e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__misc__uniform-location-length-limits.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_field.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_field.vert.html new file mode 100644 index 000000000000..e78c68fa9ec2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_field.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_function.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_function.vert.html new file mode 100644 index 000000000000..848112794d32 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_function.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_struct.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_struct.vert.html new file mode 100644 index 000000000000..31a8449a043e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_struct.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_variable.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_variable.vert.html new file mode 100644 index 000000000000..861e56c93389 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved___webgl_variable.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_field.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_field.vert.html new file mode 100644 index 000000000000..796a5e07a2b8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_field.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_function.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_function.vert.html new file mode 100644 index 000000000000..107b1f2abe79 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_function.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_struct.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_struct.vert.html new file mode 100644 index 000000000000..c2827f454997 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_struct.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_variable.vert.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_variable.vert.html new file mode 100644 index 000000000000..a9a72aee9263 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__reserved__webgl_variable.vert.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-fragcoord.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-fragcoord.html new file mode 100644 index 000000000000..e9210497849c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-fragcoord.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-frontfacing.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-frontfacing.html new file mode 100644 index 000000000000..07c0f0f4505f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-frontfacing.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-pointcoord.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-pointcoord.html new file mode 100644 index 000000000000..1a963e87b5fa --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__glsl__variables__gl-pointcoord.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-max-texture-dimensions.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-max-texture-dimensions.html new file mode 100644 index 000000000000..89c64a76bbad --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-max-texture-dimensions.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-attribs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-attribs.html new file mode 100644 index 000000000000..50a2fb26911b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-attribs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-textures.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-textures.html new file mode 100644 index 000000000000..812dfb0b86e9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-textures.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-uniforms.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-uniforms.html new file mode 100644 index 000000000000..a66f81be094d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__limits__gl-min-uniforms.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__bad-arguments-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__bad-arguments-test.html new file mode 100644 index 000000000000..3e58c2f9b125 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__bad-arguments-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__error-reporting.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__error-reporting.html new file mode 100644 index 000000000000..e640756b6134 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__error-reporting.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__functions-returning-strings.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__functions-returning-strings.html new file mode 100644 index 000000000000..483f98c6912e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__functions-returning-strings.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__instanceof-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__instanceof-test.html new file mode 100644 index 000000000000..b62554954e74 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__instanceof-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__invalid-passed-params.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__invalid-passed-params.html new file mode 100644 index 000000000000..42f9b1053298 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__invalid-passed-params.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__is-object.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__is-object.html new file mode 100644 index 000000000000..aa35bd63945a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__is-object.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__null-object-behaviour.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__null-object-behaviour.html new file mode 100644 index 000000000000..60a200dabbd4 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__null-object-behaviour.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__object-deletion-behaviour.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__object-deletion-behaviour.html new file mode 100644 index 000000000000..5325ba091639 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__object-deletion-behaviour.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__shader-precision-format.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__shader-precision-format.html new file mode 100644 index 000000000000..daecd025935e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__shader-precision-format.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__type-conversion-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__type-conversion-test.html new file mode 100644 index 000000000000..c10010e63643 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__type-conversion-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__uninitialized-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__uninitialized-test.html new file mode 100644 index 000000000000..a1bab914a521 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__uninitialized-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__webgl-specific.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__webgl-specific.html new file mode 100644 index 000000000000..1a804c12be43 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__misc__webgl-specific.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__constants.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__constants.html new file mode 100644 index 000000000000..53ef41d71262 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__constants.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__getContext.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__getContext.html new file mode 100644 index 000000000000..3704eb18c255 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__getContext.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__methods.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__methods.html new file mode 100644 index 000000000000..7919bda142b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__methods.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-A.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-A.html new file mode 100644 index 000000000000..ec8805bef5b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-A.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B1.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B1.html new file mode 100644 index 000000000000..862abb1aea74 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B1.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B2.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B2.html new file mode 100644 index 000000000000..8d7bc6c1694d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B2.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B3.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B3.html new file mode 100644 index 000000000000..0c82ccf9773f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B3.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B4.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B4.html new file mode 100644 index 000000000000..0d87559013dd --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-B4.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-C.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-C.html new file mode 100644 index 000000000000..e766d039fb6b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-C.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-D_G.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-D_G.html new file mode 100644 index 000000000000..84da596a9396 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-D_G.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-G_I.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-G_I.html new file mode 100644 index 000000000000..5ca394e408a6 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-G_I.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-L_S.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-L_S.html new file mode 100644 index 000000000000..fe5915234314 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-L_S.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-S_V.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-S_V.html new file mode 100644 index 000000000000..f97fe730ccc8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__quickCheckAPI-S_V.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__webGLArrays.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__webGLArrays.html new file mode 100644 index 000000000000..205af15df6f9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__conformance__webGLArrays.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBuffer.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBuffer.html new file mode 100644 index 000000000000..0f357b40b191 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBuffer.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBufferBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBufferBadArgs.html new file mode 100644 index 000000000000..d2e988db25c7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindBufferBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindFramebufferLeaveNonZero.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindFramebufferLeaveNonZero.html new file mode 100644 index 000000000000..dee2bb4df6b7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bindFramebufferLeaveNonZero.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferData.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferData.html new file mode 100644 index 000000000000..045d2c46b765 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferData.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferDataBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferDataBadArgs.html new file mode 100644 index 000000000000..848f9237d399 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferDataBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubData.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubData.html new file mode 100644 index 000000000000..1145d935e4b7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubData.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubDataBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubDataBadArgs.html new file mode 100644 index 000000000000..0c84481dcff7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__bufferSubDataBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2D.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2D.html new file mode 100644 index 000000000000..5f0b506b6bf2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2D.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2DBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2DBadArgs.html new file mode 100644 index 000000000000..1be576e27b7c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexImage2DBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2D.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2D.html new file mode 100644 index 000000000000..67bcf9ca07bb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2D.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2DBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2DBadArgs.html new file mode 100644 index 000000000000..9f0e41499ee8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__copyTexSubImage2DBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__deleteBufferBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__deleteBufferBadArgs.html new file mode 100644 index 000000000000..412ef4168388 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__deleteBufferBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArrays.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArrays.html new file mode 100644 index 000000000000..f7aca4041e53 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArrays.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArraysOutOfBounds.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArraysOutOfBounds.html new file mode 100644 index 000000000000..96a687dba215 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawArraysOutOfBounds.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElements.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElements.html new file mode 100644 index 000000000000..5b70f65b8cff --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElements.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElementsBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElementsBadArgs.html new file mode 100644 index 000000000000..2df86d4b1a30 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__drawElementsBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__isTests.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__isTests.html new file mode 100644 index 000000000000..16ec0507d93a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__isTests.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixels.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixels.html new file mode 100644 index 000000000000..a28f3a09f955 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixels.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixelsBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixelsBadArgs.html new file mode 100644 index 000000000000..f9bbbf0cc418 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__readPixelsBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2D.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2D.html new file mode 100644 index 000000000000..84972611676f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2D.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DBadArgs.html new file mode 100644 index 000000000000..a02458217e5d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTML.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTML.html new file mode 100644 index 000000000000..964b3d6a3233 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTML.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTMLBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTMLBadArgs.html new file mode 100644 index 000000000000..42047bbeda7a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texImage2DHTMLBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2D.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2D.html new file mode 100644 index 000000000000..43aeca22c857 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2D.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DBadArgs.html new file mode 100644 index 000000000000..8335e6f6b5bb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTML.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTML.html new file mode 100644 index 000000000000..c3f710f739d7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTML.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTMLBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTMLBadArgs.html new file mode 100644 index 000000000000..aff02c5e0404 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__texSubImage2DHTMLBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrix.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrix.html new file mode 100644 index 000000000000..26d078ce1947 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrix.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrixBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrixBadArgs.html new file mode 100644 index 000000000000..bb9b63bbbf99 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformMatrixBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformf.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformf.html new file mode 100644 index 000000000000..148a5ed29926 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformf.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfArrayLen1.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfArrayLen1.html new file mode 100644 index 000000000000..901393183ca5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfArrayLen1.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfBadArgs.html new file mode 100644 index 000000000000..db28df30f7fb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformfBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformi.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformi.html new file mode 100644 index 000000000000..2b6c1481765b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformi.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformiBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformiBadArgs.html new file mode 100644 index 000000000000..5f9cb87cea32 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__uniformiBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttrib.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttrib.html new file mode 100644 index 000000000000..5a8fe516b1b9 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttrib.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribBadArgs.html new file mode 100644 index 000000000000..08bdf9067f81 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointer.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointer.html new file mode 100644 index 000000000000..a925e0f992f8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointer.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointerBadArgs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointerBadArgs.html new file mode 100644 index 000000000000..47f0154a78e5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__functions__vertexAttribPointerBadArgs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__arrayOutOfBounds.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__arrayOutOfBounds.html new file mode 100644 index 000000000000..2759ec0d383a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__arrayOutOfBounds.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__uniformOutOfBounds.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__uniformOutOfBounds.html new file mode 100644 index 000000000000..7eb5f0ecc5cf --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__more__glsl__uniformOutOfBounds.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__get-active-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__get-active-test.html new file mode 100644 index 000000000000..602487cb1ded --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__get-active-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html new file mode 100644 index 000000000000..7b1dd7693d7b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-attribute.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-attribute.html new file mode 100644 index 000000000000..7494e0e50d59 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-attribute.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-uniform.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-uniform.html new file mode 100644 index 000000000000..5bcf77bdafce --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-get-active-uniform.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-getshadersource.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-getshadersource.html new file mode 100644 index 000000000000..bdd5170f17a7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-getshadersource.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-shader-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-shader-test.html new file mode 100644 index 000000000000..690eed92e7fb --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__gl-shader-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__invalid-UTF-16.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__invalid-UTF-16.html new file mode 100644 index 000000000000..8dee105242a2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__invalid-UTF-16.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__program-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__program-test.html new file mode 100644 index 000000000000..040a2a5c0747 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__programs__program-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-pack-alignment.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-pack-alignment.html new file mode 100644 index 000000000000..19aaa15288b2 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-pack-alignment.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-test.html new file mode 100644 index 000000000000..234c5c0eefe0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__reading__read-pixels-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html new file mode 100644 index 000000000000..b214c03f849c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-test.html new file mode 100644 index 000000000000..34349ec4fde8 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__framebuffer-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html new file mode 100644 index 000000000000..939480135257 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html new file mode 100644 index 000000000000..f70689e73386 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html new file mode 100644 index 000000000000..d21e48f84e41 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-clear.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-clear.html new file mode 100644 index 000000000000..682a60acad3c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-clear.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-drawelements.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-drawelements.html new file mode 100644 index 000000000000..111b0faee206 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-drawelements.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-scissor-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-scissor-test.html new file mode 100644 index 000000000000..a791d47cef9d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__gl-scissor-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__line-loop-tri-fan.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__line-loop-tri-fan.html new file mode 100644 index 000000000000..ba97c48a2e9b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__line-loop-tri-fan.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__more-than-65536-indices.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__more-than-65536-indices.html new file mode 100644 index 000000000000..b5742885a25e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__more-than-65536-indices.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__point-size.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__point-size.html new file mode 100644 index 000000000000..1dd58ccd4ab0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__point-size.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__triangle.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__triangle.html new file mode 100644 index 000000000000..a3269f888a69 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__rendering__triangle.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enable-enum-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enable-enum-test.html new file mode 100644 index 000000000000..10b321306f76 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enable-enum-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enum-tests.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enum-tests.html new file mode 100644 index 000000000000..3dc184a2908f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-enum-tests.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-get-calls.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-get-calls.html new file mode 100644 index 000000000000..b17bca8e30b0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-get-calls.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-geterror.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-geterror.html new file mode 100644 index 000000000000..ad20a97c6588 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-geterror.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-getstring.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-getstring.html new file mode 100644 index 000000000000..8ecb4904ad67 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-getstring.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-object-get-calls.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-object-get-calls.html new file mode 100644 index 000000000000..98ff81f236cf --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__state__gl-object-get-calls.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__compressed-tex-image.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__compressed-tex-image.html new file mode 100644 index 000000000000..34839c4a8d51 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__compressed-tex-image.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html new file mode 100644 index 000000000000..6d5caa67f903 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-pixelstorei.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-pixelstorei.html new file mode 100644 index 000000000000..db66679e60bc --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-pixelstorei.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-teximage.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-teximage.html new file mode 100644 index 000000000000..1a09a4425748 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__gl-teximage.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__origin-clean-conformance.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__origin-clean-conformance.html new file mode 100644 index 000000000000..260b8fb2d754 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__origin-clean-conformance.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html new file mode 100644 index 000000000000..6b07577816db --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html new file mode 100644 index 000000000000..9d9f9aeac017 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html new file mode 100644 index 000000000000..4c24cca77bee --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html new file mode 100644 index 000000000000..fd40cd4f24ef --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html new file mode 100644 index 000000000000..25929ab18b40 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html new file mode 100644 index 000000000000..b0f5d6d67c8f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-format-and-type.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-format-and-type.html new file mode 100644 index 000000000000..19a2ada2451c --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-format-and-type.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-invalid-data.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-invalid-data.html new file mode 100644 index 000000000000..2c038ea03c89 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-image-with-invalid-data.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-input-validation.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-input-validation.html new file mode 100644 index 000000000000..0a623a9db8d7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-input-validation.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html new file mode 100644 index 000000000000..e61c4155a11d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d.html new file mode 100644 index 000000000000..343c47647ed0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texparameter-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texparameter-test.html new file mode 100644 index 000000000000..d8b64f756718 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texparameter-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind-2.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind-2.html new file mode 100644 index 000000000000..4011b277900e --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind-2.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind.html new file mode 100644 index 000000000000..489777327b7f --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-complete.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-complete.html new file mode 100644 index 000000000000..5bbc699cbf92 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-complete.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html new file mode 100644 index 000000000000..ea62f8612453 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html new file mode 100644 index 000000000000..27d0fee5520a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html new file mode 100644 index 000000000000..4050730c0c31 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html new file mode 100644 index 000000000000..c7f19f8d13a6 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size-cube-maps.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size-cube-maps.html new file mode 100644 index 000000000000..eb6b1d7ab1a7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size-cube-maps.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size.html new file mode 100644 index 000000000000..7dfcfb20bf63 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-size.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html new file mode 100644 index 000000000000..7af2dbe45f6b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-crash.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-crash.html new file mode 100644 index 000000000000..b354487d680b --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-crash.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html new file mode 100644 index 000000000000..9b3a0ac9ef87 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-unit-tests.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-unit-tests.html new file mode 100644 index 000000000000..3fd2ae100bee --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__typedarrays__array-unit-tests.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-arrays.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-arrays.html new file mode 100644 index 000000000000..ded77fb8bcaa --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-arrays.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-bool.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-bool.html new file mode 100644 index 000000000000..6bc3763c40e5 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniform-bool.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniformmatrix4fv.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniformmatrix4fv.html new file mode 100644 index 000000000000..de6efb4bf9db --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-uniformmatrix4fv.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-unknown-uniform.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-unknown-uniform.html new file mode 100644 index 000000000000..995073d4e4e7 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__gl-unknown-uniform.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__null-uniform-location.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__null-uniform-location.html new file mode 100644 index 000000000000..c847d2110f6d --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__null-uniform-location.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-location.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-location.html new file mode 100644 index 000000000000..7e29f516b128 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-location.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-samplers-test.html b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-samplers-test.html new file mode 100644 index 000000000000..619cfc4307f0 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_conformance__uniforms__uniform-samplers-test.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + From fe3b20f8fe3fe2e06c422147f85e4c875164a481 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 17:31:39 -0700 Subject: [PATCH 051/120] Bug 1052240 - Fix test failures. - r=kamidphish --- .../conformance/textures/texture-npot-video.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dom/canvas/test/webgl-conformance/conformance/textures/texture-npot-video.html b/dom/canvas/test/webgl-conformance/conformance/textures/texture-npot-video.html index f50777598c5e..e5e0ad47a9e6 100644 --- a/dom/canvas/test/webgl-conformance/conformance/textures/texture-npot-video.html +++ b/dom/canvas/test/webgl-conformance/conformance/textures/texture-npot-video.html @@ -124,8 +124,13 @@ function runOneIteration(videoElement, useTexSubImage2D, flipY, topColor, bottom debug(""); } +alreadyDone = false; function runTest(videoElement) { + if (alreadyDone) + return; + alreadyDone = true; + var red = [255, 0, 0]; var green = [0, 255, 0]; var black = [0, 0, 0]; From 0337a93f510b062811c19f14888d1354c2f750fe Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 17:31:40 -0700 Subject: [PATCH 052/120] Bug 1052240 - Rearrange some code. - r=kamidphish --- .../test/webgl-conformance/mochi-single.html | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/dom/canvas/test/webgl-conformance/mochi-single.html b/dom/canvas/test/webgl-conformance/mochi-single.html index 125f549306e4..9b1b88352d07 100644 --- a/dom/canvas/test/webgl-conformance/mochi-single.html +++ b/dom/canvas/test/webgl-conformance/mochi-single.html @@ -22,16 +22,49 @@ WebGL Conformance Test Suite Single Test Wrapper var IFRAME_BODY_MARGIN = 8; var IFRAME_SIZE_UPDATE_INTERVAL = 100; // ms -//////////////////////////////////////// - var statusElem = document.getElementById('status'); var pathElem = document.getElementById('path'); var resultsElem = document.getElementById('results'); var frameElem = document.getElementById('test-frame'); +//////////////////////////////////////////////////////////////////////// +// Forward SimpleTest functions and replace if missing. + +if (!window.ok) { + window.ok = parent.ok; +} +if (!window.todo) { + window.todo = parent.todo; +} +if (!window.SimpleTest) { + window.SimpleTest = parent.SimpleTest; +} + +if (!window.ok) { + window.ok = function(status, message) { + console.log('ok(' + status + ', "' + message + '")'); + } +} +if (!window.todo) { + window.todo = function(status, message) { + console.log('todo(' + status + ', "' + message + '")'); + } +} +if (!window.SimpleTest) { + window.SimpleTest = { + waitForExplicitFinish: function(){}, + finish: function(){}, + }; +} + +//////////////////////////////////////////////////////////////////////// +// Test running and harness. + +var gTestPath = null; function RunTest(testPath) { pathElem.innerHTML = testPath; + gTestPath = testPath; // Auto-update to grow the size of the doc. function UpdateFrameSize() { @@ -78,8 +111,6 @@ window.webglTestHarness = { }, }; -var gTestPath = null; - function OnTestComplete() { statusElem.innerHTML = 'Complete'; @@ -88,34 +119,7 @@ function OnTestComplete() { SimpleTest.finish(); } -if (!window.ok) { - window.ok = parent.ok; -} -if (!window.todo) { - window.todo = parent.todo; -} -if (!window.SimpleTest) { - window.SimpleTest = parent.SimpleTest; -} - -if (!window.ok) { - window.ok = function(status, message) { - console.log('ok(' + status + ', "' + message + '")'); - } -} -if (!window.todo) { - window.todo = function(status, message) { - console.log('todo(' + status + ', "' + message + '")'); - } -} -if (!window.SimpleTest) { - window.SimpleTest = { - waitForExplicitFinish: function(){}, - finish: function(){}, - }; -} - -//////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// // Begin execution SimpleTest.waitForExplicitFinish(); From 2fd2b1c2de2074baf5754c4158109dde85d87c9c Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 17:31:40 -0700 Subject: [PATCH 053/120] Bug 1052240 - Mark tests to fail/skip. - r=kamidphish --- .../test/webgl-conformance/00_test_list.txt | 2 + .../test/webgl-conformance/_mochitest.ini | 18 ++- .../_wrappers/test_always-fail.html | 16 +++ .../test/webgl-conformance/always-fail.html | 25 ++++ .../generate-wrappers-and-manifest.py | 76 ++++++++++- .../test/webgl-conformance/mochi-single.html | 121 +++++++++++++++++- .../webgl-conformance/mochitest-errata.ini | 74 +++++++++++ .../webgl-conformance/mochitest.ini.template | 3 +- 8 files changed, 325 insertions(+), 10 deletions(-) create mode 100644 dom/canvas/test/webgl-conformance/_wrappers/test_always-fail.html create mode 100644 dom/canvas/test/webgl-conformance/always-fail.html create mode 100644 dom/canvas/test/webgl-conformance/mochitest-errata.ini diff --git a/dom/canvas/test/webgl-conformance/00_test_list.txt b/dom/canvas/test/webgl-conformance/00_test_list.txt index 03c181f2393a..0dfec1244325 100644 --- a/dom/canvas/test/webgl-conformance/00_test_list.txt +++ b/dom/canvas/test/webgl-conformance/00_test_list.txt @@ -1,6 +1,8 @@ // files that end in .txt list other tests // other lines are assumed to be .html files +always-fail.html + conformance/00_test_list.txt conformance/more/00_test_list.txt diff --git a/dom/canvas/test/webgl-conformance/_mochitest.ini b/dom/canvas/test/webgl-conformance/_mochitest.ini index 5029548bb667..5ebad4c63721 100644 --- a/dom/canvas/test/webgl-conformance/_mochitest.ini +++ b/dom/canvas/test/webgl-conformance/_mochitest.ini @@ -1,7 +1,9 @@ [DEFAULT] -skip-if = e10s +skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g')) + support-files = mochi-single.html mochi-wrapper.css + always-fail.html conformance/00_readme.txt conformance/00_test_list.txt conformance/LICENSE_CHROMIUM @@ -477,6 +479,7 @@ support-files = mochi-single.html resources/webgl-logo.png resources/webgl-test-harness.js +[_wrappers/test_always-fail.html] [_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html] [_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html] [_wrappers/test_conformance__attribs__gl-vertex-attrib.html] @@ -498,6 +501,7 @@ support-files = mochi-single.html [_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html] [_wrappers/test_conformance__context__constants.html] [_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html] +skip-if = (os == 'b2g') [_wrappers/test_conformance__context__context-lost-restored.html] [_wrappers/test_conformance__context__context-lost.html] [_wrappers/test_conformance__context__context-type-test.html] @@ -687,13 +691,16 @@ support-files = mochi-single.html [_wrappers/test_conformance__misc__error-reporting.html] [_wrappers/test_conformance__misc__instanceof-test.html] [_wrappers/test_conformance__misc__invalid-passed-params.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__misc__is-object.html] [_wrappers/test_conformance__misc__null-object-behaviour.html] [_wrappers/test_conformance__misc__functions-returning-strings.html] [_wrappers/test_conformance__misc__object-deletion-behaviour.html] [_wrappers/test_conformance__misc__shader-precision-format.html] [_wrappers/test_conformance__misc__type-conversion-test.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__misc__uninitialized-test.html] +skip-if = os == 'android' [_wrappers/test_conformance__misc__webgl-specific.html] [_wrappers/test_conformance__programs__get-active-test.html] [_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html] @@ -705,7 +712,9 @@ support-files = mochi-single.html [_wrappers/test_conformance__programs__program-test.html] [_wrappers/test_conformance__reading__read-pixels-pack-alignment.html] [_wrappers/test_conformance__reading__read-pixels-test.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html] +skip-if = os == 'android' [_wrappers/test_conformance__renderbuffers__framebuffer-test.html] [_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html] [_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html] @@ -727,16 +736,21 @@ support-files = mochi-single.html [_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html] [_wrappers/test_conformance__textures__gl-pixelstorei.html] [_wrappers/test_conformance__textures__gl-teximage.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__origin-clean-conformance.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html] +skip-if = (os == 'b2g') [_wrappers/test_conformance__textures__tex-image-with-format-and-type.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__tex-image-with-invalid-data.html] [_wrappers/test_conformance__textures__tex-input-validation.html] +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html] [_wrappers/test_conformance__textures__tex-sub-image-2d.html] [_wrappers/test_conformance__textures__texparameter-test.html] @@ -748,7 +762,9 @@ support-files = mochi-single.html [_wrappers/test_conformance__textures__texture-npot-video.html] [_wrappers/test_conformance__textures__texture-npot.html] [_wrappers/test_conformance__textures__texture-size.html] +skip-if = os == 'android' [_wrappers/test_conformance__textures__texture-size-cube-maps.html] +skip-if = os == 'android' [_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html] [_wrappers/test_conformance__typedarrays__array-buffer-crash.html] [_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html] diff --git a/dom/canvas/test/webgl-conformance/_wrappers/test_always-fail.html b/dom/canvas/test/webgl-conformance/_wrappers/test_always-fail.html new file mode 100644 index 000000000000..fa21cf050e9a --- /dev/null +++ b/dom/canvas/test/webgl-conformance/_wrappers/test_always-fail.html @@ -0,0 +1,16 @@ + + + + + +Mochitest wrapper for WebGL Conformance Test Suite tests + + + + + + + + + diff --git a/dom/canvas/test/webgl-conformance/always-fail.html b/dom/canvas/test/webgl-conformance/always-fail.html new file mode 100644 index 000000000000..397c950e54e4 --- /dev/null +++ b/dom/canvas/test/webgl-conformance/always-fail.html @@ -0,0 +1,25 @@ + + + + + Always fail test + + + + + + +
+
+ + + + + + diff --git a/dom/canvas/test/webgl-conformance/generate-wrappers-and-manifest.py b/dom/canvas/test/webgl-conformance/generate-wrappers-and-manifest.py index ec190773af23..0876d343eb84 100644 --- a/dom/canvas/test/webgl-conformance/generate-wrappers-and-manifest.py +++ b/dom/canvas/test/webgl-conformance/generate-wrappers-and-manifest.py @@ -220,16 +220,41 @@ def WriteWrappers(testFilePathList): def WriteManifest(wrapperFilePathList, supportFilePathList): - manifestTestList = [] - for cur in wrapperFilePathList: - manifestTestList.append('[' + cur + ']') + errataMap = LoadErrata() + # DEFAULT_ERRATA + defaultHeader = '[DEFAULT]' + defaultErrataStr = '' + if defaultHeader in errataMap: + defaultErrataStr = '\n'.join(errataMap[defaultHeader]) + del errataMap[defaultHeader] + + # SUPPORT_FILES supportFilePathList = sorted(supportFilePathList) - supportFilesStr = '\n'.join(supportFilePathList) - manifestTestsStr = '\n'.join(manifestTestList) + # MANIFEST_TESTS + headerList = ['[' + x + ']' for x in wrapperFilePathList] + + manifestTestLineList = [] + for header in headerList: + manifestTestLineList.append(header) + + if not header in errataMap: + continue + + errataLineList = errataMap[header] + del errataMap[header] + manifestTestLineList += errataLineList + continue + + assert not errataMap, 'Errata left in map: {}'.format(str(errataMap)) + + manifestTestsStr = '\n'.join(manifestTestLineList) + + # Fill the template. templateDict = { + 'DEFAULT_ERRATA': defaultErrataStr, 'SUPPORT_FILES': supportFilesStr, 'MANIFEST_TESTS': manifestTestsStr, } @@ -245,6 +270,39 @@ WRAPPER_TEMPLATE_FILEPATH = 'mochi-wrapper.html.template' WRAPPERS_DIR = '_wrappers' MANIFEST_TEMPLATE_FILEPATH = 'mochitest.ini.template' MANIFEST_OUTPUT_FILEPATH = '_mochitest.ini' +ERRATA_FILEPATH = 'mochitest-errata.ini' +kManifestHeaderRegex = re.compile(r'\[[^\]]*?\]') + + +def LoadErrata(): + nodeMap = {} + + nodeHeader = None + nodeLineList = [] + with open(ERRATA_FILEPATH, 'r') as f: + for line in f: + line = line.rstrip() + cur = line.lstrip() + if cur.startswith('#'): + continue + + if not cur: + continue + + if not cur.startswith('['): + nodeLineList.append(line) + continue + + match = kManifestHeaderRegex.search(cur) + assert match, line + + nodeHeader = match.group() + assert not nodeHeader in nodeMap, 'Duplicate header: ' + nodeHeader + nodeLineList = [] + nodeMap[nodeHeader] = nodeLineList + continue + + return nodeMap ######################################################################## @@ -253,13 +311,21 @@ SUPPORT_DIRS = [ 'resources', ] +EXTRA_SUPPORT_FILES = [ + 'always-fail.html', +] + + def GetSupportFileList(): ret = [] for supportDir in SUPPORT_DIRS: ret += GetFilePathListForDir(supportDir) + ret += EXTRA_SUPPORT_FILES + return ret + def GetFilePathListForDir(baseDir): ret = [] for root, folders, files in os.walk(baseDir): diff --git a/dom/canvas/test/webgl-conformance/mochi-single.html b/dom/canvas/test/webgl-conformance/mochi-single.html index 9b1b88352d07..8919985ec209 100644 --- a/dom/canvas/test/webgl-conformance/mochi-single.html +++ b/dom/canvas/test/webgl-conformance/mochi-single.html @@ -57,12 +57,120 @@ if (!window.SimpleTest) { }; } +//////////////////////////////////////////////////////////////////////// +// Implement our own version of `fail-if` expected failure handling. +// `fail-if` in mochitest.ini doesn't work yet. (bug 987849) + +var OS_VERSION_WIN7 = 6.1; +var OS_VERSION_OSX_10_6 = 10.6; +var OS_VERSION_OSX_10_8 = 10.8; + +// ICS 4.0-4.0.2 was 14, 4.0.3+ was 15. +var OS_VERSION_ANDROID_ICS = 14; + +var ALWAYS_FAIL_TEST_FILEPATH = 'always-fail.html'; + +function GetExpectedTestFailSet() { + var failSet = {}; + + failSet[ALWAYS_FAIL_TEST_FILEPATH] = true; + + switch (DriverInfo.getOS()) { + case DriverInfo.OS.WINDOWS: + if (DriverInfo.getOSVersion() >= OS_VERSION_WIN7) { + // Win7 and Win8 slaves. + failSet['conformance/textures/tex-image-and-sub-image-2d-with-video.html'] = true; + failSet['conformance/textures/texture-npot-video.html'] = true; + } + break; + + case DriverInfo.OS.MAC: + if (DriverInfo.getOSVersion() == OS_VERSION_OSX_10_8) { + failSet['conformance/glsl/functions/glsl-function-smoothstep-gentype.html'] = true; + failSet['conformance/glsl/variables/gl-pointcoord.html'] = true; + failSet['conformance/limits/gl-max-texture-dimensions.html'] = true; + failSet['conformance/textures/texture-size.html'] = true; + } else if (DriverInfo.getOSVersion() == OS_VERSION_OSX_10_6) { + failSet['conformance/glsl/misc/glsl-function-nodes.html'] = true; + } + break; + + case DriverInfo.OS.LINUX: + failSet['conformance/extensions/oes-texture-float.html'] = true; + failSet['conformance/glsl/functions/glsl-function-sin.html'] = true; + failSet['conformance/misc/type-conversion-test.html'] = true; + failSet['conformance/textures/texture-mips.html'] = true; + failSet['conformance/textures/texture-size-cube-maps.html'] = true; + break; + + case DriverInfo.OS.ANDROID: + failSet['conformance/extensions/oes-texture-float.html'] = true; + + if (DriverInfo.getOSVersion() >= OS_VERSION_ANDROID_ICS) { + // Android 4.0 slaves. + failSet['conformance/extensions/oes-vertex-array-object.html'] = true; + failSet['conformance/glsl/functions/glsl-function-abs.html'] = true; + failSet['conformance/glsl/functions/glsl-function-faceforward.html'] = true; + failSet['conformance/glsl/functions/glsl-function-sign.html'] = true; + failSet['conformance/glsl/functions/glsl-function-smoothstep-float.html'] = true; + failSet['conformance/glsl/functions/glsl-function-step-float.html'] = true; + failSet['conformance/glsl/functions/glsl-function-step-gentype.html'] = true; + failSet['conformance/limits/gl-max-texture-dimensions.html'] = true; + failSet['conformance/limits/gl-min-textures.html'] = true; + failSet['conformance/rendering/draw-elements-out-of-bounds.html'] = true; + failSet['conformance/state/gl-get-calls.html'] = true; + failSet['conformance/textures/tex-image-with-format-and-type.html'] = true; + failSet['conformance/textures/tex-sub-image-2d.html'] = true; + failSet['conformance/textures/texture-mips.html'] = true; + failSet['conformance/textures/texture-npot.html'] = true; + failSet['conformance/textures/texture-size-cube-maps.html'] = true; + } else { + // Android 2.3 slaves. + failSet['conformance/glsl/functions/glsl-function-sin.html'] = true; + failSet['conformance/misc/error-reporting.html'] = true; + failSet['conformance/misc/object-deletion-behaviour.html'] = true; + failSet['conformance/programs/get-active-test.html'] = true; + failSet['conformance/textures/tex-image-and-sub-image-2d-with-video.html'] = true; + failSet['conformance/textures/texture-mips.html'] = true; + failSet['conformance/textures/texture-npot.html'] = true; + } + break; + + case DriverInfo.OS.B2G: + failSet['conformance/context/context-attributes-alpha-depth-stencil-antialias.html'] = true; + failSet['conformance/extensions/oes-texture-float.html'] = true; + failSet['conformance/glsl/functions/glsl-function-sin.html'] = true; + failSet['conformance/glsl/reserved/_webgl_function.vert.html'] = true; + failSet['conformance/glsl/reserved/webgl_function.vert.html'] = true; + failSet['conformance/misc/error-reporting.html'] = true; + failSet['conformance/misc/object-deletion-behaviour.html'] = true; + failSet['conformance/programs/get-active-test.html'] = true; + failSet['conformance/textures/tex-input-validation.html'] = true; + failSet['conformance/textures/texture-mips.html'] = true; + failSet['conformance/textures/texture-npot.html'] = true; + failSet['conformance/textures/texture-size-cube-maps.html'] = true; + failSet['conformance/textures/texture-size.html'] = true; + break; + } + + return failSet; +} + //////////////////////////////////////////////////////////////////////// // Test running and harness. var gTestPath = null; function RunTest(testPath) { + console.log('testPath: ' + testPath); + + if (testPath == ALWAYS_FAIL_TEST_FILEPATH) { + // Make it easier to respond to new test failures. + console.log('OS: ' + DriverInfo.getOS()); + console.log('OS version: ' + DriverInfo.getOSVersion()); + console.log('Driver: ' + DriverInfo.getDriver()); + } + pathElem.innerHTML = testPath; gTestPath = testPath; @@ -115,7 +223,15 @@ function OnTestComplete() { statusElem.innerHTML = 'Complete'; var passed = failureCount == 0; - ok(passed, 'Should pass: ' + gTestPath); + + var passExpected = true; + if (gTestPath in GetExpectedTestFailSet()) + passExpected = false; + + var expectedStatus = passExpected ? 'pass' : 'fail'; + var text = 'Should ' + expectedStatus + ': ' + gTestPath; + + ok(passed == passExpected, text); SimpleTest.finish(); } @@ -137,8 +253,7 @@ do { break; } - gTestPath = arg; - RunTest(gTestPath); + RunTest(arg); } while (false); diff --git a/dom/canvas/test/webgl-conformance/mochitest-errata.ini b/dom/canvas/test/webgl-conformance/mochitest-errata.ini new file mode 100644 index 000000000000..6f0012af76ec --- /dev/null +++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini @@ -0,0 +1,74 @@ +# See python/mozbuild/mozbuild/mozinfo.py for incoming data. + +[DEFAULT] +# No e10s yet. +# 'B2G Desktop Linux' fails to create WebGL contexts. +# Also skip B2G for now, until we get a handle on the longer tail of emulator +# bugs. +skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g')) + +######################################################################## +# All +#[_wrappers/test_always-fail.html] +#fail-if = 1 +# We'll be able to use `fail-if` after bug 987849. + +######################################################################## +# "tst-linux{32,64}-spot-NNN" Slaves: +# Android 2.3, B2G Emu, Linux, and Mulet. +# Android: os == 'android'. (Not enough info to separate out 2.3) +# B2G Emu: os == 'b2g'. +# Linux: os == 'linux'. +# Mulet: os == 'b2g' && buildapp == 'mulet'. +[_wrappers/test_conformance__misc__invalid-passed-params.html] +# Causes consistent *blues*: "DMError: Remote Device Error: unable to +# connect to 127.0.0.1 after 5 attempts" on 'Android 2.3 Opt'. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +[_wrappers/test_conformance__reading__read-pixels-test.html] +# Causes consistent *blues*: "DMError: Remote Device Error: unable to +# connect to 127.0.0.1 after 5 attempts" on 'Android 2.3 Opt'. +# Crashes near on B2G ICS Emulator. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +[_wrappers/test_conformance__textures__gl-teximage.html] +# Crashes on Android 2.3. +# Crashes near on B2G ICS Emulator. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +[_wrappers/test_conformance__misc__type-conversion-test.html] +# Resets device on Android 2.3. +# Crashes on B2G ICS Emulator, desktop Linux, and Mulet Linux x64. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html] +# Random fail on Android 2.3. +# Crashes on Mulet Linux x64 and B2G ICS Emulator. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +[_wrappers/test_conformance__textures__tex-image-with-format-and-type.html] +# Crashes or blues on Android 2.3 +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +[_wrappers/test_conformance__textures__tex-input-validation.html] +# Crashes on 'Android 2.3' +# Asserts on 'B2G ICS Emulator Debug'. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') + +######################################################################## +# Android +[_wrappers/test_conformance__misc__uninitialized-test.html] +# Crashes on Android. +skip-if = os == 'android' +[_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html] +# Crashes on Android. +skip-if = os == 'android' +[_wrappers/test_conformance__textures__texture-size.html] +# Crashes on Android 4.0. +skip-if = os == 'android' +[_wrappers/test_conformance__textures__texture-size-cube-maps.html] +# Crashes on Android 4.0. +skip-if = os == 'android' + +######################################################################## +# B2G +[_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html] +# Asserts on 'B2G ICS Emulator Debug'. +skip-if = (os == 'b2g') +[_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html] +# Intermittently asserts on 'B2G ICS Emulator Debug'. +skip-if = (os == 'b2g') diff --git a/dom/canvas/test/webgl-conformance/mochitest.ini.template b/dom/canvas/test/webgl-conformance/mochitest.ini.template index c6d478aba0d8..f4c74cdd7dc9 100644 --- a/dom/canvas/test/webgl-conformance/mochitest.ini.template +++ b/dom/canvas/test/webgl-conformance/mochitest.ini.template @@ -1,5 +1,6 @@ [DEFAULT] -skip-if = e10s +%%DEFAULT_ERRATA%% + support-files = mochi-single.html mochi-wrapper.css %%SUPPORT_FILES%% From ba6539ecd7f482687ffdaa43a5ab02840729b132 Mon Sep 17 00:00:00 2001 From: Tim Abraldes Date: Fri, 29 Aug 2014 17:34:26 -0700 Subject: [PATCH 054/120] bug 1027906. Set delayed token level for GMP plugin processes to USER_RESTRICTED. Whitelist certain files and registry keys that are required for EME plugins to successfully load. r=bobowen. r=jesup. r=bent. --- content/media/gmp/GMPProcessParent.cpp | 13 ++ ipc/glue/GeckoChildProcessHost.cpp | 11 +- ipc/glue/GeckoChildProcessHost.h | 1 + .../win/src/sandboxbroker/sandboxBroker.cpp | 166 +++++++++++++++--- .../win/src/sandboxbroker/sandboxBroker.h | 5 + 5 files changed, 175 insertions(+), 21 deletions(-) diff --git a/content/media/gmp/GMPProcessParent.cpp b/content/media/gmp/GMPProcessParent.cpp index 0264f4672cc9..fceb8b21796e 100644 --- a/content/media/gmp/GMPProcessParent.cpp +++ b/content/media/gmp/GMPProcessParent.cpp @@ -9,6 +9,12 @@ #include "base/string_util.h" #include "base/process_util.h" +#ifdef XP_WIN +#include +#endif + +#include + using std::vector; using std::string; @@ -43,6 +49,13 @@ GMPProcessParent::Launch(int32_t aTimeoutMs) { vector args; args.push_back(mGMPPath); + +#ifdef XP_WIN + std::wstring_convert> converter; + std::wstring wGMPPath = converter.from_bytes(mGMPPath.c_str()); + mAllowedFilesRead.push_back(wGMPPath + L"\\*"); +#endif + return SyncLaunch(args, aTimeoutMs, base::GetCurrentProcessArchitecture()); } diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index faacb1e5b139..6da996216c05 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -794,7 +794,16 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt MOZ_CRASH("Bad process type in GeckoChildProcessHost"); break; }; -#endif + + if (shouldSandboxCurrentProcess) { + for (auto it = mAllowedFilesRead.begin(); + it != mAllowedFilesRead.end(); + ++it) { + mSandboxBroker.AllowReadFile(it->c_str()); + } + } + +#endif // XP_WIN // Add the application directory path (-appdir path) AddAppDirToCommandLine(cmdLine); diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h index fc3097bc6acb..3442320fa43d 100644 --- a/ipc/glue/GeckoChildProcessHost.h +++ b/ipc/glue/GeckoChildProcessHost.h @@ -168,6 +168,7 @@ protected: #ifdef MOZ_SANDBOX SandboxBroker mSandboxBroker; + std::vector mAllowedFilesRead; #endif #endif // XP_WIN diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp index 715abae99c2e..7e45c077b676 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp @@ -67,12 +67,18 @@ SandboxBroker::SetSecurityLevelForContentProcess() return false; } - mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); - mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, - sandbox::USER_RESTRICTED_SAME_ACCESS); - mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); - mPolicy->SetAlternateDesktop(true); - return true; + auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); + bool ret = (sandbox::SBOX_ALL_OK == result); + result = + mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, + sandbox::USER_RESTRICTED_SAME_ACCESS); + ret = ret && (sandbox::SBOX_ALL_OK == result); + result = + mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); + ret = ret && (sandbox::SBOX_ALL_OK == result); + result = mPolicy->SetAlternateDesktop(true); + ret = ret && (sandbox::SBOX_ALL_OK == result); + return ret; } bool @@ -82,10 +88,12 @@ SandboxBroker::SetSecurityLevelForPluginProcess() return false; } - mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); - mPolicy->SetTokenLevel(sandbox::USER_UNPROTECTED, - sandbox::USER_UNPROTECTED); - return true; + auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); + bool ret = (sandbox::SBOX_ALL_OK == result); + result = mPolicy->SetTokenLevel(sandbox::USER_UNPROTECTED, + sandbox::USER_UNPROTECTED); + ret = ret && (sandbox::SBOX_ALL_OK == result); + return ret; } bool @@ -95,10 +103,13 @@ SandboxBroker::SetSecurityLevelForIPDLUnitTestProcess() return false; } - mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); - mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, - sandbox::USER_RESTRICTED_SAME_ACCESS); - return true; + auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); + bool ret = (sandbox::SBOX_ALL_OK == result); + result = + mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, + sandbox::USER_RESTRICTED_SAME_ACCESS); + ret = ret && (sandbox::SBOX_ALL_OK == result); + return ret; } bool @@ -108,14 +119,129 @@ SandboxBroker::SetSecurityLevelForGMPlugin() return false; } - mPolicy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); - mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, - sandbox::USER_RESTRICTED_SAME_ACCESS); - mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); - mPolicy->SetAlternateDesktop(true); - return true; + auto result = mPolicy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); + bool ret = (sandbox::SBOX_ALL_OK == result); + result = + mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, + sandbox::USER_RESTRICTED); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->SetAlternateDesktop(true); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + // We can't use an alternate desktop/window station AND initially + // set the process to low integrity. Upstream changes have been + // made to allow this and we should uncomment this section once + // we've rolled forward. + // result = + // mPolicy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); + // ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = + mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + // Add the policy for the client side of a pipe. It is just a file + // in the \pipe\ namespace. We restrict it to pipes that start with + // "chrome." so the sandboxed process cannot connect to system services. + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + L"\\??\\pipe\\chrome.*"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + +#ifdef DEBUG + // The plugin process can't create named events, but we'll + // make an exception for the events used in logging. Removing + // this will break EME in debug builds. + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_SYNC, + sandbox::TargetPolicy::EVENTS_ALLOW_ANY, + L"ChromeIPCLog.*"); + ret = ret && (sandbox::SBOX_ALL_OK == result); +#endif + + // The following rules were added because, during analysis of an EME + // plugin during development, these registry keys were accessed when + // loading the plugin. Commenting out these policy exceptions caused + // plugin loading to fail, so they are necessary for proper functioning + // of at least one EME plugin. + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_CURRENT_USER"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_CURRENT_USER\\Control Panel\\Desktop"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_CURRENT_USER\\Control Panel\\Desktop\\LanguageConfiguration"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SideBySide"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + + // The following rules were added because, during analysis of an EME + // plugin during development, these registry keys were accessed when + // loading the plugin. Commenting out these policy exceptions did not + // cause anything to break during initial testing, but might cause + // unforeseen issues down the road. + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\MUI\\Settings"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\Control Panel\\Desktop"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_CURRENT_USER\\Control Panel\\Desktop\\PreferredUILanguages"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_READONLY, + L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SideBySide\\PreferExternalManifest"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + return ret; } +bool +SandboxBroker::AllowReadFile(wchar_t const *file) +{ + auto result = + mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_READONLY, + file); + return (sandbox::SBOX_ALL_OK == result); +} + +bool +SandboxBroker::AllowReadWriteFile(wchar_t const *file) +{ + auto result = + mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + file); + return (sandbox::SBOX_ALL_OK == result); +} + +bool +SandboxBroker::AllowDirectory(wchar_t const *dir) +{ + auto result = + mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_DIR_ANY, + dir); + return (sandbox::SBOX_ALL_OK == result); +} SandboxBroker::~SandboxBroker() { diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h index 08621dc4d987..29055040fec0 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h @@ -35,6 +35,11 @@ public: bool SetSecurityLevelForIPDLUnitTestProcess(); bool SetSecurityLevelForGMPlugin(); + // File system permissions + bool AllowReadFile(wchar_t const *file); + bool AllowReadWriteFile(wchar_t const *file); + bool AllowDirectory(wchar_t const *dir); + private: static sandbox::BrokerServices *sBrokerService; sandbox::TargetPolicy *mPolicy; From 119b349026c74477dd7d6261d60ec3ee0bdf24a3 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 17:38:39 -0700 Subject: [PATCH 055/120] Bug 1052240 - Mark more tests. --- dom/canvas/test/webgl-conformance/_mochitest.ini | 2 +- .../test/webgl-conformance/mochitest-errata.ini | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dom/canvas/test/webgl-conformance/_mochitest.ini b/dom/canvas/test/webgl-conformance/_mochitest.ini index 5ebad4c63721..25037e0a63c6 100644 --- a/dom/canvas/test/webgl-conformance/_mochitest.ini +++ b/dom/canvas/test/webgl-conformance/_mochitest.ini @@ -743,7 +743,7 @@ skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html] [_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html] -skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') || (os == 'win') [_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html] skip-if = (os == 'b2g') [_wrappers/test_conformance__textures__tex-image-with-format-and-type.html] diff --git a/dom/canvas/test/webgl-conformance/mochitest-errata.ini b/dom/canvas/test/webgl-conformance/mochitest-errata.ini index 6f0012af76ec..5d89dce417f6 100644 --- a/dom/canvas/test/webgl-conformance/mochitest-errata.ini +++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini @@ -13,6 +13,14 @@ skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g')) #fail-if = 1 # We'll be able to use `fail-if` after bug 987849. +######################################################################## +# "tst-linux{32,64}-spot-NNN" Slaves and Windows +[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html] +# Random fail on Android 2.3. +# Crashes on Mulet Linux x64 and B2G ICS Emulator. +# Intermittent crash on Windows. +skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') || (os == 'win') + ######################################################################## # "tst-linux{32,64}-spot-NNN" Slaves: # Android 2.3, B2G Emu, Linux, and Mulet. @@ -37,10 +45,6 @@ skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') # Resets device on Android 2.3. # Crashes on B2G ICS Emulator, desktop Linux, and Mulet Linux x64. skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') -[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html] -# Random fail on Android 2.3. -# Crashes on Mulet Linux x64 and B2G ICS Emulator. -skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__tex-image-with-format-and-type.html] # Crashes or blues on Android 2.3 skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') From 84319734434931eb8cd8904ec97189eaa14e0dae Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 11:26:07 -0400 Subject: [PATCH 056/120] Bug 1059765: enable content metrics for H.264 r=gcp --- media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc index 2c877f9ff4ff..6f3550708a9a 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc @@ -705,7 +705,8 @@ void ViEEncoder::DeliverFrame(int id, return; } #endif - if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) { + if (vcm_.AddVideoFrame(*decimated_frame, + vpm_.ContentMetrics()) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), From 08ed16c76d3f81fdb11298ba13ac37a92c874809 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 11:26:34 -0400 Subject: [PATCH 057/120] Bug 1059765: handle incoming resolution changes in GMP video encode r=pkerr --- .../src/media-conduit/WebrtcGmpVideoCodec.cpp | 60 ++++++++++++++----- .../src/media-conduit/WebrtcGmpVideoCodec.h | 2 + 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp index 83d40507689c..58c52177af54 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp @@ -143,12 +143,13 @@ WebrtcGmpVideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores, uint32_t aMaxPayloadSize) { - mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + if (!mMPS) { + mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + } MOZ_ASSERT(mMPS); if (!mGMPThread) { if (NS_WARN_IF(NS_FAILED(mMPS->GetThread(getter_AddRefs(mGMPThread))))) { - mMPS = nullptr; return WEBRTC_VIDEO_CODEC_ERROR; } } @@ -182,31 +183,30 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings, mHost = nullptr; return WEBRTC_VIDEO_CODEC_ERROR; } - mMPS = nullptr; if (!mGMP || !mHost) { return WEBRTC_VIDEO_CODEC_ERROR; } // Bug XXXXXX: transfer settings from codecSettings to codec. - GMPVideoCodec codec; - memset(&codec, 0, sizeof(codec)); + memset(&mCodecParams, 0, sizeof(mCodecParams)); - codec.mGMPApiVersion = 33; - codec.mWidth = aCodecSettings->width; - codec.mHeight = aCodecSettings->height; - codec.mStartBitrate = aCodecSettings->startBitrate; - codec.mMinBitrate = aCodecSettings->minBitrate; - codec.mMaxBitrate = aCodecSettings->maxBitrate; - codec.mMaxFramerate = aCodecSettings->maxFramerate; + mCodecParams.mGMPApiVersion = 33; + mCodecParams.mWidth = aCodecSettings->width; + mCodecParams.mHeight = aCodecSettings->height; + mCodecParams.mStartBitrate = aCodecSettings->startBitrate; + mCodecParams.mMinBitrate = aCodecSettings->minBitrate; + mCodecParams.mMaxBitrate = aCodecSettings->maxBitrate; + mCodecParams.mMaxFramerate = aCodecSettings->maxFramerate; + mMaxPayloadSize = aMaxPayloadSize; if (aCodecSettings->codecSpecific.H264.packetizationMode == 1) { - aMaxPayloadSize = 4*1024*1024; // insanely large + mMaxPayloadSize = 4*1024*1024; // insanely large } // Pass dummy codecSpecific data for now... nsTArray codecSpecific; - GMPErr err = mGMP->InitEncode(codec, codecSpecific, this, 1, aMaxPayloadSize); + GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize); if (err != GMPNoErr) { return WEBRTC_VIDEO_CODEC_ERROR; } @@ -245,6 +245,38 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage, return WEBRTC_VIDEO_CODEC_ERROR; } + if (aInputImage->width() != mCodecParams.mWidth || + aInputImage->height() != mCodecParams.mHeight) { + LOGD(("GMP Encode: resolution change from %ux%u to %ux%u", + mCodecParams.mWidth, mCodecParams.mHeight, aInputImage->width(), aInputImage->height())); + + mGMP->Close(); + + // OpenH264 codec (at least) can't handle dynamic input resolution changes + // re-init the plugin when the resolution changes + // XXX allow codec to indicate it doesn't need re-init! + nsTArray tags; + tags.AppendElement(NS_LITERAL_CSTRING("h264")); + if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags, + NS_LITERAL_STRING(""), + &mHost, + &mGMP)))) { + mGMP = nullptr; + mHost = nullptr; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + mCodecParams.mWidth = aInputImage->width(); + mCodecParams.mHeight = aInputImage->height(); + // Pass dummy codecSpecific data for now... + nsTArray codecSpecific; + + GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize); + if (err != GMPNoErr) { + return WEBRTC_VIDEO_CODEC_ERROR; + } + } + GMPVideoFrame* ftmp = nullptr; GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp); if (err != GMPNoErr) { diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h index bafc7dec3c21..47b68bc93c8d 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h @@ -92,6 +92,8 @@ private: nsCOMPtr mGMPThread; GMPVideoEncoderProxy* mGMP; GMPVideoHost* mHost; + GMPVideoCodec mCodecParams; + uint32_t mMaxPayloadSize; webrtc::EncodedImageCallback* mCallback; uint64_t mCachedPluginId; }; From 110ee74f4d6917671ada4753a6a4b8b1e42fdd08 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 21:29:17 -0400 Subject: [PATCH 058/120] Bug 1049087: set temporary allowed screensharing domain of mozilla.github.io - replace for release r=gcp --- modules/libpref/init/all.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 21a5ba01b5fb..ec65c9eb01a4 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -371,7 +371,12 @@ pref("media.navigator.enabled", true); #endif pref("media.getusermedia.screensharing.enabled", true); +#ifdef RELEASE_BUILD pref("media.getusermedia.screensharing.allowed_domains", ""); +#else + // temporary value, not intended for release - bug 1049087 +pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io"); +#endif // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); From 4ae84caa93a5d1d329fc9178e9a14b0c8e4e4056 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 21:29:17 -0400 Subject: [PATCH 059/120] Bug 1060249: disable frame motion/complexity analysis in webrtc on Gonk r=gcp --- .../main/source/content_metrics_processing.cc | 9 +++++++++ .../modules/video_coding/main/source/qm_select.cc | 11 +++++++++++ .../video_processing/main/source/content_analysis.cc | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc index 757ffb0e46f6..3e8b2ec963a4 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc @@ -77,7 +77,16 @@ int VCMContentMetricsProcessing::UpdateContentData( if (contentMetrics == NULL) { return VCM_OK; } +#if defined(WEBRTC_GONK) + // "average" values that should yield kDefault in qm_select.cc + contentMetrics->motion_magnitude = 0.05f; + contentMetrics->spatial_pred_err = 0.03f; + contentMetrics->spatial_pred_err_h = 0.03f; + contentMetrics->spatial_pred_err_v = 0.03f; + return VCM_OK; +#else return ProcessContent(contentMetrics); +#endif } int VCMContentMetricsProcessing::ProcessContent( diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc index 72f408beee32..cd36fc059b14 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc @@ -60,6 +60,10 @@ void VCMQmMethod::UpdateContent(const VideoContentMetrics* contentMetrics) { } void VCMQmMethod::ComputeMotionNFD() { +#if defined(WEBRTC_GONK) + motion_.value = (kHighMotionNfd + kLowMotionNfd)/2; + motion_.level = kDefault; +#else if (content_metrics_) { motion_.value = content_metrics_->motion_magnitude; } @@ -71,9 +75,15 @@ void VCMQmMethod::ComputeMotionNFD() { } else { motion_.level = kDefault; } +#endif } void VCMQmMethod::ComputeSpatial() { +#if defined(WEBRTC_GONK) + float scale2 = image_type_ > kVGA ? kScaleTexture : 1.0; + spatial_.value = (kHighTexture + kLowTexture)*scale2/2; + spatial_.level = kDefault; +#else float spatial_err = 0.0; float spatial_err_h = 0.0; float spatial_err_v = 0.0; @@ -95,6 +105,7 @@ void VCMQmMethod::ComputeSpatial() { } else { spatial_.level = kDefault; } +#endif } ImageType VCMQmMethod::GetImageType(uint16_t width, diff --git a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc index 981e0e606a87..6d777116239c 100644 --- a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc +++ b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc @@ -58,6 +58,7 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( if (VPM_OK != Initialize(inputFrame.width(), inputFrame.height())) return NULL; } +#if !defined(WEBRTC_GONK) // Compute motion metrics if (ca_Init_) { // Only interested in the Y plane. @@ -75,6 +76,7 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( first_frame_ = false; } +#endif return ContentMetrics(); } @@ -123,10 +125,12 @@ int32_t VPMContentAnalysis::Initialize(int width, int height) { return VPM_MEMORY; } +#if !defined(WEBRTC_GONK) prev_frame_.reset(new uint8_t[width_ * height_]); // Y only. if (!prev_frame_) { return VPM_MEMORY; } +#endif // ok, all initialized ca_Init_ = true; From c2cbe72d864b2aac00a72550431676d4418d92af Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 21:29:18 -0400 Subject: [PATCH 060/120] Bug 1056350: Make H.264 Level configurable and change OpenH264 default to 3.1 r=bwc --- .../signaling/src/media/VcmSIPCCBinding.cpp | 31 +++++++++++-------- .../webrtc/signaling/src/sipcc/include/vcm.h | 5 +-- modules/libpref/init/all.js | 2 ++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp index 577e9baa322b..cf8469823c26 100644 --- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp +++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp @@ -1719,12 +1719,11 @@ static int vcmEnsureExternalCodec( // Register H.264 codec. if (send) { - VideoEncoder* encoder = nullptr; + VideoEncoder* encoder = nullptr; #ifdef MOZ_WEBRTC_OMX - encoder = OMXVideoCodec::CreateEncoder( - OMXVideoCodec::CodecType::CODEC_H264); + encoder = OMXVideoCodec::CreateEncoder(OMXVideoCodec::CodecType::CODEC_H264); #else - encoder = mozilla::GmpVideoCodec::CreateEncoder(); + encoder = mozilla::GmpVideoCodec::CreateEncoder(); #endif if (encoder) { return conduit->SetExternalSendCodec(config, encoder); @@ -2311,16 +2310,15 @@ int vcmGetH264SupportedPacketizationModes() */ uint32_t vcmGetVideoH264ProfileLevelID() { - // constrained baseline level 1.2 - // XXX make variable based on openh264 and OMX support -#ifdef MOZ_WEBRTC_OMX + // For OMX, constrained baseline level 1.2 (via a pref) // Max resolution CIF; we should include max-mbps - return 0x42E00C; -#else - // XXX See bug 1043515 - we may want to support a higher profile than - // 1.3, depending on hardware(?) - return 0x42E00D; -#endif + int32_t level = 13; // minimum suggested for WebRTC spec + + vcmGetVideoLevel(0, &level); + level &= 0xFF; + level |= 0x42E000; + + return (uint32_t) level; } /** @@ -2786,6 +2784,13 @@ static short vcmGetVideoPref(uint16_t codec, return VCM_ERROR; } +short vcmGetVideoLevel(uint16_t codec, + int32_t *level) { + return vcmGetVideoPref(codec, + "media.navigator.video.h264.level", + level); +} + short vcmGetVideoMaxFs(uint16_t codec, int32_t *max_fs) { return vcmGetVideoPref(codec, diff --git a/media/webrtc/signaling/src/sipcc/include/vcm.h b/media/webrtc/signaling/src/sipcc/include/vcm.h index 4b498e22a963..f23dff720123 100755 --- a/media/webrtc/signaling/src/sipcc/include/vcm.h +++ b/media/webrtc/signaling/src/sipcc/include/vcm.h @@ -1083,14 +1083,11 @@ int vcmOnSdpParseError(const char *peercconnection, const char *message); */ int vcmDisableRtcpComponent(const char *peerconnection, int level); +short vcmGetVideoLevel(uint16_t codec, int32_t *level); short vcmGetVideoMaxFs(uint16_t codec, int32_t *max_fs); - short vcmGetVideoMaxFr(uint16_t codec, int32_t *max_fr); - short vcmGetVideoMaxBr(uint16_t codec, int32_t *max_br); - short vcmGetVideoMaxMbps(uint16_t codec, int32_t *max_mbps); - short vcmGetVideoPreferredCodec(int32_t *preferred_codec); //Using C++ for gips. This is the end of extern "C" above. diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index ec65c9eb01a4..3e9a7d9d4f7d 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -303,6 +303,7 @@ pref("media.peerconnection.enabled", true); pref("media.peerconnection.video.enabled", true); pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb pref("media.navigator.video.max_fr", 30); +pref("media.navigator.video.h264.level", 12); // 0x42E00C - level 1.2 pref("media.navigator.video.h264.max_br", 700); // 8x10 pref("media.navigator.video.h264.max_mbps", 11880); // CIF@30fps pref("media.peerconnection.video.h264_enabled", false); @@ -314,6 +315,7 @@ pref("media.peerconnection.enabled", true); pref("media.peerconnection.video.enabled", true); pref("media.navigator.video.max_fs", 0); // unrestricted pref("media.navigator.video.max_fr", 0); // unrestricted +pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1 pref("media.navigator.video.h264.max_br", 0); pref("media.navigator.video.h264.max_mbps", 0); pref("media.peerconnection.video.h264_enabled", false); From 30e6573815db61ae0c3fb34a6fa3003039e77ed0 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 29 Aug 2014 21:41:20 -0400 Subject: [PATCH 061/120] Bug 921453 followup. Remove pointless AvailableIn and CheckPermissions annotations on MozNFCManager. --- dom/webidl/MozNFC.webidl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dom/webidl/MozNFC.webidl b/dom/webidl/MozNFC.webidl index c070511811fe..8318d46c8942 100644 --- a/dom/webidl/MozNFC.webidl +++ b/dom/webidl/MozNFC.webidl @@ -4,8 +4,7 @@ /* Copyright © 2013 Deutsche Telekom, Inc. */ -[NoInterfaceObject, - CheckPermissions="nfc-manager", AvailableIn="CertifiedApps"] +[NoInterfaceObject] interface MozNFCManager { /** * API to check if the given application's manifest From ac7b5a4b3be7ef15df78be08c391768890f3710a Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 29 Aug 2014 19:00:07 -0700 Subject: [PATCH 062/120] Backed out 5 changesets (bug 1058136) for S4 orange Backed out changeset 713e1d6f09c4 (bug 1058136) Backed out changeset 032246f68eaa (bug 1058136) Backed out changeset 7e5502347731 (bug 1058136) Backed out changeset 37addbdb5cd1 (bug 1058136) Backed out changeset d9f97b62e3c4 (bug 1058136) --- mobile/android/base/GeckoEditable.java | 64 ++---- mobile/android/base/GeckoEvent.java | 16 +- mobile/android/base/GeckoInputConnection.java | 32 ++- widget/android/AndroidJavaWrappers.cpp | 3 +- widget/android/AndroidJavaWrappers.h | 1 - widget/android/nsWindow.cpp | 182 ++++++------------ widget/android/nsWindow.h | 3 +- 7 files changed, 95 insertions(+), 206 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 8f0a304d137f..a15fc28599f2 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -67,7 +67,7 @@ interface GeckoEditableListener { void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint); void onSelectionChange(int start, int end); - void onTextChange(CharSequence text, int start, int oldEnd, int newEnd); + void onTextChange(String text, int start, int oldEnd, int newEnd); } /* @@ -131,8 +131,6 @@ final class GeckoEditable static final int TYPE_ACKNOWLEDGE_FOCUS = 5; // For switching handler; use with IME_SYNCHRONIZE static final int TYPE_SET_HANDLER = 6; - // For Editable.replace() call involving compositions; use with IME_COMPOSE_TEXT - static final int TYPE_COMPOSE_TEXT = 7; final int mType; int mStart; @@ -152,22 +150,7 @@ final class GeckoEditable throw new IllegalArgumentException( "invalid replace text offsets: " + start + " to " + end); } - - int actionType = TYPE_REPLACE_TEXT; - - if (text instanceof Spanned) { - final Spanned spanned = (Spanned) text; - final Object[] spans = spanned.getSpans(0, spanned.length(), Object.class); - - for (Object span : spans) { - if ((spanned.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) { - actionType = TYPE_COMPOSE_TEXT; - break; - } - } - } - - final Action action = new Action(actionType); + final Action action = new Action(TYPE_REPLACE_TEXT); action.mSequence = text; action.mStart = start; action.mEnd = end; @@ -246,7 +229,6 @@ final class GeckoEditable mActionsActive.tryAcquire(); mActions.offer(action); } - switch (action.mType) { case Action.TYPE_EVENT: case Action.TYPE_SET_SELECTION: @@ -256,29 +238,17 @@ final class GeckoEditable GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent( GeckoEvent.ImeAction.IME_SYNCHRONIZE)); break; - - case Action.TYPE_COMPOSE_TEXT: - // Send different event for composing text. - GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEComposeEvent( - action.mStart, action.mEnd, action.mSequence.toString())); - return; - case Action.TYPE_REPLACE_TEXT: // try key events first sendCharKeyEvents(action); GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEReplaceEvent( action.mStart, action.mEnd, action.mSequence.toString())); break; - case Action.TYPE_ACKNOWLEDGE_FOCUS: GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent( GeckoEvent.ImeAction.IME_ACKNOWLEDGE_FOCUS)); break; - - default: - throw new IllegalStateException("Action not processed"); } - ++mIcUpdateSeqno; } @@ -337,10 +307,12 @@ final class GeckoEditable throw new IllegalStateException("empty actions queue"); } mActions.poll(); - - synchronized(this) { - if (mActions.isEmpty()) { - mActionsActive.release(); + // Don't bother locking if queue is not empty yet + if (mActions.isEmpty()) { + synchronized(this) { + if (mActions.isEmpty()) { + mActionsActive.release(); + } } } } @@ -708,12 +680,6 @@ final class GeckoEditable getConstantName(Action.class, "TYPE_", action.mType) + ")"); } switch (action.mType) { - case Action.TYPE_COMPOSE_TEXT: - // Compositions don't trigger text change notification, so notify manually. - onTextChange(action.mSequence, action.mStart, action.mEnd, - action.mStart + action.mSequence.length()); - break; - case Action.TYPE_SET_SELECTION: final int len = mText.length(); final int curStart = Selection.getSelectionStart(mText); @@ -901,7 +867,7 @@ final class GeckoEditable } @Override - public void onTextChange(final CharSequence text, final int start, + public void onTextChange(final String text, final int start, final int unboundedOldEnd, final int unboundedNewEnd) { if (DEBUG) { // GeckoEditableListener methods should all be called from the Gecko thread @@ -1068,13 +1034,11 @@ final class GeckoEditable if (DEBUG) { StringBuilder log = new StringBuilder(method.getName()); log.append("("); - if (args != null) { - for (Object arg : args) { - debugAppend(log, arg).append(", "); - } - if (args.length > 0) { - log.setLength(log.length() - 2); - } + for (Object arg : args) { + debugAppend(log, arg).append(", "); + } + if (args.length > 0) { + log.setLength(log.length() - 2); } if (method.getReturnType().equals(Void.TYPE)) { log.append(")"); diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 1ac15c391d86..e2c897230248 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -147,8 +147,7 @@ public class GeckoEvent { IME_ADD_COMPOSITION_RANGE(3), IME_UPDATE_COMPOSITION(4), IME_REMOVE_COMPOSITION(5), - IME_ACKNOWLEDGE_FOCUS(6), - IME_COMPOSE_TEXT(7); + IME_ACKNOWLEDGE_FOCUS(6); public final int value; @@ -601,17 +600,10 @@ public class GeckoEvent { return event; } - public static GeckoEvent createIMEReplaceEvent(int start, int end, String text) { - return createIMETextEvent(false, start, end, text); - } - - public static GeckoEvent createIMEComposeEvent(int start, int end, String text) { - return createIMETextEvent(true, start, end, text); - } - - private static GeckoEvent createIMETextEvent(boolean compose, int start, int end, String text) { + public static GeckoEvent createIMEReplaceEvent(int start, int end, + String text) { GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); - event.mAction = (compose ? ImeAction.IME_COMPOSE_TEXT : ImeAction.IME_REPLACE_TEXT).value; + event.mAction = ImeAction.IME_REPLACE_TEXT.value; event.mStart = start; event.mEnd = end; event.mCharacters = text; diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index a6e56d4e854b..272fbb081349 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -430,7 +430,7 @@ class GeckoInputConnection } @Override - public void onTextChange(CharSequence text, int start, int oldEnd, int newEnd) { + public void onTextChange(String text, int start, int oldEnd, int newEnd) { if (mUpdateRequest == null) { // Android always expects selection updates when not in extracted mode; @@ -1024,23 +1024,21 @@ final class DebugGeckoInputConnection StringBuilder log = new StringBuilder(mCallLevel); log.append("> ").append(method.getName()).append("("); - if (args != null) { - for (Object arg : args) { - // translate argument values to constant names - if ("notifyIME".equals(method.getName()) && arg == args[0]) { - log.append(GeckoEditable.getConstantName( - GeckoEditableListener.class, "NOTIFY_IME_", arg)); - } else if ("notifyIMEContext".equals(method.getName()) && arg == args[0]) { - log.append(GeckoEditable.getConstantName( - GeckoEditableListener.class, "IME_STATE_", arg)); - } else { - GeckoEditable.debugAppend(log, arg); - } - log.append(", "); - } - if (args.length > 0) { - log.setLength(log.length() - 2); + for (Object arg : args) { + // translate argument values to constant names + if ("notifyIME".equals(method.getName()) && arg == args[0]) { + log.append(GeckoEditable.getConstantName( + GeckoEditableListener.class, "NOTIFY_IME_", arg)); + } else if ("notifyIMEContext".equals(method.getName()) && arg == args[0]) { + log.append(GeckoEditable.getConstantName( + GeckoEditableListener.class, "IME_STATE_", arg)); + } else { + GeckoEditable.debugAppend(log, arg); } + log.append(", "); + } + if (args.length > 0) { + log.setLength(log.length() - 2); } log.append(")"); Log.d(LOGTAG, log.toString()); diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 244f24fce389..688262ff11f9 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -471,8 +471,7 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj) mStart = jenv->GetIntField(jobj, jStartField); mEnd = jenv->GetIntField(jobj, jEndField); - if (mAction == IME_REPLACE_TEXT || - mAction == IME_COMPOSE_TEXT) { + if (mAction == IME_REPLACE_TEXT) { ReadCharactersField(jenv); } else if (mAction == IME_UPDATE_COMPOSITION || mAction == IME_ADD_COMPOSITION_RANGE) { diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index b1b9760cff15..63bb99fe9bf6 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -744,7 +744,6 @@ public: IME_UPDATE_COMPOSITION = 4, IME_REMOVE_COMPOSITION = 5, IME_ACKNOWLEDGE_FOCUS = 6, - IME_COMPOSE_TEXT = 7, dummy_ime_enum_list_end }; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index e41546df7f1c..9ef305188d47 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -177,7 +177,6 @@ nsWindow::nsWindow() : mParent(nullptr), mFocus(nullptr), mIMEComposing(false), - mIMEComposingStart(-1), mIMEMaskSelectionUpdate(false), mIMEMaskTextUpdate(false), mIMEMaskEventsCount(1), // Mask IME events since there's no focus yet @@ -680,7 +679,6 @@ nsWindow::DispatchEvent(WidgetGUIEvent* aEvent) case NS_COMPOSITION_END: MOZ_ASSERT(mIMEComposing); mIMEComposing = false; - mIMEComposingStart = -1; mIMEComposingText.Truncate(); break; case NS_TEXT_TEXT: @@ -1712,7 +1710,6 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); return; - } else if (ae->Action() == AndroidGeckoEvent::IME_UPDATE_CONTEXT) { mozilla::widget::android::GeckoAppShell::NotifyIMEContext(mInputContext.mIMEState.mEnabled, mInputContext.mHTMLInputType, @@ -1721,33 +1718,27 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) mIMEUpdatingContext = false; return; } - if (mIMEMaskEventsCount > 0) { // Still reply to events, but don't do anything else if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE || - ae->Action() == AndroidGeckoEvent::IME_COMPOSE_TEXT || ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } return; } - switch (ae->Action()) { case AndroidGeckoEvent::IME_FLUSH_CHANGES: { FlushIMEChanges(); } break; - case AndroidGeckoEvent::IME_SYNCHRONIZE: { FlushIMEChanges(); mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } break; - case AndroidGeckoEvent::IME_REPLACE_TEXT: - case AndroidGeckoEvent::IME_COMPOSE_TEXT: { /* Replace text in Gecko thread from ae->Start() to ae->End() @@ -1760,48 +1751,31 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) Gecko text */ AutoIMEMask selMask(mIMEMaskSelectionUpdate); - - if (!mIMEKeyEvents.IsEmpty() || - mIMEComposingStart < 0 || - ae->Start() != mIMEComposingStart || - ae->End() != mIMEComposingStart + - int32_t(mIMEComposingText.Length())) { - - // Only start a new composition if we have key events, - // if we don't have an existing composition, or - // the replaced text does not match our composition. - RemoveIMEComposition(); - - { - WidgetSelectionEvent event(true, NS_SELECTION_SET, this); - InitEvent(event, nullptr); - event.mOffset = uint32_t(ae->Start()); - event.mLength = uint32_t(ae->End() - ae->Start()); - event.mExpandToClusterBoundary = false; - DispatchEvent(&event); - } - - if (!mIMEKeyEvents.IsEmpty()) { - for (uint32_t i = 0; i < mIMEKeyEvents.Length(); i++) { - OnKeyEvent(&mIMEKeyEvents[i]); - } - mIMEKeyEvents.Clear(); - FlushIMEChanges(); - mozilla::widget::android::GeckoAppShell::NotifyIME( - AndroidBridge::NOTIFY_IME_REPLY_EVENT); - // Break out of the switch block - break; - } - - { - WidgetCompositionEvent event( - true, NS_COMPOSITION_START, this); - InitEvent(event, nullptr); - DispatchEvent(&event); - mIMEComposingStart = ae->Start(); - } + RemoveIMEComposition(); + { + WidgetSelectionEvent event(true, NS_SELECTION_SET, this); + InitEvent(event, nullptr); + event.mOffset = uint32_t(ae->Start()); + event.mLength = uint32_t(ae->End() - ae->Start()); + event.mExpandToClusterBoundary = false; + DispatchEvent(&event); } + if (!mIMEKeyEvents.IsEmpty()) { + for (uint32_t i = 0; i < mIMEKeyEvents.Length(); i++) { + OnKeyEvent(&mIMEKeyEvents[i]); + } + mIMEKeyEvents.Clear(); + FlushIMEChanges(); + mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); + break; + } + + { + WidgetCompositionEvent event(true, NS_COMPOSITION_START, this); + InitEvent(event, nullptr); + DispatchEvent(&event); + } { WidgetCompositionEvent event(true, NS_COMPOSITION_UPDATE, this); InitEvent(event, nullptr); @@ -1814,23 +1788,16 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) event.theText = ae->Characters(); DispatchEvent(&event); } - - // Don't end composition when composing text. - if (ae->Action() != AndroidGeckoEvent::IME_COMPOSE_TEXT) { WidgetCompositionEvent event(true, NS_COMPOSITION_END, this); InitEvent(event, nullptr); event.data = ae->Characters(); DispatchEvent(&event); - - FlushIMEChanges(); } - - mozilla::widget::android::GeckoAppShell::NotifyIME( - AndroidBridge::NOTIFY_IME_REPLY_EVENT); + FlushIMEChanges(); + mozilla::widget::android::GeckoAppShell::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT); } break; - case AndroidGeckoEvent::IME_SET_SELECTION: { /* @@ -1907,6 +1874,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) */ AutoIMEMask selMask(mIMEMaskSelectionUpdate); AutoIMEMask textMask(mIMEMaskTextUpdate); + RemoveIMEComposition(); WidgetTextEvent event(true, NS_TEXT_TEXT, this); InitEvent(event, nullptr); @@ -1914,49 +1882,28 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) event.mRanges = new TextRangeArray(); mIMERanges.swap(event.mRanges); - if (mIMEComposingStart < 0 || - ae->Start() != mIMEComposingStart || - ae->End() != mIMEComposingStart + - int32_t(mIMEComposingText.Length())) { - - // Only start new composition if we don't have an existing one, - // or if the existing composition doesn't match the new one. - RemoveIMEComposition(); - - { - WidgetSelectionEvent event(true, NS_SELECTION_SET, this); - InitEvent(event, nullptr); - event.mOffset = uint32_t(ae->Start()); - event.mLength = uint32_t(ae->End() - ae->Start()); - event.mExpandToClusterBoundary = false; - DispatchEvent(&event); - } - - { - WidgetQueryContentEvent queryEvent(true, - NS_QUERY_SELECTED_TEXT, - this); - InitEvent(queryEvent, nullptr); - DispatchEvent(&queryEvent); - MOZ_ASSERT(queryEvent.mSucceeded && !queryEvent.mWasAsync); - event.theText = queryEvent.mReply.mString; - - mIMEComposingStart = queryEvent.mReply.mOffset; - } - - { - WidgetCompositionEvent event( - true, NS_COMPOSITION_START, this); - InitEvent(event, nullptr); - DispatchEvent(&event); - } - - } else { - // If the new composition matches the existing composition, - // reuse the old composition. - event.theText = mIMEComposingText; + { + WidgetSelectionEvent event(true, NS_SELECTION_SET, this); + InitEvent(event, nullptr); + event.mOffset = uint32_t(ae->Start()); + event.mLength = uint32_t(ae->End() - ae->Start()); + event.mExpandToClusterBoundary = false; + DispatchEvent(&event); + } + { + WidgetQueryContentEvent queryEvent(true, + NS_QUERY_SELECTED_TEXT, + this); + InitEvent(queryEvent, nullptr); + DispatchEvent(&queryEvent); + MOZ_ASSERT(queryEvent.mSucceeded && !queryEvent.mWasAsync); + event.theText = queryEvent.mReply.mString; + } + { + WidgetCompositionEvent event(true, NS_COMPOSITION_START, this); + InitEvent(event, nullptr); + DispatchEvent(&event); } - { WidgetCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, @@ -1977,14 +1924,12 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) // Notify SelectionHandler of final caret position // Required in cases of keyboards providing autoCorrections - AndroidGeckoEvent* broadcastEvent = - AndroidGeckoEvent::MakeBroadcastEvent( - NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"), - NS_LITERAL_CSTRING("")); + AndroidGeckoEvent* broadcastEvent = AndroidGeckoEvent::MakeBroadcastEvent( + NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"), + NS_LITERAL_CSTRING("")); nsAppShell::gAppShell->PostEvent(broadcastEvent); } break; - case AndroidGeckoEvent::IME_REMOVE_COMPOSITION: { /* @@ -2189,25 +2134,18 @@ nsWindow::FlushIMEChanges() for (uint32_t i = 0; i < mIMETextChanges.Length(); i++) { IMEChange &change = mIMETextChanges[i]; - if (change.mStart == change.mOldEnd && - change.mStart == change.mNewEnd) { - continue; - } - WidgetQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this); + InitEvent(event, nullptr); + event.InitForQueryTextContent(change.mStart, + change.mNewEnd - change.mStart); + DispatchEvent(&event); + if (!event.mSucceeded) + return; - if (change.mNewEnd != change.mStart) { - InitEvent(event, nullptr); - event.InitForQueryTextContent(change.mStart, - change.mNewEnd - change.mStart); - DispatchEvent(&event); - if (!event.mSucceeded) - return; - } - - mozilla::widget::android::GeckoAppShell::NotifyIMEChange( - event.mReply.mString, change.mStart, - change.mOldEnd, change.mNewEnd); + mozilla::widget::android::GeckoAppShell::NotifyIMEChange(event.mReply.mString, + change.mStart, + change.mOldEnd, + change.mNewEnd); } mIMETextChanges.Clear(); diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index f5325973965c..7c80ddd29344 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -188,10 +188,9 @@ protected: nsCOMPtr mIdleService; bool mIMEComposing; - int32_t mIMEComposingStart; - nsString mIMEComposingText; bool mIMEMaskSelectionUpdate, mIMEMaskTextUpdate; int32_t mIMEMaskEventsCount; // Mask events when > 0 + nsString mIMEComposingText; nsRefPtr mIMERanges; bool mIMEUpdatingContext; nsAutoTArray mIMEKeyEvents; From 45e4b73aa813613bc4ec3b7e6381f3d4a24f97bc Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Fri, 29 Aug 2014 19:38:19 -0700 Subject: [PATCH 063/120] Back out 5 changesets (bug 1059765, bug 1056350, bug 1049087, bug 1060249) for build bustage on a CLOSED TREE Backed out changeset a202e2f54b45 (bug 1056350) Backed out changeset 13c8d9e68cb6 (bug 1060249) Backed out changeset 9c86bdb3ff21 (bug 1049087) Backed out changeset 7b7cb046d45f (bug 1059765) Backed out changeset c52e50a27c8c (bug 1059765) --- .../src/media-conduit/WebrtcGmpVideoCodec.cpp | 60 +++++-------------- .../src/media-conduit/WebrtcGmpVideoCodec.h | 2 - .../signaling/src/media/VcmSIPCCBinding.cpp | 31 ++++------ .../webrtc/signaling/src/sipcc/include/vcm.h | 5 +- .../main/source/content_metrics_processing.cc | 9 --- .../video_coding/main/source/qm_select.cc | 11 ---- .../main/source/content_analysis.cc | 4 -- .../trunk/webrtc/video_engine/vie_encoder.cc | 3 +- modules/libpref/init/all.js | 7 --- 9 files changed, 32 insertions(+), 100 deletions(-) diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp index 58c52177af54..83d40507689c 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp @@ -143,13 +143,12 @@ WebrtcGmpVideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores, uint32_t aMaxPayloadSize) { - if (!mMPS) { - mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); - } + mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); MOZ_ASSERT(mMPS); if (!mGMPThread) { if (NS_WARN_IF(NS_FAILED(mMPS->GetThread(getter_AddRefs(mGMPThread))))) { + mMPS = nullptr; return WEBRTC_VIDEO_CODEC_ERROR; } } @@ -183,30 +182,31 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings, mHost = nullptr; return WEBRTC_VIDEO_CODEC_ERROR; } + mMPS = nullptr; if (!mGMP || !mHost) { return WEBRTC_VIDEO_CODEC_ERROR; } // Bug XXXXXX: transfer settings from codecSettings to codec. - memset(&mCodecParams, 0, sizeof(mCodecParams)); + GMPVideoCodec codec; + memset(&codec, 0, sizeof(codec)); - mCodecParams.mGMPApiVersion = 33; - mCodecParams.mWidth = aCodecSettings->width; - mCodecParams.mHeight = aCodecSettings->height; - mCodecParams.mStartBitrate = aCodecSettings->startBitrate; - mCodecParams.mMinBitrate = aCodecSettings->minBitrate; - mCodecParams.mMaxBitrate = aCodecSettings->maxBitrate; - mCodecParams.mMaxFramerate = aCodecSettings->maxFramerate; - mMaxPayloadSize = aMaxPayloadSize; + codec.mGMPApiVersion = 33; + codec.mWidth = aCodecSettings->width; + codec.mHeight = aCodecSettings->height; + codec.mStartBitrate = aCodecSettings->startBitrate; + codec.mMinBitrate = aCodecSettings->minBitrate; + codec.mMaxBitrate = aCodecSettings->maxBitrate; + codec.mMaxFramerate = aCodecSettings->maxFramerate; if (aCodecSettings->codecSpecific.H264.packetizationMode == 1) { - mMaxPayloadSize = 4*1024*1024; // insanely large + aMaxPayloadSize = 4*1024*1024; // insanely large } // Pass dummy codecSpecific data for now... nsTArray codecSpecific; - GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize); + GMPErr err = mGMP->InitEncode(codec, codecSpecific, this, 1, aMaxPayloadSize); if (err != GMPNoErr) { return WEBRTC_VIDEO_CODEC_ERROR; } @@ -245,38 +245,6 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage, return WEBRTC_VIDEO_CODEC_ERROR; } - if (aInputImage->width() != mCodecParams.mWidth || - aInputImage->height() != mCodecParams.mHeight) { - LOGD(("GMP Encode: resolution change from %ux%u to %ux%u", - mCodecParams.mWidth, mCodecParams.mHeight, aInputImage->width(), aInputImage->height())); - - mGMP->Close(); - - // OpenH264 codec (at least) can't handle dynamic input resolution changes - // re-init the plugin when the resolution changes - // XXX allow codec to indicate it doesn't need re-init! - nsTArray tags; - tags.AppendElement(NS_LITERAL_CSTRING("h264")); - if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags, - NS_LITERAL_STRING(""), - &mHost, - &mGMP)))) { - mGMP = nullptr; - mHost = nullptr; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - mCodecParams.mWidth = aInputImage->width(); - mCodecParams.mHeight = aInputImage->height(); - // Pass dummy codecSpecific data for now... - nsTArray codecSpecific; - - GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize); - if (err != GMPNoErr) { - return WEBRTC_VIDEO_CODEC_ERROR; - } - } - GMPVideoFrame* ftmp = nullptr; GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp); if (err != GMPNoErr) { diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h index 47b68bc93c8d..bafc7dec3c21 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h @@ -92,8 +92,6 @@ private: nsCOMPtr mGMPThread; GMPVideoEncoderProxy* mGMP; GMPVideoHost* mHost; - GMPVideoCodec mCodecParams; - uint32_t mMaxPayloadSize; webrtc::EncodedImageCallback* mCallback; uint64_t mCachedPluginId; }; diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp index cf8469823c26..577e9baa322b 100644 --- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp +++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp @@ -1719,11 +1719,12 @@ static int vcmEnsureExternalCodec( // Register H.264 codec. if (send) { - VideoEncoder* encoder = nullptr; + VideoEncoder* encoder = nullptr; #ifdef MOZ_WEBRTC_OMX - encoder = OMXVideoCodec::CreateEncoder(OMXVideoCodec::CodecType::CODEC_H264); + encoder = OMXVideoCodec::CreateEncoder( + OMXVideoCodec::CodecType::CODEC_H264); #else - encoder = mozilla::GmpVideoCodec::CreateEncoder(); + encoder = mozilla::GmpVideoCodec::CreateEncoder(); #endif if (encoder) { return conduit->SetExternalSendCodec(config, encoder); @@ -2310,15 +2311,16 @@ int vcmGetH264SupportedPacketizationModes() */ uint32_t vcmGetVideoH264ProfileLevelID() { - // For OMX, constrained baseline level 1.2 (via a pref) + // constrained baseline level 1.2 + // XXX make variable based on openh264 and OMX support +#ifdef MOZ_WEBRTC_OMX // Max resolution CIF; we should include max-mbps - int32_t level = 13; // minimum suggested for WebRTC spec - - vcmGetVideoLevel(0, &level); - level &= 0xFF; - level |= 0x42E000; - - return (uint32_t) level; + return 0x42E00C; +#else + // XXX See bug 1043515 - we may want to support a higher profile than + // 1.3, depending on hardware(?) + return 0x42E00D; +#endif } /** @@ -2784,13 +2786,6 @@ static short vcmGetVideoPref(uint16_t codec, return VCM_ERROR; } -short vcmGetVideoLevel(uint16_t codec, - int32_t *level) { - return vcmGetVideoPref(codec, - "media.navigator.video.h264.level", - level); -} - short vcmGetVideoMaxFs(uint16_t codec, int32_t *max_fs) { return vcmGetVideoPref(codec, diff --git a/media/webrtc/signaling/src/sipcc/include/vcm.h b/media/webrtc/signaling/src/sipcc/include/vcm.h index f23dff720123..4b498e22a963 100755 --- a/media/webrtc/signaling/src/sipcc/include/vcm.h +++ b/media/webrtc/signaling/src/sipcc/include/vcm.h @@ -1083,11 +1083,14 @@ int vcmOnSdpParseError(const char *peercconnection, const char *message); */ int vcmDisableRtcpComponent(const char *peerconnection, int level); -short vcmGetVideoLevel(uint16_t codec, int32_t *level); short vcmGetVideoMaxFs(uint16_t codec, int32_t *max_fs); + short vcmGetVideoMaxFr(uint16_t codec, int32_t *max_fr); + short vcmGetVideoMaxBr(uint16_t codec, int32_t *max_br); + short vcmGetVideoMaxMbps(uint16_t codec, int32_t *max_mbps); + short vcmGetVideoPreferredCodec(int32_t *preferred_codec); //Using C++ for gips. This is the end of extern "C" above. diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc index 3e8b2ec963a4..757ffb0e46f6 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/content_metrics_processing.cc @@ -77,16 +77,7 @@ int VCMContentMetricsProcessing::UpdateContentData( if (contentMetrics == NULL) { return VCM_OK; } -#if defined(WEBRTC_GONK) - // "average" values that should yield kDefault in qm_select.cc - contentMetrics->motion_magnitude = 0.05f; - contentMetrics->spatial_pred_err = 0.03f; - contentMetrics->spatial_pred_err_h = 0.03f; - contentMetrics->spatial_pred_err_v = 0.03f; - return VCM_OK; -#else return ProcessContent(contentMetrics); -#endif } int VCMContentMetricsProcessing::ProcessContent( diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc index cd36fc059b14..72f408beee32 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc @@ -60,10 +60,6 @@ void VCMQmMethod::UpdateContent(const VideoContentMetrics* contentMetrics) { } void VCMQmMethod::ComputeMotionNFD() { -#if defined(WEBRTC_GONK) - motion_.value = (kHighMotionNfd + kLowMotionNfd)/2; - motion_.level = kDefault; -#else if (content_metrics_) { motion_.value = content_metrics_->motion_magnitude; } @@ -75,15 +71,9 @@ void VCMQmMethod::ComputeMotionNFD() { } else { motion_.level = kDefault; } -#endif } void VCMQmMethod::ComputeSpatial() { -#if defined(WEBRTC_GONK) - float scale2 = image_type_ > kVGA ? kScaleTexture : 1.0; - spatial_.value = (kHighTexture + kLowTexture)*scale2/2; - spatial_.level = kDefault; -#else float spatial_err = 0.0; float spatial_err_h = 0.0; float spatial_err_v = 0.0; @@ -105,7 +95,6 @@ void VCMQmMethod::ComputeSpatial() { } else { spatial_.level = kDefault; } -#endif } ImageType VCMQmMethod::GetImageType(uint16_t width, diff --git a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc index 6d777116239c..981e0e606a87 100644 --- a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc +++ b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc @@ -58,7 +58,6 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( if (VPM_OK != Initialize(inputFrame.width(), inputFrame.height())) return NULL; } -#if !defined(WEBRTC_GONK) // Compute motion metrics if (ca_Init_) { // Only interested in the Y plane. @@ -76,7 +75,6 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( first_frame_ = false; } -#endif return ContentMetrics(); } @@ -125,12 +123,10 @@ int32_t VPMContentAnalysis::Initialize(int width, int height) { return VPM_MEMORY; } -#if !defined(WEBRTC_GONK) prev_frame_.reset(new uint8_t[width_ * height_]); // Y only. if (!prev_frame_) { return VPM_MEMORY; } -#endif // ok, all initialized ca_Init_ = true; diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc index 6f3550708a9a..2c877f9ff4ff 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc @@ -705,8 +705,7 @@ void ViEEncoder::DeliverFrame(int id, return; } #endif - if (vcm_.AddVideoFrame(*decimated_frame, - vpm_.ContentMetrics()) != VCM_OK) { + if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 3e9a7d9d4f7d..21a5ba01b5fb 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -303,7 +303,6 @@ pref("media.peerconnection.enabled", true); pref("media.peerconnection.video.enabled", true); pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb pref("media.navigator.video.max_fr", 30); -pref("media.navigator.video.h264.level", 12); // 0x42E00C - level 1.2 pref("media.navigator.video.h264.max_br", 700); // 8x10 pref("media.navigator.video.h264.max_mbps", 11880); // CIF@30fps pref("media.peerconnection.video.h264_enabled", false); @@ -315,7 +314,6 @@ pref("media.peerconnection.enabled", true); pref("media.peerconnection.video.enabled", true); pref("media.navigator.video.max_fs", 0); // unrestricted pref("media.navigator.video.max_fr", 0); // unrestricted -pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1 pref("media.navigator.video.h264.max_br", 0); pref("media.navigator.video.h264.max_mbps", 0); pref("media.peerconnection.video.h264_enabled", false); @@ -373,12 +371,7 @@ pref("media.navigator.enabled", true); #endif pref("media.getusermedia.screensharing.enabled", true); -#ifdef RELEASE_BUILD pref("media.getusermedia.screensharing.allowed_domains", ""); -#else - // temporary value, not intended for release - bug 1049087 -pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io"); -#endif // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); From c28208b9f8b344f145728178f6a4401e2b49eb55 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 19:40:53 -0700 Subject: [PATCH 064/120] Bug 1052240 - Skip canvas/drawingbuffer-static-canvas-test. DONTBUILD --- dom/canvas/test/webgl-conformance/_mochitest.ini | 1 + dom/canvas/test/webgl-conformance/mochitest-errata.ini | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/dom/canvas/test/webgl-conformance/_mochitest.ini b/dom/canvas/test/webgl-conformance/_mochitest.ini index 25037e0a63c6..0fb51da04903 100644 --- a/dom/canvas/test/webgl-conformance/_mochitest.ini +++ b/dom/canvas/test/webgl-conformance/_mochitest.ini @@ -497,6 +497,7 @@ support-files = mochi-single.html [_wrappers/test_conformance__canvas__canvas-test.html] [_wrappers/test_conformance__canvas__canvas-zero-size.html] [_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html] +skip-if = os == 'mac' [_wrappers/test_conformance__canvas__drawingbuffer-test.html] [_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html] [_wrappers/test_conformance__context__constants.html] diff --git a/dom/canvas/test/webgl-conformance/mochitest-errata.ini b/dom/canvas/test/webgl-conformance/mochitest-errata.ini index 5d89dce417f6..db50357e2f1d 100644 --- a/dom/canvas/test/webgl-conformance/mochitest-errata.ini +++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini @@ -76,3 +76,9 @@ skip-if = (os == 'b2g') [_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html] # Intermittently asserts on 'B2G ICS Emulator Debug'. skip-if = (os == 'b2g') + +######################################################################## +# Mac +[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html] +# Intermittent crash on OSX. +skip-if = os == 'mac' From 02c81efdf7f60b7e706951f0677decd7ed932a2e Mon Sep 17 00:00:00 2001 From: David Major Date: Sat, 30 Aug 2014 15:49:33 +1200 Subject: [PATCH 065/120] Bug 1048091 - Support for multiple upload files in Breakpad. r=ted --- .../client/crashreporter_gtk_common.cpp | 6 +- .../client/crashreporter_win.cpp | 5 +- .../windows/sender/crash_report_sender.cc | 4 +- .../windows/sender/crash_report_sender.h | 4 +- .../src/common/linux/http_upload.cc | 15 ++--- .../src/common/linux/http_upload.h | 9 ++- .../src/common/windows/http_upload.cc | 56 +++++++++---------- .../src/common/windows/http_upload.h | 14 ++--- 8 files changed, 58 insertions(+), 55 deletions(-) diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp index ff6249f0153a..40706e182161 100644 --- a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp +++ b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp @@ -193,11 +193,13 @@ gpointer SendThread(gpointer args) string response, error; long response_code; + std::map files; + files["upload_file_minidump"] = gDumpFile; + bool success = google_breakpad::HTTPUpload::SendRequest (gSendURL, gQueryParameters, - gDumpFile, - "upload_file_minidump", + files, gHttpProxy, gAuth, gCACertificateFile, &response, diff --git a/toolkit/crashreporter/client/crashreporter_win.cpp b/toolkit/crashreporter/client/crashreporter_win.cpp index 62c2a6032af7..7ee491673540 100644 --- a/toolkit/crashreporter/client/crashreporter_win.cpp +++ b/toolkit/crashreporter/client/crashreporter_win.cpp @@ -397,9 +397,12 @@ static DWORD WINAPI SendThreadProc(LPVOID param) LogMessage("No server URL, not sending report"); } else { google_breakpad::CrashReportSender sender(L""); + std::map files; + files[L"upload_file_minidump"] = td->dumpFile; + finishedOk = (sender.SendCrashReport(td->sendURL, td->queryParameters, - td->dumpFile, + files, &td->serverResponse) == google_breakpad::RESULT_SUCCEEDED); if (finishedOk) { diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.cc b/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.cc index ecf626d84cff..70c36b0e271e 100644 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.cc +++ b/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.cc @@ -59,7 +59,7 @@ CrashReportSender::CrashReportSender(const wstring &checkpoint_file) ReportResult CrashReportSender::SendCrashReport( const wstring &url, const map ¶meters, - const wstring &dump_file_name, wstring *report_code) { + const map &files, wstring *report_code) { int today = GetCurrentDate(); if (today == last_sent_date_ && max_reports_per_day_ != -1 && @@ -69,7 +69,7 @@ ReportResult CrashReportSender::SendCrashReport( int http_response = 0; bool result = HTTPUpload::SendRequest( - url, parameters, dump_file_name, L"upload_file_minidump", NULL, report_code, + url, parameters, files, NULL, report_code, &http_response); if (result) { diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.h b/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.h index da1ed0af8b99..7786cc699c14 100644 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.h +++ b/toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.h @@ -77,7 +77,7 @@ class CrashReportSender { int max_reports_per_day() const { return max_reports_per_day_; } - // Sends the specified minidump file, along with the map of + // Sends the specified files, along with the map of // name value pairs, as a multipart POST request to the given URL. // Parameter names must contain only printable ASCII characters, // and may not contain a quote (") character. @@ -89,7 +89,7 @@ class CrashReportSender { // (Otherwise, report_code will be unchanged.) ReportResult SendCrashReport(const wstring &url, const map ¶meters, - const wstring &dump_file_name, + const map &files, wstring *report_code); private: diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc index fead76e91ba1..7aa0bc1844ca 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc @@ -56,8 +56,7 @@ static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; // static bool HTTPUpload::SendRequest(const string &url, const map ¶meters, - const string &upload_file, - const string &file_part_name, + const map &files, const string &proxy, const string &proxy_user_pwd, const string &ca_certificate_file, @@ -125,11 +124,13 @@ bool HTTPUpload::SendRequest(const string &url, CURLFORM_COPYCONTENTS, iter->second.c_str(), CURLFORM_END); - // Add form file. - (*curl_formadd)(&formpost, &lastptr, - CURLFORM_COPYNAME, file_part_name.c_str(), - CURLFORM_FILE, upload_file.c_str(), - CURLFORM_END); + // Add form files. + for (iter = files.begin(); iter != files.end(); ++iter) { + (*curl_formadd)(&formpost, &lastptr, + CURLFORM_COPYNAME, iter->first.c_str(), + CURLFORM_FILE, iter->second.c_str(), + CURLFORM_END); + } (*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost); diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h index 6dd36ea04e00..4f0e452f469d 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h @@ -45,9 +45,9 @@ using std::map; class HTTPUpload { public: - // Sends the given set of parameters, along with the contents of - // upload_file, as a multipart POST request to the given URL. - // file_part_name contains the name of the file part of the request + // Sends the given sets of parameters and files as a multipart POST + // request to the given URL. + // Each key in |files| is the name of the file part of the request // (i.e. it corresponds to the name= attribute on an . // Parameter names must contain only printable ASCII characters, // and may not contain a quote (") character. @@ -60,8 +60,7 @@ class HTTPUpload { // returned in error_description. static bool SendRequest(const string &url, const map ¶meters, - const string &upload_file, - const string &file_part_name, + const map &files, const string &proxy, const string &proxy_user_pwd, const string &ca_certificate_file, diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc index aabb9a469811..fc356dfad5d0 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc @@ -64,8 +64,7 @@ class HTTPUpload::AutoInternetHandle { // static bool HTTPUpload::SendRequest(const wstring &url, const map ¶meters, - const wstring &upload_file, - const wstring &file_part_name, + const map &files, int *timeout, wstring *response_body, int *response_code) { @@ -143,8 +142,7 @@ bool HTTPUpload::SendRequest(const wstring &url, HTTP_ADDREQ_FLAG_ADD); string request_body; - if (!GenerateRequestBody(parameters, upload_file, - file_part_name, boundary, &request_body)) { + if (!GenerateRequestBody(parameters, files, boundary, &request_body)) { return false; } @@ -269,15 +267,9 @@ wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) { // static bool HTTPUpload::GenerateRequestBody(const map ¶meters, - const wstring &upload_file, - const wstring &file_part_name, + const map &files, const wstring &boundary, string *request_body) { - vector contents; - if (!GetFileContents(upload_file, &contents)) { - return false; - } - string boundary_str = WideToUTF8(boundary); if (boundary_str.empty()) { return false; @@ -294,28 +286,36 @@ bool HTTPUpload::GenerateRequestBody(const map ¶meters, WideToUTF8(pos->second) + "\r\n"); } - // Now append the upload file as a binary (octet-stream) part - string filename_utf8 = WideToUTF8(upload_file); - if (filename_utf8.empty()) { - return false; - } + for (map::const_iterator pos = files.begin(); + pos != files.end(); ++pos) { + vector contents; + if (!GetFileContents(pos->second, &contents)) { + return false; + } - string file_part_name_utf8 = WideToUTF8(file_part_name); - if (file_part_name_utf8.empty()) { - return false; - } + // Now append the upload files as a binary (octet-stream) part + string filename_utf8 = WideToUTF8(pos->second); + if (filename_utf8.empty()) { + return false; + } - request_body->append("--" + boundary_str + "\r\n"); - request_body->append("Content-Disposition: form-data; " - "name=\"" + file_part_name_utf8 + "\"; " - "filename=\"" + filename_utf8 + "\"\r\n"); - request_body->append("Content-Type: application/octet-stream\r\n"); - request_body->append("\r\n"); + string file_part_name_utf8 = WideToUTF8(pos->first); + if (file_part_name_utf8.empty()) { + return false; + } - if (!contents.empty()) { + request_body->append("--" + boundary_str + "\r\n"); + request_body->append("Content-Disposition: form-data; " + "name=\"" + file_part_name_utf8 + "\"; " + "filename=\"" + filename_utf8 + "\"\r\n"); + request_body->append("Content-Type: application/octet-stream\r\n"); + request_body->append("\r\n"); + + if (!contents.empty()) { request_body->append(&(contents[0]), contents.size()); + } + request_body->append("\r\n"); } - request_body->append("\r\n"); request_body->append("--" + boundary_str + "--\r\n"); return true; } diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h index 8a17aab17052..bb18a56d1a46 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h @@ -54,9 +54,9 @@ using std::vector; class HTTPUpload { public: - // Sends the given set of parameters, along with the contents of - // upload_file, as a multipart POST request to the given URL. - // file_part_name contains the name of the file part of the request + // Sends the given sets of parameters and files as a multipart POST + // request to the given URL. + // Each key in |files| is the name of the file part of the request // (i.e. it corresponds to the name= attribute on an . // Parameter names must contain only printable ASCII characters, // and may not contain a quote (") character. @@ -67,8 +67,7 @@ class HTTPUpload { // received (or 0 if the request failed before getting an HTTP response). static bool SendRequest(const wstring &url, const map ¶meters, - const wstring &upload_file, - const wstring &file_part_name, + const map &files, int *timeout, wstring *response_body, int *response_code); @@ -88,12 +87,11 @@ class HTTPUpload { // Generates a HTTP request header for a multipart form submit. static wstring GenerateRequestHeader(const wstring &boundary); - // Given a set of parameters, an upload filename, and a file part name, + // Given a set of parameters, a set of upload files, and a file part name, // generates a multipart request body string with these parameters // and minidump contents. Returns true on success. static bool GenerateRequestBody(const map ¶meters, - const wstring &upload_file, - const wstring &file_part_name, + const map &files, const wstring &boundary, string *request_body); From d104d9b4da4c60ce78bc2ad0f124d3b964aada12 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Fri, 29 Aug 2014 21:07:37 -0700 Subject: [PATCH 066/120] Backed out 3 changesets (bug 992267) for OS X non-unified bustage Backed out changeset fc9f83afab31 (bug 992267) Backed out changeset 9afc72a12cb9 (bug 992267) Backed out changeset 55fb5688e85c (bug 992267) --- js/src/asmjs/AsmJSFrameIterator.cpp | 6 +- js/src/asmjs/AsmJSFrameIterator.h | 1 + js/src/asmjs/AsmJSLink.cpp | 219 +--- js/src/asmjs/AsmJSModule.cpp | 8 +- js/src/asmjs/AsmJSModule.h | 207 +--- js/src/asmjs/AsmJSValidate.cpp | 1085 +++-------------- js/src/builtin/SIMD.cpp | 22 +- js/src/builtin/SIMD.h | 6 - js/src/builtin/TestingFunctions.cpp | 17 - .../irregexp/NativeRegExpMacroAssembler.cpp | 2 +- js/src/jit-test/lib/asm.js | 4 +- js/src/jit-test/tests/asm.js/testSIMD.js | 657 ---------- js/src/jit/CodeGenerator.cpp | 11 +- js/src/jit/Ion.cpp | 6 - js/src/jit/Ion.h | 1 - js/src/jit/IonFrames.cpp | 2 +- js/src/jit/IonMacroAssembler.h | 10 +- js/src/jit/LIR.h | 8 +- js/src/jit/Lowering.cpp | 6 +- js/src/jit/MIR.cpp | 1 - js/src/jit/MIR.h | 2 +- js/src/jit/arm/Assembler-arm.h | 8 +- js/src/jit/arm/MacroAssembler-arm.cpp | 12 +- js/src/jit/arm/Simulator-arm.cpp | 4 +- js/src/jit/mips/Assembler-mips.h | 6 +- js/src/jit/mips/MacroAssembler-mips.cpp | 22 +- js/src/jit/mips/Simulator-mips.cpp | 4 +- js/src/jit/none/Architecture-none.h | 1 - js/src/jit/none/MacroAssembler-none.h | 3 +- js/src/jit/shared/Assembler-shared.h | 4 +- js/src/jit/shared/Assembler-x86-shared.h | 1 - js/src/jit/shared/BaseAssembler-x86-shared.h | 38 - js/src/jit/shared/CodeGenerator-shared.cpp | 60 +- js/src/jit/shared/CodeGenerator-shared.h | 2 + .../jit/shared/CodeGenerator-x86-shared.cpp | 22 +- js/src/jit/shared/Lowering-shared-inl.h | 6 - js/src/jit/x64/Assembler-x64.cpp | 30 +- js/src/jit/x64/Assembler-x64.h | 25 +- js/src/jit/x64/CodeGenerator-x64.cpp | 49 +- js/src/jit/x64/MacroAssembler-x64.cpp | 8 +- js/src/jit/x64/Trampoline-x64.cpp | 1 + js/src/jit/x86/Assembler-x86.cpp | 12 +- js/src/jit/x86/Assembler-x86.h | 31 +- js/src/jit/x86/CodeGenerator-x86.cpp | 46 +- js/src/jit/x86/MacroAssembler-x86.cpp | 8 +- js/src/jit/x86/Trampoline-x86.cpp | 1 + js/src/js.msg | 1 - js/src/jscntxt.h | 1 - js/src/vm/Runtime.cpp | 2 - js/src/vm/Runtime.h | 1 - js/src/vm/Stack.cpp | 4 +- js/src/vm/Stack.h | 4 +- 52 files changed, 379 insertions(+), 2319 deletions(-) delete mode 100644 js/src/jit-test/tests/asm.js/testSIMD.js diff --git a/js/src/asmjs/AsmJSFrameIterator.cpp b/js/src/asmjs/AsmJSFrameIterator.cpp index 1d196e4c4a20..3b8e20cdb317 100644 --- a/js/src/asmjs/AsmJSFrameIterator.cpp +++ b/js/src/asmjs/AsmJSFrameIterator.cpp @@ -356,11 +356,11 @@ js::GenerateAsmJSStackOverflowExit(MacroAssembler &masm, Label *overflowExit, La masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfFP())); // Prepare the stack for calling C++. - if (uint32_t d = StackDecrementForCall(ABIStackAlignment, sizeof(AsmJSFrame), ShadowStackSpace)) - masm.subPtr(Imm32(d), StackPointer); + if (unsigned stackDec = StackDecrementForCall(sizeof(AsmJSFrame), ShadowStackSpace)) + masm.subPtr(Imm32(stackDec), StackPointer); // No need to restore the stack; the throw stub pops everything. - masm.assertStackAlignment(ABIStackAlignment); + masm.assertStackAlignment(); masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed)); masm.jump(throwLabel); } diff --git a/js/src/asmjs/AsmJSFrameIterator.h b/js/src/asmjs/AsmJSFrameIterator.h index f8aaea2859a3..27ffd94c89ef 100644 --- a/js/src/asmjs/AsmJSFrameIterator.h +++ b/js/src/asmjs/AsmJSFrameIterator.h @@ -170,6 +170,7 @@ void GenerateAsmJSExitEpilogue(jit::MacroAssembler &masm, unsigned framePushed, AsmJSExit::Reason reason, jit::Label *profilingReturn); + } // namespace js #endif // asmjs_AsmJSFrameIterator_h diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 4cba533f5775..4eac3030bde4 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -30,7 +30,6 @@ #include "jswrapper.h" #include "asmjs/AsmJSModule.h" -#include "builtin/SIMD.h" #include "frontend/BytecodeCompiler.h" #include "jit/Ion.h" #include "jit/JitCommon.h" @@ -97,75 +96,59 @@ GetDataProperty(JSContext *cx, HandleValue objVal, HandlePropertyName field, Mut return true; } -static bool -HasPureCoercion(JSContext *cx, HandleValue v) -{ - if (IsVectorObject(v) || IsVectorObject(v)) - return true; - - // Ideally, we'd reject all non-SIMD non-primitives, but Emscripten has a - // bug that generates code that passes functions for some imports. To avoid - // breaking all the code that contains this bug, we make an exception for - // functions that don't have user-defined valueOf or toString, for their - // coercions are not observable and coercion via ToNumber/ToInt32 - // definitely produces NaN/0. We should remove this special case later once - // most apps have been built with newer Emscripten. - jsid toString = NameToId(cx->names().toString); - if (v.toObject().is() && - HasObjectValueOf(&v.toObject(), cx) && - ClassMethodIsNative(cx, &v.toObject(), &JSFunction::class_, toString, fun_toString)) - { - return true; - } - - return false; -} - static bool ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Global &global, HandleValue importVal) { JS_ASSERT(global.which() == AsmJSModule::Global::Variable); - void *datum = module.globalVarToGlobalDatum(global); + void *datum = module.globalVarIndexToGlobalDatum(global.varIndex()); switch (global.varInitKind()) { case AsmJSModule::Global::InitConstant: { const AsmJSNumLit &lit = global.varInitNumLit(); + const Value &v = lit.value(); switch (lit.which()) { case AsmJSNumLit::Fixnum: case AsmJSNumLit::NegativeInt: case AsmJSNumLit::BigUnsigned: - *(int32_t *)datum = lit.scalarValue().toInt32(); + *(int32_t *)datum = v.toInt32(); break; case AsmJSNumLit::Double: - *(double *)datum = lit.scalarValue().toDouble(); + *(double *)datum = v.toDouble(); break; case AsmJSNumLit::Float: - *(float *)datum = static_cast(lit.scalarValue().toDouble()); - break; - case AsmJSNumLit::Int32x4: - memcpy(datum, lit.simdValue().asInt32x4(), Simd128DataSize); - break; - case AsmJSNumLit::Float32x4: - memcpy(datum, lit.simdValue().asFloat32x4(), Simd128DataSize); + *(float *)datum = static_cast(v.toDouble()); break; case AsmJSNumLit::OutOfRangeInt: MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("OutOfRangeInt isn't valid in the first place"); } break; } - case AsmJSModule::Global::InitImport: { RootedPropertyName field(cx, global.varImportField()); RootedValue v(cx); if (!GetDataProperty(cx, importVal, field, &v)) return false; - if (!v.isPrimitive() && !HasPureCoercion(cx, v)) - return LinkFail(cx, "Imported values must be primitives"); + if (!v.isPrimitive()) { + // Ideally, we'd reject all non-primitives, but Emscripten has a bug + // that generates code that passes functions for some imports. To + // avoid breaking all the code that contains this bug, we make an + // exception for functions that don't have user-defined valueOf or + // toString, for their coercions are not observable and coercion via + // ToNumber/ToInt32 definitely produces NaN/0. We should remove this + // special case later once most apps have been built with newer + // Emscripten. + jsid toString = NameToId(cx->names().toString); + if (!v.toObject().is() || + !HasObjectValueOf(&v.toObject(), cx) || + !ClassMethodIsNative(cx, &v.toObject(), &JSFunction::class_, toString, fun_toString)) + { + return LinkFail(cx, "Imported values must be primitives"); + } + } - SimdConstant simdConstant; switch (global.varInitCoercion()) { case AsmJS_ToInt32: if (!ToInt32(cx, v, (int32_t *)datum)) @@ -179,16 +162,6 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl if (!RoundFloat32(cx, v, (float *)datum)) return false; break; - case AsmJS_ToInt32x4: - if (!ToSimdConstant(cx, v, &simdConstant)) - return false; - memcpy(datum, simdConstant.asInt32x4(), Simd128DataSize); - break; - case AsmJS_ToFloat32x4: - if (!ToSimdConstant(cx, v, &simdConstant)) - return false; - memcpy(datum, simdConstant.asFloat32x4(), Simd128DataSize); - break; } break; } @@ -268,103 +241,6 @@ ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleVa return true; } -static PropertyName * -SimdTypeToName(JSContext *cx, AsmJSSimdType type) -{ - switch (type) { - case AsmJSSimdType_int32x4: return cx->names().int32x4; - case AsmJSSimdType_float32x4: return cx->names().float32x4; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type"); -} - -static X4TypeDescr::Type -AsmJSSimdTypeToTypeDescrType(AsmJSSimdType type) -{ - switch (type) { - case AsmJSSimdType_int32x4: return Int32x4::type; - case AsmJSSimdType_float32x4: return Float32x4::type; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSSimdType"); -} - -static bool -ValidateSimdType(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal, - MutableHandleValue out) -{ - RootedValue v(cx); - if (!GetDataProperty(cx, globalVal, cx->names().SIMD, &v)) - return false; - - AsmJSSimdType type; - if (global.which() == AsmJSModule::Global::SimdCtor) - type = global.simdCtorType(); - else - type = global.simdOperationType(); - - RootedPropertyName simdTypeName(cx, SimdTypeToName(cx, type)); - if (!GetDataProperty(cx, v, simdTypeName, &v)) - return false; - - if (!v.isObject()) - return LinkFail(cx, "bad SIMD type"); - - RootedObject x4desc(cx, &v.toObject()); - if (!x4desc->is()) - return LinkFail(cx, "bad SIMD type"); - - if (AsmJSSimdTypeToTypeDescrType(type) != x4desc->as().type()) - return LinkFail(cx, "bad SIMD type"); - - out.set(v); - return true; -} - -static bool -ValidateSimdType(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal) -{ - RootedValue _(cx); - return ValidateSimdType(cx, global, globalVal, &_); -} - -static bool -ValidateSimdOperation(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal) -{ - // SIMD operations are loaded from the SIMD type, so the type must have been - // validated before the operation. - RootedValue v(cx); - JS_ALWAYS_TRUE(ValidateSimdType(cx, global, globalVal, &v)); - - RootedPropertyName opName(cx, global.simdOperationName()); - if (!GetDataProperty(cx, v, opName, &v)) - return false; - - Native native = nullptr; - switch (global.simdOperationType()) { - case AsmJSSimdType_int32x4: - switch (global.simdOperation()) { - case AsmJSSimdOperation_add: native = simd_int32x4_add; break; - case AsmJSSimdOperation_sub: native = simd_int32x4_sub; break; - case AsmJSSimdOperation_mul: - case AsmJSSimdOperation_div: - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Mul and div shouldn't have been validated in " - "the first place"); - } - break; - case AsmJSSimdType_float32x4: - switch (global.simdOperation()) { - case AsmJSSimdOperation_add: native = simd_float32x4_add; break; - case AsmJSSimdOperation_sub: native = simd_float32x4_sub; break; - case AsmJSSimdOperation_mul: native = simd_float32x4_mul; break; - case AsmJSSimdOperation_div: native = simd_float32x4_div; break; - } - break; - } - if (!native || !IsNativeFunction(v, native)) - return LinkFail(cx, "bad SIMD.type.* operation"); - return true; -} - static bool ValidateConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal) { @@ -501,14 +377,6 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module) if (!ValidateConstant(cx, global, globalVal)) return false; break; - case AsmJSModule::Global::SimdCtor: - if (!ValidateSimdType(cx, global, globalVal)) - return false; - break; - case AsmJSModule::Global::SimdOperation: - if (!ValidateSimdOperation(cx, global, globalVal)) - return false; - break; } } @@ -569,14 +437,14 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) const AsmJSModule::ExportedFunction &func = FunctionToExportedFunction(callee, module); // The calling convention for an external call into asm.js is to pass an - // array of 16-byte values where each value contains either a coerced int32 - // (in the low word), a double value (in the low dword) or a SIMD vector - // value, with the coercions specified by the asm.js signature. The - // external entry point unpacks this array into the system-ABI-specified - // registers and stack memory and then calls into the internal entry point. - // The return value is stored in the first element of the array (which, - // therefore, must have length >= 1). - js::Vector coercedArgs(cx); + // array of 8-byte values where each value contains either a coerced int32 + // (in the low word) or double value, with the coercions specified by the + // asm.js signature. The external entry point unpacks this array into the + // system-ABI-specified registers and stack memory and then calls into the + // internal entry point. The return value is stored in the first element of + // the array (which, therefore, must have length >= 1). + + js::Vector coercedArgs(cx); if (!coercedArgs.resize(Max(1, func.numArgs()))) return false; @@ -596,20 +464,6 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) if (!RoundFloat32(cx, v, (float *)&coercedArgs[i])) return false; break; - case AsmJS_ToInt32x4: { - SimdConstant simd; - if (!ToSimdConstant(cx, v, &simd)) - return false; - memcpy(&coercedArgs[i], simd.asInt32x4(), Simd128DataSize); - break; - } - case AsmJS_ToFloat32x4: { - SimdConstant simd; - if (!ToSimdConstant(cx, v, &simd)) - return false; - memcpy(&coercedArgs[i], simd.asFloat32x4(), Simd128DataSize); - break; - } } } @@ -647,7 +501,6 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) return true; } - JSObject *x4obj; switch (func.returnType()) { case AsmJSModule::Return_Void: callArgs.rval().set(UndefinedValue()); @@ -658,18 +511,6 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) case AsmJSModule::Return_Double: callArgs.rval().set(NumberValue(*(double*)&coercedArgs[0])); break; - case AsmJSModule::Return_Int32x4: - x4obj = CreateSimd(cx, (int32_t*)&coercedArgs[0]); - if (!x4obj) - return false; - callArgs.rval().set(ObjectValue(*x4obj)); - break; - case AsmJSModule::Return_Float32x4: - x4obj = CreateSimd(cx, (float*)&coercedArgs[0]); - if (!x4obj) - return false; - callArgs.rval().set(ObjectValue(*x4obj)); - break; } return true; diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index 3b6b38f39f0c..32645f0f9746 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -303,8 +303,8 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl // The global data section sits immediately after the executable (and // other) data allocated by the MacroAssembler, so ensure it is - // SIMD-aligned. - pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), SimdStackAlignment); + // double-aligned. + pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), sizeof(double)); // The entire region is allocated via mmap/VirtualAlloc which requires // units of pages. @@ -518,11 +518,11 @@ TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t if (fun->nargs() > size_t(argc)) return true; - // Normally the types should correspond, since we just ran with those types, + // Normally the types should corresond, since we just ran with those types, // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only. if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType())) return true; - for (uint32_t i = 0; i < fun->nargs(); i++) { + for(uint32_t i = 0; i < fun->nargs(); i++) { types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i); types::Type type = types::Type::DoubleType(); if (!argv[i].isDouble()) diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index f47d4ba86e08..2021ce5779af 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -27,10 +27,8 @@ #include "asmjs/AsmJSFrameIterator.h" #include "asmjs/AsmJSValidate.h" -#include "builtin/SIMD.h" #include "gc/Marking.h" #include "jit/IonMacroAssembler.h" -#include "jit/IonTypes.h" #ifdef JS_ION_PERF # include "jit/PerfSpewer.h" #endif @@ -49,9 +47,7 @@ enum AsmJSCoercion { AsmJS_ToInt32, AsmJS_ToNumber, - AsmJS_FRound, - AsmJS_ToInt32x4, - AsmJS_ToFloat32x4 + AsmJS_FRound }; // The asm.js spec recognizes this set of builtin Math functions. @@ -66,22 +62,6 @@ enum AsmJSMathBuiltinFunction AsmJSMathBuiltin_clz32 }; -// Set of known global object SIMD's attributes, i.e. types -enum AsmJSSimdType -{ - AsmJSSimdType_int32x4, - AsmJSSimdType_float32x4 -}; - -// Set of known operations, for a given SIMD type (int32x4, float32x4,...) -enum AsmJSSimdOperation -{ - AsmJSSimdOperation_add, - AsmJSSimdOperation_sub, - AsmJSSimdOperation_mul, - AsmJSSimdOperation_div -}; - // These labels describe positions in the prologue/epilogue of functions while // compiling an AsmJSModule. struct AsmJSFunctionLabels @@ -118,32 +98,18 @@ class AsmJSNumLit BigUnsigned, Double, Float, - Int32x4, - Float32x4, OutOfRangeInt = -1 }; private: Which which_; - union { - Value scalar_; - jit::SimdConstant simd_; - } value; + Value value_; public: static AsmJSNumLit Create(Which w, Value v) { AsmJSNumLit lit; lit.which_ = w; - lit.value.scalar_ = v; - JS_ASSERT(!lit.isSimd()); - return lit; - } - - static AsmJSNumLit Create(Which w, jit::SimdConstant c) { - AsmJSNumLit lit; - lit.which_ = w; - lit.value.simd_ = c; - JS_ASSERT(lit.isSimd()); + lit.value_ = v; return lit; } @@ -153,31 +119,22 @@ class AsmJSNumLit int32_t toInt32() const { JS_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned); - return value.scalar_.toInt32(); + return value_.toInt32(); } double toDouble() const { JS_ASSERT(which_ == Double); - return value.scalar_.toDouble(); + return value_.toDouble(); } float toFloat() const { JS_ASSERT(which_ == Float); - return float(value.scalar_.toDouble()); + return float(value_.toDouble()); } - Value scalarValue() const { + Value value() const { JS_ASSERT(which_ != OutOfRangeInt); - return value.scalar_; - } - - bool isSimd() const { - return which_ == Int32x4 || which_ == Float32x4; - } - - const jit::SimdConstant &simdValue() const { - JS_ASSERT(isSimd()); - return value.simd_; + return value_; } bool hasType() const { @@ -201,8 +158,7 @@ class AsmJSModule class Global { public: - enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant, - SimdCtor, SimdOperation}; + enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant }; enum VarInitKind { InitConstant, InitImport }; enum ConstantKind { GlobalConstant, MathConstant }; @@ -221,11 +177,6 @@ class AsmJSModule uint32_t ffiIndex_; Scalar::Type viewType_; AsmJSMathBuiltinFunction mathBuiltinFunc_; - AsmJSSimdType simdCtorType_; - struct { - AsmJSSimdType type_; - AsmJSSimdOperation which_; - } simdOp; struct { ConstantKind kind_; double value_; @@ -246,7 +197,7 @@ class AsmJSModule if (name_) MarkStringUnbarriered(trc, &name_, "asm.js global name"); JS_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant, - !pod.u.var.u.numLit_.scalarValue().isMarkable()); + !pod.u.var.u.numLit_.value().isMarkable()); } public: @@ -301,26 +252,6 @@ class AsmJSModule JS_ASSERT(pod.which_ == MathBuiltinFunction); return pod.u.mathBuiltinFunc_; } - AsmJSSimdType simdCtorType() const { - JS_ASSERT(pod.which_ == SimdCtor); - return pod.u.simdCtorType_; - } - PropertyName *simdCtorName() const { - JS_ASSERT(pod.which_ == SimdCtor); - return name_; - } - PropertyName *simdOperationName() const { - JS_ASSERT(pod.which_ == SimdOperation); - return name_; - } - AsmJSSimdOperation simdOperation() const { - JS_ASSERT(pod.which_ == SimdOperation); - return pod.u.simdOp.which_; - } - AsmJSSimdType simdOperationType() const { - JS_ASSERT(pod.which_ == SimdOperation); - return pod.u.simdOp.type_; - } PropertyName *constantName() const { JS_ASSERT(pod.which_ == Constant); return name_; @@ -379,13 +310,7 @@ class AsmJSModule const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); bool clone(ExclusiveContext *cx, Exit *out) const; }; - - struct EntryArg { - uint64_t lo; - uint64_t hi; - }; - JS_STATIC_ASSERT(sizeof(EntryArg) >= jit::Simd128DataSize); - typedef int32_t (*CodePtr)(EntryArg *args, uint8_t *global); + typedef int32_t (*CodePtr)(uint64_t *args, uint8_t *global); // An Exit holds bookkeeping information about an exit; the ExitDatum // struct overlays the actual runtime data stored in the global data @@ -398,7 +323,7 @@ class AsmJSModule typedef Vector ArgCoercionVector; - enum ReturnType { Return_Int32, Return_Double, Return_Int32x4, Return_Float32x4, Return_Void }; + enum ReturnType { Return_Int32, Return_Double, Return_Void }; class ExportedFunction { @@ -748,8 +673,7 @@ class AsmJSModule size_t codeBytes_; // function bodies and stubs size_t totalBytes_; // function bodies, stubs, and global data uint32_t minHeapLength_; - uint32_t numGlobalScalarVars_; - uint32_t numGlobalSimdVars_; + uint32_t numGlobalVars_; uint32_t numFFIs_; uint32_t srcLength_; uint32_t srcLengthWithRightBrace_; @@ -896,43 +820,20 @@ class AsmJSModule } bool addGlobalVarInit(const AsmJSNumLit &lit, uint32_t *globalIndex) { JS_ASSERT(!isFinishedWithModulePrologue()); + if (pod.numGlobalVars_ == UINT32_MAX) + return false; Global g(Global::Variable, nullptr); g.pod.u.var.initKind_ = Global::InitConstant; g.pod.u.var.u.numLit_ = lit; - - if (lit.isSimd()) { - if (pod.numGlobalSimdVars_ == UINT32_MAX) - return false; - *globalIndex = pod.numGlobalSimdVars_++; - } else { - if (pod.numGlobalScalarVars_ == UINT32_MAX) - return false; - *globalIndex = pod.numGlobalScalarVars_++; - } - - g.pod.u.var.index_ = *globalIndex; + g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++; return globals_.append(g); } - static bool IsSimdCoercion(AsmJSCoercion c) { - switch (c) { - case AsmJS_ToInt32: - case AsmJS_ToNumber: - case AsmJS_FRound: - return false; - case AsmJS_ToInt32x4: - case AsmJS_ToFloat32x4: - return true; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSCoercion"); - } bool addGlobalVarImport(PropertyName *name, AsmJSCoercion coercion, uint32_t *globalIndex) { JS_ASSERT(!isFinishedWithModulePrologue()); Global g(Global::Variable, name); g.pod.u.var.initKind_ = Global::InitImport; g.pod.u.var.u.coercion_ = coercion; - *globalIndex = IsSimdCoercion(coercion) ? pod.numGlobalSimdVars_++ - : pod.numGlobalScalarVars_++; - g.pod.u.var.index_ = *globalIndex; + g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++; return globals_.append(g); } bool addFFI(PropertyName *field, uint32_t *ffiIndex) { @@ -963,17 +864,6 @@ class AsmJSModule g.pod.u.constant.kind_ = Global::MathConstant; return globals_.append(g); } - bool addSimdCtor(AsmJSSimdType type, PropertyName *field) { - Global g(Global::SimdCtor, field); - g.pod.u.simdCtorType_ = type; - return globals_.append(g); - } - bool addSimdOperation(AsmJSSimdType type, AsmJSSimdOperation op, PropertyName *field) { - Global g(Global::SimdOperation, field); - g.pod.u.simdOp.type_ = type; - g.pod.u.simdOp.which_ = op; - return globals_.append(g); - } bool addGlobalConstant(double value, PropertyName *name) { JS_ASSERT(!isFinishedWithModulePrologue()); Global g(Global::Constant, name); @@ -1220,11 +1110,10 @@ class AsmJSModule // are laid out in this order: // 0. a pointer to the current AsmJSActivation // 1. a pointer to the heap that was linked to the module - // 2. the double float constant NaN - // 3. the float32 constant NaN, padded to Simd128DataSize - // 4. global SIMD variable state (elements are Simd128DataSize) - // 5. global variable state (elements are sizeof(uint64_t)) - // 6. interleaved function-pointer tables and exits. These are allocated + // 2. the double float constant NaN. + // 3. the float32 constant NaN, padded to sizeof(double). + // 4. global variable state (elements are sizeof(uint64_t)) + // 5. interleaved function-pointer tables and exits. These are allocated // while type checking function bodies (as exits and uses of // function-pointer tables are encountered). size_t offsetOfGlobalData() const { @@ -1235,18 +1124,13 @@ class AsmJSModule JS_ASSERT(isFinished()); return code_ + offsetOfGlobalData(); } - size_t globalSimdVarsOffset() const { - return AlignBytes(/* 0 */ sizeof(void*) + - /* 1 */ sizeof(void*) + - /* 2 */ sizeof(double) + - /* 3 */ sizeof(float), - jit::Simd128DataSize); - } size_t globalDataBytes() const { - return globalSimdVarsOffset() + - /* 4 */ pod.numGlobalSimdVars_ * jit::Simd128DataSize + - /* 5 */ pod.numGlobalScalarVars_ * sizeof(uint64_t) + - /* 6 */ pod.funcPtrTableAndExitBytes_; + return sizeof(void*) + + sizeof(void*) + + sizeof(double) + + sizeof(double) + + pod.numGlobalVars_ * sizeof(uint64_t) + + pod.funcPtrTableAndExitBytes_; } static unsigned activationGlobalDataOffset() { JS_STATIC_ASSERT(jit::AsmJSActivationGlobalDataOffset == 0); @@ -1281,39 +1165,20 @@ class AsmJSModule *(double *)(globalData() + nan64GlobalDataOffset()) = GenericNaN(); *(float *)(globalData() + nan32GlobalDataOffset()) = GenericNaN(); } - unsigned globalSimdVarIndexToGlobalDataOffset(unsigned i) const { - JS_ASSERT(isFinishedWithModulePrologue()); - JS_ASSERT(i < pod.numGlobalSimdVars_); - return globalSimdVarsOffset() + - i * jit::Simd128DataSize; + unsigned globalVariableOffset() const { + static_assert((2 * sizeof(void*) + 2 * sizeof(double)) % sizeof(double) == 0, + "Global data should be aligned"); + return 2 * sizeof(void*) + 2 * sizeof(double); } - unsigned globalScalarVarIndexToGlobalDataOffset(unsigned i) const { + unsigned globalVarIndexToGlobalDataOffset(unsigned i) const { JS_ASSERT(isFinishedWithModulePrologue()); - JS_ASSERT(i < pod.numGlobalScalarVars_); - return globalSimdVarsOffset() + - pod.numGlobalSimdVars_ * jit::Simd128DataSize + + JS_ASSERT(i < pod.numGlobalVars_); + return globalVariableOffset() + i * sizeof(uint64_t); } - void *globalScalarVarIndexToGlobalDatum(unsigned i) const { + void *globalVarIndexToGlobalDatum(unsigned i) const { JS_ASSERT(isFinished()); - return (void *)(globalData() + globalScalarVarIndexToGlobalDataOffset(i)); - } - void *globalSimdVarIndexToGlobalDatum(unsigned i) const { - JS_ASSERT(isFinished()); - return (void *)(globalData() + globalSimdVarIndexToGlobalDataOffset(i)); - } - void *globalVarToGlobalDatum(const Global &g) const { - unsigned index = g.varIndex(); - if (g.varInitKind() == Global::VarInitKind::InitConstant) { - return g.varInitNumLit().isSimd() - ? globalSimdVarIndexToGlobalDatum(index) - : globalScalarVarIndexToGlobalDatum(index); - } - - JS_ASSERT(g.varInitKind() == Global::VarInitKind::InitImport); - return IsSimdCoercion(g.varInitCoercion()) - ? globalSimdVarIndexToGlobalDatum(index) - : globalScalarVarIndexToGlobalDatum(index); + return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i)); } uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const { JS_ASSERT(isFinished()); diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 8703aeb2df6a..9a1df82472a9 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -32,7 +32,6 @@ #include "asmjs/AsmJSLink.h" #include "asmjs/AsmJSModule.h" #include "asmjs/AsmJSSignalHandlers.h" -#include "builtin/SIMD.h" #include "frontend/Parser.h" #include "jit/CodeGenerator.h" #include "jit/CompileWrappers.h" @@ -388,8 +387,6 @@ class Type Unsigned = AsmJSNumLit::BigUnsigned, Double = AsmJSNumLit::Double, Float = AsmJSNumLit::Float, - Int32x4 = AsmJSNumLit::Int32x4, - Float32x4 = AsmJSNumLit::Float32x4, MaybeDouble, MaybeFloat, Floatish, @@ -405,23 +402,12 @@ class Type Type() : which_(Which(-1)) {} static Type Of(const AsmJSNumLit &lit) { JS_ASSERT(lit.hasType()); - JS_ASSERT(Type::Which(lit.which()) >= Fixnum && Type::Which(lit.which()) <= Float32x4); + JS_ASSERT(Type::Which(lit.which()) >= Fixnum && Type::Which(lit.which()) <= Float); Type t; t.which_ = Type::Which(lit.which()); return t; } MOZ_IMPLICIT Type(Which w) : which_(w) {} - MOZ_IMPLICIT Type(AsmJSSimdType type) { - switch (type) { - case AsmJSSimdType_int32x4: - which_ = Int32x4; - return; - case AsmJSSimdType_float32x4: - which_ = Float32x4; - return; - } - MOZ_CRASH("unexpected AsmJSSimdType"); - } bool operator==(Type rhs) const { return which_ == rhs.which_; } bool operator!=(Type rhs) const { return which_ != rhs.which_; } @@ -470,20 +456,8 @@ class Type return isDouble() || isSigned(); } - bool isInt32x4() const { - return which_ == Int32x4; - } - - bool isFloat32x4() const { - return which_ == Float32x4; - } - - bool isSimd() const { - return isInt32x4() || isFloat32x4(); - } - bool isVarType() const { - return isInt() || isDouble() || isFloat() || isSimd(); + return isInt() || isDouble() || isFloat(); } MIRType toMIRType() const { @@ -501,64 +475,12 @@ class Type case Unsigned: case Intish: return MIRType_Int32; - case Int32x4: - return MIRType_Int32x4; - case Float32x4: - return MIRType_Float32x4; case Void: return MIRType_None; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid Type"); } - Type simdToScalarType() const { - JS_ASSERT(isSimd()); - switch (which_) { - case Int32x4: - return Int; - case Float32x4: - return Float; - // Scalar types - case Double: - case MaybeDouble: - case Float: - case MaybeFloat: - case Floatish: - case Fixnum: - case Int: - case Signed: - case Unsigned: - case Intish: - case Void: - break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid SIMD Type"); - } - - AsmJSSimdType simdToSimdType() const { - JS_ASSERT(isSimd()); - switch (which_) { - case Int32x4: - return AsmJSSimdType_int32x4; - case Float32x4: - return AsmJSSimdType_float32x4; - // Scalar types - case Double: - case MaybeDouble: - case Float: - case MaybeFloat: - case Floatish: - case Fixnum: - case Int: - case Signed: - case Unsigned: - case Intish: - case Void: - break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid SIMD Type"); - } - const char *toChars() const { switch (which_) { case Double: return "double"; @@ -571,8 +493,6 @@ class Type case Signed: return "signed"; case Unsigned: return "unsigned"; case Intish: return "intish"; - case Int32x4: return "int32x4"; - case Float32x4: return "float32x4"; case Void: return "void"; } MOZ_CRASH("Invalid Type"); @@ -590,9 +510,7 @@ class RetType Void = Type::Void, Signed = Type::Signed, Double = Type::Double, - Float = Type::Float, - Int32x4 = Type::Int32x4, - Float32x4 = Type::Float32x4 + Float = Type::Float }; private: @@ -606,8 +524,6 @@ class RetType case AsmJS_ToInt32: which_ = Signed; break; case AsmJS_ToNumber: which_ = Double; break; case AsmJS_FRound: which_ = Float; break; - case AsmJS_ToInt32x4: which_ = Int32x4; break; - case AsmJS_ToFloat32x4: which_ = Float32x4; break; } } Which which() const { @@ -622,8 +538,6 @@ class RetType case Signed: return AsmJSModule::Return_Int32; case Float: // will be converted to a Double case Double: return AsmJSModule::Return_Double; - case Int32x4: return AsmJSModule::Return_Int32x4; - case Float32x4: return AsmJSModule::Return_Float32x4; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected return type"); } @@ -633,8 +547,6 @@ class RetType case Signed: return MIRType_Int32; case Double: return MIRType_Double; case Float: return MIRType_Float32; - case Int32x4: return MIRType_Int32x4; - case Float32x4: return MIRType_Float32x4; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected return type"); } @@ -700,9 +612,7 @@ class VarType enum Which { Int = Type::Int, Double = Type::Double, - Float = Type::Float, - Int32x4 = Type::Int32x4, - Float32x4 = Type::Float32x4 + Float = Type::Float }; private: @@ -718,8 +628,6 @@ class VarType case AsmJS_ToInt32: which_ = Int; break; case AsmJS_ToNumber: which_ = Double; break; case AsmJS_FRound: which_ = Float; break; - case AsmJS_ToInt32x4: which_ = Int32x4; break; - case AsmJS_ToFloat32x4: which_ = Float32x4; break; } } static VarType Of(const AsmJSNumLit &lit) { @@ -737,12 +645,6 @@ class VarType case AsmJSNumLit::Float: v.which_ = Float; return v; - case AsmJSNumLit::Int32x4: - v.which_ = Int32x4; - return v; - case AsmJSNumLit::Float32x4: - v.which_ = Float32x4; - return v; case AsmJSNumLit::OutOfRangeInt: MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("can't be out of range int"); } @@ -757,37 +659,28 @@ class VarType } MIRType toMIRType() const { switch(which_) { - case Int: return MIRType_Int32; - case Double: return MIRType_Double; - case Float: return MIRType_Float32; - case Int32x4: return MIRType_Int32x4; - case Float32x4: return MIRType_Float32x4; + case Int: return MIRType_Int32; + case Double: return MIRType_Double; + case Float: return MIRType_Float32; } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, SIMD, Double or Float"); + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, Double or Float"); } AsmJSCoercion toCoercion() const { switch(which_) { - case Int: return AsmJS_ToInt32; - case Double: return AsmJS_ToNumber; - case Float: return AsmJS_FRound; - case Int32x4: return AsmJS_ToInt32x4; - case Float32x4: return AsmJS_ToFloat32x4; + case Int: return AsmJS_ToInt32; + case Double: return AsmJS_ToNumber; + case Float: return AsmJS_FRound; } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, SIMD, Double or Float"); + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("VarType can only be Int, Double or Float"); } static VarType FromCheckedType(Type type) { - JS_ASSERT(type.isInt() || type.isMaybeDouble() || type.isFloatish() || type.isSimd()); + JS_ASSERT(type.isInt() || type.isMaybeDouble() || type.isFloatish()); if (type.isMaybeDouble()) return Double; else if (type.isFloatish()) return Float; - else if (type.isInt()) + else return Int; - else if (type.isInt32x4()) - return Int32x4; - else if (type.isFloat32x4()) - return Float32x4; - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unknown type in FromCheckedType"); } bool operator==(VarType rhs) const { return which_ == rhs.which_; } bool operator!=(VarType rhs) const { return which_ != rhs.which_; } @@ -800,11 +693,9 @@ static inline bool operator<=(Type lhs, VarType rhs) { switch (rhs.which()) { - case VarType::Int: return lhs.isInt(); - case VarType::Double: return lhs.isDouble(); - case VarType::Float: return lhs.isFloat(); - case VarType::Int32x4: return lhs.isInt32x4(); - case VarType::Float32x4: return lhs.isFloat32x4(); + case VarType::Int: return lhs.isInt(); + case VarType::Double: return lhs.isDouble(); + case VarType::Float: return lhs.isFloat(); } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected rhs type"); } @@ -1044,9 +935,7 @@ class MOZ_STACK_CLASS ModuleCompiler FuncPtrTable, FFI, ArrayView, - MathBuiltinFunction, - SimdCtor, - SimdOperation + MathBuiltinFunction }; private: @@ -1062,11 +951,6 @@ class MOZ_STACK_CLASS ModuleCompiler uint32_t ffiIndex_; Scalar::Type viewType_; AsmJSMathBuiltinFunction mathBuiltinFunc_; - AsmJSSimdType simdCtorType_; - struct { - AsmJSSimdType type_; - AsmJSSimdOperation which_; - } simdOp; } u; friend class ModuleCompiler; @@ -1116,24 +1000,6 @@ class MOZ_STACK_CLASS ModuleCompiler JS_ASSERT(which_ == MathBuiltinFunction); return u.mathBuiltinFunc_; } - bool isSimdCtor() const { - return which_ == SimdCtor; - } - AsmJSSimdType simdCtorType() const { - JS_ASSERT(which_ == SimdCtor); - return u.simdCtorType_; - } - bool isSimdOperation() const { - return which_ == SimdOperation; - } - AsmJSSimdOperation simdOperation() const { - JS_ASSERT(which_ == SimdOperation); - return u.simdOp.which_; - } - AsmJSSimdType simdOperationType() const { - JS_ASSERT(which_ == SimdOperation); - return u.simdOp.type_; - } }; typedef Vector FuncPtrVector; @@ -1235,7 +1101,6 @@ class MOZ_STACK_CLASS ModuleCompiler }; typedef HashMap MathNameMap; - typedef HashMap SimdOperationNameMap; typedef HashMap GlobalMap; typedef Vector FuncVector; typedef Vector GlobalAccessVector; @@ -1256,7 +1121,6 @@ class MOZ_STACK_CLASS ModuleCompiler FuncPtrTableVector funcPtrTables_; ExitMap exits_; MathNameMap standardLibraryMathNames_; - SimdOperationNameMap standardLibrarySimdOpNames_; NonAssertingLabel stackOverflowLabel_; NonAssertingLabel asyncInterruptLabel_; NonAssertingLabel syncInterruptLabel_; @@ -1269,7 +1133,6 @@ class MOZ_STACK_CLASS ModuleCompiler SlowFunctionVector slowFunctions_; DebugOnly finishedFunctionBodies_; - bool supportsSimd_; bool addStandardLibraryMathName(const char *name, AsmJSMathBuiltinFunction func) { JSAtom *atom = Atomize(cx_, name, strlen(name)); @@ -1285,12 +1148,6 @@ class MOZ_STACK_CLASS ModuleCompiler MathBuiltin builtin(cst); return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin); } - bool addStandardLibrarySimdOpName(const char *name, AsmJSSimdOperation op) { - JSAtom *atom = Atomize(cx_, name, strlen(name)); - if (!atom) - return false; - return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op); - } public: ModuleCompiler(ExclusiveContext *cx, AsmJSParser &parser) @@ -1305,14 +1162,12 @@ class MOZ_STACK_CLASS ModuleCompiler funcPtrTables_(cx), exits_(cx), standardLibraryMathNames_(cx), - standardLibrarySimdOpNames_(cx), errorString_(nullptr), errorOffset_(UINT32_MAX), errorOverRecursed_(false), usecBefore_(PRMJ_Now()), slowFunctions_(cx), - finishedFunctionBodies_(false), - supportsSimd_(cx->jitSupportsSimd()) + finishedFunctionBodies_(false) { JS_ASSERT(moduleFunctionNode_->pn_funbox == parser.pc->sc->asFunctionBox()); } @@ -1364,15 +1219,6 @@ class MOZ_STACK_CLASS ModuleCompiler return false; } - if (!standardLibrarySimdOpNames_.init() || - !addStandardLibrarySimdOpName("add", AsmJSSimdOperation_add) || - !addStandardLibrarySimdOpName("sub", AsmJSSimdOperation_sub) || - !addStandardLibrarySimdOpName("mul", AsmJSSimdOperation_mul) || - !addStandardLibrarySimdOpName("div", AsmJSSimdOperation_div)) - { - return false; - } - uint32_t srcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin; uint32_t srcBodyStart = tokenStream().currentToken().pos.end; @@ -1454,7 +1300,6 @@ class MOZ_STACK_CLASS ModuleCompiler uint32_t srcStart() const { return module_->srcStart(); } bool usesSignalHandlersForInterrupt() const { return module_->usesSignalHandlersForInterrupt(); } bool usesSignalHandlersForOOB() const { return module_->usesSignalHandlersForOOB(); } - bool supportsSimd() const { return supportsSimd_; } ParseNode *moduleFunctionNode() const { return moduleFunctionNode_; } PropertyName *moduleFunctionName() const { return moduleFunctionName_; } @@ -1491,13 +1336,6 @@ class MOZ_STACK_CLASS ModuleCompiler } return false; } - bool lookupStandardSimdOpName(PropertyName *name, AsmJSSimdOperation *op) const { - if (SimdOperationNameMap::Ptr p = standardLibrarySimdOpNames_.lookup(name)) { - *op = p->value(); - return true; - } - return false; - } ExitMap::Range allExits() const { return exits_.all(); } @@ -1601,27 +1439,6 @@ class MOZ_STACK_CLASS ModuleCompiler global->u.mathBuiltinFunc_ = func; return globals_.putNew(varName, global); } - bool addSimdCtor(PropertyName *varName, AsmJSSimdType type, PropertyName *fieldName) { - if (!module_->addSimdCtor(type, fieldName)) - return false; - Global *global = moduleLifo_.new_(Global::SimdCtor); - if (!global) - return false; - global->u.simdCtorType_ = type; - return globals_.putNew(varName, global); - } - bool addSimdOperation(PropertyName *varName, AsmJSSimdType type, AsmJSSimdOperation op, - PropertyName *typeVarName, PropertyName *opName) - { - if (!module_->addSimdOperation(type, op, opName)) - return false; - Global *global = moduleLifo_.new_(Global::SimdOperation); - if (!global) - return false; - global->u.simdOp.type_ = type; - global->u.simdOp.which_ = op; - return globals_.putNew(varName, global); - } private: bool addGlobalDoubleConstant(PropertyName *varName, double constant) { Global *global = moduleLifo_.new_(Global::ConstantLiteral); @@ -1855,118 +1672,39 @@ IsCallToGlobal(ModuleCompiler &m, ParseNode *pn, const ModuleCompiler::Global ** } static bool -IsCoercionCall(ModuleCompiler &m, ParseNode *pn, AsmJSCoercion *coercion, ParseNode **coercedExpr) +IsFloatCoercion(ModuleCompiler &m, ParseNode *pn, ParseNode **coercedExpr) { const ModuleCompiler::Global *global; if (!IsCallToGlobal(m, pn, &global)) return false; + if (!global->isMathFunction() || global->mathBuiltinFunction() != AsmJSMathBuiltin_fround) + return false; + if (CallArgListLength(pn) != 1) return false; if (coercedExpr) *coercedExpr = CallArgList(pn); - if (global->isMathFunction() && global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) { - *coercion = AsmJS_FRound; - return true; - } - - if (global->isSimdCtor()) { - switch (global->simdCtorType()) { - case AsmJSSimdType_int32x4: - *coercion = AsmJS_ToInt32x4; - return true; - case AsmJSSimdType_float32x4: - *coercion = AsmJS_ToFloat32x4; - return true; - } - } - - return false; + return true; } static bool -IsFloatLiteral(ModuleCompiler &m, ParseNode *pn) +IsNumericFloatLiteral(ModuleCompiler &m, ParseNode *pn) { ParseNode *coercedExpr; - AsmJSCoercion coercion; - if (!IsCoercionCall(m, pn, &coercion, &coercedExpr) || coercion != AsmJS_FRound) + if (!IsFloatCoercion(m, pn, &coercedExpr)) return false; + return IsNumericNonFloatLiteral(coercedExpr); } -static unsigned -SimdTypeToLength(AsmJSSimdType type) -{ - switch (type) { - case AsmJSSimdType_float32x4: - case AsmJSSimdType_int32x4: - return 4; - } - MOZ_CRASH("unexpected SIMD type"); -} - -static bool -IsSimdTuple(ModuleCompiler &m, ParseNode *pn, AsmJSSimdType *type) -{ - const ModuleCompiler::Global *global; - if (!IsCallToGlobal(m, pn, &global)) - return false; - - if (!global->isSimdCtor()) - return false; - - if (CallArgListLength(pn) != SimdTypeToLength(global->simdCtorType())) - return false; - - *type = global->simdCtorType(); - return true; -} - -static bool -IsNumericLiteral(ModuleCompiler &m, ParseNode *pn); -static AsmJSNumLit -ExtractNumericLiteral(ModuleCompiler &m, ParseNode *pn); -static inline bool -IsLiteralInt(ModuleCompiler &m, ParseNode *pn, uint32_t *u32); - -static bool -IsSimdLiteral(ModuleCompiler &m, ParseNode *pn) -{ - AsmJSSimdType type; - if (!IsSimdTuple(m, pn, &type)) - return false; - - ParseNode *arg = CallArgList(pn); - unsigned length = SimdTypeToLength(type); - for (unsigned i = 0; i < length; i++) { - if (!IsNumericLiteral(m, arg)) - return false; - - uint32_t _; - switch (type) { - case AsmJSSimdType_int32x4: - if (!IsLiteralInt(m, arg, &_)) - return false; - case AsmJSSimdType_float32x4: - if (!IsNumericNonFloatLiteral(arg)) - return false; - } - - arg = NextNode(arg); - } - - JS_ASSERT(arg == nullptr); - return true; -} - static bool IsNumericLiteral(ModuleCompiler &m, ParseNode *pn) { return IsNumericNonFloatLiteral(pn) || - IsFloatLiteral(m, pn) || - IsSimdLiteral(m, pn); + IsNumericFloatLiteral(m, pn); } // The JS grammar treats -42 as -(42) (i.e., with separate grammar @@ -1974,53 +1712,16 @@ IsNumericLiteral(ModuleCompiler &m, ParseNode *pn) // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal // so fold the two potential parse nodes into a single double value. static double -ExtractNumericNonFloatValue(ParseNode *pn, ParseNode **out = nullptr) +ExtractNumericNonFloatValue(ParseNode **pn) { - JS_ASSERT(IsNumericNonFloatLiteral(pn)); + JS_ASSERT(IsNumericNonFloatLiteral(*pn)); - if (pn->isKind(PNK_NEG)) { - pn = UnaryKid(pn); - if (out) - *out = pn; - return -NumberNodeValue(pn); + if ((*pn)->isKind(PNK_NEG)) { + *pn = UnaryKid(*pn); + return -NumberNodeValue(*pn); } - return NumberNodeValue(pn); -} - -static AsmJSNumLit -ExtractSimdValue(ModuleCompiler &m, ParseNode *pn) -{ - JS_ASSERT(IsSimdLiteral(m, pn)); - - AsmJSSimdType type; - JS_ALWAYS_TRUE(IsSimdTuple(m, pn, &type)); - - ParseNode *arg = CallArgList(pn); - unsigned length = SimdTypeToLength(type); - switch (type) { - case AsmJSSimdType_int32x4: { - JS_ASSERT(length == 4); - int32_t val[4]; - for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = int32_t(u32); - } - JS_ASSERT(arg== nullptr); - return AsmJSNumLit::Create(AsmJSNumLit::Int32x4, SimdConstant::CreateX4(val)); - } - case AsmJSSimdType_float32x4: { - JS_ASSERT(length == 4); - float val[4]; - for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) - val[i] = float(ExtractNumericNonFloatValue(arg)); - JS_ASSERT(arg == nullptr); - return AsmJSNumLit::Create(AsmJSNumLit::Float32x4, SimdConstant::CreateX4(val)); - } - } - - MOZ_CRASH("Unexpected SIMD type."); + return NumberNodeValue(*pn); } static AsmJSNumLit @@ -2028,20 +1729,15 @@ ExtractNumericLiteral(ModuleCompiler &m, ParseNode *pn) { JS_ASSERT(IsNumericLiteral(m, pn)); + // Float literals are explicitly coerced and thus the coerced literal may be + // any valid (non-float) numeric literal. if (pn->isKind(PNK_CALL)) { - // Float literals are explicitly coerced and thus the coerced literal may be - // any valid (non-float) numeric literal. - if (CallArgListLength(pn) == 1) { - pn = CallArgList(pn); - double d = ExtractNumericNonFloatValue(pn); - return AsmJSNumLit::Create(AsmJSNumLit::Float, DoubleValue(d)); - } - - JS_ASSERT(CallArgListLength(pn) == 4); - return ExtractSimdValue(m, pn); + pn = CallArgList(pn); + double d = ExtractNumericNonFloatValue(&pn); + return AsmJSNumLit::Create(AsmJSNumLit::Float, DoubleValue(d)); } - double d = ExtractNumericNonFloatValue(pn, &pn); + double d = ExtractNumericNonFloatValue(&pn); // The asm.js spec syntactically distinguishes any literal containing a // decimal point or the literal -0 as having double type. @@ -2088,8 +1784,6 @@ IsLiteralInt(ModuleCompiler &m, ParseNode *pn, uint32_t *u32) case AsmJSNumLit::Double: case AsmJSNumLit::Float: case AsmJSNumLit::OutOfRangeInt: - case AsmJSNumLit::Int32x4: - case AsmJSNumLit::Float32x4: return false; } @@ -2260,14 +1954,7 @@ class FunctionCompiler unsigned firstLocalSlot = argTypes.length(); for (unsigned i = 0; i < varInitializers_.length(); i++) { AsmJSNumLit &lit = varInitializers_[i]; - MIRType type = Type::Of(lit).toMIRType(); - - MInstruction *ins; - if (lit.isSimd()) - ins = MSimdConstant::New(alloc(), lit.simdValue(), type); - else - ins = MConstant::NewAsmJS(alloc(), lit.scalarValue(), type); - + MConstant *ins = MConstant::NewAsmJS(alloc(), lit.value(), Type::Of(lit).toMIRType()); curBlock_->add(ins); curBlock_->initSlot(info().localSlot(firstLocalSlot + i), ins); if (!mirGen_->ensureBallast()) @@ -2318,23 +2005,13 @@ class FunctionCompiler return m_.lookupGlobal(name); } - bool supportsSimd() const { - return m_.supportsSimd(); - } - /***************************** Code generation (after local scope setup) */ MDefinition *constant(const AsmJSNumLit &lit) { if (inDeadCode()) return nullptr; - - MInstruction *constant; - if (lit.isSimd()) - constant = MSimdConstant::New(alloc(), lit.simdValue(), Type::Of(lit).toMIRType()); - else - constant = MConstant::NewAsmJS(alloc(), lit.scalarValue(), Type::Of(lit).toMIRType()); - + MConstant *constant = MConstant::NewAsmJS(alloc(), lit.value(), Type::Of(lit).toMIRType()); curBlock_->add(constant); return constant; } @@ -2388,19 +2065,6 @@ class FunctionCompiler return ins; } - MDefinition *binarySimd(MDefinition *lhs, MDefinition *rhs, MSimdBinaryArith::Operation op, - MIRType type) - { - if (inDeadCode()) - return nullptr; - - JS_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); - JS_ASSERT(lhs->type() == type); - MSimdBinaryArith *ins = MSimdBinaryArith::NewAsmJS(alloc(), lhs, rhs, op, type); - curBlock_->add(ins); - return ins; - } - MDefinition *minMax(MDefinition *lhs, MDefinition *rhs, MIRType type, bool isMax) { if (inDeadCode()) return nullptr; @@ -2498,14 +2162,9 @@ class FunctionCompiler if (inDeadCode()) return nullptr; + uint32_t index = global.varOrConstIndex(); + unsigned globalDataOffset = module().globalVarIndexToGlobalDataOffset(index); MIRType type = global.varOrConstType().toMIRType(); - - unsigned globalDataOffset; - if (IsSimdType(type)) - globalDataOffset = module().globalSimdVarIndexToGlobalDataOffset(global.varOrConstIndex()); - else - globalDataOffset = module().globalScalarVarIndexToGlobalDataOffset(global.varOrConstIndex()); - MAsmJSLoadGlobalVar *load = MAsmJSLoadGlobalVar::New(alloc(), type, globalDataOffset, global.isConst()); curBlock_->add(load); @@ -2517,13 +2176,7 @@ class FunctionCompiler if (inDeadCode()) return; JS_ASSERT(!global.isConst()); - - unsigned globalDataOffset; - if (IsSimdType(v->type())) - globalDataOffset = module().globalSimdVarIndexToGlobalDataOffset(global.varOrConstIndex()); - else - globalDataOffset = module().globalScalarVarIndexToGlobalDataOffset(global.varOrConstIndex()); - + unsigned globalDataOffset = module().globalVarIndexToGlobalDataOffset(global.varOrConstIndex()); curBlock_->add(MAsmJSStoreGlobalVar::New(alloc(), globalDataOffset, v)); } @@ -2541,31 +2194,6 @@ class FunctionCompiler curBlock_->add(MAsmJSInterruptCheck::New(alloc(), &m().syncInterruptLabel(), callDesc)); } - MDefinition *extractSimdElement(SimdLane lane, MDefinition *base, MIRType type) - { - if (inDeadCode()) - return nullptr; - - JS_ASSERT(IsSimdType(base->type())); - JS_ASSERT(!IsSimdType(type)); - MSimdExtractElement *ins = MSimdExtractElement::NewAsmJS(alloc(), base, type, lane); - curBlock_->add(ins); - return ins; - } - - template - MDefinition *constructSimd(MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w, - MIRType type) - { - if (inDeadCode()) - return nullptr; - - JS_ASSERT(IsSimdType(type)); - T *ins = T::New(alloc(), type, x, y, z, w); - curBlock_->add(ins); - return ins; - } - /***************************************************************** Calls */ // The IonMonkey backend maintains a single stack offset (from the stack @@ -2655,7 +2283,7 @@ class FunctionCompiler uint32_t parentStackBytes = call->abi_.stackBytesConsumedSoFar(); uint32_t newStackBytes; if (call->childClobbers_) { - call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, AsmJSStackAlignment); + call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, StackAlignment); for (unsigned i = 0; i < call->stackArgs_.length(); i++) call->stackArgs_[i]->incrementOffset(call->spIncrement_); newStackBytes = Max(call->prevMaxStackBytes_, @@ -3336,13 +2964,15 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c return true; } case PNK_CALL: { - if (IsCoercionCall(m, coercionNode, coercion, coercedExpr)) - return true; + *coercion = AsmJS_FRound; + if (!IsFloatCoercion(m, coercionNode, coercedExpr)) + return m.fail(coercionNode, "call must be to fround coercion"); + return true; } default:; } - return m.fail(coercionNode, "must be of the form +x, fround(x), simdType(x) or x|0"); + return m.fail(coercionNode, "must be of the form +x, fround(x) or x|0"); } static bool @@ -3425,82 +3055,6 @@ CheckNewArrayView(ModuleCompiler &m, PropertyName *varName, ParseNode *newExpr) return m.addArrayView(varName, type, field); } -static bool -IsSimdTypeName(ModuleCompiler &m, PropertyName *name, AsmJSSimdType *type) -{ - if (name == m.cx()->names().int32x4) { - *type = AsmJSSimdType_int32x4; - return true; - } - if (name == m.cx()->names().float32x4) { - *type = AsmJSSimdType_float32x4; - return true; - } - return false; -} - -static bool -IsSimdValidOperationType(AsmJSSimdType type, AsmJSSimdOperation op) -{ - switch (op) { - case AsmJSSimdOperation_add: - case AsmJSSimdOperation_sub: - return true; - case AsmJSSimdOperation_mul: - case AsmJSSimdOperation_div: - return type == AsmJSSimdType_float32x4; - } - return false; -} - -static bool -CheckGlobalMathImport(ModuleCompiler &m, ParseNode *initNode, PropertyName *varName, - PropertyName *field) -{ - // Math builtin, with the form glob.Math.[[builtin]] - ModuleCompiler::MathBuiltin mathBuiltin; - if (!m.lookupStandardLibraryMathName(field, &mathBuiltin)) - return m.failName(initNode, "'%s' is not a standard Math builtin", field); - - switch (mathBuiltin.kind) { - case ModuleCompiler::MathBuiltin::Function: - return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field); - case ModuleCompiler::MathBuiltin::Constant: - return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field); - default: - break; - } - MOZ_CRASH("unexpected or uninitialized math builtin type"); -} - -static bool -CheckGlobalSimdImport(ModuleCompiler &m, ParseNode *initNode, PropertyName *varName, - PropertyName *field) -{ - if (!m.supportsSimd()) - return m.fail(initNode, "SIMD is not supported on this platform"); - - // SIMD constructor, with the form glob.SIMD.[[type]] - AsmJSSimdType simdType; - if (!IsSimdTypeName(m, field, &simdType)) - return m.failName(initNode, "'%s' is not a standard SIMD type", field); - return m.addSimdCtor(varName, simdType, field); -} - -static bool -CheckGlobalSimdOperationImport(ModuleCompiler &m, const ModuleCompiler::Global *global, - ParseNode *initNode, PropertyName *varName, PropertyName *ctorVarName, - PropertyName *opName) -{ - AsmJSSimdType simdType = global->simdCtorType(); - AsmJSSimdOperation simdOp; - if (!m.lookupStandardSimdOpName(opName, &simdOp)) - return m.failName(initNode, "'%s' is not a standard SIMD operation", opName); - if (!IsSimdValidOperationType(simdType, simdOp)) - return m.failName(initNode, "'%s' is not an operation supported by the SIMD type", opName); - return m.addSimdOperation(varName, simdType, simdOp, ctorVarName, opName); -} - static bool CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode) { @@ -3509,22 +3063,26 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo if (base->isKind(PNK_DOT)) { ParseNode *global = DotBase(base); - PropertyName *mathOrSimd = DotMember(base); + PropertyName *math = DotMember(base); + if (!IsUseOfName(global, m.module().globalArgumentName()) || math != m.cx()->names().Math) + return m.fail(base, "expecting global.Math"); - if (!IsUseOfName(global, m.module().globalArgumentName())) - return m.failf(base, "expecting %s.*", m.module().globalArgumentName()); + ModuleCompiler::MathBuiltin mathBuiltin; + if (!m.lookupStandardLibraryMathName(field, &mathBuiltin)) + return m.failName(initNode, "'%s' is not a standard Math builtin", field); - if (mathOrSimd == m.cx()->names().Math) - return CheckGlobalMathImport(m, initNode, varName, field); - if (mathOrSimd == m.cx()->names().SIMD) - return CheckGlobalSimdImport(m, initNode, varName, field); - return m.failf(base, "expecting %s.{Math|SIMD}", m.module().globalArgumentName()); + switch (mathBuiltin.kind) { + case ModuleCompiler::MathBuiltin::Function: + return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field); + case ModuleCompiler::MathBuiltin::Constant: + return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field); + default: + break; + } + MOZ_CRASH("unexpected or uninitialized math builtin type"); } - if (!base->isKind(PNK_NAME)) - return m.fail(base, "expected name of variable or parameter"); - - if (base->name() == m.module().globalArgumentName()) { + if (IsUseOfName(base, m.module().globalArgumentName())) { if (field == m.cx()->names().NaN) return m.addGlobalConstant(varName, GenericNaN(), field); if (field == m.cx()->names().Infinity) @@ -3532,17 +3090,10 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo return m.failName(initNode, "'%s' is not a standard global constant", field); } - if (base->name() == m.module().importArgumentName()) + if (IsUseOfName(base, m.module().importArgumentName())) return m.addFFI(varName, field); - const ModuleCompiler::Global *global = m.lookupGlobal(base->name()); - if (!global) - return m.failName(initNode, "%s not found in module global scope", base->name()); - - if (!global->isSimdCtor()) - return m.failName(base, "expecting SIMD constructor name, got %s", field); - - return CheckGlobalSimdOperationImport(m, global, initNode, varName, base->name(), field); + return m.fail(initNode, "expecting c.y where c is either the global or foreign parameter"); } static bool @@ -3674,12 +3225,6 @@ CheckFinalReturn(FunctionCompiler &f, ParseNode *stmt, RetType *retType) case AsmJSNumLit::Float: *retType = RetType::Float; break; - case AsmJSNumLit::Int32x4: - *retType = RetType::Int32x4; - break; - case AsmJSNumLit::Float32x4: - *retType = RetType::Float32x4; - break; } return true; } @@ -3795,8 +3340,6 @@ CheckVarRef(FunctionCompiler &f, ParseNode *varRef, MDefinition **def, Type *typ case ModuleCompiler::Global::MathBuiltinFunction: case ModuleCompiler::Global::FuncPtrTable: case ModuleCompiler::Global::ArrayView: - case ModuleCompiler::Global::SimdCtor: - case ModuleCompiler::Global::SimdOperation: return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name); } return true; @@ -3819,7 +3362,7 @@ IsLiteralOrConstInt(FunctionCompiler &f, ParseNode *pn, uint32_t *u32) if (!global || global->which() != ModuleCompiler::Global::ConstantLiteral) return false; - const Value &v = global->constLiteralValue().scalarValue(); + const Value &v = global->constLiteralValue().value(); if (!v.isInt32()) return false; @@ -3955,40 +3498,6 @@ CheckLoadArray(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *ty return true; } -static bool -CheckDotAccess(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type) -{ - JS_ASSERT(elem->isKind(PNK_DOT)); - - ParseNode *base = DotBase(elem); - MDefinition *baseDef; - Type baseType; - if (!CheckExpr(f, base, &baseDef, &baseType)) - return false; - if (!baseType.isSimd()) - return f.failf(base, "expected SIMD type, got %s", baseType.toChars()); - - ModuleCompiler &m = f.m(); - PropertyName *field = DotMember(elem); - - SimdLane lane; - JSAtomState &names = m.cx()->names(); - if (field == names.x) - lane = LaneX; - else if (field == names.y) - lane = LaneY; - else if (field == names.z) - lane = LaneZ; - else if (field == names.w) - lane = LaneW; - else - return f.fail(base, "dot access field must be a lane name (x, y, z, w)"); - - *type = baseType.simdToScalarType(); - *def = f.extractSimdElement(lane, baseDef, type->toMIRType()); - return true; -} - static bool CheckStoreArray(FunctionCompiler &f, ParseNode *lhs, ParseNode *rhs, MDefinition **def, Type *type) { @@ -4427,8 +3936,6 @@ CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetTyp if (retType == RetType::Float) return f.fail(callNode, "FFI calls can't return float"); - if (retType.toType().isSimd()) - return f.fail(callNode, "FFI calls can't return SIMD values"); FunctionCompiler::Call call(f, callNode, retType); if (!CheckCallArgs(f, callNode, CheckIsExternType, &call)) @@ -4445,82 +3952,37 @@ CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetTyp return true; } -static bool -CheckFloatCoercionArg(FunctionCompiler &f, ParseNode *inputNode, Type inputType, - MDefinition *inputDef, MDefinition **def) -{ - if (inputType.isMaybeDouble() || inputType.isSigned()) { - *def = f.unary(inputDef); - return true; - } - if (inputType.isUnsigned()) { - *def = f.unary(inputDef); - return true; - } - if (inputType.isFloatish()) { - *def = inputDef; - return true; - } - - return f.failf(inputNode, "%s is not a subtype of signed, unsigned, double? or floatish", - inputType.toChars()); -} - static bool CheckCoercedCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type); -static bool -CheckCoercionArg(FunctionCompiler &f, ParseNode *arg, AsmJSCoercion expected, MDefinition **def, - Type *type) -{ - RetType retType(expected); - if (arg->isKind(PNK_CALL)) - return CheckCoercedCall(f, arg, retType, def, type); - - MDefinition *argDef; - Type argType; - if (!CheckExpr(f, arg, &argDef, &argType)) - return false; - - switch (expected) { - case AsmJS_FRound: - if (!CheckFloatCoercionArg(f, arg, argType, argDef, def)) - return false; - break; - case AsmJS_ToInt32x4: - if (!argType.isInt32x4()) - return f.fail(arg, "argument to SIMD int32x4 coercion isn't int32x4"); - *def = argDef; - break; - case AsmJS_ToFloat32x4: - if (!argType.isFloat32x4()) - return f.fail(arg, "argument to SIMD float32x4 coercion isn't float32x4"); - *def = argDef; - break; - case AsmJS_ToInt32: - case AsmJS_ToNumber: - MOZ_CRASH("not call coercions"); - } - - *type = retType.toType(); - return true; -} - static bool CheckMathFRound(FunctionCompiler &f, ParseNode *callNode, MDefinition **def, MathRetType *type) { - if (CallArgListLength(callNode) != 1) - return f.fail(callNode, "Math.fround must be passed 1 argument"); + ParseNode *argNode = nullptr; + if (!IsFloatCoercion(f.m(), callNode, &argNode)) + return f.fail(callNode, "invalid call to fround"); + + // Make sure to do this before calling CheckCoercedCall + *type = MathRetType::Float; + + Type _; + if (argNode->isKind(PNK_CALL)) + return CheckCoercedCall(f, argNode, RetType::Float, def, &_); - ParseNode *argNode = CallArgList(callNode); MDefinition *argDef; Type argType; - if (!CheckCoercionArg(f, argNode, AsmJS_FRound, &argDef, &argType)) + if (!CheckExpr(f, argNode, &argDef, &argType)) return false; - JS_ASSERT(argType == Type::Float); - *def = argDef; - *type = MathRetType::Float; + if (argType.isMaybeDouble() || argType.isSigned()) + *def = f.unary(argDef); + else if (argType.isUnsigned()) + *def = f.unary(argDef); + else if (argType.isFloatish()) + *def = argDef; + else + return f.failf(argNode, "%s is not a subtype of signed, unsigned, double? or floatish", argType.toChars()); + return true; } @@ -4603,120 +4065,19 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltinF return true; } -static bool -CheckBinarySimd(FunctionCompiler &f, ParseNode *call, AsmJSSimdType simdType, - MSimdBinaryArith::Operation op, MDefinition **def, Type *type) -{ - unsigned numArgs = CallArgListLength(call); - if (numArgs != 2) - return f.failf(call, "expected 2 arguments to binary arithmetic SIMD operation, got %u", numArgs); - - ParseNode *lhs = CallArgList(call); - ParseNode *rhs = NextNode(lhs); - - MDefinition *lhsDef, *rhsDef; - Type lhsType, rhsType; - if (!CheckExpr(f, lhs, &lhsDef, &lhsType)) - return false; - if (!CheckExpr(f, rhs, &rhsDef, &rhsType)) - return false; - - Type retType = simdType; - JS_ASSERT_IF(retType.isInt32x4(), op != MSimdBinaryArith::Mul && op != MSimdBinaryArith::Div); - if (lhsType != retType || rhsType != retType) - return f.failf(lhs, "arguments to SIMD binary op should both be %s", retType.toChars()); - - *type = retType; - *def = f.binarySimd(lhsDef, rhsDef, op, retType.toMIRType()); - return true; -} - -static bool -CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, - MDefinition **def, Type *type) -{ - JS_ASSERT(global->isSimdOperation()); - switch (global->simdOperation()) { - case AsmJSSimdOperation_add: - return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Add, def, type); - case AsmJSSimdOperation_sub: - return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Sub, def, type); - case AsmJSSimdOperation_mul: - return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Mul, def, type); - case AsmJSSimdOperation_div: - return CheckBinarySimd(f, call, global->simdOperationType(), MSimdBinaryArith::Div, def, type); - } - MOZ_CRASH("unexpected simd operation in CheckSimdOperationCall"); -} - -static bool -CheckSimdCtorCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, - MDefinition **def, Type *type) -{ - JS_ASSERT(call->isKind(PNK_CALL)); - - AsmJSCoercion coercion; - ParseNode *argNode; - if (IsCoercionCall(f.m(), call, &coercion, &argNode)) - return CheckCoercionArg(f, argNode, coercion, def, type); - - AsmJSSimdType simdType = global->simdCtorType(); - unsigned numArgs = CallArgListLength(call); - unsigned length = SimdTypeToLength(simdType); - if (numArgs != length) - return f.failName(call, "invalid number of arguments in call to '%s'", CallCallee(call)->name()); - - Vector defs; - if (!defs.resize(length)) - return false; - - argNode = CallArgList(call); - size_t i = 0; - for (; argNode; argNode = NextNode(argNode), ++i) - { - JS_ASSERT(i < length); - - Type argType; - if (!CheckExpr(f, argNode, &defs[i], &argType)) - return false; - - switch (simdType) { - case AsmJSSimdType_int32x4: - if (!argType.isIntish()) - return f.failf(argNode, "argument %d of Int32x4 ctor isn't a subtype of intish", i); - break; - case AsmJSSimdType_float32x4: - if (!CheckFloatCoercionArg(f, argNode, argType, defs[i], &defs[i])) - return false; - break; - } - } - JS_ASSERT(i == length); - - *type = simdType; - *def = f.constructSimd(defs[0], defs[1], defs[2], defs[3], type->toMIRType()); - return true; -} - static bool CheckUncoercedCall(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) { JS_ASSERT(expr->isKind(PNK_CALL)); const ModuleCompiler::Global *global; - if (IsCallToGlobal(f.m(), expr, &global)) { - if (global->isMathFunction()) { - MathRetType mathRetType; - if (!CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), def, &mathRetType)) - return false; - *type = mathRetType.toType(); - return true; - } - - if (global->isSimdCtor()) - return CheckSimdCtorCall(f, expr, global, def, type); - if (global->isSimdOperation()) - return CheckSimdOperationCall(f, expr, global, def, type); + if (IsCallToGlobal(f.m(), expr, &global) && global->isMathFunction()) + { + MathRetType mathRetType; + if (!CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), def, &mathRetType)) + return false; + *type = mathRetType.toType(); + return true; } return f.fail(expr, "all function calls must either be calls to standard lib math functions, " @@ -4734,10 +4095,6 @@ CheckCoercedMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathB return false; switch (retType.which()) { - case RetType::Int32x4: - case RetType::Float32x4: - return f.failf(callNode, "%s is not a vector type", actualRetType.toType().toChars()); - case RetType::Double: switch (actualRetType.which()) { case MathRetType::Double: @@ -4798,46 +4155,6 @@ CheckCoercedMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathB return true; } -static bool -CheckCoercedSimdCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, - RetType retType, MDefinition **def, Type *type) -{ - if (global->isSimdCtor()) { - if (!CheckSimdCtorCall(f, call, global, def, type)) - return false; - } else { - JS_ASSERT(global->isSimdOperation()); - if (!CheckSimdOperationCall(f, call, global, def, type)) - return false; - } - - JS_ASSERT(type->isSimd()); - switch (retType.which()) { - case RetType::Signed: - case RetType::Double: - case RetType::Float: - return f.failf(call, "SIMD call returns %s, used as scalar", type->toChars()); - - case RetType::Int32x4: - if (!type->isInt32x4()) - return f.failf(call, "SIMD call returns %s, used as int32x4", type->toChars()); - break; - - case RetType::Float32x4: - if (!type->isFloat32x4()) - return f.failf(call, "SIMD call returns %s, used as float32x4", type->toChars()); - break; - - case RetType::Void: - *def = nullptr; - break; - } - - JS_ASSERT_IF(retType == RetType::Void || f.inDeadCode(), !*def); - JS_ASSERT_IF(retType != RetType::Void && !f.inDeadCode(), !!*def); - return true; -} - static bool CheckCoercedCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type) { @@ -4865,9 +4182,6 @@ CheckCoercedCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinit case ModuleCompiler::Global::FuncPtrTable: case ModuleCompiler::Global::ArrayView: return f.failName(callee, "'%s' is not callable function", callee->name()); - case ModuleCompiler::Global::SimdCtor: - case ModuleCompiler::Global::SimdOperation: - return CheckCoercedSimdCall(f, call, global, retType, def, type); case ModuleCompiler::Global::Function: break; } @@ -5100,8 +4414,6 @@ IsValidIntMultiplyConstant(ModuleCompiler &m, ParseNode *expr) case AsmJSNumLit::Double: case AsmJSNumLit::Float: case AsmJSNumLit::OutOfRangeInt: - case AsmJSNumLit::Int32x4: - case AsmJSNumLit::Float32x4: return false; } @@ -5388,7 +4700,6 @@ CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) switch (expr->getKind()) { case PNK_NAME: return CheckVarRef(f, expr, def, type); case PNK_ELEM: return CheckLoadArray(f, expr, def, type); - case PNK_DOT: return CheckDotAccess(f, expr, def, type); case PNK_ASSIGN: return CheckAssign(f, expr, def, type); case PNK_POS: return CheckPos(f, expr, def, type); case PNK_NOT: return CheckNot(f, expr, def, type); @@ -5798,8 +5109,6 @@ CheckCaseExpr(FunctionCompiler &f, ParseNode *caseExpr, int32_t *value) return f.fail(caseExpr, "switch case expression out of integer range"); case AsmJSNumLit::Double: case AsmJSNumLit::Float: - case AsmJSNumLit::Int32x4: - case AsmJSNumLit::Float32x4: return f.fail(caseExpr, "switch case expression must be an integer literal"); } @@ -5958,10 +5267,6 @@ CheckReturn(FunctionCompiler &f, ParseNode *returnStmt) retType = RetType::Double; else if (type.isFloat()) retType = RetType::Float; - else if (type.isInt32x4()) - retType = RetType::Int32x4; - else if (type.isFloat32x4()) - retType = RetType::Float32x4; else if (type.isVoid()) retType = RetType::Void; else @@ -6631,16 +5936,16 @@ CheckModuleReturn(ModuleCompiler &m) } static void -AssertStackAlignment(MacroAssembler &masm, uint32_t alignment) +AssertStackAlignment(MacroAssembler &masm) { - JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % alignment == 0); - masm.assertStackAlignment(alignment); + JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % StackAlignment == 0); + masm.assertStackAlignment(); } static unsigned -StackDecrementForCall(MacroAssembler &masm, uint32_t alignment, unsigned bytesToPush) +StackDecrementForCall(MacroAssembler &masm, unsigned bytesToPush) { - return StackDecrementForCall(alignment, sizeof(AsmJSFrame) + masm.framePushed(), bytesToPush); + return StackDecrementForCall(sizeof(AsmJSFrame) + masm.framePushed(), bytesToPush); } template @@ -6655,10 +5960,9 @@ StackArgBytes(const VectorT &argTypes) template static unsigned -StackDecrementForCall(MacroAssembler &masm, uint32_t alignment, const VectorT &argTypes, - unsigned extraBytes = 0) +StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0) { - return StackDecrementForCall(masm, alignment, StackArgBytes(argTypes) + extraBytes); + return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes); } #if defined(JS_CODEGEN_ARM) @@ -6673,8 +5977,6 @@ static const RegisterSet NonVolatileRegs = RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask), FloatRegisterSet(FloatRegisters::NonVolatileMask)); #endif -static const FloatRegisterSet NonVolatileSimdRegs = SupportsSimd ? NonVolatileRegs.fpus() - : FloatRegisterSet(); #if defined(JS_CODEGEN_MIPS) // Mips is using one more double slot due to stack alignment for double values. @@ -6683,13 +5985,9 @@ static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * siz NonVolatileRegs.fpus().getPushSizeInBytes() + sizeof(double); #else -static const unsigned FramePushedAfterSave = - SupportsSimd ? NonVolatileRegs.gprs().size() * sizeof(intptr_t) + - NonVolatileRegs.fpus().size() * Simd128DataSize - : NonVolatileRegs.gprs().size() * sizeof(intptr_t) + - NonVolatileRegs.fpus().getPushSizeInBytes(); +static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) + + NonVolatileRegs.fpus().getPushSizeInBytes(); #endif -static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void*); static bool GenerateEntry(ModuleCompiler &m, unsigned exportIndex) @@ -6700,19 +5998,18 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) masm.align(CodeAlignment); masm.bind(&begin); - // Save the return address if it wasn't already saved by the call insn. #if defined(JS_CODEGEN_ARM) masm.push(lr); #elif defined(JS_CODEGEN_MIPS) masm.push(ra); -#elif defined(JS_CODEGEN_X86) - static const unsigned EntryFrameSize = sizeof(void*); #endif - - // Save all caller non-volatile registers before we clobber them here and in - // the asm.js callee (which does not preserve non-volatile registers). + masm.subPtr(Imm32(AsmJSFrameBytesAfterReturnAddress), StackPointer); masm.setFramePushed(0); - masm.PushRegsInMask(NonVolatileRegs, NonVolatileSimdRegs); + + // In constrast to the system ABI, the Ion convention is that all registers + // are clobbered by calls. Thus, we must save the caller's non-volatile + // registers. + masm.PushRegsInMask(NonVolatileRegs); JS_ASSERT(masm.framePushed() == FramePushedAfterSave); // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative @@ -6729,107 +6026,70 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) masm.loadPtr(Address(IntArgReg1, AsmJSModule::heapGlobalDataOffset()), HeapReg); #endif - // Put the 'argv' argument into a non-argument/return register so that we - // can use 'argv' while we fill in the arguments for the asm.js callee. - // Also, save 'argv' on the stack so that we can recover it after the call. - // Use a second non-argument/return register as temporary scratch. + // Remember the stack pointer in the current AsmJSActivation. This will be + // used by error exit paths to set the stack pointer back to what it was + // right after the (C++) caller's non-volatile registers were saved so that + // they can be restored. + Register activation = ABIArgGenerator::NonArgReturnReg0; + masm.loadAsmJSActivation(activation); + masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP())); + + // Get 'argv' into a non-arg register and save it on the stack. Register argv = ABIArgGenerator::NonArgReturnReg0; Register scratch = ABIArgGenerator::NonArgReturnReg1; #if defined(JS_CODEGEN_X86) - masm.loadPtr(Address(StackPointer, EntryFrameSize + masm.framePushed()), argv); + masm.loadPtr(Address(StackPointer, sizeof(AsmJSFrame) + masm.framePushed()), argv); #else masm.movePtr(IntArgReg0, argv); #endif masm.Push(argv); - // Save the stack pointer to the saved non-volatile registers. We will use - // this on two paths: normal return and exceptional return. Since - // loadAsmJSActivation uses GlobalReg, we must do this after loading - // GlobalReg. - JS_ASSERT(masm.framePushed() == FramePushedForEntrySP); - masm.loadAsmJSActivation(scratch); - masm.storePtr(StackPointer, Address(scratch, AsmJSActivation::offsetOfEntrySP())); - - // Dynamically align the stack since ABIStackAlignment is not necessarily - // AsmJSStackAlignment. We'll use entrySP to recover the original stack - // pointer on return. - masm.andPtr(Imm32(~(AsmJSStackAlignment - 1)), StackPointer); - // Bump the stack for the call. PropertyName *funcName = m.module().exportedFunction(exportIndex).name(); const ModuleCompiler::Func &func = *m.lookupFunction(funcName); - masm.reserveStack(AlignBytes(StackArgBytes(func.sig().args()), AsmJSStackAlignment)); + unsigned stackDec = StackDecrementForCall(masm, func.sig().args()); + masm.reserveStack(stackDec); // Copy parameters out of argv and into the registers/stack-slots specified by // the system ABI. for (ABIArgTypeIter iter(func.sig().args()); !iter.done(); iter++) { - unsigned argOffset = iter.index() * sizeof(AsmJSModule::EntryArg); + unsigned argOffset = iter.index() * sizeof(uint64_t); Address src(argv, argOffset); - MIRType type = iter.mirType(); switch (iter->kind()) { case ABIArg::GPR: masm.load32(src, iter->gpr()); break; case ABIArg::FPU: - switch (type) { - case MIRType_Int32x4: - masm.loadUnalignedInt32x4(src, iter->fpu()); - break; - case MIRType_Float32x4: - masm.loadUnalignedFloat32x4(src, iter->fpu()); - break; - case MIRType_Double: + if (iter.mirType() == MIRType_Double) { masm.loadDouble(src, iter->fpu()); - break; - case MIRType_Float32: + } else { + JS_ASSERT(iter.mirType() == MIRType_Float32); masm.loadFloat32(src, iter->fpu()); - break; - default: - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected FPU type"); - break; } break; case ABIArg::Stack: - switch (type) { - case MIRType_Int32: + if (iter.mirType() == MIRType_Int32) { masm.load32(src, scratch); masm.storePtr(scratch, Address(StackPointer, iter->offsetFromArgBase())); - break; - case MIRType_Double: + } else if (iter.mirType() == MIRType_Double) { masm.loadDouble(src, ScratchDoubleReg); masm.storeDouble(ScratchDoubleReg, Address(StackPointer, iter->offsetFromArgBase())); - break; - case MIRType_Float32: + } else { + JS_ASSERT(iter.mirType() == MIRType_Float32); masm.loadFloat32(src, ScratchFloat32Reg); masm.storeFloat32(ScratchFloat32Reg, Address(StackPointer, iter->offsetFromArgBase())); - break; - case MIRType_Int32x4: - masm.loadUnalignedInt32x4(src, ScratchSimdReg); - masm.storeAlignedInt32x4(ScratchSimdReg, - Address(StackPointer, iter->offsetFromArgBase())); - break; - case MIRType_Float32x4: - masm.loadUnalignedFloat32x4(src, ScratchSimdReg); - masm.storeAlignedFloat32x4(ScratchSimdReg, - Address(StackPointer, iter->offsetFromArgBase())); - break; - default: - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected stack arg type"); } break; } } // Call into the real function. - masm.assertStackAlignment(AsmJSStackAlignment); + AssertStackAlignment(masm); masm.call(CallSiteDesc(CallSiteDesc::Relative), &func.entry()); - // Recover the stack pointer value before dynamic alignment. - masm.loadAsmJSActivation(scratch); - masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfEntrySP()), StackPointer); - masm.setFramePushed(FramePushedForEntrySP); - - // Recover the 'argv' pointer which was saved before aligning the stack. + // Pop the stack and recover the original 'argv' argument passed to the + // trampoline (which was pushed on the stack). + masm.freeStack(stackDec); masm.Pop(argv); // Store the return value in argv[0] @@ -6846,21 +6106,14 @@ GenerateEntry(ModuleCompiler &m, unsigned exportIndex) masm.canonicalizeDouble(ReturnDoubleReg); masm.storeDouble(ReturnDoubleReg, Address(argv, 0)); break; - case RetType::Int32x4: - // We don't have control on argv alignment, do an unaligned access. - masm.storeUnalignedInt32x4(ReturnSimdReg, Address(argv, 0)); - break; - case RetType::Float32x4: - // We don't have control on argv alignment, do an unaligned access. - masm.storeUnalignedFloat32x4(ReturnSimdReg, Address(argv, 0)); - break; } // Restore clobbered non-volatile registers of the caller. - masm.PopRegsInMask(NonVolatileRegs, NonVolatileSimdRegs); + masm.PopRegsInMask(NonVolatileRegs); JS_ASSERT(masm.framePushed() == 0); masm.move32(Imm32(true), ReturnReg); + masm.addPtr(Imm32(AsmJSFrameBytesAfterReturnAddress), StackPointer); masm.ret(); return m.finishGeneratingEntry(exportIndex, &begin) && !masm.oom(); @@ -6924,7 +6177,7 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e // padding between argv and retaddr ensures that sp is aligned. unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes), sizeof(double)); unsigned argvBytes = Max(1, exit.sig().args().length()) * sizeof(Value); - unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, offsetToArgv + argvBytes); + unsigned framePushed = StackDecrementForCall(masm, offsetToArgv + argvBytes); Label begin; GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::SlowFFI, &begin); @@ -6964,7 +6217,7 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e JS_ASSERT(i.done()); // Make the call, test whether it succeeded, and extract the return value. - AssertStackAlignment(masm, ABIStackAlignment); + AssertStackAlignment(masm); switch (exit.sig().retType().which()) { case RetType::Void: masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore)); @@ -6982,9 +6235,6 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e break; case RetType::Float: MOZ_CRASH("Float32 shouldn't be returned from a FFI"); - case RetType::Int32x4: - case RetType::Float32x4: - MOZ_CRASH("SIMD types shouldn't be returned from a FFI"); } Label profilingReturn; @@ -7029,7 +6279,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit unsigned offsetToIonArgs = MaybeRetAddr; unsigned ionArgBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value); unsigned totalIonBytes = offsetToIonArgs + ionArgBytes + savedRegBytes; - unsigned ionFrameSize = StackDecrementForCall(masm, AsmJSStackAlignment, totalIonBytes); + unsigned ionFrameSize = StackDecrementForCall(masm, totalIonBytes); // Coercion calls use the following stack layout (sp grows to the left): // | stack args | padding | Value argv[1] | ... @@ -7038,7 +6288,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit coerceArgTypes.infallibleAppend(MIRType_Pointer); // argv unsigned offsetToCoerceArgv = AlignBytes(StackArgBytes(coerceArgTypes), sizeof(double)); unsigned totalCoerceBytes = offsetToCoerceArgv + sizeof(Value) + savedRegBytes; - unsigned coerceFrameSize = StackDecrementForCall(masm, AsmJSStackAlignment, totalCoerceBytes); + unsigned coerceFrameSize = StackDecrementForCall(masm, totalCoerceBytes); unsigned framePushed = Max(ionFrameSize, coerceFrameSize); @@ -7139,9 +6389,9 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit } // 2. Call - AssertStackAlignment(masm, AsmJSStackAlignment); + AssertStackAlignment(masm); masm.callIonFromAsmJS(callee); - AssertStackAlignment(masm, AsmJSStackAlignment); + AssertStackAlignment(masm); { // Disable Activation. @@ -7196,9 +6446,6 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit break; case RetType::Float: MOZ_CRASH("Float shouldn't be returned from a FFI"); - case RetType::Int32x4: - case RetType::Float32x4: - MOZ_CRASH("SIMD types shouldn't be returned from a FFI"); } Label done; @@ -7227,7 +6474,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit JS_ASSERT(i.done()); // Call coercion function - AssertStackAlignment(masm, ABIStackAlignment); + AssertStackAlignment(masm); switch (exit.sig().retType().which()) { case RetType::Signed: masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32)); @@ -7322,7 +6569,7 @@ GenerateBuiltinThunk(ModuleCompiler &m, AsmJSExit::BuiltinKind builtin) MOZ_CRASH("Bad builtin"); } - uint32_t framePushed = StackDecrementForCall(masm, ABIStackAlignment, argTypes); + uint32_t framePushed = StackDecrementForCall(masm, argTypes); Label begin; GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::Builtin(builtin), &begin); @@ -7347,7 +6594,7 @@ GenerateBuiltinThunk(ModuleCompiler &m, AsmJSExit::BuiltinKind builtin) #endif } - AssertStackAlignment(masm, ABIStackAlignment); + AssertStackAlignment(masm); masm.call(BuiltinToImmKind(builtin)); Label profilingReturn; @@ -7390,7 +6637,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.push(Imm32(0)); // space for resumePC masm.pushFlags(); // after this we are safe to use sub masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below - masm.PushRegsInMask(AllRegsExceptSP, AllRegsExceptSP.fpus()); // save all GP/FP registers (except SP) + masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP) Register scratch = ABIArgGenerator::NonArgReturnReg0; @@ -7402,11 +6649,11 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // We know that StackPointer is word-aligned, but not necessarily // stack-aligned, so we need to align it dynamically. masm.mov(StackPointer, ABIArgGenerator::NonVolatileReg); - masm.andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); + masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer); if (ShadowStackSpace) masm.subPtr(Imm32(ShadowStackSpace), StackPointer); - masm.assertStackAlignment(ABIStackAlignment); + masm.assertStackAlignment(); masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt)); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -7415,7 +6662,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.mov(ABIArgGenerator::NonVolatileReg, StackPointer); // Restore the machine state to before the interrupt. - masm.PopRegsInMask(AllRegsExceptSP, AllRegsExceptSP.fpus()); // restore all GP/FP registers (except SP) + masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP) masm.popFlags(); // after this, nothing that sets conditions masm.ret(); // pop resumePC into PC #elif defined(JS_CODEGEN_MIPS) @@ -7423,16 +6670,13 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.subPtr(Imm32(sizeof(intptr_t)), StackPointer); // set to zero so we can use masm.framePushed() below. masm.setFramePushed(0); - // When this platform supports SIMD extensions, we'll need to push high lanes - // of SIMD registers as well. - JS_STATIC_ASSERT(!SupportsSimd); // save all registers,except sp. After this stack is alligned. masm.PushRegsInMask(AllRegsExceptSP); // Save the stack pointer in a non-volatile register. masm.movePtr(StackPointer, s0); // Align the stack. - masm.ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); + masm.ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1))); // Store resumePC into the reserved space. masm.loadAsmJSActivation(IntArgReg0); @@ -7442,7 +6686,7 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // MIPS ABI requires rewserving stack for registes $a0 to $a3. masm.subPtr(Imm32(4 * sizeof(intptr_t)), StackPointer); - masm.assertStackAlignment(ABIStackAlignment); + masm.assertStackAlignment(); masm.call(AsmJSImm_HandleExecutionInterrupt); masm.addPtr(Imm32(4 * sizeof(intptr_t)), StackPointer); @@ -7477,12 +6721,9 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1); masm.storePtr(IntArgReg1, Address(r6, 14 * sizeof(uint32_t*))); - // When this platform supports SIMD extensions, we'll need to push and pop - // high lanes of SIMD registers as well. - JS_STATIC_ASSERT(!SupportsSimd); masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllDoubleMask))); // save all FP registers - masm.assertStackAlignment(ABIStackAlignment); + masm.assertStackAlignment(); masm.call(AsmJSImm_HandleExecutionInterrupt); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -7526,11 +6767,11 @@ GenerateSyncInterruptExit(ModuleCompiler &m, Label *throwLabel) MacroAssembler &masm = m.masm(); masm.setFramePushed(0); - unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, ShadowStackSpace); + unsigned framePushed = StackDecrementForCall(masm, ShadowStackSpace); GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::Interrupt, &m.syncInterruptLabel()); - AssertStackAlignment(masm, ABIStackAlignment); + AssertStackAlignment(masm); masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt)); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -7554,17 +6795,17 @@ GenerateThrowStub(ModuleCompiler &m, Label *throwLabel) // We are about to pop all frames in this AsmJSActivation. Set fp to null to // maintain the invariant that fp is either null or pointing to a valid // frame. - Register scratch = ABIArgGenerator::NonArgReturnReg0; - masm.loadAsmJSActivation(scratch); - masm.storePtr(ImmWord(0), Address(scratch, AsmJSActivation::offsetOfFP())); + Register activation = ABIArgGenerator::NonArgReturnReg0; + masm.loadAsmJSActivation(activation); + masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfFP())); - masm.setFramePushed(FramePushedForEntrySP); - masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfEntrySP()), StackPointer); - masm.Pop(scratch); - masm.PopRegsInMask(NonVolatileRegs, NonVolatileSimdRegs); + masm.setFramePushed(FramePushedAfterSave); + masm.loadPtr(Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()), StackPointer); + masm.PopRegsInMask(NonVolatileRegs); JS_ASSERT(masm.framePushed() == 0); masm.mov(ImmWord(0), ReturnReg); + masm.addPtr(Imm32(AsmJSFrameBytesAfterReturnAddress), StackPointer); masm.ret(); return m.finishGeneratingInlineStub(throwLabel) && !masm.oom(); diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index dabbf39c2831..438f23031511 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -39,8 +39,8 @@ extern const JSFunctionSpec Int32x4Methods[]; static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"}; template -bool -js::IsVectorObject(HandleValue v) +static bool +IsVectorObject(HandleValue v) { if (!v.isObject()) return false; @@ -56,24 +56,6 @@ js::IsVectorObject(HandleValue v) return typeRepr.as().type() == V::type; } -template -bool -js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out) -{ - typedef typename V::Elem Elem; - if (!IsVectorObject(v)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR); - return false; - } - - Elem *mem = reinterpret_cast(v.toObject().as().typedMem()); - *out = jit::SimdConstant::CreateX4(mem); - return true; -} - -template bool js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out); -template bool js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out); - template static Elem TypedObjectMemory(HandleValue v) diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h index ea7d83244471..b3c84f08477a 100644 --- a/js/src/builtin/SIMD.h +++ b/js/src/builtin/SIMD.h @@ -166,12 +166,6 @@ struct Int32x4 { template JSObject *CreateSimd(JSContext *cx, typename V::Elem *data); -template -bool IsVectorObject(HandleValue v); - -template -bool ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out); - #define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags) \ extern bool \ simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 59ed58e40206..acb17c74cac9 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1974,19 +1974,6 @@ EvalReturningScope(JSContext *cx, unsigned argc, jsval *vp) return true; } -static bool -IsSimdAvailable(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); -#ifdef JS_CODEGEN_NONE - bool available = false; -#else - bool available = cx->jitSupportsSimd(); -#endif - args.rval().set(BooleanValue(available)); - return true; -} - static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'compartment')", @@ -2170,10 +2157,6 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " Returns whether asm.js compilation is currently available or whether it is disabled\n" " (e.g., by the debugger)."), - JS_FN_HELP("isSimdAvailable", IsSimdAvailable, 0, 0, -"isSimdAvailable", -" Returns true if SIMD extensions are supported on this platform."), - JS_FN_HELP("getJitCompilerOptions", GetJitCompilerOptions, 0, 0, "getCompilerOptions()", "Return an object describing some of the JIT compiler options.\n"), diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index fad374596758..4600bc0847cd 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -144,7 +144,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx) #endif size_t frameSize = sizeof(FrameData) + num_registers_ * sizeof(void *); - frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), ABIStackAlignment) - masm.framePushed(); + frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), StackAlignment) - masm.framePushed(); // Actually emit code to start a new stack frame. masm.reserveStack(frameSize); diff --git a/js/src/jit-test/lib/asm.js b/js/src/jit-test/lib/asm.js index c38420317660..fe7ec5a171c0 100644 --- a/js/src/jit-test/lib/asm.js +++ b/js/src/jit-test/lib/asm.js @@ -108,8 +108,8 @@ function assertAsmLinkFail(f) assertEq(isAsmJSFunction(ret), false); if (typeof ret === 'object') - for (var i in ret) - assertEq(isAsmJSFunction(ret[i]), false); + for (f of ret) + assertEq(isAsmJSFunction(f), false); // Turn on warnings-as-errors var oldOpts = options("werror"); diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js deleted file mode 100644 index ce9bac08d2b9..000000000000 --- a/js/src/jit-test/tests/asm.js/testSIMD.js +++ /dev/null @@ -1,657 +0,0 @@ -load(libdir + "asm.js"); -var heap = new ArrayBuffer(4096); - -// Set to true to see more JS debugging spew -const DEBUG = false; - -if (!isSimdAvailable() || typeof SIMD === 'undefined') { - DEBUG && print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -const I32 = 'var i4 = glob.SIMD.int32x4;' -const I32A = 'var i4a = i4.add;' -const I32S = 'var i4s = i4.sub;' -const F32 = 'var f4 = glob.SIMD.float32x4;' -const F32A = 'var f4a = f4.add;' -const F32S = 'var f4s = f4.sub;' -const F32M = 'var f4m = f4.mul;' -const F32D = 'var f4d = f4.div;' -const FROUND = 'var f32=glob.Math.fround;' - -const INT32_MAX = Math.pow(2, 31) - 1; -const INT32_MIN = INT32_MAX + 1 | 0; - -const assertEqFFI = {assertEq:assertEq}; - -function assertEqX4(real, expected) { - assertEq(real.x, expected[0]); - assertEq(real.y, expected[1]); - assertEq(real.z, expected[2]); - assertEq(real.w, expected[3]); -} - -function CheckI4(header, code, expected) { - // code needs to contain a local called x - header = USE_ASM + I32 + header; - var lanes = ['x', 'y', 'z', 'w']; - for (var i = 0; i < 4; ++i) { - var lane = lanes[i]; - assertEq(asmLink(asmCompile('glob', header + ';function f() {' + code + ';return x.' + lane + '|0} return f'), this)(), expected[i]); - } -} - -function CheckF4(header, code, expected) { - // code needs to contain a local called x - var lanes = ['x', 'y', 'z', 'w']; - header = USE_ASM + F32 + header; - for (var i = 0; i < 4; ++i) { - var lane = lanes[i]; - assertEq(asmLink(asmCompile('glob', header + ';function f() {' + code + ';return +x.' + lane + '} return f'), this)(), Math.fround(expected[i])); - } -} - -try { - -// 1. Constructors - -// 1.1 Compilation -assertAsmTypeFail('glob', USE_ASM + "var i4 = int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.globglob.int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Math.int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var herd = glob.SIMD.ponyX4 ; return {}") ; - -// 1.2 Linking -assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: 42}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: Math.fround}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: 42}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: Math.fround}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: new Array}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: SIMD.float32x4}}); - -[Type, int32] = [TypedObject.StructType, TypedObject.int32]; -var MyStruct = new Type({'x': int32, 'y': int32, 'z': int32, 'w': int32}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: MyStruct}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: new MyStruct}}); - -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {} return f"), {SIMD:{int32x4: SIMD.int32x4}})(), undefined); - -assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: 42}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: Math.fround}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: new Array}}); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {} return f"), {SIMD:{float32x4: SIMD.float32x4}})(), undefined); - -// 1.3 Correctness -// 1.3.1 Local variables declarations -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Int32x4(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2, 3);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2, 3, 4.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2.0, 3, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4a(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,2+2|0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3," + (INT32_MIN - 1) + ");} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(i4(1,2,3,4));} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3," + (INT32_MAX + 1) + ");} return f"), this)(), undefined); - -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4();} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,3.);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,f32(3.),4.);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,3.,4.);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3," + (INT32_MIN - 1) + ");} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3," + (INT32_MAX + 1) + ");} return f"), this)(), undefined); - -// Places where NumLit can creep in -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {i=i|0; var z=0; switch(i|0) {case i4(1,2,3,4): z=1; break; default: z=2; break;}} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {i=i|0; var z=0; return i * i4(1,2,3,4) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {var x=i4(1,2,3,i4(4,5,6,7))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=i4(1,2,3,f4(4,5,6,7))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=f4(1,2,3,i4(4,5,6,7))} return f"); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(i4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(f4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]); - -// Int32x4 ctor should accept int? -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return i4(i4(i32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [0, 2, 3, 4]); -// Float32x4 ctor should accept floatish, i.e. float || float? || floatish -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Float32Array(heap); function f(i) {i=i|0; return f4(f4(f32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [NaN, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "var f32=glob.Math.fround; function f(i) {i=i|0; return f4(f4(f32(1) + f32(2), 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]); - -// 1.3.2 Reading values out of lanes -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1; return x.y | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1; return (x + x).y | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1.; return x.y | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + "var f32=glob.Math.fround;" + I32 + "function f() {var x=f32(1); return x.y | 0;} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return x.length|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4).y; return x|0;} return f"); - -CheckI4('', 'var x=i4(0,0,0,0)', [0,0,0,0]); -CheckI4('', 'var x=i4(1,2,3,4)', [1,2,3,4]); -CheckI4('', 'var x=i4(' + INT32_MIN + ',2,3,' + INT32_MAX + ')', [INT32_MIN,2,3,INT32_MAX]); -CheckI4('', 'var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); -CheckI4('', 'var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); -CheckI4('', 'var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]); - -CheckF4('', 'var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]); -CheckF4('', 'var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]); -CheckF4('', 'var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]); -CheckF4('', 'var x=f4(13.37, 2., 3., -0)', [13.37, 2, 3, -0]); - -// 1.3.3. Variable assignments -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1.0, 2, 3, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2.0, 3, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3.0, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3, 4.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var c=4.0; x=i4(1, 2, 3, +c);} return f"); - -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f() {var x=i4(1,2,3,4); i32[0] = x;} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f() {var x=i4(1,2,3,4); x = i32[0];} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Float32Array(heap); function f() {var x=f4(1,2,3,4); f32[0] = x;} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Int32Array(heap); function f() {var x=f4(1,2,3,4); x = f32[0];} return f"); - -CheckI4('', 'var x=i4(1,2,3,4); x=i4(5,6,7,8)', [5, 6, 7, 8]); -CheckI4('', 'var x=i4(1,2,3,4); var c=6; x=i4(5,c|0,7,8)', [5, 6, 7, 8]); -CheckI4('', 'var x=i4(8,7,6,5); x=i4(x.w|0,x.z|0,x.y|0,x.x|0)', [5, 6, 7, 8]); - -CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(7.); x=f4(5,6,y,8)', [5, 6, 7, 8]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5.),6.,7.,8.)', [5, 6, 7, 8]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5),6,7,8)', [5, 6, 7, 8]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5.),f32(6.),f32(7.),f32(8.))', [5, 6, 7, 8]); -CheckF4('', 'var x=f4(1.,2.,3.,4.); x=f4(5.,6.,7.,8.)', [5, 6, 7, 8]); -CheckF4('', 'var x=f4(1.,2.,3.,4.); x=f4(1,2,3,4)', [1, 2, 3, 4]); -CheckF4(FROUND, 'var x=f4(1.,2.,3.,4.); var y=f32(7.); x=f4(9, 4, 2, 1)', [9, 4, 2, 1]); -CheckF4('', 'var x=f4(8.,7.,6.,5.); x=f4(x.w, x.z, x.y, x.x)', [5, 6, 7, 8]); - -// 1.3.4 Return values -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x + x)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1.; return i4(x)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=f32(1.); return i4(x)} return f"); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return i4(x)} return f"), this)(), [1,2,3,4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); return f4(x)} return f"), this)(), [1,2,3,4]); - -// 1.3.5 Coerce and pass arguments -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x,y) {x=i4(y);y=+y} return f"); - -var i32x4 = SIMD.int32x4(1, 3, 3, 7); -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x)} return f"), this)(i32x4), undefined); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x); return i4(x);} return f"), this)(i32x4), [1,3,3,7]); - -var f32x4 = SIMD.float32x4(13.37, 42.42, -0, NaN); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x)} return f"), this)(f32x4), undefined); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x); return f4(x);} return f"), this)(f32x4), - [Math.fround(13.37), Math.fround(42.42), -0, NaN]); - -function assertCaught(f) { - var caught = false; - try { - f.apply(null, Array.prototype.slice.call(arguments, 1)); - } catch (e) { - DEBUG && print('Assert caught: ', e, '\n', e.stack); - assertEq(e instanceof TypeError, true); - caught = true; - } - assertEq(caught, true); -} - -var f = asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x); return f4(x);} return f"), this); -assertCaught(f); -assertCaught(f, 1); -assertCaught(f, {}); -assertCaught(f, "I sincerely am a SIMD typed object."); -assertCaught(f, SIMD.int32x4(1,2,3,4)); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x); return i4(x);} return f"), this); -assertCaught(f); -assertCaught(f, 1); -assertCaught(f, {}); -assertCaught(f, "I sincerely am a SIMD typed object."); -assertCaught(f, SIMD.float32x4(4,3,2,1)); - -// 1.3.6 Globals -// 1.3.6.1 Local globals -// Read -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4; x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); x=i4(g);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); x=f4(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0; function f() {var x=i4(1,2,3,4); x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0.; function f() {var x=i4(1,2,3,4); x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=i4(1,2,3,4); x=f32(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0; function f() {var x=f4(0.,0.,0.,0.); x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0.; function f() {var x=f4(0.,0.,0.,0.); x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=f4(0.,0.,0.,0.); x=f32(g);} return f"); - -CheckI4('var x=i4(1,2,3,4)', '', [1, 2, 3, 4]); -CheckI4('var _=42; var h=i4(5,5,5,5); var __=13.37; var x=i4(4,7,9,2);', '', [4,7,9,2]); - -CheckF4('var x=f4(1.,2.,3.,4.)', '', [1, 2, 3, 4]); -CheckF4('var _=42; var h=f4(5.,5.,5.,5.); var __=13.37; var x=f4(4.,13.37,9.,-0.);', '', [4, 13.37, 9, -0]); -CheckF4('var x=f4(1,2,3,4)', '', [1, 2, 3, 4]); - -// Write -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; g=x|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; g=+x;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4; g=x|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; g=+x;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=i4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=f4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=f4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=i4(x);} return f"); - -CheckI4('var x=i4(0,0,0,0);', 'x=i4(1,2,3,4)', [1,2,3,4]); -CheckF4('var x=f4(0.,0.,0.,0.);', 'x=f4(5.,3.,4.,2.)', [5,3,4,2]); - -CheckI4('var x=i4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=i4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]); -CheckF4('var x=f4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=f4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]); - -// 1.3.6.2 Imported globals -// Read -var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {return i4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})(); -assertEq(int32x4.x, 1); -assertEq(int32x4.y, 2); -assertEq(int32x4.z, 3); -assertEq(int32x4.w, 4); - -for (var v of [1, {}, "totally legit SIMD variable", SIMD.float32x4(1,2,3,4)]) - assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {return i4(g)} return f"), this, {g: v}); - -var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {return f4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})(); -assertEq(float32x4.x, 1); -assertEq(float32x4.y, 2); -assertEq(float32x4.z, 3); -assertEq(float32x4.w, 4); - -for (var v of [1, {}, "totally legit SIMD variable", SIMD.int32x4(1,2,3,4)]) - assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {return f4(g)} return f"), this, {g: v}); - -// Write -var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {g=i4(4,5,6,7); return i4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})(); -assertEq(int32x4.x, 4); -assertEq(int32x4.y, 5); -assertEq(int32x4.z, 6); -assertEq(int32x4.w, 7); - -var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return f4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})(); -assertEq(float32x4.x, 4); -assertEq(float32x4.y, 5); -assertEq(float32x4.z, 6); -assertEq(float32x4.w, 7); - -// 2. SIMD operations -// 2.1 Compilation -assertAsmTypeFail('glob', USE_ASM + "var add = int32x4.add; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32A + I32 + "return {}"); -assertAsmTypeFail('glob', USE_ASM + "var g = 3; var add = g.add; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.doTheHarlemShake; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var div = i4.div; return {}"); -assertAsmTypeFail('glob', USE_ASM + "var f32 = glob.Math.fround; var i4a = f32.add; return {}"); - -// 2.2 Linking -assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {}); -assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: Math.fround}); - -var oldInt32x4Add = SIMD.int32x4.add; -var code = asmCompile('glob', USE_ASM + I32 + I32A + "return {}"); -for (var v of [42, Math.fround, SIMD.float32x4.add, function(){}, SIMD.int32x4.mul]) { - SIMD.int32x4.add = v; - assertAsmLinkFail(code, {SIMD: {int32x4: SIMD.int32x4}}); -} -SIMD.int32x4.add = oldInt32x4Add; // finally replace the add function with the original one -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: {int32x4: SIMD.int32x4}})(), undefined); - -// 2.3. Binary arithmetic operations -// 2.3.1 Additions -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(13, 37);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(23.10, 19.89);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, 42);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, 13.37);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var y=4; x=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; x=i4a(y, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; y=i4a(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=f4a(y, y);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0; y=i4(x,x)|0} return f'); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0.; y=+i4(x,x)} return f'); - -CheckI4(I32A, 'var z=i4(1,2,3,4); var y=i4(0,1,0,3); var x=i4(0,0,0,0); x=i4a(z,y)', [1,3,3,7]); -CheckI4(I32A, 'var x=i4(2,3,4,5); var y=i4(0,1,0,3); x=i4a(x,y)', [2,4,4,8]); -CheckI4(I32A, 'var x=i4(1,2,3,4); x=i4a(x,x)', [2,4,6,8]); -CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4a(x,y)', [INT32_MIN,3,3,7]); -CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4(i4a(x,y))', [INT32_MIN,3,3,7]); - -CheckF4(F32A, 'var x=f4(1,2,3,4); x=f4a(x,x)', [2,4,6,8]); -CheckF4(F32A, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [5,5,8,6]); -CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [Math.fround(13.37) + 4,5,8,6]); -CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4a(x,y))', [Math.fround(13.37) + 4,5,8,6]); - -// 2.3.2. Subtracts -CheckI4(I32S, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=i4s(x,y)', [2,1,3,2]); -CheckI4(I32S, 'var x=i4(5,4,3,2); var y=i4(1,2,3,4); x=i4s(x,y)', [4,2,0,-2]); -CheckI4(I32S, 'var x=i4(1,2,3,4); x=i4s(x,x)', [0,0,0,0]); -CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4s(x,y)', [INT32_MAX,1,3,1]); -CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4(i4s(x,y))', [INT32_MAX,1,3,1]); - -CheckF4(F32S, 'var x=f4(1,2,3,4); x=f4s(x,x)', [0,0,0,0]); -CheckF4(F32S, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [-3,-1,-2,2]); -CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [Math.fround(13.37) - 4,-1,-2,2]); -CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4s(x,y))', [Math.fround(13.37) - 4,-1,-2,2]); - -// 2.3.3. Multiplications / Divisions -assertAsmTypeFail('glob', USE_ASM + I32 + "var f4m=i4.mul; function f() {} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var f4d=i4.div; function f() {} return f"); - -CheckF4(F32M, 'var x=f4(1,2,3,4); x=f4m(x,x)', [1,4,9,16]); -CheckF4(F32M, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [4,6,15,8]); -CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [Math.fround(13.37) * 4,6,15,8]); -CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]); - -// Test NaN -var f32x4 = SIMD.float32x4(0, NaN, -0, NaN); -var another = SIMD.float32x4(NaN, -1, -0, NaN); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32M + "function f(x, y) {x=f4(x); y=f4(y); x=f4m(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, 0, NaN]); - -CheckF4(F32D, 'var x=f4(1,2,3,4); x=f4d(x,x)', [1,1,1,1]); -CheckF4(F32D, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4d(x,y)', [1/4,2/3,3/5,2]); -CheckF4(F32D, 'var x=f4(13.37,1,1,4); var y=f4(4,0,-0.,2); x=f4d(x,y)', [Math.fround(13.37) / 4,+Infinity,-Infinity,2]); - -// Test NaN -var f32x4 = SIMD.float32x4(0, 0, -0, NaN); -var another = SIMD.float32x4(0, -0, 0, 0); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + "function f(x,y) {x=f4(x); y=f4(y); x=f4d(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]); - -// Dead code -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); return i4(x); x=i4(5,6,7,8); return i4(x);} return f'), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); c=x.x|0; return i4(x);} return f'), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4a(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32S + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4s(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]); - -// 3. Function calls -// 3.1. No math builtins -assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); return +fround(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var sin=glob.Math.sin; function f() {var x=i4(1,2,3,4); return +sin(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var ceil=glob.Math.ceil; function f() {var x=i4(1,2,3,4); return +ceil(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {var x=i4(1,2,3,4); return +pow(1.0, x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); x=i4(fround(3));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var sin=glob.Math.sin; function f() {var x=i4(1,2,3,4); x=i4(sin(3.0));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var ceil=glob.Math.sin; function f() {var x=i4(1,2,3,4); x=i4(ceil(3.0));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {var x=i4(1,2,3,4); x=i4(pow(1.0, 2.0));} return f"); - -// 3.2. FFI calls -// Can't pass SIMD arguments to FFI -assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); func(x);} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); func(x);} return f"); - -// Can't have FFI return SIMD values -assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); x=i4(func());} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); x=f4(func());} return f"); - -// 3.3 Internal calls -// asm.js -> asm.js -// Retrieving values from asm.js -var code = USE_ASM + I32 + I32A + ` - var check = ffi.check; - - function g() { - var i = 0; - var y = i4(0,0,0,0); - var tmp = i4(0,0,0,0); var z = i4(1,1,1,1); - var w = i4(5,5,5,5); - for (; (i|0) < 30; i = i + 1 |0) - y = i4a(z, y); - y = i4a(w, y); - check(y.x | 0, y.y | 0, y.z | 0, y.w | 0); - return i4(y); - } - - function f(x) { - x = i4(x); - var y = i4(0,0,0,0); - y = i4(g()); - check(y.x | 0, y.y | 0, y.z | 0, y.w | 0); - return i4(x); - } - return f; -`; - -var v4 = SIMD.int32x4(1,2,3,4); -function check(x, y, z, w) { - assertEq(x, 35); - assertEq(y, 35); - assertEq(z, 35); - assertEq(w, 35); -} -var ffi = {check}; -assertEqX4(asmLink(asmCompile('glob', 'ffi', code), this, ffi)(v4), [1,2,3,4]); - -// Passing arguments from asm.js to asm.js -// TODO make this code look better with templatized strings -var code = USE_ASM + I32 + I32A + ` - var assertEq = ffi.assertEq; - - function internal([args]) { - [coerc] - assertEq([last].x | 0, [i] | 0); - assertEq([last].y | 0, [i] + 1 |0); - assertEq([last].z | 0, [i] + 2 |0); - assertEq([last].w | 0, [i] + 3 |0); - } - - function external() { - [decls] - internal([args]); - } - return external; -`; - -var ffi = {assertEq}; -var args = ''; -var decls = ''; -var coerc = ''; -for (var i = 1; i < 10; ++i) { - var j = i; - args += ((i > 1) ? ', ':'') + 'x' + i; - decls += 'var x' + i + ' = i4(' + j++ + ', ' + j++ + ', ' + j++ + ', ' + j++ + ');\n'; - coerc += 'x' + i + ' = i4(x' + i + ');\n'; - last = 'x' + i; - var c = code.replace(/\[args\]/g, args) - .replace(/\[last\]/g, last) - .replace(/\[decls\]/i, decls) - .replace(/\[coerc\]/i, coerc) - .replace(/\[i\]/g, i); - asmLink(asmCompile('glob', 'ffi', c), this, ffi)(); -} - -// Stress-test for register spilling code and stack depth checks -var code = ` - "use asm"; - var i4 = glob.SIMD.int32x4; - var i4a = i4.add; - var assertEq = ffi.assertEq; - function g() { - var x = i4(1,2,3,4); - var y = i4(2,3,4,5); - var z = i4(0,0,0,0); - z = i4a(x, y); - assertEq(z.x | 0, 3); - assertEq(z.y | 0, 5); - assertEq(z.z | 0, 7); - assertEq(z.w | 0, 9); - } - return g -` -asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)(); - -(function() { - var code = ` - "use asm"; - var i4 = glob.SIMD.int32x4; - var i4a = i4.add; - var assertEq = ffi.assertEq; - var one = ffi.one; - - // Function call with arguments on the stack (1 on x64, 3 on x86) - function h(x1, x2, x3, x4, x5, x6, x7) { - x1=x1|0 - x2=x2|0 - x3=x3|0 - x4=x4|0 - x5=x5|0 - x6=x6|0 - x7=x7|0 - return x1 + x2 |0 - } - - function g() { - var x = i4(1,2,3,4); - var y = i4(2,3,4,5); - var z = i4(0,0,0,0); - var w = 1; - z = i4a(x, y); - w = w + (one() | 0) | 0; - assertEq(z.x | 0, 3); - assertEq(z.y | 0, 5); - assertEq(z.z | 0, 7); - assertEq(z.w | 0, 9); - h(1, 2, 3, 4, 42, 42, 42)|0 - return w | 0; - } - return g - `; - - asmLink(asmCompile('glob', 'ffi', code), this, {assertEq: assertEq, one: () => 1})(); -})(); - -// Function calls with mixed arguments on the stack (SIMD and scalar). In the -// worst case (x64), we have 6 int arg registers and 8 float registers. -(function() { - var code = ` - "use asm"; - var i4 = glob.SIMD.int32x4; - function h( - // In registers: - gpr1, gpr2, gpr3, gpr4, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, - // On the stack: - sint1, ssimd1, sdouble1, ssimd2, sint2, sint3, sint4, ssimd3, sdouble2 - ) - { - gpr1=gpr1|0; - gpr2=gpr2|0; - gpr3=gpr3|0; - gpr4=gpr4|0; - - xmm1=+xmm1; - xmm2=+xmm2; - xmm3=+xmm3; - xmm4=+xmm4; - xmm5=+xmm5; - xmm6=+xmm6; - xmm7=+xmm7; - xmm8=+xmm8; - - sint1=sint1|0; - ssimd1=i4(ssimd1); - sdouble1=+sdouble1; - ssimd2=i4(ssimd2); - sint2=sint2|0; - sint3=sint3|0; - sint4=sint4|0; - ssimd3=i4(ssimd3); - sdouble2=+sdouble2; - - return (ssimd1.x|0) + (ssimd2.y|0) + (ssimd3.z|0) + sint2 + gpr3 | 0; - } - - function g() { - var simd1 = i4(1,2,3,4); - var simd2 = i4(5,6,7,8); - var simd3 = i4(9,10,11,12); - return h(1, 2, 3, 4, - 1., 2., 3., 4., 5., 6., 7., 8., - 5, simd1, 9., simd2, 6, 7, 8, simd3, 10.) | 0; - } - return g - `; - - assertEq(asmLink(asmCompile('glob', 'ffi', code), this)(), 1 + 6 + 11 + 6 + 3); -})(); - -// Check that the interrupt callback doesn't erase high components of simd -// registers: - -// WARNING: must be the last test in this file -(function() { - var iters = 2000000; - var code = ` - "use asm"; - var i4 = glob.SIMD.int32x4; - var i4a = i4.add; - function _() { - var i = 0; - var n = i4(0,0,0,0); - var one = i4(1,1,1,1); - for (; (i>>>0) < ` + iters + `; i=(i+1)>>>0) { - n = i4a(n, one); - } - return i4(n); - } - return _;`; - // This test relies on the fact that setting the timeout will call the - // interrupt callback at fixed intervals, even before the timeout. - timeout(1000); - var x4 = asmLink(asmCompile('glob', code), this)(); - assertEq(x4.x, iters); - assertEq(x4.y, iters); - assertEq(x4.z, iters); - assertEq(x4.w, iters); -})(); - -} catch(e) { - print('Stack:', e.stack) - print('Error:', e) - throw e; -} - diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 67b94bb0d150..38b7b754f92b 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8769,15 +8769,12 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins) if (mir->spIncrement()) masm.freeStack(mir->spIncrement()); - JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % AsmJSStackAlignment == 0); + JS_ASSERT((sizeof(AsmJSFrame) + masm.framePushed()) % StackAlignment == 0); #ifdef DEBUG - static_assert(AsmJSStackAlignment >= ABIStackAlignment, - "The asm.js stack alignment should subsume the ABI-required alignment"); - static_assert(AsmJSStackAlignment % ABIStackAlignment == 0, - "The asm.js stack alignment should subsume the ABI-required alignment"); Label ok; - masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(AsmJSStackAlignment - 1), &ok); + JS_ASSERT(IsPowerOfTwo(StackAlignment)); + masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok); masm.breakpoint(); masm.bind(&ok); #endif @@ -9016,7 +9013,7 @@ CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir) masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin); { uint32_t stackFixup = ComputeByteAlignment(masm.framePushed() + sizeof(AsmJSFrame), - ABIStackAlignment); + StackAlignment); masm.reserveStack(stackFixup); masm.call(lir->funcDesc(), lir->interruptExit()); masm.freeStack(stackFixup); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 3c970273ff65..29f5d9d2c04b 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -3214,9 +3214,3 @@ jit::JitSupportsFloatingPoint() { return js::jit::MacroAssembler::SupportsFloatingPoint(); } - -bool -jit::JitSupportsSimd() -{ - return js::jit::MacroAssembler::SupportsSimd(); -} diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 285f41b31fb9..608afb936df6 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -207,7 +207,6 @@ bool UpdateForDebugMode(JSContext *maybecx, JSCompartment *comp, AutoDebugModeInvalidation &invalidate); bool JitSupportsFloatingPoint(); -bool JitSupportsSimd(); } // namespace jit } // namespace js diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index 88de264262d2..6f628a11daac 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -1075,7 +1075,7 @@ uint8_t * alignDoubleSpillWithOffset(uint8_t *pointer, int32_t offset) { uint32_t address = reinterpret_cast(pointer); - address = (address - offset) & ~(ABIStackAlignment - 1); + address = (address - offset) & ~(StackAlignment - 1); return reinterpret_cast(address); } diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index c64baa3bb7ff..9066ef3f6ad8 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -1426,11 +1426,11 @@ class MacroAssembler : public MacroAssemblerSpecific PopRegsInMask(liveRegs); } - void assertStackAlignment(uint32_t alignment) { + void assertStackAlignment() { #ifdef DEBUG Label ok; - JS_ASSERT(IsPowerOfTwo(alignment)); - branchTestPtr(Assembler::Zero, StackPointer, Imm32(alignment - 1), &ok); + JS_ASSERT(IsPowerOfTwo(StackAlignment)); + branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok); breakpoint(); bind(&ok); #endif @@ -1508,10 +1508,10 @@ JSOpToCondition(JSOp op, bool isSigned) } static inline size_t -StackDecrementForCall(uint32_t alignment, size_t bytesAlreadyPushed, size_t bytesToPush) +StackDecrementForCall(size_t bytesAlreadyPushed, size_t bytesToPush) { return bytesToPush + - ComputeByteAlignment(bytesAlreadyPushed + bytesToPush, alignment); + ComputeByteAlignment(bytesAlreadyPushed + bytesToPush, StackAlignment); } } // namespace jit diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index 40498f2bddfd..e9d96f6cd128 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -1586,10 +1586,10 @@ class LIRGraph // platform stack alignment requirement, and so that it's a multiple of // the number of slots per Value. uint32_t paddedLocalSlotCount() const { - // Round to ABIStackAlignment, but also round to at least sizeof(Value) - // in case that's greater, because StackOffsetOfPassedArg rounds - // argument slots to 8-byte boundaries. - size_t Alignment = Max(size_t(ABIStackAlignment), sizeof(Value)); + // Round to StackAlignment, but also round to at least sizeof(Value) in + // case that's greater, because StackOffsetOfPassedArg rounds argument + // slots to 8-byte boundaries. + size_t Alignment = Max(size_t(StackAlignment), sizeof(Value)); return AlignBytes(localSlotCount(), Alignment); } size_t paddedLocalSlotsSize() const { diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 9fa0419cbe97..f3af7ff088eb 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3553,7 +3553,7 @@ LIRGenerator::visitAsmJSParameter(MAsmJSParameter *ins) if (abi.argInRegister()) return defineFixed(new(alloc()) LAsmJSParameter, ins, LAllocation(abi.reg())); - JS_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type())); + JS_ASSERT(IsNumberType(ins->type())); return defineFixed(new(alloc()) LAsmJSParameter, ins, LArgument(abi.offsetFromArgBase())); } @@ -3566,8 +3566,6 @@ LIRGenerator::visitAsmJSReturn(MAsmJSReturn *ins) lir->setOperand(0, useFixed(rval, ReturnFloat32Reg)); else if (rval->type() == MIRType_Double) lir->setOperand(0, useFixed(rval, ReturnDoubleReg)); - else if (IsSimdType(rval->type())) - lir->setOperand(0, useFixed(rval, ReturnSimdReg)); else if (rval->type() == MIRType_Int32) lir->setOperand(0, useFixed(rval, ReturnReg)); else @@ -3584,7 +3582,7 @@ LIRGenerator::visitAsmJSVoidReturn(MAsmJSVoidReturn *ins) bool LIRGenerator::visitAsmJSPassStackArg(MAsmJSPassStackArg *ins) { - if (IsFloatingPointType(ins->arg()->type()) || IsSimdType(ins->arg()->type())) { + if (IsFloatingPointType(ins->arg()->type())) { JS_ASSERT(!ins->arg()->isEmittedAtUses()); return add(new(alloc()) LAsmJSPassStackArg(useRegisterAtStart(ins->arg())), ins); } diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index e41794f18e42..bada2ff1638e 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -493,7 +493,6 @@ MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintLi MConstant * MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type) { - JS_ASSERT(!IsSimdType(type)); MConstant *constant = new(alloc) MConstant(v, nullptr); constant->setResultType(type); return constant; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index a17bd367c11f..34706af25705 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -11187,7 +11187,7 @@ class MAsmJSLoadGlobalVar : public MNullaryInstruction MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant) : globalDataOffset_(globalDataOffset), isConstant_(isConstant) { - JS_ASSERT(IsNumberType(type) || IsSimdType(type)); + JS_ASSERT(IsNumberType(type)); setResultType(type); setMovable(); } diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index f2cedd5a3289..91c8ca8b52b1 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -145,8 +145,9 @@ static MOZ_CONSTEXPR_VAR FloatRegister d15 = {FloatRegisters::d15, VFPRegister:: // load/store) operate in a single cycle when the address they are dealing with // is 8 byte aligned. Also, the ARM abi wants the stack to be 8 byte aligned at // function boundaries. I'm trying to make sure this is always true. -static const uint32_t ABIStackAlignment = 8; +static const uint32_t StackAlignment = 8; static const uint32_t CodeAlignment = 8; +static const bool StackKeptAligned = true; // This boolean indicates whether we support SIMD instructions flavoured for // this architecture or not. Rather than a method in the LIRGenerator, it is @@ -155,8 +156,6 @@ static const uint32_t CodeAlignment = 8; static const bool SupportsSimd = false; static const uint32_t SimdStackAlignment = 8; -static const uint32_t AsmJSStackAlignment = SimdStackAlignment; - static const Scale ScalePointer = TimesFour; class Instruction; @@ -1553,9 +1552,6 @@ class Assembler : public AssemblerShared static bool SupportsFloatingPoint() { return HasVFP(); } - static bool SupportsSimd() { - return js::jit::SupportsSimd; - } protected: void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 2b2ecf51d4fa..c9d840e1c293 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1880,7 +1880,7 @@ MacroAssemblerARMCompat::freeStack(Register amount) void MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet) { - JS_ASSERT(!SupportsSimd() && simdSet.size() == 0); + JS_ASSERT(!SupportsSimd && simdSet.size() == 0); int32_t diffF = set.fpus().getPushSizeInBytes(); int32_t diffG = set.gprs().size() * sizeof(intptr_t); @@ -1909,7 +1909,7 @@ MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet) void MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore, FloatRegisterSet simdSet) { - JS_ASSERT(!SupportsSimd() && simdSet.size() == 0); + JS_ASSERT(!SupportsSimd && simdSet.size() == 0); int32_t diffG = set.gprs().size() * sizeof(intptr_t); int32_t diffF = set.fpus().getPushSizeInBytes(); const int32_t reservedG = diffG; @@ -3778,7 +3778,7 @@ MacroAssemblerARMCompat::setupUnalignedABICall(uint32_t args, Register scratch) ma_mov(sp, scratch); // Force sp to be aligned. - ma_and(Imm32(~(ABIStackAlignment - 1)), sp, sp); + ma_and(Imm32(~(StackAlignment - 1)), sp, sp); ma_push(scratch); } @@ -3937,7 +3937,7 @@ MacroAssemblerARMCompat::passABIArg(FloatRegister freg, MoveOp::Type type) void MacroAssemblerARMCompat::checkStackAlignment() { #ifdef DEBUG - ma_tst(sp, Imm32(ABIStackAlignment - 1)); + ma_tst(sp, Imm32(StackAlignment - 1)); breakpoint(NonZero); #endif } @@ -3956,11 +3956,11 @@ MacroAssemblerARMCompat::callWithABIPre(uint32_t *stackAdjust, bool callFromAsmJ if (!dynamicAlignment_) { *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust + alignmentAtPrologue, - ABIStackAlignment); + StackAlignment); } else { // sizeof(intptr_t) accounts for the saved stack pointer pushed by // setupUnalignedABICall. - *stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), ABIStackAlignment); + *stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), StackAlignment); } reserveStack(*stackAdjust); diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp index ea4ec2d915b6..610b3fc27f84 100644 --- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -2117,7 +2117,7 @@ Simulator::softwareInterrupt(SimInstruction *instr) int32_t saved_lr = get_register(lr); intptr_t external = reinterpret_cast(redirection->nativeFunction()); - bool stack_aligned = (get_register(sp) & (ABIStackAlignment - 1)) == 0; + bool stack_aligned = (get_register(sp) & (StackAlignment - 1)) == 0; if (!stack_aligned) { fprintf(stderr, "Runtime call with unaligned stack!\n"); MOZ_CRASH(); @@ -4258,7 +4258,7 @@ Simulator::call(uint8_t* entry, int argument_count, ...) if (argument_count >= 4) entry_stack -= (argument_count - 4) * sizeof(int32_t); - entry_stack &= ~ABIStackAlignment; + entry_stack &= ~StackAlignment; // Store remaining arguments on stack, from low to high memory. intptr_t *stack_argument = reinterpret_cast(entry_stack); diff --git a/js/src/jit/mips/Assembler-mips.h b/js/src/jit/mips/Assembler-mips.h index 094b715f9ad2..ee901094f427 100644 --- a/js/src/jit/mips/Assembler-mips.h +++ b/js/src/jit/mips/Assembler-mips.h @@ -158,8 +158,9 @@ static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegiste // MIPS CPUs can only load multibyte data that is "naturally" // four-byte-aligned, sp register should be eight-byte-aligned. -static const uint32_t ABIStackAlignment = 8; +static const uint32_t StackAlignment = 8; static const uint32_t CodeAlignment = 4; +static const bool StackKeptAligned = true; // This boolean indicates whether we support SIMD instructions flavoured for // this architecture or not. Rather than a method in the LIRGenerator, it is @@ -170,8 +171,6 @@ static const bool SupportsSimd = false; // alignment requirements still need to be explored. static const uint32_t SimdStackAlignment = 8; -static const uint32_t AsmJSStackAlignment = SimdStackAlignment; - static const Scale ScalePointer = TimesFour; // MIPS instruction types @@ -239,6 +238,7 @@ static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; static const uint32_t RegMask = Registers::Total - 1; +static const uint32_t StackAlignmentMask = StackAlignment - 1; static const uint32_t MAX_BREAK_CODE = 1024 - 1; diff --git a/js/src/jit/mips/MacroAssembler-mips.cpp b/js/src/jit/mips/MacroAssembler-mips.cpp index f7243ccd2644..3bb1aa88e836 100644 --- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -1574,7 +1574,7 @@ MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet) // Double values have to be aligned. We reserve extra space so that we can // start writing from the first aligned location. // We reserve a whole extra double so that the buffer has even size. - ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1))); + ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1))); reserveStack(diffF + sizeof(double)); for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) { @@ -1596,7 +1596,7 @@ MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore, FloatRe // Read the buffer form the first aligned location. ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double))); - ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1))); + ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1))); for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) { if (!ignore.has(*iter) && ((*iter).code() % 2 == 0)) @@ -3158,7 +3158,7 @@ MacroAssemblerMIPSCompat::setupUnalignedABICall(uint32_t args, Register scratch) // Force sp to be aligned ma_subu(StackPointer, StackPointer, Imm32(sizeof(uint32_t))); - ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); + ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1))); as_sw(scratch, StackPointer, 0); } @@ -3259,7 +3259,7 @@ MacroAssemblerMIPSCompat::checkStackAlignment() { #ifdef DEBUG Label aligned; - as_andi(ScratchRegister, sp, ABIStackAlignment - 1); + as_andi(ScratchRegister, sp, StackAlignment - 1); ma_b(ScratchRegister, zero, &aligned, Equal, ShortJump); as_break(MAX_BREAK_CODE); bind(&aligned); @@ -3271,7 +3271,7 @@ MacroAssemblerMIPSCompat::alignStackPointer() { movePtr(StackPointer, SecondScratchReg); subPtr(Imm32(sizeof(uintptr_t)), StackPointer); - andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); + andPtr(Imm32(~(StackAlignment - 1)), StackPointer); storePtr(SecondScratchReg, Address(StackPointer, 0)); } @@ -3284,13 +3284,13 @@ MacroAssemblerMIPSCompat::restoreStackPointer() void MacroAssembler::alignFrameForICArguments(AfterICSaveLive &aic) { - if (framePushed() % ABIStackAlignment != 0) { - aic.alignmentPadding = ABIStackAlignment - (framePushed() % StackAlignment); + if (framePushed() % StackAlignment != 0) { + aic.alignmentPadding = StackAlignment - (framePushed() % StackAlignment); reserveStack(aic.alignmentPadding); } else { aic.alignmentPadding = 0; } - MOZ_ASSERT(framePushed() % ABIStackAlignment == 0); + MOZ_ASSERT(framePushed() % StackAlignment == 0); checkStackAlignment(); } @@ -3316,10 +3316,10 @@ MacroAssemblerMIPSCompat::callWithABIPre(uint32_t *stackAdjust, bool callFromAsm uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0; if (dynamicAlignment_) { - *stackAdjust += ComputeByteAlignment(*stackAdjust, ABIStackAlignment); + *stackAdjust += ComputeByteAlignment(*stackAdjust, StackAlignment); } else { *stackAdjust += ComputeByteAlignment(framePushed_ + alignmentAtPrologue + *stackAdjust, - ABIStackAlignment); + StackAlignment); } reserveStack(*stackAdjust); @@ -3444,7 +3444,7 @@ void MacroAssemblerMIPSCompat::handleFailureWithHandler(void *handler) { // Reserve space for exception information. - int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1); + int size = (sizeof(ResumeFromException) + StackAlignment) & ~(StackAlignment - 1); ma_subu(StackPointer, StackPointer, Imm32(size)); ma_move(a0, StackPointer); // Use a0 since it is a first function argument diff --git a/js/src/jit/mips/Simulator-mips.cpp b/js/src/jit/mips/Simulator-mips.cpp index b33c6cf7d0f3..25f39937a79a 100644 --- a/js/src/jit/mips/Simulator-mips.cpp +++ b/js/src/jit/mips/Simulator-mips.cpp @@ -1871,7 +1871,7 @@ Simulator::softwareInterrupt(SimInstruction *instr) intptr_t external = reinterpret_cast(redirection->nativeFunction()); - bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0; + bool stack_aligned = (getRegister(sp) & (StackAlignment - 1)) == 0; if (!stack_aligned) { fprintf(stderr, "Runtime call with unaligned stack!\n"); MOZ_CRASH(); @@ -3405,7 +3405,7 @@ Simulator::call(uint8_t *entry, int argument_count, ...) else entry_stack = entry_stack - kCArgsSlotsSize; - entry_stack &= ~ABIStackAlignment; + entry_stack &= ~StackAlignment; intptr_t *stack_argument = reinterpret_cast(entry_stack); diff --git a/js/src/jit/none/Architecture-none.h b/js/src/jit/none/Architecture-none.h index e5dd5b5fce34..40bf91e11480 100644 --- a/js/src/jit/none/Architecture-none.h +++ b/js/src/jit/none/Architecture-none.h @@ -16,7 +16,6 @@ namespace jit { static const bool SupportsSimd = false; static const uint32_t SimdStackAlignment = 0; -static const uint32_t AsmJSStackAlignment = 0; class Registers { diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 2582bb465e92..9049f4497222 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -68,8 +68,9 @@ static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg); #error "Bad architecture" #endif -static const uint32_t ABIStackAlignment = 4; +static const uint32_t StackAlignment = 8; static const uint32_t CodeAlignment = 4; +static const bool StackKeptAligned = false; static const Scale ScalePointer = TimesOne; diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 7df6f01900fa..038fd421b799 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -640,9 +640,9 @@ class CallSite : public CallSiteDesc typedef Vector CallSiteVector; // As an invariant across architectures, within asm.js code: -// $sp % AsmJSStackAlignment = (sizeof(AsmJSFrame) + masm.framePushed) % AsmJSStackAlignment +// $sp % StackAlignment = (sizeof(AsmJSFrame) + masm.framePushed) % StackAlignment // Thus, AsmJSFrame represents the bytes pushed after the call (which occurred -// with a AsmJSStackAlignment-aligned StackPointer) that are not included in +// with a StackAlignment-aligned StackPointer) that are not included in // masm.framePushed. struct AsmJSFrame { diff --git a/js/src/jit/shared/Assembler-x86-shared.h b/js/src/jit/shared/Assembler-x86-shared.h index 7095e78c6c8d..9bb420ae30a1 100644 --- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -926,7 +926,6 @@ class AssemblerX86Shared : public AssemblerShared static bool HasSSE3() { return CPUInfo::IsSSE3Present(); } static bool HasSSE41() { return CPUInfo::IsSSE41Present(); } static bool SupportsFloatingPoint() { return CPUInfo::IsSSE2Present(); } - static bool SupportsSimd() { return CPUInfo::IsSSE2Present(); } // The below cmpl methods switch the lhs and rhs when it invokes the // macroassembler to conform with intel standard. When calling this diff --git a/js/src/jit/shared/BaseAssembler-x86-shared.h b/js/src/jit/shared/BaseAssembler-x86-shared.h index a93a71e3e220..76ae77fb7d4a 100644 --- a/js/src/jit/shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/shared/BaseAssembler-x86-shared.h @@ -2978,21 +2978,6 @@ public: m_formatter.prefix(PRE_SSE_F3); m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, address); } - - void movdqa_rm(XMMRegisterID src, const void* address) - { - spew("movdqa %s, %p", - nameFPReg(src), address); - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp(OP2_MOVDQ_WdqVdq, (RegisterID)src, address); - } - - void movaps_rm(XMMRegisterID src, const void* address) - { - spew("movaps %s, %p", - nameFPReg(src), address); - m_formatter.twoByteOp(OP2_MOVPS_WpsVps, (RegisterID)src, address); - } #else JmpSrc movsd_ripr(XMMRegisterID dst) { @@ -3018,29 +3003,6 @@ public: m_formatter.twoByteRipOp(OP2_MOVSD_WsdVsd, (RegisterID)src, 0); return JmpSrc(m_formatter.size()); } - JmpSrc movss_rrip(XMMRegisterID src) - { - spew("movss %s, ?(%%rip)", - nameFPReg(src)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteRipOp(OP2_MOVSD_WsdVsd, (RegisterID)src, 0); - return JmpSrc(m_formatter.size()); - } - JmpSrc movdqa_rrip(XMMRegisterID src) - { - spew("movdqa %s, ?(%%rip)", - nameFPReg(src)); - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteRipOp(OP2_MOVDQ_WdqVdq, (RegisterID)src, 0); - return JmpSrc(m_formatter.size()); - } - JmpSrc movaps_rrip(XMMRegisterID src) - { - spew("movaps %s, ?(%%rip)", - nameFPReg(src)); - m_formatter.twoByteRipOp(OP2_MOVPS_WpsVps, (RegisterID)src, 0); - return JmpSrc(m_formatter.size()); - } #endif void movaps_rr(XMMRegisterID src, XMMRegisterID dst) diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 568879f7f90c..dc7546795005 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -69,25 +69,25 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac if (!gen->compilingAsmJS()) masm.setInstrumentation(&sps_); + // Since asm.js uses the system ABI which does not necessarily use a + // regular array where all slots are sizeof(Value), it maintains the max + // argument stack depth separately. if (gen->compilingAsmJS()) { - // Since asm.js uses the system ABI which does not necessarily use a - // regular array where all slots are sizeof(Value), it maintains the max - // argument stack depth separately. JS_ASSERT(graph->argumentSlotCount() == 0); frameDepth_ += gen->maxAsmJSStackArgBytes(); - // If the function uses any SIMD, we may need to insert padding so that - // local slots are aligned for SIMD. - if (gen->usesSimd()) { - frameInitialAdjustment_ = ComputeByteAlignment(sizeof(AsmJSFrame), AsmJSStackAlignment); - frameDepth_ += frameInitialAdjustment_; - } - // An MAsmJSCall does not align the stack pointer at calls sites but instead - // relies on the a priori stack adjustment. This must be the last - // adjustment of frameDepth_. - if (gen->performsCall()) - frameDepth_ += ComputeByteAlignment(sizeof(AsmJSFrame) + frameDepth_, AsmJSStackAlignment); + // relies on the a priori stack adjustment (in the prologue) on platforms + // (like x64) which require the stack to be aligned. + if (StackKeptAligned || gen->performsCall() || gen->usesSimd()) { + unsigned alignmentAtCall = sizeof(AsmJSFrame) + frameDepth_; + unsigned firstFixup = 0; + if (unsigned rem = alignmentAtCall % StackAlignment) + frameDepth_ += (firstFixup = StackAlignment - rem); + + if (gen->usesSimd()) + setupSimdAlignment(firstFixup); + } // FrameSizeClass is only used for bailing, which cannot happen in // asm.js code. @@ -97,6 +97,38 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac } } +void +CodeGeneratorShared::setupSimdAlignment(unsigned fixup) +{ + JS_STATIC_ASSERT(SimdStackAlignment % StackAlignment == 0); + // At this point, we have: + // (frameDepth_ + sizeof(AsmJSFrame)) % StackAlignment == 0 + // which means we can add as many SimdStackAlignment as needed. + + // The next constraint is to have all stack slots + // aligned for SIMD. That's done by having the first stack slot + // aligned. We need an offset such that: + // (frameDepth_ - offset) % SimdStackAlignment == 0 + frameInitialAdjustment_ = frameDepth_ % SimdStackAlignment; + + // We need to ensure that the first stack slot is actually + // located in this frame and not beforehand, when taking this + // offset into account, i.e.: + // frameDepth_ - initial adjustment >= frameDepth_ - fixup + // <=> fixup >= initial adjustment + // + // For instance, on x86 with gcc, if the initial frameDepth + // % 16 is 8, then the fixup is 0, although the initial + // adjustment is 8. The first stack slot would be located at + // frameDepth - 8 in this case, which is obviously before + // frameDepth. + // + // If that's not the case, we add SimdStackAlignment to the + // fixup, which will keep on satisfying other constraints. + if (frameInitialAdjustment_ > int32_t(fixup)) + frameDepth_ += SimdStackAlignment; +} + bool CodeGeneratorShared::generateOutOfLineCode() { diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 24899fb2164d..35e6950b62f2 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -496,6 +496,8 @@ class CodeGeneratorShared : public LInstructionVisitor private: void generateInvalidateEpilogue(); + void setupSimdAlignment(unsigned fixup); + public: CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm); diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 1bb23233f948..92c7bc8d0986 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -319,26 +319,10 @@ CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins) if (ins->arg()->isConstant()) { masm.storePtr(ImmWord(ToInt32(ins->arg())), dst); } else { - if (ins->arg()->isGeneralReg()) { + if (ins->arg()->isGeneralReg()) masm.storePtr(ToRegister(ins->arg()), dst); - } else { - switch (mir->input()->type()) { - case MIRType_Double: - case MIRType_Float32: - masm.storeDouble(ToFloatRegister(ins->arg()), dst); - return true; - // StackPointer is SimdStackAlignment-aligned and ABIArgGenerator guarantees stack - // offsets are SimdStackAlignment-aligned. - case MIRType_Int32x4: - masm.storeAlignedInt32x4(ToFloatRegister(ins->arg()), dst); - return true; - case MIRType_Float32x4: - masm.storeAlignedFloat32x4(ToFloatRegister(ins->arg()), dst); - return true; - default: break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected mir type in AsmJSPassStackArg"); - } + else + masm.storeDouble(ToFloatRegister(ins->arg()), dst); } return true; } diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index c2868db3dccd..f2280705c8de 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -154,12 +154,6 @@ LIRGeneratorShared::defineReturn(LInstruction *lir, MDefinition *mir) case MIRType_Double: lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg))); break; - case MIRType_Int32x4: - lir->setDef(0, LDefinition(vreg, LDefinition::INT32X4, LFloatReg(ReturnSimdReg))); - break; - case MIRType_Float32x4: - lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32X4, LFloatReg(ReturnSimdReg))); - break; default: LDefinition::Type type = LDefinition::TypeFrom(mir->type()); JS_ASSERT(type != LDefinition::DOUBLE && type != LDefinition::FLOAT32); diff --git a/js/src/jit/x64/Assembler-x64.cpp b/js/src/jit/x64/Assembler-x64.cpp index 2970870eca54..c55d9dc66dd8 100644 --- a/js/src/jit/x64/Assembler-x64.cpp +++ b/js/src/jit/x64/Assembler-x64.cpp @@ -30,17 +30,8 @@ ABIArgGenerator::next(MIRType type) #if defined(XP_WIN) JS_STATIC_ASSERT(NumIntArgRegs == NumFloatArgRegs); if (regIndex_ == NumIntArgRegs) { - if (IsSimdType(type)) { - // On Win64, >64 bit args need to be passed by reference, but asm.js - // doesn't allow passing SIMD values to FFIs. The only way to reach - // here is asm to asm calls, so we can break the ABI here. - stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment); - current_ = ABIArg(stackOffset_); - stackOffset_ += Simd128DataSize; - } else { - stackOffset_ += sizeof(uint64_t); - current_ = ABIArg(stackOffset_); - } + current_ = ABIArg(stackOffset_); + stackOffset_ += sizeof(uint64_t); return current_; } switch (type) { @@ -52,13 +43,6 @@ ABIArgGenerator::next(MIRType type) case MIRType_Double: current_ = ABIArg(FloatArgRegs[regIndex_++]); break; - case MIRType_Int32x4: - case MIRType_Float32x4: - // On Win64, >64 bit args need to be passed by reference, but asm.js - // doesn't allow passing SIMD values to FFIs. The only way to reach - // here is asm to asm calls, so we can break the ABI here. - current_ = ABIArg(FloatArgRegs[regIndex_++]); - break; default: MOZ_CRASH("Unexpected argument type"); } @@ -83,16 +67,6 @@ ABIArgGenerator::next(MIRType type) } current_ = ABIArg(FloatArgRegs[floatRegIndex_++]); break; - case MIRType_Int32x4: - case MIRType_Float32x4: - if (floatRegIndex_ == NumFloatArgRegs) { - stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment); - current_ = ABIArg(stackOffset_); - stackOffset_ += Simd128DataSize; - break; - } - current_ = ABIArg(FloatArgRegs[floatRegIndex_++]); - break; default: MOZ_CRASH("Unexpected argument type"); } diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index bd633ada45f0..9d84a2492907 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -184,7 +184,10 @@ static MOZ_CONSTEXPR_VAR Register OsrFrameReg = IntArgReg3; static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx; -static const uint32_t ABIStackAlignment = 16; +// GCC stack is aligned on 16 bytes, but we don't maintain the invariant in +// jitted code. +static const uint32_t StackAlignment = 16; +static const bool StackKeptAligned = false; static const uint32_t CodeAlignment = 8; // This boolean indicates whether we support SIMD instructions flavoured for @@ -194,8 +197,6 @@ static const uint32_t CodeAlignment = 8; static const bool SupportsSimd = true; static const uint32_t SimdStackAlignment = 16; -static const uint32_t AsmJSStackAlignment = SimdStackAlignment; - static const Scale ScalePointer = TimesEight; } // namespace jit @@ -602,30 +603,12 @@ class Assembler : public AssemblerX86Shared CodeOffsetLabel loadRipRelativeDouble(FloatRegister dest) { return CodeOffsetLabel(masm.movsd_ripr(dest.code()).offset()); } - CodeOffsetLabel loadRipRelativeFloat32(FloatRegister dest) { - return CodeOffsetLabel(masm.movss_ripr(dest.code()).offset()); - } - CodeOffsetLabel loadRipRelativeInt32x4(FloatRegister dest) { - return CodeOffsetLabel(masm.movdqa_ripr(dest.code()).offset()); - } - CodeOffsetLabel loadRipRelativeFloat32x4(FloatRegister dest) { - return CodeOffsetLabel(masm.movaps_ripr(dest.code()).offset()); - } CodeOffsetLabel storeRipRelativeInt32(Register dest) { return CodeOffsetLabel(masm.movl_rrip(dest.code()).offset()); } CodeOffsetLabel storeRipRelativeDouble(FloatRegister dest) { return CodeOffsetLabel(masm.movsd_rrip(dest.code()).offset()); } - CodeOffsetLabel storeRipRelativeFloat32(FloatRegister dest) { - return CodeOffsetLabel(masm.movss_rrip(dest.code()).offset()); - } - CodeOffsetLabel storeRipRelativeInt32x4(FloatRegister dest) { - return CodeOffsetLabel(masm.movdqa_rrip(dest.code()).offset()); - } - CodeOffsetLabel storeRipRelativeFloat32x4(FloatRegister dest) { - return CodeOffsetLabel(masm.movaps_rrip(dest.code()).offset()); - } CodeOffsetLabel leaRipRelative(Register dest) { return CodeOffsetLabel(masm.leaq_rip(dest.code()).offset()); } diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index bb68322c99d6..048d7ee1fddb 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -349,32 +349,11 @@ CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins) { MAsmJSLoadGlobalVar *mir = ins->mir(); - MIRType type = mir->type(); - JS_ASSERT(IsNumberType(type) || IsSimdType(type)); - CodeOffsetLabel label; - switch (type) { - case MIRType_Int32: + if (mir->type() == MIRType_Int32) label = masm.loadRipRelativeInt32(ToRegister(ins->output())); - break; - case MIRType_Float32: - label = masm.loadRipRelativeFloat32(ToFloatRegister(ins->output())); - break; - case MIRType_Double: + else label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output())); - break; - // Aligned access: code is aligned on PageSize + there is padding - // before the global data section. - case MIRType_Int32x4: - label = masm.loadRipRelativeInt32x4(ToFloatRegister(ins->output())); - break; - case MIRType_Float32x4: - label = masm.loadRipRelativeFloat32x4(ToFloatRegister(ins->output())); - break; - default: - MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSLoadGlobalVar"); - } - masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } @@ -385,31 +364,13 @@ CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins) MAsmJSStoreGlobalVar *mir = ins->mir(); MIRType type = mir->value()->type(); - JS_ASSERT(IsNumberType(type) || IsSimdType(type)); + JS_ASSERT(IsNumberType(type)); CodeOffsetLabel label; - switch (type) { - case MIRType_Int32: + if (type == MIRType_Int32) label = masm.storeRipRelativeInt32(ToRegister(ins->value())); - break; - case MIRType_Float32: - label = masm.storeRipRelativeFloat32(ToFloatRegister(ins->value())); - break; - case MIRType_Double: + else label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value())); - break; - // Aligned access: code is aligned on PageSize + there is padding - // before the global data section. - case MIRType_Int32x4: - label = masm.storeRipRelativeInt32x4(ToFloatRegister(ins->value())); - break; - case MIRType_Float32x4: - label = masm.storeRipRelativeFloat32x4(ToFloatRegister(ins->value())); - break; - default: - MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSStoreGlobalVar"); - } - masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 49986e8c1f86..c87136f9dff9 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -200,7 +200,7 @@ MacroAssemblerX64::setupUnalignedABICall(uint32_t args, Register scratch) dynamicAlignment_ = true; movq(rsp, scratch); - andq(Imm32(~(ABIStackAlignment - 1)), rsp); + andq(Imm32(~(StackAlignment - 1)), rsp); push(scratch); } @@ -270,11 +270,11 @@ MacroAssemblerX64::callWithABIPre(uint32_t *stackAdjust) if (dynamicAlignment_) { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t), - ABIStackAlignment); + StackAlignment); } else { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + framePushed_, - ABIStackAlignment); + StackAlignment); } reserveStack(*stackAdjust); @@ -293,7 +293,7 @@ MacroAssemblerX64::callWithABIPre(uint32_t *stackAdjust) #ifdef DEBUG { Label good; - testq(rsp, Imm32(ABIStackAlignment - 1)); + testq(rsp, Imm32(StackAlignment - 1)); j(Equal, &good); breakpoint(); bind(&good); diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index cacaa5025fb7..583b25f0cdd5 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -551,6 +551,7 @@ JitRuntime::generateBailoutHandler(JSContext *cx, ExecutionMode mode) JitCode * JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { + JS_ASSERT(!StackKeptAligned); JS_ASSERT(functionWrappers_); JS_ASSERT(functionWrappers_->initialized()); VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f); diff --git a/js/src/jit/x86/Assembler-x86.cpp b/js/src/jit/x86/Assembler-x86.cpp index 15aba0dea5b3..bcdac920f180 100644 --- a/js/src/jit/x86/Assembler-x86.cpp +++ b/js/src/jit/x86/Assembler-x86.cpp @@ -19,26 +19,16 @@ ABIArgGenerator::ABIArgGenerator() ABIArg ABIArgGenerator::next(MIRType type) { + current_ = ABIArg(stackOffset_); switch (type) { case MIRType_Int32: case MIRType_Pointer: - current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); break; case MIRType_Float32: // Float32 moves are actually double moves case MIRType_Double: - current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); break; - case MIRType_Int32x4: - case MIRType_Float32x4: - // SIMD values aren't passed in or out of C++, so we can make up - // whatever internal ABI we like. visitAsmJSPassArg assumes - // SimdStackAlignment. - stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment); - current_ = ABIArg(stackOffset_); - stackOffset_ += Simd128DataSize; - break; default: MOZ_CRASH("Unexpected argument type"); } diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index fe1b329fa5ea..3067607ae515 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -108,13 +108,14 @@ static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = edi; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = eax; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = esi; -// GCC stack is aligned on 16 bytes. Ion does not maintain this for internal -// calls. asm.js code does. +// GCC stack is aligned on 16 bytes, but we don't maintain the invariant in +// jitted code. #if defined(__GNUC__) -static const uint32_t ABIStackAlignment = 16; +static const uint32_t StackAlignment = 16; #else -static const uint32_t ABIStackAlignment = 4; +static const uint32_t StackAlignment = 4; #endif +static const bool StackKeptAligned = false; static const uint32_t CodeAlignment = 8; // This boolean indicates whether we support SIMD instructions flavoured for @@ -124,8 +125,6 @@ static const uint32_t CodeAlignment = 8; static const bool SupportsSimd = true; static const uint32_t SimdStackAlignment = 16; -static const uint32_t AsmJSStackAlignment = SimdStackAlignment; - struct ImmTag : public Imm32 { ImmTag(JSValueTag mask) @@ -523,16 +522,6 @@ class Assembler : public AssemblerX86Shared masm.movsd_mr(src.addr, dest.code()); return CodeOffsetLabel(masm.currentOffset()); } - CodeOffsetLabel movdqaWithPatch(PatchedAbsoluteAddress src, FloatRegister dest) { - JS_ASSERT(HasSSE2()); - masm.movdqa_mr(src.addr, dest.code()); - return CodeOffsetLabel(masm.currentOffset()); - } - CodeOffsetLabel movapsWithPatch(PatchedAbsoluteAddress src, FloatRegister dest) { - JS_ASSERT(HasSSE2()); - masm.movaps_mr(src.addr, dest.code()); - return CodeOffsetLabel(masm.currentOffset()); - } // Store to *dest where dest can be patched. CodeOffsetLabel movbWithPatch(Register src, PatchedAbsoluteAddress dest) { @@ -557,16 +546,6 @@ class Assembler : public AssemblerX86Shared masm.movsd_rm(src.code(), dest.addr); return CodeOffsetLabel(masm.currentOffset()); } - CodeOffsetLabel movdqaWithPatch(FloatRegister src, PatchedAbsoluteAddress dest) { - JS_ASSERT(HasSSE2()); - masm.movdqa_rm(src.code(), dest.addr); - return CodeOffsetLabel(masm.currentOffset()); - } - CodeOffsetLabel movapsWithPatch(FloatRegister src, PatchedAbsoluteAddress dest) { - JS_ASSERT(HasSSE2()); - masm.movaps_rm(src.code(), dest.addr); - return CodeOffsetLabel(masm.currentOffset()); - } void loadAsmJSActivation(Register dest) { CodeOffsetLabel label = movlWithPatch(PatchedAbsoluteAddress(), dest); diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index 8a5d303defe9..adfd2ae2370b 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -462,30 +462,15 @@ CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins) { MAsmJSLoadGlobalVar *mir = ins->mir(); MIRType type = mir->type(); - JS_ASSERT(IsNumberType(type) || IsSimdType(type)); + JS_ASSERT(IsNumberType(type)); CodeOffsetLabel label; - switch (type) { - case MIRType_Int32: + if (type == MIRType_Int32) label = masm.movlWithPatch(PatchedAbsoluteAddress(), ToRegister(ins->output())); - break; - case MIRType_Float32: + else if (type == MIRType_Float32) label = masm.movssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); - break; - case MIRType_Double: + else label = masm.movsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); - break; - // Aligned access: code is aligned on PageSize + there is padding - // before the global data section. - case MIRType_Int32x4: - label = masm.movdqaWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); - break; - case MIRType_Float32x4: - label = masm.movapsWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output())); - break; - default: - MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSLoadGlobalVar"); - } masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } @@ -496,30 +481,15 @@ CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins) MAsmJSStoreGlobalVar *mir = ins->mir(); MIRType type = mir->value()->type(); - JS_ASSERT(IsNumberType(type) || IsSimdType(type)); + JS_ASSERT(IsNumberType(type)); CodeOffsetLabel label; - switch (type) { - case MIRType_Int32: + if (type == MIRType_Int32) label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress()); - break; - case MIRType_Float32: + else if (type == MIRType_Float32) label = masm.movssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); - break; - case MIRType_Double: + else label = masm.movsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); - break; - // Aligned access: code is aligned on PageSize + there is padding - // before the global data section. - case MIRType_Int32x4: - label = masm.movdqaWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); - break; - case MIRType_Float32x4: - label = masm.movapsWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress()); - break; - default: - MOZ_ASSUME_UNREACHABLE("unexpected type in visitAsmJSStoreGlobalVar"); - } masm.append(AsmJSGlobalAccess(label, mir->globalDataOffset())); return true; } diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 23d1224fa1e0..90e94db0844d 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -227,7 +227,7 @@ MacroAssemblerX86::setupUnalignedABICall(uint32_t args, Register scratch) dynamicAlignment_ = true; movl(esp, scratch); - andl(Imm32(~(ABIStackAlignment - 1)), esp); + andl(Imm32(~(StackAlignment - 1)), esp); push(scratch); } @@ -267,11 +267,11 @@ MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust) if (dynamicAlignment_) { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t), - ABIStackAlignment); + StackAlignment); } else { *stackAdjust = stackForCall_ + ComputeByteAlignment(stackForCall_ + framePushed_, - ABIStackAlignment); + StackAlignment); } reserveStack(*stackAdjust); @@ -291,7 +291,7 @@ MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust) { // Check call alignment. Label good; - testl(esp, Imm32(ABIStackAlignment - 1)); + testl(esp, Imm32(StackAlignment - 1)); j(Equal, &good); breakpoint(); bind(&good); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 808fe7de0a2d..9ee84f2a476e 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -590,6 +590,7 @@ JitRuntime::generateBailoutHandler(JSContext *cx, ExecutionMode mode) JitCode * JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { + JS_ASSERT(!StackKeptAligned); JS_ASSERT(functionWrappers_); JS_ASSERT(functionWrappers_->initialized()); VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f); diff --git a/js/src/js.msg b/js/src/js.msg index 3a1cbc16f7f1..ab6a265feb3f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -291,7 +291,6 @@ MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function") MSG_DEF(JSMSG_SYNTAX_ERROR, 0, JSEXN_SYNTAXERR, "syntax error") MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string") -MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 0, JSEXN_TYPEERR, "value isn't a SIMD value object") MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases") MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables") MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments") diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 1e27edc03731..59b79a0e8253 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -295,7 +295,6 @@ struct ThreadSafeContext : ContextFriendFields, bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); } bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); } bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; } - bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; } // Thread local data that may be accessed freely. DtoaState *dtoaState() { diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 346e7c04c71f..9371afaa7a1e 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -211,7 +211,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) wrapObjectCallbacks(&DefaultWrapObjectCallbacks), preserveWrapperCallback(nullptr), jitSupportsFloatingPoint(false), - jitSupportsSimd(false), ionPcScriptCache(nullptr), threadPool(this), defaultJSContextCallback(nullptr), @@ -316,7 +315,6 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) nativeStackBase = GetNativeStackBase(); jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint(); - jitSupportsSimd = js::jit::JitSupportsSimd(); signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this); canUseSignalHandlers_ = signalHandlersInstalled_ && !SignalBasedTriggersDisabled(); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 784e3b1d45ca..7daa9bbaa25c 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1274,7 +1274,6 @@ struct JSRuntime : public JS::shadow::Runtime, } bool jitSupportsFloatingPoint; - bool jitSupportsSimd; // Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1) // has been noticed by Ion/Baseline. diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 2abd6a942f8e..b6de66540be9 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1550,7 +1550,7 @@ jit::JitActivation::markRematerializedFrames(JSTracer *trc) AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) : Activation(cx, AsmJS), module_(module), - entrySP_(nullptr), + errorRejoinSP_(nullptr), profiler_(nullptr), resumePC_(nullptr), fp_(nullptr), @@ -1573,7 +1573,7 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) JSRuntime::AutoLockForInterrupt lock(cx->runtime()); cx->mainThread().asmJSActivationStack_ = this; - (void) entrySP_; // squelch GCC warning + (void) errorRejoinSP_; // squelch GCC warning } AsmJSActivation::~AsmJSActivation() diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 0f9b2b0bd676..d1bfab36d587 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1482,7 +1482,7 @@ class AsmJSActivation : public Activation AsmJSModule &module_; AsmJSActivation *prevAsmJS_; AsmJSActivation *prevAsmJSForModule_; - void *entrySP_; + void *errorRejoinSP_; SPSProfiler *profiler_; void *resumePC_; uint8_t *fp_; @@ -1512,7 +1512,7 @@ class AsmJSActivation : public Activation static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); } // Written by JIT code: - static unsigned offsetOfEntrySP() { return offsetof(AsmJSActivation, entrySP_); } + static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); } static unsigned offsetOfFP() { return offsetof(AsmJSActivation, fp_); } static unsigned offsetOfExitReason() { return offsetof(AsmJSActivation, exitReason_); } From 5eb77c79f7f2cb1ff026ccc07020cca6d1bb6c76 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 11:26:07 -0400 Subject: [PATCH 067/120] Bug 1059765: enable content metrics for H.264 r=gcp --- media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc index 2c877f9ff4ff..6f3550708a9a 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc @@ -705,7 +705,8 @@ void ViEEncoder::DeliverFrame(int id, return; } #endif - if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) { + if (vcm_.AddVideoFrame(*decimated_frame, + vpm_.ContentMetrics()) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), From ece9d13eb1018fc86ab6eedbcffe4e4b53c1c61e Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 11:26:34 -0400 Subject: [PATCH 068/120] Bug 1059765: handle incoming resolution changes in GMP video encode r=pkerr --- .../src/media-conduit/WebrtcGmpVideoCodec.cpp | 60 ++++++++++++++----- .../src/media-conduit/WebrtcGmpVideoCodec.h | 2 + 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp index 83d40507689c..58c52177af54 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp @@ -143,12 +143,13 @@ WebrtcGmpVideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores, uint32_t aMaxPayloadSize) { - mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + if (!mMPS) { + mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + } MOZ_ASSERT(mMPS); if (!mGMPThread) { if (NS_WARN_IF(NS_FAILED(mMPS->GetThread(getter_AddRefs(mGMPThread))))) { - mMPS = nullptr; return WEBRTC_VIDEO_CODEC_ERROR; } } @@ -182,31 +183,30 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings, mHost = nullptr; return WEBRTC_VIDEO_CODEC_ERROR; } - mMPS = nullptr; if (!mGMP || !mHost) { return WEBRTC_VIDEO_CODEC_ERROR; } // Bug XXXXXX: transfer settings from codecSettings to codec. - GMPVideoCodec codec; - memset(&codec, 0, sizeof(codec)); + memset(&mCodecParams, 0, sizeof(mCodecParams)); - codec.mGMPApiVersion = 33; - codec.mWidth = aCodecSettings->width; - codec.mHeight = aCodecSettings->height; - codec.mStartBitrate = aCodecSettings->startBitrate; - codec.mMinBitrate = aCodecSettings->minBitrate; - codec.mMaxBitrate = aCodecSettings->maxBitrate; - codec.mMaxFramerate = aCodecSettings->maxFramerate; + mCodecParams.mGMPApiVersion = 33; + mCodecParams.mWidth = aCodecSettings->width; + mCodecParams.mHeight = aCodecSettings->height; + mCodecParams.mStartBitrate = aCodecSettings->startBitrate; + mCodecParams.mMinBitrate = aCodecSettings->minBitrate; + mCodecParams.mMaxBitrate = aCodecSettings->maxBitrate; + mCodecParams.mMaxFramerate = aCodecSettings->maxFramerate; + mMaxPayloadSize = aMaxPayloadSize; if (aCodecSettings->codecSpecific.H264.packetizationMode == 1) { - aMaxPayloadSize = 4*1024*1024; // insanely large + mMaxPayloadSize = 4*1024*1024; // insanely large } // Pass dummy codecSpecific data for now... nsTArray codecSpecific; - GMPErr err = mGMP->InitEncode(codec, codecSpecific, this, 1, aMaxPayloadSize); + GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize); if (err != GMPNoErr) { return WEBRTC_VIDEO_CODEC_ERROR; } @@ -245,6 +245,38 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage, return WEBRTC_VIDEO_CODEC_ERROR; } + if (aInputImage->width() != mCodecParams.mWidth || + aInputImage->height() != mCodecParams.mHeight) { + LOGD(("GMP Encode: resolution change from %ux%u to %ux%u", + mCodecParams.mWidth, mCodecParams.mHeight, aInputImage->width(), aInputImage->height())); + + mGMP->Close(); + + // OpenH264 codec (at least) can't handle dynamic input resolution changes + // re-init the plugin when the resolution changes + // XXX allow codec to indicate it doesn't need re-init! + nsTArray tags; + tags.AppendElement(NS_LITERAL_CSTRING("h264")); + if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags, + NS_LITERAL_STRING(""), + &mHost, + &mGMP)))) { + mGMP = nullptr; + mHost = nullptr; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + mCodecParams.mWidth = aInputImage->width(); + mCodecParams.mHeight = aInputImage->height(); + // Pass dummy codecSpecific data for now... + nsTArray codecSpecific; + + GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize); + if (err != GMPNoErr) { + return WEBRTC_VIDEO_CODEC_ERROR; + } + } + GMPVideoFrame* ftmp = nullptr; GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp); if (err != GMPNoErr) { diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h index bafc7dec3c21..47b68bc93c8d 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h @@ -92,6 +92,8 @@ private: nsCOMPtr mGMPThread; GMPVideoEncoderProxy* mGMP; GMPVideoHost* mHost; + GMPVideoCodec mCodecParams; + uint32_t mMaxPayloadSize; webrtc::EncodedImageCallback* mCallback; uint64_t mCachedPluginId; }; From 2a2f6b1b89380707af70d0e03c996d1e29854ff6 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 21:29:17 -0400 Subject: [PATCH 069/120] Bug 1049087: set temporary allowed screensharing domain of mozilla.github.io - replace for release r=gcp --- modules/libpref/init/all.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 21a5ba01b5fb..ec65c9eb01a4 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -371,7 +371,12 @@ pref("media.navigator.enabled", true); #endif pref("media.getusermedia.screensharing.enabled", true); +#ifdef RELEASE_BUILD pref("media.getusermedia.screensharing.allowed_domains", ""); +#else + // temporary value, not intended for release - bug 1049087 +pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io"); +#endif // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); From 53878161ceeb97aef4f0fcfd485112921642a14f Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 21:29:17 -0400 Subject: [PATCH 070/120] Bug 1060249: disable frame motion/complexity analysis in webrtc on Gonk r=gcp --- .../modules/video_coding/main/source/qm_select.cc | 11 +++++++++++ .../video_processing/main/source/content_analysis.cc | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc index 72f408beee32..cd36fc059b14 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/qm_select.cc @@ -60,6 +60,10 @@ void VCMQmMethod::UpdateContent(const VideoContentMetrics* contentMetrics) { } void VCMQmMethod::ComputeMotionNFD() { +#if defined(WEBRTC_GONK) + motion_.value = (kHighMotionNfd + kLowMotionNfd)/2; + motion_.level = kDefault; +#else if (content_metrics_) { motion_.value = content_metrics_->motion_magnitude; } @@ -71,9 +75,15 @@ void VCMQmMethod::ComputeMotionNFD() { } else { motion_.level = kDefault; } +#endif } void VCMQmMethod::ComputeSpatial() { +#if defined(WEBRTC_GONK) + float scale2 = image_type_ > kVGA ? kScaleTexture : 1.0; + spatial_.value = (kHighTexture + kLowTexture)*scale2/2; + spatial_.level = kDefault; +#else float spatial_err = 0.0; float spatial_err_h = 0.0; float spatial_err_v = 0.0; @@ -95,6 +105,7 @@ void VCMQmMethod::ComputeSpatial() { } else { spatial_.level = kDefault; } +#endif } ImageType VCMQmMethod::GetImageType(uint16_t width, diff --git a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc index 981e0e606a87..6d777116239c 100644 --- a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc +++ b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/content_analysis.cc @@ -58,6 +58,7 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( if (VPM_OK != Initialize(inputFrame.width(), inputFrame.height())) return NULL; } +#if !defined(WEBRTC_GONK) // Compute motion metrics if (ca_Init_) { // Only interested in the Y plane. @@ -75,6 +76,7 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( first_frame_ = false; } +#endif return ContentMetrics(); } @@ -123,10 +125,12 @@ int32_t VPMContentAnalysis::Initialize(int width, int height) { return VPM_MEMORY; } +#if !defined(WEBRTC_GONK) prev_frame_.reset(new uint8_t[width_ * height_]); // Y only. if (!prev_frame_) { return VPM_MEMORY; } +#endif // ok, all initialized ca_Init_ = true; From 00a116cb2538f1ee595ce2d2fb5f556fe23f5301 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 29 Aug 2014 21:29:18 -0400 Subject: [PATCH 071/120] Bug 1056350: Make H.264 Level configurable and change OpenH264 default to 3.1 r=bwc --- .../signaling/src/media/VcmSIPCCBinding.cpp | 31 +++++++++++-------- .../webrtc/signaling/src/sipcc/include/vcm.h | 5 +-- modules/libpref/init/all.js | 2 ++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp index 577e9baa322b..cf8469823c26 100644 --- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp +++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp @@ -1719,12 +1719,11 @@ static int vcmEnsureExternalCodec( // Register H.264 codec. if (send) { - VideoEncoder* encoder = nullptr; + VideoEncoder* encoder = nullptr; #ifdef MOZ_WEBRTC_OMX - encoder = OMXVideoCodec::CreateEncoder( - OMXVideoCodec::CodecType::CODEC_H264); + encoder = OMXVideoCodec::CreateEncoder(OMXVideoCodec::CodecType::CODEC_H264); #else - encoder = mozilla::GmpVideoCodec::CreateEncoder(); + encoder = mozilla::GmpVideoCodec::CreateEncoder(); #endif if (encoder) { return conduit->SetExternalSendCodec(config, encoder); @@ -2311,16 +2310,15 @@ int vcmGetH264SupportedPacketizationModes() */ uint32_t vcmGetVideoH264ProfileLevelID() { - // constrained baseline level 1.2 - // XXX make variable based on openh264 and OMX support -#ifdef MOZ_WEBRTC_OMX + // For OMX, constrained baseline level 1.2 (via a pref) // Max resolution CIF; we should include max-mbps - return 0x42E00C; -#else - // XXX See bug 1043515 - we may want to support a higher profile than - // 1.3, depending on hardware(?) - return 0x42E00D; -#endif + int32_t level = 13; // minimum suggested for WebRTC spec + + vcmGetVideoLevel(0, &level); + level &= 0xFF; + level |= 0x42E000; + + return (uint32_t) level; } /** @@ -2786,6 +2784,13 @@ static short vcmGetVideoPref(uint16_t codec, return VCM_ERROR; } +short vcmGetVideoLevel(uint16_t codec, + int32_t *level) { + return vcmGetVideoPref(codec, + "media.navigator.video.h264.level", + level); +} + short vcmGetVideoMaxFs(uint16_t codec, int32_t *max_fs) { return vcmGetVideoPref(codec, diff --git a/media/webrtc/signaling/src/sipcc/include/vcm.h b/media/webrtc/signaling/src/sipcc/include/vcm.h index 4b498e22a963..f23dff720123 100755 --- a/media/webrtc/signaling/src/sipcc/include/vcm.h +++ b/media/webrtc/signaling/src/sipcc/include/vcm.h @@ -1083,14 +1083,11 @@ int vcmOnSdpParseError(const char *peercconnection, const char *message); */ int vcmDisableRtcpComponent(const char *peerconnection, int level); +short vcmGetVideoLevel(uint16_t codec, int32_t *level); short vcmGetVideoMaxFs(uint16_t codec, int32_t *max_fs); - short vcmGetVideoMaxFr(uint16_t codec, int32_t *max_fr); - short vcmGetVideoMaxBr(uint16_t codec, int32_t *max_br); - short vcmGetVideoMaxMbps(uint16_t codec, int32_t *max_mbps); - short vcmGetVideoPreferredCodec(int32_t *preferred_codec); //Using C++ for gips. This is the end of extern "C" above. diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index ec65c9eb01a4..3e9a7d9d4f7d 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -303,6 +303,7 @@ pref("media.peerconnection.enabled", true); pref("media.peerconnection.video.enabled", true); pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb pref("media.navigator.video.max_fr", 30); +pref("media.navigator.video.h264.level", 12); // 0x42E00C - level 1.2 pref("media.navigator.video.h264.max_br", 700); // 8x10 pref("media.navigator.video.h264.max_mbps", 11880); // CIF@30fps pref("media.peerconnection.video.h264_enabled", false); @@ -314,6 +315,7 @@ pref("media.peerconnection.enabled", true); pref("media.peerconnection.video.enabled", true); pref("media.navigator.video.max_fs", 0); // unrestricted pref("media.navigator.video.max_fr", 0); // unrestricted +pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1 pref("media.navigator.video.h264.max_br", 0); pref("media.navigator.video.h264.max_mbps", 0); pref("media.peerconnection.video.h264_enabled", false); From a4ddaa8f723e9970bc2b4a7d2e059fa7dfde78b3 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 29 Aug 2014 21:49:56 -0700 Subject: [PATCH 072/120] Bug 1052240 - Skip textures/texture-npot-video.html. --- dom/canvas/test/webgl-conformance/_mochitest.ini | 1 + dom/canvas/test/webgl-conformance/mochitest-errata.ini | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/dom/canvas/test/webgl-conformance/_mochitest.ini b/dom/canvas/test/webgl-conformance/_mochitest.ini index 0fb51da04903..57b92921df99 100644 --- a/dom/canvas/test/webgl-conformance/_mochitest.ini +++ b/dom/canvas/test/webgl-conformance/_mochitest.ini @@ -761,6 +761,7 @@ skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') [_wrappers/test_conformance__textures__texture-formats-test.html] [_wrappers/test_conformance__textures__texture-mips.html] [_wrappers/test_conformance__textures__texture-npot-video.html] +skip-if = os == 'win' [_wrappers/test_conformance__textures__texture-npot.html] [_wrappers/test_conformance__textures__texture-size.html] skip-if = os == 'android' diff --git a/dom/canvas/test/webgl-conformance/mochitest-errata.ini b/dom/canvas/test/webgl-conformance/mochitest-errata.ini index db50357e2f1d..b2ca3b2c5ea8 100644 --- a/dom/canvas/test/webgl-conformance/mochitest-errata.ini +++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini @@ -82,3 +82,9 @@ skip-if = (os == 'b2g') [_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html] # Intermittent crash on OSX. skip-if = os == 'mac' + +######################################################################## +# Win +[_wrappers/test_conformance__textures__texture-npot-video.html] +# Intermittant crash on Windows +skip-if = os == 'win' From 67df248e7600f16673d6fc2385fe07b429001873 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 30 Aug 2014 00:56:35 -0400 Subject: [PATCH 073/120] Bug 908390 followup. Fix up event timestamps on workers, and enable the test that was supposed to test for it. r=khuey pending --- dom/events/Event.cpp | 8 +++----- dom/events/test/test_eventTimeStamp.html | 18 ++++++------------ dom/workers/WorkerPrivate.cpp | 6 +++--- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index e0e53496bcb0..ff96b4acfde6 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -997,16 +997,14 @@ Event::TimeStamp() const } // For dedicated workers, we should make times relative to the navigation - // start of the document that created the worker. We currently don't have - // that information handy so for now we treat shared workers and dedicated - // workers alike and make times relative to the worker creation time. We can - // fix this when we implement WorkerPerformance. + // start of the document that created the worker, which is the same as the + // timebase for performance.now(). workers::WorkerPrivate* workerPrivate = workers::GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); TimeDuration duration = - mEvent->timeStamp - workerPrivate->CreationTimeStamp(); + mEvent->timeStamp - workerPrivate->NowBaseTimeStamp(); return duration.ToMilliseconds(); } diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html index ccb15cd7f8a7..bcf1bcb8d4c7 100644 --- a/dom/events/test/test_eventTimeStamp.html +++ b/dom/events/test/test_eventTimeStamp.html @@ -16,14 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
 
 
 

From d97f20d1cc3175fbeaee0fe47f257e0174a32200 Mon Sep 17 00:00:00 2001
From: Girish Sharma 
Date: Fri, 29 Aug 2014 18:24:52 +0530
Subject: [PATCH 096/120] Bug 970517 - Storage Inspector fron end - tests,
 r=jwalker

---
 browser/devtools/storage/moz.build            |   2 +
 browser/devtools/storage/test/browser.ini     |  15 +
 .../storage/test/browser_storage_basic.js     | 114 ++++
 .../test/browser_storage_dynamic_updates.js   | 211 ++++++++
 .../storage/test/browser_storage_sidebar.js   |  67 +++
 .../storage/test/browser_storage_values.js    | 143 +++++
 browser/devtools/storage/test/head.js         | 499 ++++++++++++++++++
 browser/devtools/storage/test/moz.build       |   8 +
 .../storage/test/storage-complex-values.html  |  99 ++++
 .../storage/test/storage-listings.html        |  94 ++++
 .../storage/test/storage-secured-iframe.html  |  71 +++
 .../test/storage-unsecured-iframe.html        |  27 +
 .../storage/test/storage-updates.html         |  63 +++
 browser/devtools/storage/ui.js                |   2 +-
 14 files changed, 1414 insertions(+), 1 deletion(-)
 create mode 100644 browser/devtools/storage/test/browser.ini
 create mode 100644 browser/devtools/storage/test/browser_storage_basic.js
 create mode 100644 browser/devtools/storage/test/browser_storage_dynamic_updates.js
 create mode 100644 browser/devtools/storage/test/browser_storage_sidebar.js
 create mode 100644 browser/devtools/storage/test/browser_storage_values.js
 create mode 100644 browser/devtools/storage/test/head.js
 create mode 100644 browser/devtools/storage/test/moz.build
 create mode 100644 browser/devtools/storage/test/storage-complex-values.html
 create mode 100644 browser/devtools/storage/test/storage-listings.html
 create mode 100644 browser/devtools/storage/test/storage-secured-iframe.html
 create mode 100644 browser/devtools/storage/test/storage-unsecured-iframe.html
 create mode 100644 browser/devtools/storage/test/storage-updates.html

diff --git a/browser/devtools/storage/moz.build b/browser/devtools/storage/moz.build
index 05c05935e9fd..d9176eb33c5a 100644
--- a/browser/devtools/storage/moz.build
+++ b/browser/devtools/storage/moz.build
@@ -4,6 +4,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/.
 
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
 EXTRA_JS_MODULES.devtools.storage += [
     'panel.js',
     'ui.js'
diff --git a/browser/devtools/storage/test/browser.ini b/browser/devtools/storage/test/browser.ini
new file mode 100644
index 000000000000..fdd555d30316
--- /dev/null
+++ b/browser/devtools/storage/test/browser.ini
@@ -0,0 +1,15 @@
+[DEFAULT]
+skip-if = e10s # Bug 1049888 - storage actors do not work in e10s for now
+subsuite = devtools
+support-files =
+  storage-complex-values.html
+  storage-listings.html
+  storage-secured-iframe.html
+  storage-unsecured-iframe.html
+  storage-updates.html
+  head.js
+
+[browser_storage_basic.js]
+[browser_storage_dynamic_updates.js]
+[browser_storage_sidebar.js]
+[browser_storage_values.js]
diff --git a/browser/devtools/storage/test/browser_storage_basic.js b/browser/devtools/storage/test/browser_storage_basic.js
new file mode 100644
index 000000000000..b1e3ce02dc75
--- /dev/null
+++ b/browser/devtools/storage/test/browser_storage_basic.js
@@ -0,0 +1,114 @@
+/* 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/. */
+
+// Basic test to assert that the storage tree and table corresponding to each
+// item in the storage tree is correctly displayed
+
+// Entries that should be present in the tree for this test
+// Format for each entry in the array :
+// [
+//   ["path", "to", "tree", "item"], - The path to the tree item to click formed
+//                                     by id of each item
+//   ["key_value1", "key_value2", ...] - The value of the first (unique) column
+//                                       for each row in the table corresponding
+//                                       to the tree item selected.
+// ]
+// These entries are formed by the cookies, local storage, session storage and
+// indexedDB entries created in storage-listings.html,
+// storage-secured-iframe.html and storage-unsecured-iframe.html
+const storeItems = [
+  [["cookies", "test1.example.org"],
+   ["c1", "cs2", "c3", "uc1"]],
+  [["cookies", "sectest1.example.org"],
+   ["uc1", "cs2", "sc1"]],
+  [["localStorage", "http://test1.example.org"],
+   ["ls1", "ls2"]],
+  [["localStorage", "http://sectest1.example.org"],
+   ["iframe-u-ls1"]],
+  [["localStorage", "https://sectest1.example.org"],
+   ["iframe-s-ls1"]],
+  [["sessionStorage", "http://test1.example.org"],
+   ["ss1"]],
+  [["sessionStorage", "http://sectest1.example.org"],
+   ["iframe-u-ss1", "iframe-u-ss2"]],
+  [["sessionStorage", "https://sectest1.example.org"],
+   ["iframe-s-ss1"]],
+  [["indexedDB", "http://test1.example.org"],
+   ["idb1", "idb2"]],
+  [["indexedDB", "http://test1.example.org", "idb1"],
+   ["obj1", "obj2"]],
+  [["indexedDB", "http://test1.example.org", "idb2"],
+   ["obj3"]],
+  [["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+   [1, 2, 3]],
+  [["indexedDB", "http://test1.example.org", "idb1", "obj2"],
+   [1]],
+  [["indexedDB", "http://test1.example.org", "idb2", "obj3"],
+   []],
+  [["indexedDB", "http://sectest1.example.org"],
+   []],
+  [["indexedDB", "https://sectest1.example.org"],
+   ["idb-s1", "idb-s2"]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s1"],
+   ["obj-s1"]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s2"],
+   ["obj-s2"]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s1", "obj-s1"],
+   [6, 7]],
+  [["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
+   [16]],
+];
+
+/**
+ * Test that the desired number of tree items are present
+ */
+function testTree() {
+  let doc = gPanelWindow.document;
+  for (let item of storeItems) {
+    ok(doc.querySelector("[data-id='" + JSON.stringify(item[0]) + "']"),
+       "Tree item " + item[0] + " should be present in the storage tree");
+  }
+}
+
+/**
+ * Test that correct table entries are shown for each of the tree item
+ */
+let testTables = Task.async(function*() {
+  let doc = gPanelWindow.document;
+  // Expand all nodes so that the synthesized click event actually works
+  gUI.tree.expandAll();
+
+  // First tree item is already selected so no clicking and waiting for update
+  for (let id of storeItems[0][1]) {
+    ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
+       "Table item " + id + " should be present");
+  }
+
+  // Click rest of the tree items and wait for the table to be updated
+  for (let item of storeItems.slice(1)) {
+    selectTreeItem(item[0]);
+    yield gUI.once("store-objects-updated");
+
+    // Check whether correct number of items are present in the table
+    is(doc.querySelectorAll(
+         ".table-widget-wrapper:first-of-type .table-widget-cell"
+       ).length, item[1].length, "Number of items in table is correct");
+
+    // Check if all the desired items are present in the table
+    for (let id of item[1]) {
+      ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
+         "Table item " + id + " should be present");
+    }
+  }
+});
+
+let startTest = Task.async(function*() {
+  testTree();
+  yield testTables();
+  finishTests();
+});
+
+function test() {
+  openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html").then(startTest);
+}
diff --git a/browser/devtools/storage/test/browser_storage_dynamic_updates.js b/browser/devtools/storage/test/browser_storage_dynamic_updates.js
new file mode 100644
index 000000000000..14fc88581b77
--- /dev/null
+++ b/browser/devtools/storage/test/browser_storage_dynamic_updates.js
@@ -0,0 +1,211 @@
+/* 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/. */
+
+let testUpdates = Task.async(function*() {
+
+  let $ = id => gPanelWindow.document.querySelector(id);
+  let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
+
+  gUI.tree.expandAll();
+
+  ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
+  selectTableItem("c1");
+  yield gUI.once("sidebar-updated");
+
+  // test that value is something initially
+  let initialValue = [[
+    {name: "c1", value: "1.2.3.4.5.6.7"},
+    {name: "c1.path", value: "/browser"}
+  ],[
+    {name: "c1", value: "Array"},
+    {name: "c1.0", value: "1"},
+    {name: "c1.6", value: "7"}
+  ]];
+
+  // test that value is something initially
+  let finalValue = [[
+    {name: "c1", value: '{"foo": 4,"bar":6}'},
+    {name: "c1.path", value: "/browser"}
+  ],[
+    {name: "c1", value: "Object"},
+    {name: "c1.foo", value: "4"},
+    {name: "c1.bar", value: "6"}
+  ]];
+  // Check that sidebar shows correct initial value
+  yield findVariableViewProperties(initialValue[0], false);
+  yield findVariableViewProperties(initialValue[1], true);
+  // Check if table shows correct initial value
+  ok($("#value [data-id='c1'].table-widget-cell"), "cell is present");
+  is($("#value [data-id='c1'].table-widget-cell").value, "1.2.3.4.5.6.7",
+       "correct initial value in table");
+  gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
+  yield gUI.once("sidebar-updated");
+
+  yield findVariableViewProperties(finalValue[0], false);
+  yield findVariableViewProperties(finalValue[1], true);
+  ok($("#value [data-id='c1'].table-widget-cell"), "cell is present after update");
+  is($("#value [data-id='c1'].table-widget-cell").value, '{"foo": 4,"bar":6}',
+       "correct final value in table");
+
+  // Add a new entry
+  is($$("#value .table-widget-cell").length, 2,
+     "Correct number of rows before update 0");
+
+  gWindow.addCookie("c3", "booyeah");
+
+  // Wait once for update and another time for value fetching
+  yield gUI.once("store-objects-updated");
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 3,
+     "Correct number of rows after update 1");
+
+  // Add another
+  gWindow.addCookie("c4", "booyeah");
+
+  // Wait once for update and another time for value fetching
+  yield gUI.once("store-objects-updated");
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 4,
+     "Correct number of rows after update 2");
+
+  // Removing cookies
+  gWindow.removeCookie("c1", "/browser");
+
+  yield gUI.once("sidebar-updated");
+
+  is($$("#value .table-widget-cell").length, 3,
+     "Correct number of rows after delete update 3");
+
+  ok(!$("#c1"), "Correct row got deleted");
+
+  ok(!gUI.sidebar.hidden, "Sidebar still visible for next row");
+
+  // Check if next element's value is visible in sidebar
+  yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
+
+  // Keep deleting till no rows
+
+  gWindow.removeCookie("c3");
+
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 2,
+     "Correct number of rows after delete update 4");
+
+  // Check if next element's value is visible in sidebar
+  yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
+
+  gWindow.removeCookie("c2", "/browser");
+
+  yield gUI.once("sidebar-updated");
+
+  yield findVariableViewProperties([{name: "c4", value: "booyeah"}]);
+
+  is($$("#value .table-widget-cell").length, 1,
+     "Correct number of rows after delete update 5");
+
+  gWindow.removeCookie("c4");
+
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 0,
+     "Correct number of rows after delete update 6");
+  ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
+
+  // Testing in local storage
+  selectTreeItem(["localStorage", "http://test1.example.org"]);
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 7,
+     "Correct number of rows after delete update 7");
+
+  ok($(".table-widget-cell[data-id='ls4']"), "ls4 exists before deleting");
+
+  gWindow.localStorage.removeItem("ls4");
+
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 6,
+     "Correct number of rows after delete update 8");
+  ok(!$(".table-widget-cell[data-id='ls4']"),
+     "ls4 does not exists after deleting");
+
+  gWindow.localStorage.setItem("ls4", "again");
+
+  yield gUI.once("store-objects-updated");
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 7,
+     "Correct number of rows after delete update 9");
+  ok($(".table-widget-cell[data-id='ls4']"),
+     "ls4 came back after adding it again");
+
+  // Updating a row
+  gWindow.localStorage.setItem("ls2", "ls2-changed");
+
+  yield gUI.once("store-objects-updated");
+  yield gUI.once("store-objects-updated");
+
+  is($("#value [data-id='ls2']").value, "ls2-changed",
+      "Value got updated for local storage");
+
+  // Testing in session storage
+  selectTreeItem(["sessionStorage", "http://test1.example.org"]);
+
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 3,
+     "Correct number of rows for session storage");
+
+  gWindow.sessionStorage.setItem("ss4", "new-item");
+
+  yield gUI.once("store-objects-updated");
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 4,
+     "Correct number of rows after session storage update");
+
+  // deleting item
+
+  gWindow.sessionStorage.removeItem("ss3");
+
+  yield gUI.once("store-objects-updated");
+
+  gWindow.sessionStorage.removeItem("ss1");
+
+  yield gUI.once("store-objects-updated");
+
+  is($$("#value .table-widget-cell").length, 2,
+     "Correct number of rows after removing items from session storage");
+
+  selectTableItem("ss2");
+
+  yield gUI.once("sidebar-updated");
+
+  ok(!gUI.sidebar.hidden, "sidebar is visible");
+
+  // Checking for correct value in sidebar before update
+  yield findVariableViewProperties([{name: "ss2", value: "foobar"}]);
+
+  gWindow.sessionStorage.setItem("ss2", "changed=ss2");
+
+  yield gUI.once("sidebar-updated");
+
+  is($("#value [data-id='ss2']").value, "changed=ss2",
+      "Value got updated for session storage in the table");
+
+  yield findVariableViewProperties([{name: "ss2", value: "changed=ss2"}]);
+
+});
+
+let startTest = Task.async(function*() {
+  yield testUpdates();
+  finishTests();
+});
+
+function test() {
+  openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html").then(startTest);
+}
diff --git a/browser/devtools/storage/test/browser_storage_sidebar.js b/browser/devtools/storage/test/browser_storage_sidebar.js
new file mode 100644
index 000000000000..26926fc7effe
--- /dev/null
+++ b/browser/devtools/storage/test/browser_storage_sidebar.js
@@ -0,0 +1,67 @@
+/* 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/. */
+
+// Test to verify that the sidebar opens, closes and updates
+// This test is not testing the values in the sidebar, being tested in _values
+
+// Format: [
+//    or  or
+//     null to press Escape,
+//   ,
+//   
+// ]
+const testCases = [
+  [["cookies", "sectest1.example.org"], 0, 0],
+  ["cs2", 1, 1],
+  [null, 0, 0],
+  ["cs2", 1, 1],
+  ["uc1", 1, 1],
+  ["uc1", 0, 1],
+  [["localStorage", "http://sectest1.example.org"], 0, 0],
+  ["iframe-u-ls1", 1, 1],
+  ["iframe-u-ls1", 0, 1],
+  [null, 0, 0],
+  [["sessionStorage", "http://test1.example.org"], 0, 0],
+  ["ss1", 1, 1],
+  [null, 0, 0],
+  [["indexedDB", "http://test1.example.org"], 0, 0],
+  ["idb2", 1, 1],
+  [["indexedDB", "http://test1.example.org", "idb2", "obj3"], 0, 0],
+  [["indexedDB", "https://sectest1.example.org", "idb-s2"], 0, 0],
+  ["obj-s2", 1, 1],
+  [null, 0, 0],
+  [null, 0, 0],
+  ["obj-s2", 1, 1],
+  [null, 0, 0],
+];
+
+let testSidebar = Task.async(function*() {
+  let doc = gPanelWindow.document;
+  for (let item of testCases) {
+    info("clicking for item " + item);
+    if (Array.isArray(item[0])) {
+      selectTreeItem(item[0]);
+      yield gUI.once("store-objects-updated");
+    }
+    else if (item[0]) {
+      selectTableItem(item[0]);
+    }
+    else {
+      EventUtils.sendKey("ESCAPE", gPanelWindow);
+    }
+    if (item[1]) {
+      yield gUI.once("sidebar-updated");
+    }
+    is(!item[2], gUI.sidebar.hidden, "Correct visibility state of sidebar");
+  }
+});
+
+let startTest = Task.async(function*() {
+  yield testSidebar();
+  finishTests();
+});
+
+function test() {
+  openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html").then(startTest);
+}
diff --git a/browser/devtools/storage/test/browser_storage_values.js b/browser/devtools/storage/test/browser_storage_values.js
new file mode 100644
index 000000000000..e75259312d88
--- /dev/null
+++ b/browser/devtools/storage/test/browser_storage_values.js
@@ -0,0 +1,143 @@
+/* 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/. */
+
+// Test to verify that the values shown in sidebar are correct
+
+// Format: [
+//    or  or
+//     null do click nothing,
+//   null to skip checking value in variables view or a key value pair object
+//     which will be asserted to exist in the storage sidebar,
+//   true if the check is to be made in the parsed value section
+// ]
+const testCases = [
+  ["cs2", [
+    {name: "cs2", value: "sessionCookie"},
+    {name: "cs2.path", value: "/"},
+    {name: "cs2.isDomain", value: "true"},
+    {name: "cs2.isHttpOnly", value: "false"},
+    {name: "cs2.host", value: ".example.org"},
+    {name: "cs2.expires", value: "Session"},
+    {name: "cs2.isSecure", value: "false"},
+  ]],
+  ["c1", [
+    {name: "c1", value: JSON.stringify(["foo", "Bar", {foo: "Bar"}])},
+    {name: "c1.path", value: "/browser"},
+    {name: "c1.isDomain", value: "false"},
+    {name: "c1.isHttpOnly", value: "false"},
+    {name: "c1.host", value: "test1.example.org"},
+    {name: "c1.expires", value: new Date(2000000000000).toLocaleString()},
+    {name: "c1.isSecure", value: "false"},
+  ]],
+  [/*"c1"*/, [
+    {name: "c1", value: "Array"},
+    {name: "c1.0", value: "foo"},
+    {name: "c1.1", value: "Bar"},
+    {name: "c1.2", value: "Object"},
+    {name: "c1.2.foo", value: "Bar"},
+  ], true],
+  [["localStorage", "http://test1.example.org"]],
+  ["ls2", [
+    {name: "ls2", value: "foobar-2"}
+  ]],
+  ["ls1", [
+    {name: "ls1", value: JSON.stringify({
+      es6: "for", the: "win", baz: [0, 2, 3, {
+        deep: "down",
+        nobody: "cares"
+      }]})}
+  ]],
+  [/*ls1*/, [
+    {name: "ls1", value: "Object"},
+    {name: "ls1.es6", value: "for"},
+    {name: "ls1.the", value: "win"},
+    {name: "ls1.baz", value: "Array"},
+    {name: "ls1.baz.0", value: "0"},
+    {name: "ls1.baz.1", value: "2"},
+    {name: "ls1.baz.2", value: "3"},
+    {name: "ls1.baz.3", value: "Object"},
+    {name: "ls1.baz.3.deep", value: "down"},
+    {name: "ls1.baz.3.nobody", value: "cares"},
+  ], true],
+  ["ls3", [
+    {name: "ls3", "value": "http://foobar.com/baz.php"}
+  ]],
+  [/*ls3*/, [
+    {name: "ls3", "value": "http://foobar.com/baz.php", dontMatch: true}
+  ], true],
+  [["sessionStorage", "http://test1.example.org"]],
+  ["ss1", [
+    {name: "ss1", value: "This#is#an#array"}
+  ]],
+  [/*ss1*/, [
+    {name: "ss1", value: "Array"},
+    {name: "ss1.0", value: "This"},
+    {name: "ss1.1", value: "is"},
+    {name: "ss1.2", value: "an"},
+    {name: "ss1.3", value: "array"},
+  ], true],
+  ["ss2", [
+    {name: "ss2", value: "Array"},
+    {name: "ss2.0", value: "This"},
+    {name: "ss2.1", value: "is"},
+    {name: "ss2.2", value: "another"},
+    {name: "ss2.3", value: "array"},
+  ], true],
+  ["ss3", [
+    {name: "ss3", value: "Object"},
+    {name: "ss3.this", value: "is"},
+    {name: "ss3.an", value: "object"},
+    {name: "ss3.foo", value: "bar"},
+  ], true],
+  [["indexedDB", "http://test1.example.org", "idb1", "obj1"]],
+  [1, [
+    {name: 1, value: JSON.stringify({id: 1, name: "foo", email: "foo@bar.com"})}
+  ]],
+  [/*1*/, [
+    {name: "1.id", value: "1"},
+    {name: "1.name", value: "foo"},
+    {name: "1.email", value: "foo@bar.com"},
+  ], true],
+  [["indexedDB", "http://test1.example.org", "idb1", "obj2"]],
+  [1, [
+    {name: 1, value: JSON.stringify({
+      id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"
+    })}
+  ]],
+  [/*1*/, [
+    {name: "1.id2", value: "1"},
+    {name: "1.name", value: "foo"},
+    {name: "1.email", value: "foo@bar.com"},
+    {name: "1.extra", value: "baz"},
+  ], true]
+];
+
+let testValues = Task.async(function*() {
+  gUI.tree.expandAll();
+  let doc = gPanelWindow.document;
+  for (let item of testCases) {
+    info("clicking for item " + item);
+    if (Array.isArray(item[0])) {
+      selectTreeItem(item[0]);
+      yield gUI.once("store-objects-updated");
+      continue;
+    }
+    else if (item[0]) {
+      selectTableItem(item[0]);
+    }
+    if (item[0] && item[1]) {
+      yield gUI.once("sidebar-updated");
+    }
+    yield findVariableViewProperties(item[1], item[2]);
+  }
+});
+
+let startTest = Task.async(function*() {
+  yield testValues();
+  finishTests();
+});
+
+function test() {
+  openTabAndSetupStorage(MAIN_DOMAIN + "storage-complex-values.html").then(startTest);
+}
diff --git a/browser/devtools/storage/test/head.js b/browser/devtools/storage/test/head.js
new file mode 100644
index 000000000000..eb897e751a63
--- /dev/null
+++ b/browser/devtools/storage/test/head.js
@@ -0,0 +1,499 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+let tempScope = {};
+Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
+Cu.import("resource://gre/modules/devtools/Console.jsm", tempScope);
+const console = tempScope.console;
+const devtools = tempScope.devtools;
+tempScope = null;
+const require = devtools.require;
+const TargetFactory = devtools.TargetFactory;
+
+const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
+const STORAGE_PREF = "devtools.storage.enabled";
+const PATH = "browser/browser/devtools/storage/test/";
+const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
+const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
+const ALT_DOMAIN_SECURED = "https://sectest1.example.org:443/" + PATH;
+
+let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+
+waitForExplicitFinish();
+
+let gToolbox, gPanelWindow, gWindow, gUI;
+
+Services.prefs.setBoolPref(STORAGE_PREF, true);
+gDevTools.testing = true;
+registerCleanupFunction(() => {
+  gToolbox = gPanelWindow = gWindow = gUI = null;
+  Services.prefs.clearUserPref(STORAGE_PREF);
+  Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
+  gDevTools.testing = false;
+  while (gBrowser.tabs.length > 1) {
+    gBrowser.removeCurrentTab();
+  }
+});
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ *
+ * @param {String} url The url to be loaded in the new tab
+ *
+ * @return a promise that resolves to the content window when the url is loaded
+ */
+function addTab(url) {
+  info("Adding a new tab with URL: '" + url + "'");
+  let def = promise.defer();
+
+  // Bug 921935 should bring waitForFocus() support to e10s, which would
+  // probably cover the case of the test losing focus when the page is loading.
+  // For now, we just make sure the window is focused.
+  window.focus();
+
+  let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
+  let linkedBrowser = tab.linkedBrowser;
+
+  linkedBrowser.addEventListener("load", function onload(event) {
+    if (event.originalTarget.location.href != url) {
+      return;
+    }
+    linkedBrowser.removeEventListener("load", onload, true);
+    info("URL '" + url + "' loading complete");
+    def.resolve(tab.linkedBrowser.contentWindow);
+  }, true);
+
+  return def.promise;
+}
+
+/**
+ * Opens the given url in a new tab, then sets up the page by waiting for
+ * all cookies, indexedDB items etc. to be created; Then opens the storage
+ * inspector and waits for the storage tree and table to be populated
+ *
+ * @param url {String} The url to be opened in the new tab
+ *
+ * @return {Promise} A promise that resolves after storage inspector is ready
+ */
+let openTabAndSetupStorage = Task.async(function*(url) {
+  /**
+   * This method iterates over iframes in a window and setups the indexed db
+   * required for this test.
+   */
+  let setupIDBInFrames = (w, i, c) => {
+    if (w[i] && w[i].idbGenerator) {
+      w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c));
+      w[i].setupIDB.next();
+    }
+    else if (w[i] && w[i + 1]) {
+      setupIDBInFrames(w, i + 1, c);
+    }
+    else {
+      c();
+    }
+  };
+
+  let content = yield addTab(url);
+
+  let def = promise.defer();
+  // Setup the indexed db in main window.
+  gWindow = content.wrappedJSObject;
+  if (gWindow.idbGenerator) {
+    gWindow.setupIDB = gWindow.idbGenerator(() => {
+      setupIDBInFrames(gWindow, 0, () => {
+        def.resolve();
+      });
+    });
+    gWindow.setupIDB.next();
+    yield def.promise;
+  }
+
+  // open storage inspector
+  return yield openStoragePanel();
+});
+
+/**
+ * Open the toolbox, with the storage tool visible.
+ *
+ * @param cb {Function} Optional callback, if you don't want to use the returned
+ *                      promise
+ *
+ * @return {Promise} a promise that resolves when the storage inspector is ready
+ */
+let openStoragePanel = Task.async(function*(cb) {
+  info("Opening the storage inspector");
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  let storage, toolbox;
+
+  // Checking if the toolbox and the storage are already loaded
+  // The storage-updated event should only be waited for if the storage
+  // isn't loaded yet
+  toolbox = gDevTools.getToolbox(target);
+  if (toolbox) {
+    storage = toolbox.getPanel("storage");
+    if (storage) {
+      gPanelWindow = storage.panelWindow;
+      gUI = storage.UI;
+      gToolbox = toolbox;
+      info("Toolbox and storage already open");
+      if (cb) {
+        return cb(storage, toolbox);
+      } else {
+        return {
+          toolbox: toolbox,
+          storage: storage
+        };
+      }
+    }
+  }
+
+  info("Opening the toolbox");
+  toolbox = yield gDevTools.showToolbox(target, "storage");
+  storage = toolbox.getPanel("storage");
+  gPanelWindow = storage.panelWindow;
+  gUI = storage.UI;
+  gToolbox = toolbox;
+
+  info("Waiting for the stores to update");
+  yield gUI.once("store-objects-updated");
+
+  yield waitForToolboxFrameFocus(toolbox);
+
+  if (cb) {
+    return cb(storage, toolbox);
+  } else {
+    return {
+      toolbox: toolbox,
+      storage: storage
+    };
+  }
+});
+
+/**
+ * Wait for the toolbox frame to receive focus after it loads
+ *
+ * @param toolbox {Toolbox}
+ *
+ * @return a promise that resolves when focus has been received
+ */
+function waitForToolboxFrameFocus(toolbox) {
+  info("Making sure that the toolbox's frame is focused");
+  let def = promise.defer();
+  let win = toolbox.frame.contentWindow;
+  waitForFocus(def.resolve, win);
+  return def.promise;
+}
+
+/**
+ * Forces GC, CC and Shrinking GC to get rid of disconnected docshells and
+ * windows.
+ */
+function forceCollections() {
+  Cu.forceGC();
+  Cu.forceCC();
+  Cu.forceShrinkingGC();
+}
+
+/**
+ * Cleans up and finishes the test
+ */
+function finishTests() {
+  // Cleanup so that indexed db created from this test do not interfere next ones
+
+  /**
+   * This method iterates over iframes in a window and clears the indexed db
+   * created by this test.
+   */
+  let clearIDB = (w, i, c) => {
+    if (w[i] && w[i].clear) {
+      w[i].clearIterator = w[i].clear(() => clearIDB(w, i + 1, c));
+      w[i].clearIterator.next();
+    }
+    else if (w[i] && w[i + 1]) {
+      clearIDB(w, i + 1, c);
+    }
+    else {
+      c();
+    }
+  };
+
+  gWindow.clearIterator = gWindow.clear(() => {
+    clearIDB(gWindow, 0, () => {
+      // Forcing GC/CC to get rid of docshells and windows created by this test.
+      forceCollections();
+      finish();
+    });
+  });
+  gWindow.clearIterator.next();
+}
+
+// Sends a click event on the passed DOM node in an async manner
+function click(node) {
+  node.scrollIntoView()
+  executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, gPanelWindow));
+}
+
+
+
+/**
+ * Recursively expand the variables view up to a given property.
+ *
+ * @param aOptions
+ *        Options for view expansion:
+ *        - rootVariable: start from the given scope/variable/property.
+ *        - expandTo: string made up of property names you want to expand.
+ *        For example: "body.firstChild.nextSibling" given |rootVariable:
+ *        document|.
+ * @return object
+ *         A promise that is resolved only when the last property in |expandTo|
+ *         is found, and rejected otherwise. Resolution reason is always the
+ *         last property - |nextSibling| in the example above. Rejection is
+ *         always the last property that was found.
+ */
+function variablesViewExpandTo(aOptions) {
+  let root = aOptions.rootVariable;
+  let expandTo = aOptions.expandTo.split(".");
+  let lastDeferred = promise.defer();
+
+  function getNext(aProp) {
+    let name = expandTo.shift();
+    let newProp = aProp.get(name);
+
+    if (expandTo.length > 0) {
+      ok(newProp, "found property " + name);
+      if (newProp && newProp.expand) {
+        newProp.expand();
+        getNext(newProp);
+      }
+      else {
+        lastDeferred.reject(aProp);
+      }
+    }
+    else {
+      if (newProp) {
+        lastDeferred.resolve(newProp);
+      }
+      else {
+        lastDeferred.reject(aProp);
+      }
+    }
+  }
+
+  function fetchError(aProp) {
+    lastDeferred.reject(aProp);
+  }
+
+  if (root && root.expand) {
+    root.expand();
+    getNext(root);
+  }
+  else {
+    lastDeferred.resolve(root)
+  }
+
+  return lastDeferred.promise;
+}
+
+/**
+ * Find variables or properties in a VariablesView instance.
+ *
+ * @param array aRules
+ *        The array of rules you want to match. Each rule is an object with:
+ *        - name (string|regexp): property name to match.
+ *        - value (string|regexp): property value to match.
+ *        - dontMatch (boolean): make sure the rule doesn't match any property.
+ * @param boolean aParsed
+ *        true if we want to test the rules in the parse value section of the
+ *        storage sidebar
+ * @return object
+ *         A promise object that is resolved when all the rules complete
+ *         matching. The resolved callback is given an array of all the rules
+ *         you wanted to check. Each rule has a new property: |matchedProp|
+ *         which holds a reference to the Property object instance from the
+ *         VariablesView. If the rule did not match, then |matchedProp| is
+ *         undefined.
+ */
+function findVariableViewProperties(aRules, aParsed) {
+  // Initialize the search.
+  function init() {
+    // If aParsed is true, we are checking rules in the parsed value section of
+    // the storage sidebar. That scope uses a blank variable as a placeholder
+    // Thus, adding a blank parent to each name
+    if (aParsed) {
+      aRules = aRules.map(({name, value, dontMatch}) => {
+        return {name: "." + name, value, dontMatch}
+      });
+    }
+    // Separate out the rules that require expanding properties throughout the
+    // view.
+    let expandRules = [];
+    let rules = aRules.filter((aRule) => {
+      if (typeof aRule.name == "string" && aRule.name.indexOf(".") > -1) {
+        expandRules.push(aRule);
+        return false;
+      }
+      return true;
+    });
+
+    // Search through the view those rules that do not require any properties to
+    // be expanded. Build the array of matchers, outstanding promises to be
+    // resolved.
+    let outstanding = [];
+
+    finder(rules, gUI.view, outstanding);
+
+    // Process the rules that need to expand properties.
+    let lastStep = processExpandRules.bind(null, expandRules);
+
+    // Return the results - a promise resolved to hold the updated aRules array.
+    let returnResults = onAllRulesMatched.bind(null, aRules);
+
+    return promise.all(outstanding).then(lastStep).then(returnResults);
+  }
+
+  function onMatch(aProp, aRule, aMatched) {
+    if (aMatched && !aRule.matchedProp) {
+      aRule.matchedProp = aProp;
+    }
+  }
+
+  function finder(aRules, aView, aPromises) {
+    for (let scope of aView) {
+      for (let [id, prop] of scope) {
+        for (let rule of aRules) {
+          let matcher = matchVariablesViewProperty(prop, rule);
+          aPromises.push(matcher.then(onMatch.bind(null, prop, rule)));
+        }
+      }
+    }
+  }
+
+  function processExpandRules(aRules) {
+    let rule = aRules.shift();
+    if (!rule) {
+      return promise.resolve(null);
+    }
+
+    let deferred = promise.defer();
+    let expandOptions = {
+      rootVariable: gUI.view.getScopeAtIndex(aParsed ? 1: 0),
+      expandTo: rule.name
+    };
+
+    variablesViewExpandTo(expandOptions).then(function onSuccess(aProp) {
+      let name = rule.name;
+      let lastName = name.split(".").pop();
+      rule.name = lastName;
+
+      let matched = matchVariablesViewProperty(aProp, rule);
+      return matched.then(onMatch.bind(null, aProp, rule)).then(function() {
+        rule.name = name;
+      });
+    }, function onFailure() {
+      return promise.resolve(null);
+    }).then(processExpandRules.bind(null, aRules)).then(function() {
+      deferred.resolve(null);
+    });
+
+    return deferred.promise;
+  }
+
+  function onAllRulesMatched(aRules) {
+    for (let rule of aRules) {
+      let matched = rule.matchedProp;
+      if (matched && !rule.dontMatch) {
+        ok(true, "rule " + rule.name + " matched for property " + matched.name);
+      }
+      else if (matched && rule.dontMatch) {
+        ok(false, "rule " + rule.name + " should not match property " +
+           matched.name);
+      }
+      else {
+        ok(rule.dontMatch, "rule " + rule.name + " did not match any property");
+      }
+    }
+    return aRules;
+  }
+
+  return init();
+}
+
+/**
+ * Check if a given Property object from the variables view matches the given
+ * rule.
+ *
+ * @param object aProp
+ *        The variable's view Property instance.
+ * @param object aRule
+ *        Rules for matching the property. See findVariableViewProperties() for
+ *        details.
+ * @return object
+ *         A promise that is resolved when all the checks complete. Resolution
+ *         result is a boolean that tells your promise callback the match
+ *         result: true or false.
+ */
+function matchVariablesViewProperty(aProp, aRule) {
+  function resolve(aResult) {
+    return promise.resolve(aResult);
+  }
+
+  if (!aProp) {
+    return resolve(false);
+  }
+
+  if (aRule.name) {
+    let match = aRule.name instanceof RegExp ?
+                aRule.name.test(aProp.name) :
+                aProp.name == aRule.name;
+    if (!match) {
+      return resolve(false);
+    }
+  }
+
+  if ("value" in aRule) {
+    let displayValue = aProp.displayValue;
+    if (aProp.displayValueClassName == "token-string") {
+      displayValue = displayValue.substring(1, displayValue.length - 1);
+    }
+
+    let match = aRule.value instanceof RegExp ?
+                aRule.value.test(displayValue) :
+                displayValue == aRule.value;
+    if (!match) {
+      info("rule " + aRule.name + " did not match value, expected '" +
+           aRule.value + "', found '" + displayValue  + "'");
+      return resolve(false);
+    }
+  }
+
+  return resolve(true);
+}
+
+/**
+ * Click selects a row in the table.
+ *
+ * @param {[String]} ids
+ *        The array id of the item in the tree
+ */
+function selectTreeItem(ids) {
+  // Expand tree as some/all items could be collapsed leading to click on an
+  // incorrect tree item
+  gUI.tree.expandAll();
+  click(gPanelWindow.document.querySelector("[data-id='" + JSON.stringify(ids) +
+        "'] > .tree-widget-item"));
+}
+
+/**
+ * Click selects a row in the table.
+ *
+ * @param {String} id
+ *        The id of the row in the table widget
+ */
+function selectTableItem(id) {
+  click(gPanelWindow.document.querySelector(".table-widget-cell[data-id='" +
+        id + "']"));
+}
diff --git a/browser/devtools/storage/test/moz.build b/browser/devtools/storage/test/moz.build
new file mode 100644
index 000000000000..33f04f853787
--- /dev/null
+++ b/browser/devtools/storage/test/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+BROWSER_CHROME_MANIFESTS += ['browser.ini']
+
diff --git a/browser/devtools/storage/test/storage-complex-values.html b/browser/devtools/storage/test/storage-complex-values.html
new file mode 100644
index 000000000000..aaaa0ef9b9a4
--- /dev/null
+++ b/browser/devtools/storage/test/storage-complex-values.html
@@ -0,0 +1,99 @@
+
+
+
+
+  
+  Storage inspector test for correct values in the sidebar
+
+
+
+
+
diff --git a/browser/devtools/storage/test/storage-listings.html b/browser/devtools/storage/test/storage-listings.html
new file mode 100644
index 000000000000..5feb100712f8
--- /dev/null
+++ b/browser/devtools/storage/test/storage-listings.html
@@ -0,0 +1,94 @@
+
+
+
+
+  
+  Storage inspector test for listing hosts and storages
+
+
+
+
+
+
+
diff --git a/browser/devtools/storage/test/storage-secured-iframe.html b/browser/devtools/storage/test/storage-secured-iframe.html
new file mode 100644
index 000000000000..98bfef344b7c
--- /dev/null
+++ b/browser/devtools/storage/test/storage-secured-iframe.html
@@ -0,0 +1,71 @@
+
+
+
+
+  
+
+
+
+
+
diff --git a/browser/devtools/storage/test/storage-unsecured-iframe.html b/browser/devtools/storage/test/storage-unsecured-iframe.html
new file mode 100644
index 000000000000..c3a1eeb570b2
--- /dev/null
+++ b/browser/devtools/storage/test/storage-unsecured-iframe.html
@@ -0,0 +1,27 @@
+
+
+
+
+  
+
+
+
+
+
diff --git a/browser/devtools/storage/test/storage-updates.html b/browser/devtools/storage/test/storage-updates.html
new file mode 100644
index 000000000000..626118d0007d
--- /dev/null
+++ b/browser/devtools/storage/test/storage-updates.html
@@ -0,0 +1,63 @@
+
+
+
+
+  
+  Storage inspector blank html for tests
+
+
+
+
+
diff --git a/browser/devtools/storage/ui.js b/browser/devtools/storage/ui.js
index 101e62555df8..ed395af611f4 100644
--- a/browser/devtools/storage/ui.js
+++ b/browser/devtools/storage/ui.js
@@ -516,7 +516,7 @@ StorageUI.prototype = {
    *        Array of objects to be populated in the storage table
    * @param {number} reason
    *        The reason of this populateTable call. 2 for update, 1 for new row
-   *        in an existing table and 1 when populating a table for the first
+   *        in an existing table and 0 when populating a table for the first
    *        time for the given host/type
    */
   populateTable: function(data, reason) {

From d6888a866b6b6e63355a7e058bb0d42da0c91575 Mon Sep 17 00:00:00 2001
From: "Raymond Etornam Agbeame(:retornam)" 
Date: Fri, 29 Aug 2014 15:49:01 -0700
Subject: [PATCH 097/120] Bug 1052856 - Copy as curl should use --compressed
 instead of -H accept-encoding gzip r=jryans

---
 browser/devtools/netmonitor/test/browser_net_copy_as_curl.js | 4 ++--
 browser/devtools/shared/Curl.jsm                             | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js b/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js
index 6cff1456f6d4..e67f67326c87 100644
--- a/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js
+++ b/browser/devtools/netmonitor/test/browser_net_copy_as_curl.js
@@ -16,7 +16,7 @@ function test() {
       "-H 'User-Agent: " + aDebuggee.navigator.userAgent + "'",
       "-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'",
       "-H 'Accept-Language: " + aDebuggee.navigator.language + "'",
-      "-H 'Accept-Encoding: gzip, deflate'",
+      "--compressed",
       "-H 'X-Custom-Header-1: Custom value'",
       "-H 'X-Custom-Header-2: 8.8.8.8'",
       "-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
@@ -31,7 +31,7 @@ function test() {
       '-H "User-Agent: ' + aDebuggee.navigator.userAgent + '"',
       '-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"',
       '-H "Accept-Language: ' + aDebuggee.navigator.language + '"',
-      '-H "Accept-Encoding: gzip, deflate"',
+      "--compressed",
       '-H "X-Custom-Header-1: Custom value"',
       '-H "X-Custom-Header-2: 8.8.8.8"',
       '-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"',
diff --git a/browser/devtools/shared/Curl.jsm b/browser/devtools/shared/Curl.jsm
index 615c3fc0662c..dc7fd37fc539 100644
--- a/browser/devtools/shared/Curl.jsm
+++ b/browser/devtools/shared/Curl.jsm
@@ -120,6 +120,10 @@ this.Curl = {
     }
     for (let i = 0; i < headers.length; i++) {
       let header = headers[i];
+      if (header.name === "Accept-Encoding"){
+        command.push("--compressed");
+        continue;
+      }
       if (ignoredHeaders.has(header.name)) {
         continue;
       }

From de2965fbbf01e0c534cf9a4148f6a93460f1b0ee Mon Sep 17 00:00:00 2001
From: Brian Grinstead 
Date: Fri, 29 Aug 2014 15:49:11 -0700
Subject: [PATCH 098/120] Bug 1060041 - Don't expand folders in projecteditor
 tree by default;r=jryans

---
 browser/devtools/projecteditor/lib/stores/resource.js      | 7 +++++++
 browser/devtools/projecteditor/lib/tree.js                 | 3 +++
 .../test/browser_projecteditor_tree_selection_01.js        | 6 ++++++
 3 files changed, 16 insertions(+)

diff --git a/browser/devtools/projecteditor/lib/stores/resource.js b/browser/devtools/projecteditor/lib/stores/resource.js
index 1c16e0e7aed7..0211281e50fd 100644
--- a/browser/devtools/projecteditor/lib/stores/resource.js
+++ b/browser/devtools/projecteditor/lib/stores/resource.js
@@ -57,6 +57,13 @@ var Resource = Class({
    */
   get hasChildren() { return this.children && this.children.size > 0; },
 
+  /**
+   * Is this Resource the root (top level for the store)?
+   */
+  get isRoot() {
+    return !this.parent
+  },
+
   /**
    * Sorted array of children for display
    */
diff --git a/browser/devtools/projecteditor/lib/tree.js b/browser/devtools/projecteditor/lib/tree.js
index c02b1e3705b0..642fe162ce17 100644
--- a/browser/devtools/projecteditor/lib/tree.js
+++ b/browser/devtools/projecteditor/lib/tree.js
@@ -84,6 +84,9 @@ var ResourceContainer = Class({
       evt.stopPropagation();
     }, true);
 
+    if (!this.resource.isRoot) {
+      this.expanded = false;
+    }
     this.update();
   },
 
diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_01.js b/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_01.js
index 656e06947308..d2458a3a4682 100644
--- a/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_01.js
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_01.js
@@ -35,8 +35,14 @@ let test = asyncTest(function*() {
 function selectFileFirstLoad(projecteditor, resource) {
   ok (resource && resource.path, "A valid resource has been passed in for selection " + (resource && resource.path));
   projecteditor.projectTree.selectResource(resource);
+  let container = projecteditor.projectTree.getViewContainer(resource);
 
+  if (resource.isRoot) {
+    ok (container.expanded, "The root directory is expanded by default.");
+    return;
+  }
   if (resource.isDir) {
+    ok (!container.expanded, "A directory is not expanded by default.");
     return;
   }
 

From da361adf4e57d94f822b42a9f94575ec14cf3e6e Mon Sep 17 00:00:00 2001
From: Michael Ratcliffe 
Date: Fri, 29 Aug 2014 13:44:59 +0100
Subject: [PATCH 099/120] Bug 1060188 - [App Manager] Cannot use Inspector to
 view app's DOM on Flame r=paul

---
 browser/devtools/framework/gDevTools.jsm    |  90 +---------------
 browser/devtools/main.js                    |   2 -
 toolkit/devtools/event-parsers.js           | 113 ++++++++++++++++++--
 toolkit/devtools/server/actors/inspector.js |  13 ++-
 4 files changed, 116 insertions(+), 102 deletions(-)

diff --git a/browser/devtools/framework/gDevTools.jsm b/browser/devtools/framework/gDevTools.jsm
index ebb2122c1c43..8b5358b0eb83 100644
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -29,7 +29,6 @@ const MAX_ORDINAL = 99;
 this.DevTools = function DevTools() {
   this._tools = new Map();     // Map
   this._themes = new Map();    // Map
-  this._eventParsers = new Map(); // Map
   this._toolboxes = new Map(); // Map
 
   // destroy() is an observer's handler so we need to preserve context.
@@ -42,7 +41,7 @@ this.DevTools = function DevTools() {
 
   Services.obs.addObserver(this._teardown, "devtools-unloaded", false);
   Services.obs.addObserver(this.destroy, "quit-application", false);
-}
+};
 
 DevTools.prototype = {
   /**
@@ -66,10 +65,6 @@ DevTools.prototype = {
     }
   },
 
-  get eventParsers() {
-    return this._eventParsers;
-  },
-
   /**
    * Register a new developer tool.
    *
@@ -145,85 +140,6 @@ DevTools.prototype = {
     }
   },
 
-  /**
-   * Register a new event parser to be used in the processing of event info.
-   *
-   * @param {Object} parserObj
-   *        Each parser must contain the following properties:
-   *        - parser, which must take the following form:
-   *   {
-   *     id {String}: "jQuery events",         // Unique id.
-   *     getListeners: function(node) { },     // Function that takes a node and
-   *                                           // returns an array of eventInfo
-   *                                           // objects (see below).
-   *
-   *     hasListeners: function(node) { },     // Optional function that takes a
-   *                                           // node and returns a boolean
-   *                                           // indicating whether a node has
-   *                                           // listeners attached.
-   *
-   *     normalizeHandler: function(fnDO) { }, // Optional function that takes a
-   *                                           // Debugger.Object instance and
-   *                                           // climbs the scope chain to get
-   *                                           // the function that should be
-   *                                           // displayed in the event bubble
-   *                                           // see the following url for
-   *                                           // details:
-   *                                           //   https://developer.mozilla.org/
-   *                                           //   docs/Tools/Debugger-API/
-   *                                           //   Debugger.Object
-   *   }
-   *
-   * An eventInfo object should take the following form:
-   *   {
-   *     type {String}:      "click",
-   *     handler {Function}: event handler,
-   *     tags {String}:      "jQuery,Live", // These tags will be displayed as
-   *                                        // attributes in the events popup.
-   *     hide: {               // Hide or show fields:
-   *       debugger: false,    // Debugger icon
-   *       type: false,        // Event type e.g. click
-   *       filename: false,    // Filename
-   *       capturing: false,   // Capturing
-   *       dom0: false         // DOM 0
-   *     },
-   *
-   *     override: {                        // The following can be overridden:
-   *       type: "click",
-   *       origin: "http://www.mozilla.com",
-   *       searchString: 'onclick="doSomething()"',
-   *       DOM0: true,
-   *       capturing: true
-   *     }
-   *   }
-   */
-  registerEventParser: function(parserObj) {
-    let parserId = parserObj.id;
-
-    if (!parserId) {
-      throw new Error("Cannot register new event parser with id " + parserId);
-    }
-    if (this._eventParsers.has(parserId)) {
-      throw new Error("Duplicate event parser id " + parserId);
-    }
-
-    this._eventParsers.set(parserId, {
-      getListeners: parserObj.getListeners,
-      hasListeners: parserObj.hasListeners,
-      normalizeHandler: parserObj.normalizeHandler
-    });
-  },
-
-  /**
-   * Removes parser that matches a given parserId.
-   *
-   * @param {String} parserId
-   *        id of the event parser to unregister.
-   */
-  unregisterEventParser: function(parserId) {
-    this._eventParsers.delete(parserId);
-  },
-
   /**
    * Sorting function used for sorting tools based on their ordinals.
    */
@@ -555,10 +471,6 @@ DevTools.prototype = {
       this.unregisterTool(key, true);
     }
 
-    for (let [id] of this._eventParsers) {
-      this.unregisterEventParser(id, true);
-    }
-
     // Cleaning down the toolboxes: i.e.
     //   for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
     // Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
diff --git a/browser/devtools/main.js b/browser/devtools/main.js
index 85eef3a47fee..84426af4494b 100644
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -21,8 +21,6 @@ loader.lazyGetter(this, "osString", () => Cc["@mozilla.org/xre/app-info;1"].getS
 
 let events = require("sdk/system/events");
 
-require("devtools/toolkit/event-parsers");
-
 // Panels
 loader.lazyGetter(this, "OptionsPanel", () => require("devtools/framework/toolbox-options").OptionsPanel);
 loader.lazyGetter(this, "InspectorPanel", () => require("devtools/inspector/inspector-panel").InspectorPanel);
diff --git a/toolkit/devtools/event-parsers.js b/toolkit/devtools/event-parsers.js
index bd8d7335395b..7d37ce109637 100644
--- a/toolkit/devtools/event-parsers.js
+++ b/toolkit/devtools/event-parsers.js
@@ -8,14 +8,13 @@
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
-const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 
 loader.lazyGetter(this, "eventListenerService", () => {
   return Cc["@mozilla.org/eventlistenerservice;1"]
            .getService(Ci.nsIEventListenerService);
 });
 
-let eventParsers = [
+let parsers = [
   {
     id: "jQuery events",
     getListeners: function(node) {
@@ -184,10 +183,6 @@ let eventParsers = [
   }
 ];
 
-for (let parserObj of eventParsers) {
-  gDevTools.registerEventParser(parserObj);
-}
-
 function jQueryLiveGetListeners(node, boolOnEventFound) {
   let global = node.ownerGlobal.wrappedJSObject;
   let hasJQuery = global.jQuery && global.jQuery.fn && global.jQuery.fn.jquery;
@@ -260,3 +255,109 @@ function jQueryLiveGetListeners(node, boolOnEventFound) {
   }
   return handlers;
 }
+
+this.EventParsers = function EventParsers() {
+  if (this._eventParsers.size === 0) {
+    for (let parserObj of parsers) {
+      this.registerEventParser(parserObj);
+    }
+  }
+};
+
+exports.EventParsers = EventParsers;
+
+EventParsers.prototype = {
+  _eventParsers: new Map(), // NOTE: This is shared amongst all instances.
+
+  get parsers() {
+    return this._eventParsers;
+  },
+
+  /**
+   * Register a new event parser to be used in the processing of event info.
+   *
+   * @param {Object} parserObj
+   *        Each parser must contain the following properties:
+   *        - parser, which must take the following form:
+   *   {
+   *     id {String}: "jQuery events",         // Unique id.
+   *     getListeners: function(node) { },     // Function that takes a node and
+   *                                           // returns an array of eventInfo
+   *                                           // objects (see below).
+   *
+   *     hasListeners: function(node) { },     // Optional function that takes a
+   *                                           // node and returns a boolean
+   *                                           // indicating whether a node has
+   *                                           // listeners attached.
+   *
+   *     normalizeHandler: function(fnDO) { }, // Optional function that takes a
+   *                                           // Debugger.Object instance and
+   *                                           // climbs the scope chain to get
+   *                                           // the function that should be
+   *                                           // displayed in the event bubble
+   *                                           // see the following url for
+   *                                           // details:
+   *                                           //   https://developer.mozilla.org/
+   *                                           //   docs/Tools/Debugger-API/
+   *                                           //   Debugger.Object
+   *   }
+   *
+   * An eventInfo object should take the following form:
+   *   {
+   *     type {String}:      "click",
+   *     handler {Function}: event handler,
+   *     tags {String}:      "jQuery,Live", // These tags will be displayed as
+   *                                        // attributes in the events popup.
+   *     hide: {               // Hide or show fields:
+   *       debugger: false,    // Debugger icon
+   *       type: false,        // Event type e.g. click
+   *       filename: false,    // Filename
+   *       capturing: false,   // Capturing
+   *       dom0: false         // DOM 0
+   *     },
+   *
+   *     override: {                        // The following can be overridden:
+   *       type: "click",
+   *       origin: "http://www.mozilla.com",
+   *       searchString: 'onclick="doSomething()"',
+   *       DOM0: true,
+   *       capturing: true
+   *     }
+   *   }
+   */
+  registerEventParser: function(parserObj) {
+    let parserId = parserObj.id;
+
+    if (!parserId) {
+      throw new Error("Cannot register new event parser with id " + parserId);
+    }
+    if (this._eventParsers.has(parserId)) {
+      throw new Error("Duplicate event parser id " + parserId);
+    }
+
+    this._eventParsers.set(parserId, {
+      getListeners: parserObj.getListeners,
+      hasListeners: parserObj.hasListeners,
+      normalizeHandler: parserObj.normalizeHandler
+    });
+  },
+
+  /**
+   * Removes parser that matches a given parserId.
+   *
+   * @param {String} parserId
+   *        id of the event parser to unregister.
+   */
+  unregisterEventParser: function(parserId) {
+    this._eventParsers.delete(parserId);
+  },
+
+  /**
+   * Tidy up parsers.
+   */
+  destroy: function() {
+    for (let [id] of this._eventParsers) {
+      this.unregisterEventParser(id, true);
+    }
+  }
+};
diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js
index 4e1150e50d93..c76cdc5846b5 100644
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -69,6 +69,8 @@ const {
 const {getLayoutChangesObserver, releaseLayoutChangesObserver} =
   require("devtools/server/actors/layout");
 
+const {EventParsers} = require("devtools/toolkit/event-parsers");
+
 const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
 const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
 const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
@@ -188,6 +190,7 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
     protocol.Actor.prototype.initialize.call(this, null);
     this.walker = walker;
     this.rawNode = node;
+    this._eventParsers = new EventParsers().parsers;
 
     // Storing the original display of the node, to track changes when reflows
     // occur
@@ -291,11 +294,11 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
 
   /**
    * Are there event listeners that are listening on this node? This method
-   * uses all parsers registered via gDevTools.registerEventParser() to check if
-   * there are any event listeners.
+   * uses all parsers registered via event-parsers.js.registerEventParser() to
+   * check if there are any event listeners.
    */
   get _hasEventListeners() {
-    let parsers = gDevTools.eventParsers;
+    let parsers = this._eventParsers;
     for (let [,{hasListeners}] of parsers) {
       if (hasListeners && hasListeners(this.rawNode)) {
         return true;
@@ -333,7 +336,7 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
    *         Node for which we are to get listeners.
    */
   getEventListeners: function(node) {
-    let parsers = gDevTools.eventParsers;
+    let parsers = this._eventParsers;
     let dbg = this.parent().tabActor.makeDebugger();
     let events = [];
 
@@ -367,7 +370,7 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
    * @param  {Debugger} dbg
    *         JSDebugger instance.
    * @param  {Object} eventInfo
-   *         See gDevTools.registerEventParser() for a description of the
+   *         See event-parsers.js.registerEventParser() for a description of the
    *         eventInfo object.
    *
    * @return {Array}

From 201a636411f2bf4bb60f7ee6bafc9440c34442a3 Mon Sep 17 00:00:00 2001
From: Chenxia Liu 
Date: Fri, 29 Aug 2014 15:52:10 -0700
Subject: [PATCH 100/120] Bug 1059440 - Don't set noHistory for onboarding
 activity. r=trivial

---
 mobile/android/base/AndroidManifest.xml.in | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in
index 8a2a163d320c..29799a550939 100644
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -236,8 +236,7 @@
 
         
+                  android:excludeFromRecents="true"/>
 
         

From 87a9dfbe309e475244fb0f092347f7d97be5ba76 Mon Sep 17 00:00:00 2001
From: Richard Newman 
Date: Fri, 29 Aug 2014 16:14:20 -0700
Subject: [PATCH 101/120] Bug 1060524 - Eliminate pre-Gingerbread support in
 Android Sync. r=nalexander

---
 .../HealthReportDatabaseStorage.java            | 13 ++-----------
 .../base/sync/setup/activities/LocaleAware.java | 17 +++++------------
 2 files changed, 7 insertions(+), 23 deletions(-)

diff --git a/mobile/android/base/background/healthreport/HealthReportDatabaseStorage.java b/mobile/android/base/background/healthreport/HealthReportDatabaseStorage.java
index 7f5162250c33..584e55fc2fa1 100644
--- a/mobile/android/base/background/healthreport/HealthReportDatabaseStorage.java
+++ b/mobile/android/base/background/healthreport/HealthReportDatabaseStorage.java
@@ -24,7 +24,6 @@ import android.database.SQLException;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.os.Build;
 import android.util.SparseArray;
 
 /**
@@ -234,22 +233,14 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
       return parent.getAbsolutePath() + File.separator + name;
     }
 
-    public static boolean CAN_USE_ABSOLUTE_DB_PATH = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO);
     public HealthReportSQLiteOpenHelper(Context context, File profileDirectory, String name) {
       this(context, profileDirectory, name, CURRENT_VERSION);
     }
 
     // For testing DBs of different versions.
     public HealthReportSQLiteOpenHelper(Context context, File profileDirectory, String name, int version) {
-      super(
-          (CAN_USE_ABSOLUTE_DB_PATH ? context : new AbsolutePathContext(context, profileDirectory)),
-          (CAN_USE_ABSOLUTE_DB_PATH ? getAbsolutePath(profileDirectory, name) : name),
-          null,
-          version);
-
-      if (CAN_USE_ABSOLUTE_DB_PATH) {
-        Logger.pii(LOG_TAG, "Opening: " + getAbsolutePath(profileDirectory, name));
-      }
+      super(context, getAbsolutePath(profileDirectory, name), null, version);
+      Logger.pii(LOG_TAG, "Opening: " + getAbsolutePath(profileDirectory, name));
     }
 
     @Override
diff --git a/mobile/android/base/sync/setup/activities/LocaleAware.java b/mobile/android/base/sync/setup/activities/LocaleAware.java
index d7e5f06b06b5..7d72e6be81dc 100644
--- a/mobile/android/base/sync/setup/activities/LocaleAware.java
+++ b/mobile/android/base/sync/setup/activities/LocaleAware.java
@@ -7,10 +7,8 @@ package org.mozilla.gecko.sync.setup.activities;
 import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.LocaleManager;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Context;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.StrictMode;
 import android.support.v4.app.FragmentActivity;
@@ -25,19 +23,14 @@ import android.support.v4.app.FragmentActivity;
  * or LocaleAwareActivity.
  */
 public class LocaleAware {
-  @TargetApi(Build.VERSION_CODES.GINGERBREAD)
   public static void initializeLocale(Context context) {
     final LocaleManager localeManager = BrowserLocaleManager.getInstance();
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+    StrictMode.allowThreadDiskWrites();
+    try {
       localeManager.getAndApplyPersistedLocale(context);
-    } else {
-      final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-      StrictMode.allowThreadDiskWrites();
-      try {
-        localeManager.getAndApplyPersistedLocale(context);
-      } finally {
-        StrictMode.setThreadPolicy(savedPolicy);
-      }
+    } finally {
+      StrictMode.setThreadPolicy(savedPolicy);
     }
   }
 

From d8d650a7eed35e68d71c3f78e93c3f1de9267e4f Mon Sep 17 00:00:00 2001
From: Richard Newman 
Date: Fri, 29 Aug 2014 16:14:54 -0700
Subject: [PATCH 102/120] Bug 1060536 - Move LocaleAware into Fennec to allow
 for easier reuse from Search. r=nalexander

--HG--
rename : mobile/android/base/sync/setup/activities/LocaleAware.java => mobile/android/base/LocaleAware.java
---
 .../android/base/{sync/setup/activities => }/LocaleAware.java   | 2 +-
 mobile/android/base/android-services.mozbuild                   | 1 -
 .../android/base/fxa/activities/FxAccountAbstractActivity.java  | 2 +-
 .../base/fxa/activities/FxAccountGetStartedActivity.java        | 2 +-
 mobile/android/base/fxa/activities/FxAccountStatusActivity.java | 2 +-
 mobile/android/base/moz.build                                   | 1 +
 mobile/android/base/sync/setup/activities/SendTabActivity.java  | 2 +-
 7 files changed, 6 insertions(+), 6 deletions(-)
 rename mobile/android/base/{sync/setup/activities => }/LocaleAware.java (97%)

diff --git a/mobile/android/base/sync/setup/activities/LocaleAware.java b/mobile/android/base/LocaleAware.java
similarity index 97%
rename from mobile/android/base/sync/setup/activities/LocaleAware.java
rename to mobile/android/base/LocaleAware.java
index 7d72e6be81dc..e34b378e8ac9 100644
--- a/mobile/android/base/sync/setup/activities/LocaleAware.java
+++ b/mobile/android/base/LocaleAware.java
@@ -2,7 +2,7 @@
  * 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/. */
 
-package org.mozilla.gecko.sync.setup.activities;
+package org.mozilla.gecko;
 
 import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.LocaleManager;
diff --git a/mobile/android/base/android-services.mozbuild b/mobile/android/base/android-services.mozbuild
index f68ef347661a..fe36ee857738 100644
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -1063,7 +1063,6 @@ sync_java_files = [
     'sync/setup/activities/AccountActivity.java',
     'sync/setup/activities/ActivityUtils.java',
     'sync/setup/activities/ClientRecordArrayAdapter.java',
-    'sync/setup/activities/LocaleAware.java',
     'sync/setup/activities/RedirectToSetupActivity.java',
     'sync/setup/activities/SendTabActivity.java',
     'sync/setup/activities/SendTabData.java',
diff --git a/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java b/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
index ecc84d759d46..1a9d44219575 100644
--- a/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
@@ -9,7 +9,7 @@ import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-import org.mozilla.gecko.sync.setup.activities.LocaleAware.LocaleAwareActivity;
+import org.mozilla.gecko.LocaleAware.LocaleAwareActivity;
 
 import android.accounts.Account;
 import android.app.Activity;
diff --git a/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java b/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
index ad20c3a468c4..c79ff0489cee 100644
--- a/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
@@ -12,7 +12,7 @@ import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-import org.mozilla.gecko.sync.setup.activities.LocaleAware;
+import org.mozilla.gecko.LocaleAware;
 
 import android.accounts.AccountAuthenticatorActivity;
 import android.content.Intent;
diff --git a/mobile/android/base/fxa/activities/FxAccountStatusActivity.java b/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
index b7f245a01b42..c8c2d47015e7 100644
--- a/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
@@ -10,7 +10,7 @@ import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.setup.activities.LocaleAware.LocaleAwareFragmentActivity;
+import org.mozilla.gecko.LocaleAware.LocaleAwareFragmentActivity;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build
index 4aee57bd0061..6c1a836faf73 100644
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -314,6 +314,7 @@ gbjar.sources += [
     'JavaAddonManager.java',
     'LightweightTheme.java',
     'LightweightThemeDrawable.java',
+    'LocaleAware.java',
     'LocaleManager.java',
     'MediaCastingBar.java',
     'MemoryMonitor.java',
diff --git a/mobile/android/base/sync/setup/activities/SendTabActivity.java b/mobile/android/base/sync/setup/activities/SendTabActivity.java
index a559c1937aba..f59542c8911a 100644
--- a/mobile/android/base/sync/setup/activities/SendTabActivity.java
+++ b/mobile/android/base/sync/setup/activities/SendTabActivity.java
@@ -27,7 +27,7 @@ import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.activities.LocaleAware.LocaleAwareActivity;
+import org.mozilla.gecko.LocaleAware.LocaleAwareActivity;
 import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
 
 import android.accounts.Account;

From 294fcbd543d1dbf672d5a81606df8ccec8e2c56a Mon Sep 17 00:00:00 2001
From: Mike Conley 
Date: Fri, 29 Aug 2014 19:54:32 -0400
Subject: [PATCH 103/120] Bug 1057966 - Fix Help menu in e10s windows. r=billm.

The help menu wasn't populating properly because gSafeBrowsing was attempting
to get the URI for the loaded page by getting content.document.documentURI.
Since bug 1051017 landed, content is unavailable for e10s windows. We use
the selected browser's currentURI instead.

--HG--
extra : rebase_source : 7dfa0f74b99ed35563bc4507c2a5ff70a703af3e
---
 browser/base/content/browser-safebrowsing.js | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/browser/base/content/browser-safebrowsing.js b/browser/base/content/browser-safebrowsing.js
index e40a31957d05..aee0a0866046 100644
--- a/browser/base/content/browser-safebrowsing.js
+++ b/browser/base/content/browser-safebrowsing.js
@@ -6,9 +6,9 @@
 var gSafeBrowsing = {
 
   setReportPhishingMenu: function() {
-
     // A phishing page will have a specific about:blocked content documentURI
-    var isPhishingPage = content.document.documentURI.startsWith("about:blocked?e=phishingBlocked");
+    var uri = getBrowser().currentURI;
+    var isPhishingPage = uri && uri.spec.startsWith("about:blocked?e=phishingBlocked");
 
     // Show/hide the appropriate menu item.
     document.getElementById("menu_HelpPopup_reportPhishingtoolmenu")
@@ -24,7 +24,6 @@ var gSafeBrowsing = {
     if (!broadcaster)
       return;
 
-    var uri = getBrowser().currentURI;
     if (uri && (uri.schemeIs("http") || uri.schemeIs("https")))
       broadcaster.removeAttribute("disabled");
     else

From abbc2d7245a64a0ae3ec63824eaa97ba9aaa5735 Mon Sep 17 00:00:00 2001
From: Garvan Keeley 
Date: Thu, 28 Aug 2014 17:19:00 -0700
Subject: [PATCH 104/120] Bug 1038843 - Part 1: Land initial stumbler Java code
 and manifest fragments. r=nalexander,rnewman

The stumbler is a geolocation data collecting and uploading service.

This code is a partial export of the MozStumbler repository hosted at
https://github.com/mozilla/MozStumbler.
---
 .../mozstumbler/service/AppGlobals.java       |  60 ++
 .../mozilla/mozstumbler/service/Prefs.java    | 210 +++++++
 .../mainthread/PassiveServiceReceiver.java    |  73 +++
 .../service/stumblerthread/Reporter.java      | 199 +++++++
 .../stumblerthread/StumblerService.java       | 247 ++++++++
 .../blocklist/BSSIDBlockList.java             |  65 +++
 .../blocklist/SSIDBlockList.java              |  41 ++
 .../blocklist/WifiBlockListInterface.java}    |  11 +-
 .../datahandling/DataStorageContract.java     |  34 ++
 .../datahandling/DataStorageManager.java      | 527 ++++++++++++++++++
 .../datahandling/StumblerBundle.java          | 157 ++++++
 .../stumblerthread/scanners/GPSScanner.java   | 260 +++++++++
 .../scanners/LocationBlockList.java           | 101 ++++
 .../stumblerthread/scanners/ScanManager.java  | 190 +++++++
 .../stumblerthread/scanners/WifiScanner.java  | 220 ++++++++
 .../scanners/cellscanner/CellInfo.java        | 389 +++++++++++++
 .../scanners/cellscanner/CellScanner.java     | 135 +++++
 .../cellscanner/CellScannerNoWCDMA.java       | 254 +++++++++
 .../service/uploadthread/AsyncUploader.java   | 213 +++++++
 .../uploadthread/UploadAlarmReceiver.java     | 130 +++++
 .../service/utils/AbstractCommunicator.java   | 156 ++++++
 .../service/utils/NetworkUtils.java           |  41 ++
 .../utils/PersistentIntentService.java        |  85 +++
 .../mozstumbler/service/utils/Zipper.java     |  48 ++
 .../StumblerManifest_services.xml.in          |  17 +-
 .../stumbler/stumbler_sources.mozbuild        |  25 +-
 26 files changed, 3879 insertions(+), 9 deletions(-)
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/PassiveServiceReceiver.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java
 rename mobile/android/stumbler/java/org/mozilla/mozstumbler/{PlaceHolder.java => service/stumblerthread/blocklist/WifiBlockListInterface.java} (50%)
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerNoWCDMA.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java
 create mode 100644 mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java

diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java
new file mode 100644
index 000000000000..a97010ae01c4
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/AppGlobals.java
@@ -0,0 +1,60 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class AppGlobals {
+    public static final String LOG_PREFIX = "Stumbler:";
+
+    /* All intent actions start with this string. Only locally broadcasted. */
+    public static final String ACTION_NAMESPACE = "org.mozilla.mozstumbler.intent.action";
+
+    /* Handle this for logging reporter info. */
+    public static final String ACTION_GUI_LOG_MESSAGE = AppGlobals.ACTION_NAMESPACE + ".LOG_MESSAGE";
+    public static final String ACTION_GUI_LOG_MESSAGE_EXTRA = ACTION_GUI_LOG_MESSAGE + ".MESSAGE";
+
+    /* Defined here so that the Reporter class can access the time of an Intent in a generic fashion.
+     * Classes should have their own constant that is assigned to this, for example,
+     * WifiScanner has ACTION_WIFIS_SCANNED_ARG_TIME = ACTION_ARG_TIME.
+     * This member definition in the broadcaster makes it clear what the extra Intent args are for that class. */
+    public static final String ACTION_ARG_TIME = "time";
+
+    /* Location constructor requires a named origin, these are created in the app. */
+    public static final String LOCATION_ORIGIN_INTERNAL = "internal";
+
+    public enum ActiveOrPassiveStumbling { ACTIVE_STUMBLING, PASSIVE_STUMBLING }
+
+    /* In passive mode, only scan this many times for each gps. */
+    public static final int PASSIVE_MODE_MAX_SCANS_PER_GPS = 3;
+
+    /* These are set on startup. The appVersionName and code are not used in the service-only case. */
+    public static String appVersionName = "0.0.0";
+    public static int appVersionCode = 0;
+    public static String appName = "StumblerService";
+    public static boolean isDebug;
+
+    /* The log activity will clear this periodically, and display the messages.
+     * Always null when the stumbler service is used stand-alone. */
+    public static volatile ConcurrentLinkedQueue guiLogMessageBuffer;
+
+    public static void guiLogError(String msg) {
+        guiLogInfo(msg, "red", true);
+    }
+
+    public static void guiLogInfo(String msg) {
+        guiLogInfo(msg, "white", false);
+    }
+
+    public static void guiLogInfo(String msg, String color, boolean isBold) {
+        if (guiLogMessageBuffer != null) {
+            if (isBold) {
+                msg = "" + msg + "";
+            }
+            guiLogMessageBuffer.add("" + msg + "");
+        }
+    }
+}
+
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java
new file mode 100644
index 000000000000..8ef9f7b4b67a
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/Prefs.java
@@ -0,0 +1,210 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.location.Location;
+import android.os.Build.VERSION;
+import android.text.TextUtils;
+import android.util.Log;
+
+public  final class Prefs {
+    private static final String LOG_TAG = Prefs.class.getSimpleName();
+    private static final String NICKNAME_PREF = "nickname";
+    private static final String USER_AGENT_PREF = "user-agent";
+    private static final String VALUES_VERSION_PREF = "values_version";
+    private static final String WIFI_ONLY = "wifi_only";
+    private static final String LAT_PREF = "lat_pref";
+    private static final String LON_PREF = "lon_pref";
+    private static final String GEOFENCE_HERE = "geofence_here";
+    private static final String GEOFENCE_SWITCH = "geofence_switch";
+    private static final String FIREFOX_SCAN_ENABLED = "firefox_scan_on";
+    private static final String MOZ_API_KEY = "moz_api_key";
+    private static final String WIFI_SCAN_ALWAYS = "wifi_scan_always";
+    private static final String LAST_ATTEMPTED_UPLOAD_TIME = "last_attempted_upload_time";
+    // Public for MozStumbler to use for manual upgrade of old prefs.
+    public static final String PREFS_FILE = Prefs.class.getSimpleName();
+
+    private final SharedPreferences mSharedPrefs;
+    static private Prefs sInstance;
+
+    private Prefs(Context context) {
+        mSharedPrefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_MULTI_PROCESS | Context.MODE_PRIVATE);
+        if (getPrefs().getInt(VALUES_VERSION_PREF, -1) != AppGlobals.appVersionCode) {
+            Log.i(LOG_TAG, "Version of the application has changed. Updating default values.");
+            // Remove old keys
+            getPrefs().edit()
+                    .remove("reports")
+                    .remove("power_saving_mode")
+                    .commit();
+
+            getPrefs().edit().putInt(VALUES_VERSION_PREF, AppGlobals.appVersionCode).commit();
+            getPrefs().edit().commit();
+        }
+    }
+
+    /* Prefs must be created on application startup or service startup.
+     * TODO: turn into regular singleton if Context dependency can be removed. */
+    public static void createGlobalInstance(Context c) {
+        if (sInstance != null) {
+            return;
+        }
+        sInstance = new Prefs(c);
+    }
+
+    /* Only access after CreatePrefsInstance(Context) has been called at startup. */
+    public static Prefs getInstance() {
+        assert(sInstance != null);
+        return sInstance;
+    }
+
+    ///
+    /// Setters
+    ///
+    public synchronized void setUserAgent(String userAgent) {
+        setStringPref(USER_AGENT_PREF, userAgent);
+    }
+
+    public synchronized void setUseWifiOnly(boolean state) {
+        setBoolPref(WIFI_ONLY, state);
+    }
+
+    public synchronized void setGeofenceEnabled(boolean state) {
+        setBoolPref(GEOFENCE_SWITCH, state);
+    }
+
+    public synchronized void setGeofenceHere(boolean flag) {
+        setBoolPref(GEOFENCE_HERE, flag);
+    }
+
+    public synchronized void setGeofenceLocation(Location location) {
+        SharedPreferences.Editor editor = getPrefs().edit();
+        editor.putFloat(LAT_PREF, (float) location.getLatitude());
+        editor.putFloat(LON_PREF, (float) location.getLongitude());
+        apply(editor);
+    }
+
+    public synchronized void setMozApiKey(String s) {
+        setStringPref(MOZ_API_KEY, s);
+    }
+
+    ///
+    /// Getters
+    ///
+    public synchronized String getUserAgent() {
+        String s = getStringPref(USER_AGENT_PREF);
+        return (s == null)? AppGlobals.appName + "/" + AppGlobals.appVersionName : s;
+    }
+
+    public synchronized boolean getFirefoxScanEnabled() {
+        return getBoolPrefWithDefault(FIREFOX_SCAN_ENABLED, false);
+    }
+
+    public synchronized String getMozApiKey() {
+        String s = getStringPref(MOZ_API_KEY);
+        return (s == null)? "no-mozilla-api-key" : s;
+    }
+
+    public synchronized boolean getGeofenceEnabled() {
+        return getBoolPrefWithDefault(GEOFENCE_SWITCH, false);
+    }
+
+    public synchronized boolean getGeofenceHere() {
+        return getBoolPrefWithDefault(GEOFENCE_HERE, false);
+    }
+
+    public synchronized Location getGeofenceLocation() {
+        Location loc = new Location(AppGlobals.LOCATION_ORIGIN_INTERNAL);
+        loc.setLatitude(getPrefs().getFloat(LAT_PREF, 0));
+        loc.setLongitude(getPrefs().getFloat(LON_PREF,0));
+        return loc;
+    }
+
+    // This is the time an upload was last attempted, not necessarily successful.
+    // Used to ensure upload attempts aren't happening too frequently.
+    public synchronized long getLastAttemptedUploadTime() {
+        return getPrefs().getLong(LAST_ATTEMPTED_UPLOAD_TIME, 0);
+    }
+
+    public synchronized String getNickname() {
+        String nickname = getStringPref(NICKNAME_PREF);
+        if (nickname != null) {
+            nickname = nickname.trim();
+        }
+        return TextUtils.isEmpty(nickname) ? null : nickname;
+    }
+
+    public synchronized void setFirefoxScanEnabled(boolean on) {
+        setBoolPref(FIREFOX_SCAN_ENABLED, on);
+    }
+
+    public synchronized void setLastAttemptedUploadTime(long time) {
+        SharedPreferences.Editor editor = getPrefs().edit();
+        editor.putLong(LAST_ATTEMPTED_UPLOAD_TIME, time);
+        apply(editor);
+    }
+
+    public synchronized void setNickname(String nick) {
+        if (nick != null) {
+            nick = nick.trim();
+            if (nick.length() > 0) {
+                setStringPref(NICKNAME_PREF, nick);
+            }
+        }
+    }
+
+    public synchronized boolean getUseWifiOnly() {
+        return getBoolPrefWithDefault(WIFI_ONLY, true);
+    }
+
+    public synchronized boolean getWifiScanAlways() {
+        return getBoolPrefWithDefault(WIFI_SCAN_ALWAYS, false);
+    }
+
+    public synchronized void setWifiScanAlways(boolean b) {
+        setBoolPref(WIFI_SCAN_ALWAYS, b);
+    }
+
+    ///
+    /// Privates
+    ///
+
+    private String getStringPref(String key) {
+        return getPrefs().getString(key, null);
+    }
+
+    private boolean getBoolPrefWithDefault(String key, boolean def) {
+        return getPrefs().getBoolean(key, def);
+    }
+
+    private void setBoolPref(String key, Boolean state) {
+        SharedPreferences.Editor editor = getPrefs().edit();
+        editor.putBoolean(key,state);
+        apply(editor);
+    }
+
+    private void setStringPref(String key, String value) {
+        SharedPreferences.Editor editor = getPrefs().edit();
+        editor.putString(key, value);
+        apply(editor);
+    }
+
+    @TargetApi(9)
+    private static void apply(SharedPreferences.Editor editor) {
+        if (VERSION.SDK_INT >= 9) {
+            editor.apply();
+        } else if (!editor.commit()) {
+            Log.e(LOG_TAG, "", new IllegalStateException("commit() failed?!"));
+        }
+    }
+
+    @SuppressLint("InlinedApi")
+    private SharedPreferences getPrefs() {
+        return mSharedPrefs;
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/PassiveServiceReceiver.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/PassiveServiceReceiver.java
new file mode 100644
index 000000000000..6cefd3e94954
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/PassiveServiceReceiver.java
@@ -0,0 +1,73 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.mainthread;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.stumblerthread.StumblerService;
+
+/* Starts the StumblerService, an Intent service, which by definition runs on its own thread.
+ * Registered as a receiver in the AndroidManifest.xml.
+ * Starts the StumblerService in passive listening mode.
+ *
+ * The received intent serves these purposes:
+ * 1) The host application enables (or disables) the StumblerService.
+ *    Enabling requires passing in the upload API key. Both the enabled state, and the API key are stored in prefs.
+ *
+ * 2) If previously enabled by (1), notify the service to start (such as with a BOOT Intent).
+ *    The StumblerService is where the enabled state is checked, and if not enabled, the
+ *    service stops immediately.
+ *
+ * 3) Upload notification: onReceive intents are used to tell the StumblerService to check for upload.
+ *    In the Fennec host app use, startup and pause are used as indicators to the StumblerService that now
+ *    is a good time to try upload, as it is likely that the network is in use.
+ */
+public class PassiveServiceReceiver extends BroadcastReceiver {
+    static final String LOG_TAG = AppGlobals.LOG_PREFIX + PassiveServiceReceiver.class.getSimpleName();
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent == null) {
+            return;
+        }
+
+        final String action = intent.getAction();
+        final boolean isIntentFromHostApp = (action != null) && action.contains(".STUMBLER_PREF");
+        if (!isIntentFromHostApp) {
+            Log.d(LOG_TAG, "Stumbler: received intent external to host app");
+            Intent startServiceIntent = new Intent(context, StumblerService.class);
+            startServiceIntent.putExtra(StumblerService.ACTION_NOT_FROM_HOST_APP, true);
+            context.startService(startServiceIntent);
+            return;
+        }
+
+        if (intent.hasExtra("is_debug")) {
+            AppGlobals.isDebug = intent.getBooleanExtra("is_debug", false);
+        }
+        StumblerService.sFirefoxStumblingEnabled.set(intent.getBooleanExtra("enabled", false));
+
+        if (!StumblerService.sFirefoxStumblingEnabled.get()) {
+            // This calls the service's onDestroy(), and the service's onHandleIntent(...) is not called
+            context.stopService(new Intent(context, StumblerService.class));
+            return;
+        }
+
+        Log.d(LOG_TAG, "Stumbler: Sending passive start message | isDebug:" + AppGlobals.isDebug);
+
+
+        final Intent startServiceIntent = new Intent(context, StumblerService.class);
+        startServiceIntent.putExtra(StumblerService.ACTION_START_PASSIVE, true);
+        final String mozApiKey = intent.getStringExtra("moz_mozilla_api_key");
+        startServiceIntent.putExtra(StumblerService.ACTION_EXTRA_MOZ_API_KEY, mozApiKey);
+        final String userAgent = intent.getStringExtra("user_agent");
+        startServiceIntent.putExtra(StumblerService.ACTION_EXTRA_USER_AGENT, userAgent);
+        context.startService(startServiceIntent);
+    }
+}
+
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java
new file mode 100644
index 000000000000..c9d23edf07ab
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java
@@ -0,0 +1,199 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.Location;
+import android.net.wifi.ScanResult;
+import android.support.v4.content.LocalBroadcastManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageContract;
+import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
+import org.mozilla.mozstumbler.service.stumblerthread.datahandling.StumblerBundle;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellInfo;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.GPSScanner;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.WifiScanner;
+
+public final class Reporter extends BroadcastReceiver {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + Reporter.class.getSimpleName();
+    public static final String ACTION_FLUSH_TO_BUNDLE = AppGlobals.ACTION_NAMESPACE + ".FLUSH";
+    private boolean mIsStarted;
+
+    /* The maximum number of Wi-Fi access points in a single observation. */
+    private static final int MAX_WIFIS_PER_LOCATION = 200;
+
+    /* The maximum number of cells in a single observation */
+    private static final int MAX_CELLS_PER_LOCATION  = 50;
+
+    private Context mContext;
+    private int mPhoneType;
+
+    private StumblerBundle mBundle;
+
+    Reporter() {}
+
+    private void resetData() {
+        mBundle = null;
+    }
+
+    public void flush() {
+        reportCollectedLocation();
+    }
+
+    void startup(Context context) {
+        if (mIsStarted) {
+            return;
+        }
+
+        mContext = context.getApplicationContext();
+        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        mPhoneType = tm.getPhoneType();
+
+        mIsStarted = true;
+
+        resetData();
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(WifiScanner.ACTION_WIFIS_SCANNED);
+        intentFilter.addAction(CellScanner.ACTION_CELLS_SCANNED);
+        intentFilter.addAction(GPSScanner.ACTION_GPS_UPDATED);
+        intentFilter.addAction(ACTION_FLUSH_TO_BUNDLE);
+        LocalBroadcastManager.getInstance(mContext).registerReceiver(this,
+                intentFilter);
+    }
+
+    void shutdown() {
+        if (mContext == null) {
+            return;
+        }
+
+        mIsStarted = false;
+
+        Log.d(LOG_TAG, "shutdown");
+        flush();
+        LocalBroadcastManager.getInstance(mContext).unregisterReceiver(this);
+    }
+
+    private void receivedWifiMessage(Intent intent) {
+        List results = intent.getParcelableArrayListExtra(WifiScanner.ACTION_WIFIS_SCANNED_ARG_RESULTS);
+        putWifiResults(results);
+    }
+
+    private void receivedCellMessage(Intent intent) {
+        List results = intent.getParcelableArrayListExtra(CellScanner.ACTION_CELLS_SCANNED_ARG_CELLS);
+        putCellResults(results);
+    }
+
+    private void receivedGpsMessage(Intent intent) {
+        String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
+        if (subject.equals(GPSScanner.SUBJECT_NEW_LOCATION)) {
+            reportCollectedLocation();
+            Location newPosition = intent.getParcelableExtra(GPSScanner.NEW_LOCATION_ARG_LOCATION);
+            mBundle = (newPosition != null) ? new StumblerBundle(newPosition, mPhoneType) : mBundle;
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+
+        if (action.equals(ACTION_FLUSH_TO_BUNDLE)) {
+            flush();
+            return;
+        } else if (action.equals(WifiScanner.ACTION_WIFIS_SCANNED)) {
+            receivedWifiMessage(intent);
+        } else if (action.equals(CellScanner.ACTION_CELLS_SCANNED)) {
+            receivedCellMessage(intent);
+        } else if (action.equals(GPSScanner.ACTION_GPS_UPDATED)) {
+            // Calls reportCollectedLocation, this is the ideal case
+            receivedGpsMessage(intent);
+        }
+
+        if (mBundle != null &&
+            (mBundle.getWifiData().size() > MAX_WIFIS_PER_LOCATION ||
+             mBundle.getCellData().size() > MAX_CELLS_PER_LOCATION)) {
+            // no gps for a while, have too much data, just bundle it
+            reportCollectedLocation();
+        }
+    }
+
+    private void putWifiResults(List results) {
+        if (mBundle == null) {
+            return;
+        }
+
+        Map currentWifiData = mBundle.getWifiData();
+        for (ScanResult result : results) {
+            String key = result.BSSID;
+            if (!currentWifiData.containsKey(key)) {
+                currentWifiData.put(key, result);
+            }
+        }
+    }
+
+    private void putCellResults(List cells) {
+        if (mBundle == null) {
+            return;
+        }
+
+        Map currentCellData = mBundle.getCellData();
+        for (CellInfo result : cells) {
+            String key = result.getCellIdentity();
+            if (!currentCellData.containsKey(key)) {
+                currentCellData.put(key, result);
+            }
+        }
+    }
+
+    private void reportCollectedLocation() {
+        if (mBundle == null) {
+            return;
+        }
+
+        storeBundleAsJSON(mBundle);
+
+        mBundle.wasSent();
+    }
+
+    private void storeBundleAsJSON(StumblerBundle bundle) {
+        JSONObject mlsObj;
+        int wifiCount = 0;
+        int cellCount = 0;
+        try {
+            mlsObj = bundle.toMLSJSON();
+            wifiCount = mlsObj.getInt(DataStorageContract.ReportsColumns.WIFI_COUNT);
+            cellCount = mlsObj.getInt(DataStorageContract.ReportsColumns.CELL_COUNT);
+
+        } catch (JSONException e) {
+            Log.w(LOG_TAG, "Failed to convert bundle to JSON: " + e);
+            return;
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.d(LOG_TAG, "Received bundle: " + mlsObj.toString());
+        }
+
+        AppGlobals.guiLogInfo(mlsObj.toString());
+
+        try {
+            DataStorageManager.getInstance().insert(mlsObj.toString(), wifiCount, cellCount);
+        } catch (IOException e) {
+            Log.w(LOG_TAG, e.toString());
+        }
+    }
+}
+
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
new file mode 100644
index 000000000000..afa0340a306d
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
@@ -0,0 +1,247 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread;
+
+import android.content.Intent;
+import android.location.Location;
+import android.os.AsyncTask;
+import android.util.Log;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.Prefs;
+import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
+import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScannerNoWCDMA;
+import org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver;
+import org.mozilla.mozstumbler.service.utils.NetworkUtils;
+import org.mozilla.mozstumbler.service.utils.PersistentIntentService;
+
+// In stand-alone service mode (a.k.a passive scanning mode), this is created from PassiveServiceReceiver (by calling startService).
+// The StumblerService is a sticky unbound service in this usage.
+//
+public class StumblerService extends PersistentIntentService
+        implements DataStorageManager.StorageIsEmptyTracker {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + StumblerService.class.getSimpleName();
+    public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE;
+    public static final String ACTION_START_PASSIVE = ACTION_BASE + ".START_PASSIVE";
+    public static final String ACTION_EXTRA_MOZ_API_KEY = ACTION_BASE + ".MOZKEY";
+    public static final String ACTION_EXTRA_USER_AGENT = ACTION_BASE + ".USER_AGENT";
+    public static final String ACTION_NOT_FROM_HOST_APP = ACTION_BASE + ".NOT_FROM_HOST";
+    public static final AtomicBoolean sFirefoxStumblingEnabled = new AtomicBoolean();
+    protected final ScanManager mScanManager = new ScanManager();
+    protected final Reporter mReporter = new Reporter();
+
+    // This is a delay before the single-shot upload is attempted. The number is arbitrary
+    // and used to avoid startup tasks bunching up.
+    private static final int DELAY_IN_SEC_BEFORE_STARTING_UPLOAD_IN_PASSIVE_MODE = 2;
+
+    // This is the frequency of the repeating upload alarm in active scanning mode.
+    private static final int FREQUENCY_IN_SEC_OF_UPLOAD_IN_ACTIVE_MODE = 5 * 60;
+
+    // Used to guard against attempting to upload too frequently in passive mode.
+    private static final long PASSIVE_UPLOAD_FREQ_GUARD_MSEC = 5 * 60 * 1000;
+
+    public StumblerService() {
+        this("StumblerService");
+    }
+
+    public StumblerService(String name) {
+        super(name);
+    }
+
+    public boolean isScanning() {
+        return mScanManager.isScanning();
+    }
+
+    public void startScanning() {
+        mScanManager.startScanning(this);
+    }
+
+    // This is optional, not used in Fennec, and is for clients to specify a (potentially long) list
+    // of blocklisted SSIDs/BSSIDs
+    public void setWifiBlockList(WifiBlockListInterface list) {
+        mScanManager.setWifiBlockList(list);
+    }
+
+    public Prefs getPrefs() {
+        return Prefs.getInstance();
+    }
+
+    public void checkPrefs() {
+        mScanManager.checkPrefs();
+    }
+
+    public int getLocationCount() {
+        return mScanManager.getLocationCount();
+    }
+
+    public double getLatitude() {
+        return mScanManager.getLatitude();
+    }
+
+    public double getLongitude() {
+        return mScanManager.getLongitude();
+    }
+
+    public Location getLocation() {
+        return mScanManager.getLocation();
+    }
+
+    public int getWifiStatus() {
+        return mScanManager.getWifiStatus();
+    }
+
+    public int getAPCount() {
+        return mScanManager.getAPCount();
+    }
+
+    public int getVisibleAPCount() {
+        return mScanManager.getVisibleAPCount();
+    }
+
+    public int getCellInfoCount() {
+        return mScanManager.getCellInfoCount();
+    }
+
+    public int getCurrentCellInfoCount() {
+        return mScanManager.getCurrentCellInfoCount();
+    }
+
+    public boolean isGeofenced () {
+        return mScanManager.isGeofenced();
+    }
+
+    // Previously this was done in onCreate(). Moved out of that so that in the passive standalone service
+    // use (i.e. Fennec), init() can be called from this class's dedicated thread.
+    // Safe to call more than once, ensure added code complies with that intent.
+    protected void init() {
+        Prefs.createGlobalInstance(this);
+        NetworkUtils.createGlobalInstance(this);
+        DataStorageManager.createGlobalInstance(this, this);
+
+        if (!CellScanner.isCellScannerImplSet()) {
+            CellScanner.setCellScannerImpl(new CellScannerNoWCDMA(this));
+        }
+
+        mReporter.startup(this);
+    }
+
+    // Called from the main thread.
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        setIntentRedelivery(true);
+    }
+
+    // Called from the main thread
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        if (!mScanManager.isScanning()) {
+            return;
+        }
+
+        // Used to move these disk I/O ops off the calling thread. The current operations here are synchronized,
+        // however instead of creating another thread (if onDestroy grew to have concurrency complications)
+        // we could be messaging the stumbler thread to perform a shutdown function.
+        new AsyncTask() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                if (AppGlobals.isDebug) {
+                    Log.d(LOG_TAG, "onDestroy");
+                }
+
+                if (!sFirefoxStumblingEnabled.get()) {
+                    Prefs.getInstance().setFirefoxScanEnabled(false);
+                }
+
+                if (DataStorageManager.getInstance() != null) {
+                    try {
+                        DataStorageManager.getInstance().saveCurrentReportsToDisk();
+                    } catch (IOException ex) {
+                        AppGlobals.guiLogInfo(ex.toString());
+                        Log.e(LOG_TAG, "Exception in onDestroy saving reports" + ex.toString());
+                    }
+                }
+                return null;
+            }
+        }.execute();
+
+        mReporter.shutdown();
+        mScanManager.stopScanning();
+    }
+
+    // This is the entry point for the stumbler thread.
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        // Do init() in all cases, there is no cost, whereas it is easy to add code that depends on this.
+        init();
+
+        // Post-init(), set the mode to passive.
+        mScanManager.setPassiveMode(true);
+
+        if (intent == null) {
+            return;
+        }
+
+        final boolean isScanEnabledInPrefs = Prefs.getInstance().getFirefoxScanEnabled();
+
+        if (!isScanEnabledInPrefs && intent.getBooleanExtra(ACTION_NOT_FROM_HOST_APP, false)) {
+            stopSelf();
+            return;
+        }
+
+        if (!DataStorageManager.getInstance().isDirEmpty()) {
+            // non-empty on startup, schedule an upload
+            // This is the only upload trigger in Firefox mode
+            // Firefox triggers this ~4 seconds after startup (after Gecko is loaded), add a small delay to avoid
+            // clustering with other operations that are triggered at this time.
+            final long lastAttemptedTime = Prefs.getInstance().getLastAttemptedUploadTime();
+            final long timeNow = System.currentTimeMillis();
+
+            if (timeNow - lastAttemptedTime < PASSIVE_UPLOAD_FREQ_GUARD_MSEC) {
+                // TODO Consider telemetry to track this.
+                if (AppGlobals.isDebug) {
+                    Log.d(LOG_TAG, "Upload attempt too frequent.");
+                }
+            } else {
+                Prefs.getInstance().setLastAttemptedUploadTime(timeNow);
+                UploadAlarmReceiver.scheduleAlarm(this, DELAY_IN_SEC_BEFORE_STARTING_UPLOAD_IN_PASSIVE_MODE, false /* no repeat*/);
+            }
+        }
+
+        if (!isScanEnabledInPrefs) {
+            Prefs.getInstance().setFirefoxScanEnabled(true);
+        }
+
+        String apiKey = intent.getStringExtra(ACTION_EXTRA_MOZ_API_KEY);
+        if (apiKey != null && !apiKey.equals(Prefs.getInstance().getMozApiKey())) {
+            Prefs.getInstance().setMozApiKey(apiKey);
+        }
+
+        String userAgent = intent.getStringExtra(ACTION_EXTRA_USER_AGENT);
+        if (userAgent != null && !userAgent.equals(Prefs.getInstance().getUserAgent())) {
+            Prefs.getInstance().setUserAgent(userAgent);
+        }
+
+        if (!mScanManager.isScanning()) {
+            startScanning();
+        }
+    }
+
+    // Note that in passive mode, having data isn't an upload trigger, it is triggered by the start intent
+    public void notifyStorageStateEmpty(boolean isEmpty) {
+        if (isEmpty) {
+            UploadAlarmReceiver.cancelAlarm(this, !mScanManager.isPassiveMode());
+        } else if (!mScanManager.isPassiveMode()) {
+            UploadAlarmReceiver.scheduleAlarm(this, FREQUENCY_IN_SEC_OF_UPLOAD_IN_ACTIVE_MODE, true /* repeating */);
+        }
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java
new file mode 100644
index 000000000000..fdc9f3eb71df
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java
@@ -0,0 +1,65 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.blocklist;
+
+import android.net.wifi.ScanResult;
+import android.util.Log;
+import org.mozilla.mozstumbler.service.AppGlobals;
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+public final class BSSIDBlockList {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + BSSIDBlockList.class.getSimpleName();
+    private static final String NULL_BSSID = "000000000000";
+    private static final String WILDCARD_BSSID = "ffffffffffff";
+    private static final Pattern BSSID_PATTERN = Pattern.compile("([0-9a-f]{12})");
+    private static String[] sOuiList = new String[]{};
+
+    private BSSIDBlockList() {
+    }
+
+    public static void setFilterList(String[] list) {
+        sOuiList = list;
+    }
+
+    public static boolean contains(ScanResult scanResult) {
+        String BSSID = scanResult.BSSID;
+        if (BSSID == null || NULL_BSSID.equals(BSSID) || WILDCARD_BSSID.equals(BSSID)) {
+            return true; // blocked!
+        }
+
+        if (!isCanonicalBSSID(BSSID)) {
+            Log.w(LOG_TAG, "", new IllegalArgumentException("Unexpected BSSID format: " + BSSID));
+            return true; // blocked!
+        }
+
+        for (String oui : sOuiList) {
+            if (BSSID.startsWith(oui)) {
+                return true; // blocked!
+            }
+        }
+
+        return false; // OK
+    }
+
+    public static String canonicalizeBSSID(String BSSID) {
+        if (BSSID == null) {
+            return "";
+        }
+
+        if (isCanonicalBSSID(BSSID)) {
+            return BSSID;
+        }
+
+        // Some devices may return BSSIDs with ':', '-' or '.' delimiters.
+        BSSID = BSSID.toLowerCase(Locale.US).replaceAll("[\\-\\.:]", "");
+
+        return isCanonicalBSSID(BSSID) ? BSSID : "";
+    }
+
+    private static boolean isCanonicalBSSID(String BSSID) {
+        return BSSID_PATTERN.matcher(BSSID).matches();
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java
new file mode 100644
index 000000000000..f5086ab34211
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java
@@ -0,0 +1,41 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.blocklist;
+
+import android.net.wifi.ScanResult;
+
+public final class SSIDBlockList {
+    private static String[] sPrefixList = new String[]{};
+    private static String[] sSuffixList = new String[]{"_nomap"};
+
+    private SSIDBlockList() {
+    }
+
+    public static void setFilterLists(String[] prefix, String[] suffix) {
+        sPrefixList = prefix;
+        sSuffixList = suffix;
+    }
+
+    public static boolean contains(ScanResult scanResult) {
+        String SSID = scanResult.SSID;
+        if (SSID == null) {
+            return true; // no SSID?
+        }
+
+        for (String prefix : sPrefixList) {
+            if (SSID.startsWith(prefix)) {
+                return true; // blocked!
+            }
+        }
+
+        for (String suffix : sSuffixList) {
+            if (SSID.endsWith(suffix)) {
+                return true; // blocked!
+            }
+        }
+
+        return false; // OK
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/PlaceHolder.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java
similarity index 50%
rename from mobile/android/stumbler/java/org/mozilla/mozstumbler/PlaceHolder.java
rename to mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java
index 83aef63d34e6..0e940cdc99df 100644
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/PlaceHolder.java
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java
@@ -2,11 +2,10 @@
  * 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/. */
 
-package org.mozilla.mozstumbler;
+package org.mozilla.mozstumbler.service.stumblerthread.blocklist;
 
-/**
- * Bug 1024708: this class is a place-holder for landing the build integration
- * of the background stumbler into Fennec.
- */
-public class PlaceHolder {
+public interface WifiBlockListInterface {
+    String[] getSsidPrefixList();
+    String[] getSsidSuffixList();
+    String[] getBssidOuiList();
 }
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java
new file mode 100644
index 000000000000..111d63f0dd2c
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java
@@ -0,0 +1,34 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.datahandling;
+
+public final class DataStorageContract {
+
+    public static class ReportsColumns {
+        public static final String LAT = "lat";
+        public static final String LON = "lon";
+        public static final String TIME = "timestamp";
+        public static final String ACCURACY = "accuracy";
+        public static final String ALTITUDE = "altitude";
+        public static final String RADIO = "radio";
+        public static final String CELL = "cell";
+        public static final String WIFI = "wifi";
+        public static final String CELL_COUNT = "cell_count";
+        public static final String WIFI_COUNT = "wifi_count";
+    }
+
+    public static class Stats {
+        public static final String KEY_VERSION = "version_code";
+        public static final int VERSION_CODE = 1;
+        public static final String KEY_BYTES_SENT = "bytes_sent";
+        public static final String KEY_LAST_UPLOAD_TIME = "last_upload_time";
+        public static final String KEY_OBSERVATIONS_SENT = "observations_sent";
+        public static final String KEY_WIFIS_SENT = "wifis_sent";
+        public static final String KEY_CELLS_SENT = "cells_sent";
+    }
+
+    private DataStorageContract() {
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
new file mode 100644
index 000000000000..acbfe53693fb
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
@@ -0,0 +1,527 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.datahandling;
+
+import android.content.Context;
+import android.util.Log;
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.utils.Zipper;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Properties;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/* Stores reports in memory (mCurrentReports) until MAX_REPORTS_IN_MEMORY,
+ * then writes them to disk as a .gz file. The name of the file has
+ * the time written, the # of reports, and the # of cells and wifis.
+ *
+ * Each .gz file is typically 1-5KB. File name example: reports-t1406863343313-r4-w25-c7.gz
+ *
+ * The sync stats are written as a key-value pair file (not zipped).
+ *
+ * The tricky bit is the mCurrentReportsSendBuffer. When the uploader code begins accessing the
+ * report batches, mCurrentReports gets pushed to mCurrentReportsSendBuffer.
+ * The mCurrentReports is then cleared, and can continue receiving new reports.
+ * From the uploader perspective, mCurrentReportsSendBuffer looks and acts exactly like a batch file on disk.
+ *
+ * If the network is reasonably active, and reporting is slow enough, there is no disk I/O, it all happens
+ * in-memory.
+ *
+ * Also of note: the in-memory buffers (both mCurrentReports and mCurrentReportsSendBuffer) are saved
+ * when the service is destroyed.
+ */
+public class DataStorageManager {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + DataStorageManager.class.getSimpleName();
+
+    // The max number of reports stored in the mCurrentReports. Each report is a GPS location plus wifi and cell scan.
+    // After this size is reached, data is persisted to disk, mCurrentReports is cleared.
+    private static final int MAX_REPORTS_IN_MEMORY = 50;
+
+    // Used to cap the amount of data stored. When this limit is hit, no more data is saved to disk
+    // until the data is uploaded, or and data exceeds DEFAULT_MAX_WEEKS_DATA_ON_DISK.
+    private static final long DEFAULT_MAX_BYTES_STORED_ON_DISK = 1024 * 250; // 250 KiB max by default
+
+    // Used as a safeguard to ensure stumbling data is not persisted. The intended use case of the stumbler lib is not
+    // for long-term storage, and so if ANY data on disk is this old, ALL data is wiped as a privacy mechanism.
+    private static final int DEFAULT_MAX_WEEKS_DATA_ON_DISK = 2;
+
+    // Set to the default value specified above.
+    private final long mMaxBytesDiskStorage;
+
+    // Set to the default value specified above.
+    private final int mMaxWeeksStored;
+
+    private final ReportBatchBuilder mCurrentReports = new ReportBatchBuilder();
+    private final File mReportsDir;
+    private final File mStatsFile;
+    private final StorageIsEmptyTracker mTracker;
+
+    private static DataStorageManager sInstance;
+
+    private ReportBatch mCurrentReportsSendBuffer;
+    private ReportBatchIterator mReportBatchIterator;
+    private ReportFileList mFileList;
+    private Timer mFlushMemoryBuffersToDiskTimer;
+
+    static final String SEP_REPORT_COUNT = "-r";
+    static final String SEP_WIFI_COUNT = "-w";
+    static final String SEP_CELL_COUNT = "-c";
+    static final String SEP_TIME_MS = "-t";
+    static final String FILENAME_PREFIX = "reports";
+    static final String MEMORY_BUFFER_NAME = "in memory send buffer";
+
+    public static class QueuedCounts {
+        public final int mReportCount;
+        public final int mWifiCount;
+        public final int mCellCount;
+        public final long mBytes;
+
+        QueuedCounts(int reportCount, int wifiCount, int cellCount, long bytes) {
+            this.mReportCount = reportCount;
+            this.mWifiCount = wifiCount;
+            this.mCellCount = cellCount;
+            this.mBytes = bytes;
+        }
+    }
+
+    /* Some data is calculated on-demand, don't abuse this function */
+    public QueuedCounts getQueuedCounts() {
+        int reportCount = mFileList.mReportCount + mCurrentReports.reports.size();
+        int wifiCount = mFileList.mWifiCount + mCurrentReports.wifiCount;
+        int cellCount = mFileList.mCellCount + mCurrentReports.cellCount;
+        long bytes = 0;
+
+        if (mCurrentReports.reports.size() > 0) {
+            try {
+                bytes = Zipper.zipData(finalizeReports(mCurrentReports.reports).getBytes()).length;
+            } catch (IOException ex) {
+                Log.e(LOG_TAG, "Zip error in getQueuedCounts()", ex);
+            }
+
+            if (mFileList.mReportCount > 0) {
+                bytes += mFileList.mFilesOnDiskBytes;
+            }
+        }
+
+        if (mCurrentReportsSendBuffer != null) {
+            reportCount += mCurrentReportsSendBuffer.reportCount;
+            wifiCount += mCurrentReportsSendBuffer.wifiCount;
+            cellCount += mCurrentReportsSendBuffer.cellCount;
+            bytes += mCurrentReportsSendBuffer.data.length;
+        }
+        return new QueuedCounts(reportCount, wifiCount, cellCount, bytes);
+    }
+
+    private static class ReportFileList {
+        File[] mFiles;
+        int mReportCount;
+        int mWifiCount;
+        int mCellCount;
+        long mFilesOnDiskBytes;
+
+        public ReportFileList() {}
+        public ReportFileList(ReportFileList other) {
+            if (other == null) {
+                return;
+            }
+
+            if (other.mFiles != null) {
+                mFiles = other.mFiles.clone();
+            }
+
+            mReportCount = other.mReportCount;
+            mWifiCount = other.mWifiCount;
+            mCellCount = other.mCellCount;
+            mFilesOnDiskBytes = other.mFilesOnDiskBytes;
+        }
+
+        void update(File directory) {
+            mFiles = directory.listFiles();
+            if (mFiles == null) {
+                return;
+            }
+
+            if (AppGlobals.isDebug) {
+                for (File f : mFiles) {
+                    Log.d("StumblerFiles", f.getName());
+                }
+            }
+
+            mFilesOnDiskBytes = mReportCount = mWifiCount = mCellCount = 0;
+            for (File f : mFiles) {
+                mReportCount += (int) getLongFromFilename(f.getName(), SEP_REPORT_COUNT);
+                mWifiCount += (int) getLongFromFilename(f.getName(), SEP_WIFI_COUNT);
+                mCellCount += (int) getLongFromFilename(f.getName(), SEP_CELL_COUNT);
+                mFilesOnDiskBytes += f.length();
+            }
+        }
+    }
+
+    public static class ReportBatch {
+        public final String filename;
+        public final byte[] data;
+        public final int reportCount;
+        public final int wifiCount;
+        public final int cellCount;
+
+        public ReportBatch(String filename, byte[] data, int reportCount, int wifiCount, int cellCount) {
+            this.filename = filename;
+            this.data = data;
+            this.reportCount = reportCount;
+            this.wifiCount = wifiCount;
+            this.cellCount = cellCount;
+        }
+    }
+
+    private static class ReportBatchBuilder {
+        public final ArrayList reports = new ArrayList();
+        public int wifiCount;
+        public int cellCount;
+    }
+
+    private static class ReportBatchIterator {
+        public ReportBatchIterator(ReportFileList list) {
+            fileList = new ReportFileList(list);
+        }
+
+        static final int BATCH_INDEX_FOR_MEM_BUFFER = -1;
+        public int currentIndex = BATCH_INDEX_FOR_MEM_BUFFER;
+        public final ReportFileList fileList;
+    }
+
+    public interface StorageIsEmptyTracker {
+        public void notifyStorageStateEmpty(boolean isEmpty);
+    }
+
+    private String getStorageDir(Context c) {
+        File dir = null;
+        if (AppGlobals.isDebug) {
+            // in debug, put files in public location
+            dir = c.getExternalFilesDir(null);
+            if (dir != null) {
+                dir = new File(dir.getAbsolutePath() + "/mozstumbler");
+            }
+        }
+
+        if (dir == null) {
+            dir = c.getFilesDir();
+        }
+
+        if (!dir.exists()) {
+            boolean ok = dir.mkdirs();
+            if (!ok) {
+                Log.d(LOG_TAG, "getStorageDir: error in mkdirs()");
+            }
+        }
+
+        return dir.getPath();
+    }
+
+    public static synchronized void createGlobalInstance(Context context, StorageIsEmptyTracker tracker) {
+        DataStorageManager.createGlobalInstance(context, tracker,
+                DEFAULT_MAX_BYTES_STORED_ON_DISK, DEFAULT_MAX_WEEKS_DATA_ON_DISK);
+    }
+
+    public static synchronized void createGlobalInstance(Context context, StorageIsEmptyTracker tracker,
+                                                         long maxBytesStoredOnDisk, int maxWeeksDataStored) {
+        if (sInstance != null) {
+            return;
+        }
+        sInstance = new DataStorageManager(context, tracker, maxBytesStoredOnDisk, maxWeeksDataStored);
+    }
+
+    public static synchronized DataStorageManager getInstance() {
+        return sInstance;
+    }
+
+    private DataStorageManager(Context c, StorageIsEmptyTracker tracker,
+                               long maxBytesStoredOnDisk, int maxWeeksDataStored) {
+        mMaxBytesDiskStorage = maxBytesStoredOnDisk;
+        mMaxWeeksStored = maxWeeksDataStored;
+        mTracker = tracker;
+        final String baseDir = getStorageDir(c);
+        mStatsFile = new File(baseDir, "upload_stats.ini");
+        mReportsDir = new File(baseDir + "/reports");
+        if (!mReportsDir.exists()) {
+            mReportsDir.mkdirs();
+        }
+        mFileList = new ReportFileList();
+        mFileList.update(mReportsDir);
+    }
+
+    public synchronized int getMaxWeeksStored() {
+        return mMaxWeeksStored;
+    }
+
+    private static byte[] readFile(File file) throws IOException {
+        final RandomAccessFile f = new RandomAccessFile(file, "r");
+        try {
+            final byte[] data = new byte[(int) f.length()];
+            f.readFully(data);
+            return data;
+        } finally {
+            f.close();
+        }
+    }
+
+    public synchronized boolean isDirEmpty() {
+        return (mFileList.mFiles == null || mFileList.mFiles.length < 1);
+    }
+
+    /* Pass filename returned from dataToSend() */
+    public synchronized boolean delete(String filename) {
+        if (filename == MEMORY_BUFFER_NAME) {
+            mCurrentReportsSendBuffer = null;
+            return true;
+        }
+
+        final File file = new File(mReportsDir, filename);
+        final boolean ok = file.delete();
+        mFileList.update(mReportsDir);
+        return ok;
+    }
+
+    private static long getLongFromFilename(String name, String separator) {
+        final int s = name.indexOf(separator) + separator.length();
+        int e = name.indexOf('-', s);
+        if (e < 0) {
+            e = name.indexOf('.', s);
+        }
+        return Long.parseLong(name.substring(s, e));
+    }
+
+    /* return name of file used, or memory buffer sentinel value.
+     * The return value is used to delete the file/buffer later. */
+    public synchronized ReportBatch getFirstBatch() throws IOException {
+        final boolean dirEmpty = isDirEmpty();
+        final int currentReportsCount = mCurrentReports.reports.size();
+
+        if (dirEmpty && currentReportsCount < 1) {
+            return null;
+        }
+
+        mReportBatchIterator = new ReportBatchIterator(mFileList);
+
+        if (currentReportsCount > 0) {
+            final String filename = MEMORY_BUFFER_NAME;
+            final byte[] data = Zipper.zipData(finalizeReports(mCurrentReports.reports).getBytes());
+            final int wifiCount = mCurrentReports.wifiCount;
+            final int cellCount = mCurrentReports.cellCount;
+            clearCurrentReports();
+            final ReportBatch result = new ReportBatch(filename, data, currentReportsCount, wifiCount, cellCount);
+            mCurrentReportsSendBuffer = result;
+            return result;
+        } else {
+            return getNextBatch();
+        }
+    }
+
+    private void clearCurrentReports() {
+        mCurrentReports.reports.clear();
+        mCurrentReports.wifiCount = mCurrentReports.cellCount = 0;
+    }
+
+    public synchronized ReportBatch getNextBatch() throws IOException {
+        if (mReportBatchIterator == null) {
+            return null;
+        }
+
+        mReportBatchIterator.currentIndex++;
+        if (mReportBatchIterator.currentIndex < 0 ||
+            mReportBatchIterator.currentIndex > mReportBatchIterator.fileList.mFiles.length - 1) {
+            return null;
+        }
+
+        final File f = mReportBatchIterator.fileList.mFiles[mReportBatchIterator.currentIndex];
+        final String filename = f.getName();
+        final int reportCount = (int) getLongFromFilename(f.getName(), SEP_REPORT_COUNT);
+        final int wifiCount = (int) getLongFromFilename(f.getName(), SEP_WIFI_COUNT);
+        final int cellCount = (int) getLongFromFilename(f.getName(), SEP_CELL_COUNT);
+        final byte[] data = readFile(f);
+        return new ReportBatch(filename, data, reportCount, wifiCount, cellCount);
+    }
+
+    private File createFile(int reportCount, int wifiCount, int cellCount) {
+        final long time = System.currentTimeMillis();
+        final String name = FILENAME_PREFIX +
+                      SEP_TIME_MS + time +
+                      SEP_REPORT_COUNT + reportCount +
+                      SEP_WIFI_COUNT + wifiCount +
+                      SEP_CELL_COUNT + cellCount + ".gz";
+        return new File(mReportsDir, name);
+    }
+
+    public synchronized long getOldestBatchTimeMs() {
+        if (isDirEmpty()) {
+            return 0;
+        }
+
+        long oldest = Long.MAX_VALUE;
+        for (File f : mFileList.mFiles) {
+            final long t = getLongFromFilename(f.getName(), SEP_TIME_MS);
+            if (t < oldest) {
+                oldest = t;
+            }
+        }
+        return oldest;
+    }
+
+    public synchronized void saveCurrentReportsSendBufferToDisk() throws IOException {
+        if (mCurrentReportsSendBuffer == null || mCurrentReportsSendBuffer.reportCount < 1) {
+            return;
+        }
+
+        saveToDisk(mCurrentReportsSendBuffer.data,
+                   mCurrentReportsSendBuffer.reportCount,
+                   mCurrentReportsSendBuffer.wifiCount,
+                   mCurrentReportsSendBuffer.cellCount);
+        mCurrentReportsSendBuffer = null;
+    }
+
+    private void saveToDisk(byte[] bytes, int reportCount, int wifiCount, int cellCount)
+      throws IOException {
+        if (mFileList.mFilesOnDiskBytes > mMaxBytesDiskStorage) {
+            return;
+        }
+
+        final FileOutputStream fos = new FileOutputStream(createFile(reportCount, wifiCount, cellCount));
+        try {
+            fos.write(bytes);
+        } finally {
+            fos.close();
+        }
+        mFileList.update(mReportsDir);
+    }
+
+    private String finalizeReports(ArrayList reports) {
+        final String kPrefix = "{\"items\":[";
+        final String kSuffix = "]}";
+        final StringBuilder sb = new StringBuilder(kPrefix);
+        String sep = "";
+        final String separator = ",";
+        if (reports != null) {
+            for(String s: reports) {
+                sb.append(sep).append(s);
+                sep = separator;
+            }
+        }
+
+        final String result = sb.append(kSuffix).toString();
+        if (AppGlobals.isDebug) {
+            Log.d(LOG_TAG, result);
+        }
+        return result;
+    }
+
+    public synchronized void saveCurrentReportsToDisk() throws IOException {
+        saveCurrentReportsSendBufferToDisk();
+        if (mCurrentReports.reports.size() < 1) {
+            return;
+        }
+        final byte[] bytes = Zipper.zipData(finalizeReports(mCurrentReports.reports).getBytes());
+        saveToDisk(bytes, mCurrentReports.reports.size(), mCurrentReports.wifiCount, mCurrentReports.cellCount);
+        clearCurrentReports();
+    }
+
+    public synchronized void insert(String report, int wifiCount, int cellCount) throws IOException {
+        notifyStorageIsEmpty(false);
+
+        if (mFlushMemoryBuffersToDiskTimer != null) {
+            mFlushMemoryBuffersToDiskTimer.cancel();
+            mFlushMemoryBuffersToDiskTimer = null;
+        }
+
+        mCurrentReports.reports.add(report);
+        mCurrentReports.wifiCount = wifiCount;
+        mCurrentReports.cellCount = cellCount;
+
+        if (mCurrentReports.reports.size() >= MAX_REPORTS_IN_MEMORY) {
+            // save to disk
+            saveCurrentReportsToDisk();
+        } else {
+            // Schedule a timer to flush to disk after a few mins.
+            // If collection stops and wifi not available for uploading, the memory buffer is flushed to disk.
+            final int kMillis = 1000 * 60 * 3;
+            mFlushMemoryBuffersToDiskTimer = new Timer();
+            mFlushMemoryBuffersToDiskTimer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    try {
+                        saveCurrentReportsToDisk();
+                    } catch (IOException ex) {
+                        Log.e(LOG_TAG, "mFlushMemoryBuffersToDiskTimer exception" + ex);
+                    }
+                }
+            }, kMillis);
+        }
+    }
+
+    public synchronized Properties readSyncStats() throws IOException {
+        if (!mStatsFile.exists()) {
+            return new Properties();
+        }
+
+        final FileInputStream input = new FileInputStream(mStatsFile);
+        try {
+            final Properties props = new Properties();
+            props.load(input);
+            return props;
+        } finally {
+            input.close();
+        }
+    }
+
+    public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
+        if (reports + cells + wifis < 1) {
+            return;
+        }
+
+        final Properties properties = readSyncStats();
+        final long time = System.currentTimeMillis();
+        writeSyncStats(time,
+            Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_BYTES_SENT, "0")) + bytesSent,
+            Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, "0")) + reports,
+            Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_CELLS_SENT, "0")) + cells,
+            Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, "0")) + wifis);
+    }
+
+    public void writeSyncStats(long time, long bytesSent, long totalObs, long totalCells, long totalWifis) throws IOException {
+        final FileOutputStream out = new FileOutputStream(mStatsFile);
+        try {
+            final Properties props = new Properties();
+            props.setProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, String.valueOf(time));
+            props.setProperty(DataStorageContract.Stats.KEY_BYTES_SENT, String.valueOf(bytesSent));
+            props.setProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, String.valueOf(totalObs));
+            props.setProperty(DataStorageContract.Stats.KEY_CELLS_SENT, String.valueOf(totalCells));
+            props.setProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, String.valueOf(totalWifis));
+            props.setProperty(DataStorageContract.Stats.KEY_VERSION, String.valueOf(DataStorageContract.Stats.VERSION_CODE));
+            props.store(out, null);
+        } finally {
+            out.close();
+        }
+    }
+
+    public synchronized void deleteAll() {
+        if (mFileList.mFiles == null) {
+            return;
+        }
+
+        for (File f : mFileList.mFiles) {
+            f.delete();
+        }
+        mFileList.update(mReportsDir);
+    }
+
+    private void notifyStorageIsEmpty(boolean isEmpty) {
+        if (mTracker != null) {
+            mTracker.notifyStorageStateEmpty(isEmpty);
+        }
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java
new file mode 100644
index 000000000000..b642ad8c0013
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java
@@ -0,0 +1,157 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.datahandling;
+
+import android.location.Location;
+import android.net.wifi.ScanResult;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.TelephonyManager;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellInfo;
+
+public final class StumblerBundle implements Parcelable {
+    private final int mPhoneType;
+    private final Location mGpsPosition;
+    private final Map mWifiData;
+    private final Map mCellData;
+
+    public void wasSent() {
+        mGpsPosition.setTime(System.currentTimeMillis());
+        mWifiData.clear();
+        mCellData.clear();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        Bundle wifiBundle = new Bundle(ScanResult.class.getClassLoader());
+        Collection scans = mWifiData.keySet();
+        for (String s : scans) {
+            wifiBundle.putParcelable(s, mWifiData.get(s));
+        }
+
+        Bundle cellBundle = new Bundle(CellInfo.class.getClassLoader());
+        Collection cells = mCellData.keySet();
+        for (String c : cells) {
+            cellBundle.putParcelable(c, mCellData.get(c));
+        }
+
+        out.writeBundle(wifiBundle);
+        out.writeBundle(cellBundle);
+        out.writeParcelable(mGpsPosition, 0);
+        out.writeInt(mPhoneType);
+    }
+
+    public static final Parcelable.Creator CREATOR
+        = new Parcelable.Creator() {
+        @Override
+        public StumblerBundle createFromParcel(Parcel in) {
+            return new StumblerBundle(in);
+        }
+
+        @Override
+        public StumblerBundle[] newArray(int size) {
+            return new StumblerBundle[size];
+        }
+    };
+
+    private StumblerBundle(Parcel in) {
+        mWifiData = new HashMap();
+        mCellData = new HashMap();
+
+        Bundle wifiBundle = in.readBundle(ScanResult.class.getClassLoader());
+        Bundle cellBundle = in.readBundle(CellInfo.class.getClassLoader());
+
+        Collection scans = wifiBundle.keySet();
+        for (String s : scans) {
+            mWifiData.put(s, (ScanResult) wifiBundle.get(s));
+        }
+
+        Collection cells = cellBundle.keySet();
+        for (String c : cells) {
+            mCellData.put(c, (CellInfo) cellBundle.get(c));
+        }
+
+        mGpsPosition = in.readParcelable(Location.class.getClassLoader());
+        mPhoneType = in.readInt();
+    }
+
+    public StumblerBundle(Location position, int phoneType) {
+        mGpsPosition = position;
+        mPhoneType = phoneType;
+        mWifiData = new HashMap();
+        mCellData = new HashMap();
+    }
+
+    public Location getGpsPosition() {
+        return mGpsPosition;
+    }
+
+    public Map getWifiData() {
+        return mWifiData;
+    }
+
+    public Map getCellData() {
+        return mCellData;
+    }
+
+    public JSONObject toMLSJSON() throws JSONException {
+        JSONObject item = new JSONObject();
+
+        item.put(DataStorageContract.ReportsColumns.TIME, mGpsPosition.getTime());
+        item.put(DataStorageContract.ReportsColumns.LAT, Math.floor(mGpsPosition.getLatitude() * 1.0E6) / 1.0E6);
+        item.put(DataStorageContract.ReportsColumns.LON, Math.floor(mGpsPosition.getLongitude() * 1.0E6) / 1.0E6);
+
+        if (mGpsPosition.hasAccuracy()) {
+            item.put(DataStorageContract.ReportsColumns.ACCURACY, (int) Math.ceil(mGpsPosition.getAccuracy()));
+        }
+
+        if (mGpsPosition.hasAltitude()) {
+            item.put(DataStorageContract.ReportsColumns.ALTITUDE, Math.round(mGpsPosition.getAltitude()));
+        }
+
+        if (mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
+            item.put(DataStorageContract.ReportsColumns.RADIO, "gsm");
+        } else if (mPhoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+            item.put(DataStorageContract.ReportsColumns.RADIO, "cdma");
+        } else {
+            // issue #598. investigate this case further in future
+            item.put(DataStorageContract.ReportsColumns.RADIO, "");
+        }
+
+        JSONArray cellJSON = new JSONArray();
+        for (CellInfo c : mCellData.values()) {
+            JSONObject obj = c.toJSONObject();
+            cellJSON.put(obj);
+        }
+
+        item.put(DataStorageContract.ReportsColumns.CELL, cellJSON);
+        item.put(DataStorageContract.ReportsColumns.CELL_COUNT, cellJSON.length());
+
+        JSONArray wifis = new JSONArray();
+        for (ScanResult s : mWifiData.values()) {
+            JSONObject wifiEntry = new JSONObject();
+            wifiEntry.put("key", s.BSSID);
+            wifiEntry.put("frequency", s.frequency);
+            wifiEntry.put("signal", s.level);
+            wifis.put(wifiEntry);
+        }
+        item.put(DataStorageContract.ReportsColumns.WIFI, wifis);
+        item.put(DataStorageContract.ReportsColumns.WIFI_COUNT, wifis.length());
+
+        return item;
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java
new file mode 100644
index 000000000000..8ef586fcd013
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java
@@ -0,0 +1,260 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners;
+
+import android.content.Context;
+import android.content.Intent;
+import android.location.GpsSatellite;
+import android.location.GpsStatus;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
+import org.mozilla.mozstumbler.service.Prefs;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class GPSScanner implements LocationListener {
+    public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".GPSScanner.";
+    public static final String ACTION_GPS_UPDATED = ACTION_BASE + "GPS_UPDATED";
+    public static final String ACTION_ARG_TIME = AppGlobals.ACTION_ARG_TIME;
+    public static final String SUBJECT_NEW_STATUS = "new_status";
+    public static final String SUBJECT_LOCATION_LOST = "location_lost";
+    public static final String SUBJECT_NEW_LOCATION = "new_location";
+    public static final String NEW_STATUS_ARG_FIXES = "fixes";
+    public static final String NEW_STATUS_ARG_SATS = "sats";
+    public static final String NEW_LOCATION_ARG_LOCATION = "location";
+
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + GPSScanner.class.getSimpleName();
+    private static final int MIN_SAT_USED_IN_FIX = 3;
+    private static final long ACTIVE_MODE_GPS_MIN_UPDATE_TIME_MS = 1000;
+    private static final float ACTIVE_MODE_GPS_MIN_UPDATE_DISTANCE_M = 10;
+    private static final long PASSIVE_GPS_MIN_UPDATE_FREQ_MS = 3000;
+    private static final float PASSIVE_GPS_MOVEMENT_MIN_DELTA_M = 30;
+
+    private final LocationBlockList mBlockList = new LocationBlockList();
+    private final Context mContext;
+    private GpsStatus.Listener mGPSListener;
+    private int mLocationCount;
+    private Location mLocation = new Location("internal");
+    private boolean mAutoGeofencing;
+    private boolean mIsPassiveMode;
+
+    private final ScanManager mScanManager;
+
+    public GPSScanner(Context context, ScanManager scanManager) {
+        mContext = context;
+        mScanManager = scanManager;
+    }
+
+    public void start(final ActiveOrPassiveStumbling stumblingMode) {
+        mIsPassiveMode = (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING);
+        if (mIsPassiveMode ) {
+            startPassiveMode();
+        } else {
+            startActiveMode();
+        }
+    }
+
+    private void startPassiveMode() {
+        LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
+                                               0,
+                                               0, this);
+    }
+
+    private void startActiveMode() {
+        LocationManager lm = getLocationManager();
+        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
+                                  ACTIVE_MODE_GPS_MIN_UPDATE_TIME_MS,
+                                  ACTIVE_MODE_GPS_MIN_UPDATE_DISTANCE_M,
+                                  this);
+
+        reportLocationLost();
+        mGPSListener = new GpsStatus.Listener() {
+                public void onGpsStatusChanged(int event) {
+                if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
+                    GpsStatus status = getLocationManager().getGpsStatus(null);
+                    Iterable sats = status.getSatellites();
+
+                    int satellites = 0;
+                    int fixes = 0;
+
+                    for (GpsSatellite sat : sats) {
+                        satellites++;
+                        if (sat.usedInFix()) {
+                            fixes++;
+                        }
+                    }
+                    reportNewGpsStatus(fixes, satellites);
+                    if (fixes < MIN_SAT_USED_IN_FIX) {
+                        reportLocationLost();
+                    }
+
+                    if (AppGlobals.isDebug) {
+                        Log.v(LOG_TAG, "onGpsStatusChange - satellites: " + satellites + " fixes: " + fixes);
+                    }
+                } else if (event == GpsStatus.GPS_EVENT_STOPPED) {
+                    reportLocationLost();
+                }
+            }
+        };
+
+        lm.addGpsStatusListener(mGPSListener);
+    }
+
+    public void stop() {
+        LocationManager lm = getLocationManager();
+        lm.removeUpdates(this);
+        reportLocationLost();
+
+        if (mGPSListener != null) {
+          lm.removeGpsStatusListener(mGPSListener);
+          mGPSListener = null;
+        }
+    }
+
+    public int getLocationCount() {
+        return mLocationCount;
+    }
+
+    public double getLatitude() {
+        return mLocation.getLatitude();
+    }
+
+    public double getLongitude() {
+        return mLocation.getLongitude();
+    }
+
+    public Location getLocation() {
+        return mLocation;
+    }
+
+    public void checkPrefs() {
+        if (mBlockList != null) {
+            mBlockList.updateBlocks();
+        }
+
+        mAutoGeofencing = Prefs.getInstance().getGeofenceHere();
+    }
+
+    public boolean isGeofenced() {
+        return (mBlockList != null) && mBlockList.isGeofenced();
+    }
+
+    private void sendToLogActivity(String msg) {
+        AppGlobals.guiLogInfo(msg, "#33ccff", false);
+    }
+
+    @Override
+    public void onLocationChanged(Location location) {
+        if (location == null) { // TODO: is this even possible??
+            reportLocationLost();
+            return;
+        }
+
+        String logMsg = (mIsPassiveMode)? "[Passive] " : "[Active] ";
+
+        String provider = location.getProvider();
+        if (!provider.toLowerCase().contains("gps")) {
+            sendToLogActivity(logMsg + "Discard fused/network location.");
+            // only interested in GPS locations
+            return;
+        }
+
+        // Seem to get greater likelihood of non-fused location with higher update freq.
+        // Check dist and time threshold here, not set on the listener.
+        if (mIsPassiveMode) {
+            final long timeDelta = location.getTime() - mLocation.getTime();
+            final boolean hasMoved = location.distanceTo(mLocation) > PASSIVE_GPS_MOVEMENT_MIN_DELTA_M;
+
+            if (timeDelta < PASSIVE_GPS_MIN_UPDATE_FREQ_MS || !hasMoved) {
+                return;
+            }
+        }
+
+        Date date = new Date(location.getTime());
+        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
+        String time = formatter.format(date);
+        logMsg += String.format("%s Coord: %.4f,%.4f, Acc: %.0f, Speed: %.0f, Alt: %.0f, Bearing: %.1f", time, location.getLatitude(),
+                location.getLongitude(), location.getAccuracy(), location.getSpeed(), location.getAltitude(), location.getBearing());
+        sendToLogActivity(logMsg);
+
+        if (mBlockList.contains(location)) {
+            Log.w(LOG_TAG, "Blocked location: " + location);
+            reportLocationLost();
+            return;
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.d(LOG_TAG, "New location: " + location);
+        }
+
+        mLocation = location;
+
+        if (!mAutoGeofencing) {
+            reportNewLocationReceived(location);
+        }
+        mLocationCount++;
+
+        if (mIsPassiveMode) {
+            mScanManager.newPassiveGpsLocation();
+        }
+    }
+
+    @Override
+    public void onProviderDisabled(String provider) {
+        if (LocationManager.GPS_PROVIDER.equals(provider)) {
+            reportLocationLost();
+        }
+    }
+
+    @Override
+    public void onProviderEnabled(String provider) {
+    }
+
+    @Override
+    public void onStatusChanged(String provider, int status, Bundle extras) {
+        if ((status != LocationProvider.AVAILABLE) &&
+            (LocationManager.GPS_PROVIDER.equals(provider))) {
+            reportLocationLost();
+        }
+    }
+
+    private LocationManager getLocationManager() {
+        return (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+    }
+
+    private void reportNewLocationReceived(Location location) {
+        Intent i = new Intent(ACTION_GPS_UPDATED);
+        i.putExtra(Intent.EXTRA_SUBJECT, SUBJECT_NEW_LOCATION);
+        i.putExtra(NEW_LOCATION_ARG_LOCATION, location);
+        i.putExtra(ACTION_ARG_TIME, System.currentTimeMillis());
+        LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
+    }
+
+    private void reportLocationLost() {
+        Intent i = new Intent(ACTION_GPS_UPDATED);
+        i.putExtra(Intent.EXTRA_SUBJECT, SUBJECT_LOCATION_LOST);
+        i.putExtra(ACTION_ARG_TIME, System.currentTimeMillis());
+        LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
+    }
+
+    private void reportNewGpsStatus(int fixes, int sats) {
+        Intent i = new Intent(ACTION_GPS_UPDATED);
+        i.putExtra(Intent.EXTRA_SUBJECT, SUBJECT_NEW_STATUS);
+        i.putExtra(NEW_STATUS_ARG_FIXES, fixes);
+        i.putExtra(NEW_STATUS_ARG_SATS, sats);
+        i.putExtra(ACTION_ARG_TIME, System.currentTimeMillis());
+        LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java
new file mode 100644
index 000000000000..bc7b4808bdda
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java
@@ -0,0 +1,101 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners;
+
+import android.location.Location;
+import android.util.Log;
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.Prefs;
+
+public final class LocationBlockList {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + LocationBlockList.class.getSimpleName();
+    private static final double MAX_ALTITUDE = 8848;      // Mount Everest's altitude in meters
+    private static final double MIN_ALTITUDE = -418;      // Dead Sea's altitude in meters
+    private static final float MAX_SPEED = 340.29f;   // Mach 1 in meters/second
+    private static final float MIN_ACCURACY = 500;       // meter radius
+    private static final long MIN_TIMESTAMP = 946684801; // 2000-01-01 00:00:01
+    private static final double GEOFENCE_RADIUS = 0.01;      // .01 degrees is approximately 1km
+    private static final long MILLISECONDS_PER_DAY = 86400000;
+
+    private Location mBlockedLocation;
+    private boolean mGeofencingEnabled;
+    private boolean mIsGeofenced = false;
+
+    public LocationBlockList() {
+        updateBlocks();
+    }
+
+    public void updateBlocks()    {
+        mBlockedLocation = Prefs.getInstance().getGeofenceLocation();
+        mGeofencingEnabled = Prefs.getInstance().getGeofenceEnabled();
+    }
+
+    public boolean contains(Location location) {
+        final float inaccuracy = location.getAccuracy();
+        final double altitude = location.getAltitude();
+        final float bearing = location.getBearing();
+        final double latitude = location.getLatitude();
+        final double longitude = location.getLongitude();
+        final float speed = location.getSpeed();
+        final long timestamp = location.getTime();
+        final long tomorrow = System.currentTimeMillis() + MILLISECONDS_PER_DAY;
+
+        boolean block = false;
+        mIsGeofenced = false;
+
+        if (latitude == 0 && longitude == 0) {
+            block = true;
+            Log.w(LOG_TAG, "Bogus latitude,longitude: 0,0");
+        } else {
+            if (latitude < -90 || latitude > 90) {
+                block = true;
+                Log.w(LOG_TAG, "Bogus latitude: " + latitude);
+            }
+
+            if (longitude < -180 || longitude > 180) {
+                block = true;
+                Log.w(LOG_TAG, "Bogus longitude: " + longitude);
+            }
+        }
+
+        if (location.hasAccuracy() && (inaccuracy < 0 || inaccuracy > MIN_ACCURACY)) {
+            block = true;
+            Log.w(LOG_TAG, "Insufficient accuracy: " + inaccuracy + " meters");
+        }
+
+        if (location.hasAltitude() && (altitude < MIN_ALTITUDE || altitude > MAX_ALTITUDE)) {
+            block = true;
+            Log.w(LOG_TAG, "Bogus altitude: " + altitude + " meters");
+        }
+
+        if (location.hasBearing() && (bearing < 0 || bearing > 360)) {
+            block = true;
+            Log.w(LOG_TAG, "Bogus bearing: " + bearing + " degrees");
+        }
+
+        if (location.hasSpeed() && (speed < 0 || speed > MAX_SPEED)) {
+            block = true;
+            Log.w(LOG_TAG, "Bogus speed: " + speed + " meters/second");
+        }
+
+        if (timestamp < MIN_TIMESTAMP || timestamp > tomorrow) {
+            block = true;
+            Log.w(LOG_TAG, "Bogus timestamp: " + timestamp);
+        }
+
+        if (mGeofencingEnabled &&
+            Math.abs(location.getLatitude() - mBlockedLocation.getLatitude()) < GEOFENCE_RADIUS &&
+            Math.abs(location.getLongitude() - mBlockedLocation.getLongitude()) < GEOFENCE_RADIUS) {
+            block = true;
+            mIsGeofenced = true;
+        }
+
+        return block;
+    }
+
+    public boolean isGeofenced() {
+        return mIsGeofenced;
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java
new file mode 100644
index 000000000000..afdf8a11e049
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java
@@ -0,0 +1,190 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.Location;
+import android.os.BatteryManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.stumblerthread.Reporter;
+import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
+import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
+import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
+
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class ScanManager {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + ScanManager.class.getSimpleName();
+    private Timer mPassiveModeFlushTimer;
+    private Context mContext;
+    private boolean mIsScanning;
+    private GPSScanner mGPSScanner;
+    private WifiScanner mWifiScanner;
+    private CellScanner mCellScanner;
+    private ActiveOrPassiveStumbling mStumblingMode = ActiveOrPassiveStumbling.ACTIVE_STUMBLING;
+
+    public ScanManager() {
+    }
+
+    private boolean isBatteryLow() {
+        Intent intent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        if (intent == null) {
+            return false;
+        }
+
+        int rawLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+        boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING);
+        int level = Math.round(rawLevel * scale/100.0f);
+
+        final int kMinBatteryPct = 15;
+        return !isCharging && level < kMinBatteryPct;
+    }
+
+    public void newPassiveGpsLocation() {
+        if (isBatteryLow()) {
+            return;
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.d(LOG_TAG, "New passive location");
+        }
+
+        mWifiScanner.start(ActiveOrPassiveStumbling.PASSIVE_STUMBLING);
+        mCellScanner.start(ActiveOrPassiveStumbling.PASSIVE_STUMBLING);
+
+        // how often to flush a leftover bundle to the reports table
+        // If there is a bundle, and nothing happens for 10sec, then flush it
+        final int flushRate_ms = 10000;
+
+        if (mPassiveModeFlushTimer != null) {
+            mPassiveModeFlushTimer.cancel();
+        }
+
+        Date when = new Date();
+        when.setTime(when.getTime() + flushRate_ms);
+        mPassiveModeFlushTimer = new Timer();
+        mPassiveModeFlushTimer.schedule(new TimerTask() {
+          @Override
+          public void run() {
+              Intent flush = new Intent(Reporter.ACTION_FLUSH_TO_BUNDLE);
+              LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(flush);
+          }
+        }, when);
+    }
+
+    public void setPassiveMode(boolean on) {
+        mStumblingMode = (on)? ActiveOrPassiveStumbling.PASSIVE_STUMBLING :
+               ActiveOrPassiveStumbling.ACTIVE_STUMBLING;
+    }
+
+    public boolean isPassiveMode() {
+        return ActiveOrPassiveStumbling.PASSIVE_STUMBLING == mStumblingMode;
+    }
+
+    public void startScanning(Context context) {
+        if (mIsScanning) {
+            return;
+        }
+
+        mContext = context.getApplicationContext();
+        if (mGPSScanner == null) {
+            mGPSScanner = new GPSScanner(context, this);
+            mWifiScanner = new WifiScanner(context);
+            mCellScanner = new CellScanner(context);
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.d(LOG_TAG, "Scanning started...");
+        }
+
+        mGPSScanner.start(mStumblingMode);
+        if (mStumblingMode == ActiveOrPassiveStumbling.ACTIVE_STUMBLING) {
+            mWifiScanner.start(mStumblingMode);
+            mCellScanner.start(mStumblingMode);
+            // in passive mode, these scans are started by passive gps notifications
+        }
+        mIsScanning = true;
+    }
+
+    public boolean stopScanning() {
+        if (!mIsScanning) {
+            return false;
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.d(LOG_TAG, "Scanning stopped");
+        }
+
+        mGPSScanner.stop();
+        mWifiScanner.stop();
+        mCellScanner.stop();
+
+        mIsScanning = false;
+        return true;
+    }
+
+    public void setWifiBlockList(WifiBlockListInterface list) {
+        WifiScanner.setWifiBlockList(list);
+    }
+
+    public boolean isScanning() {
+        return mIsScanning;
+    }
+
+    public int getAPCount() {
+        return (mWifiScanner == null)? 0 : mWifiScanner.getAPCount();
+    }
+
+    public int getVisibleAPCount() {
+        return (mWifiScanner == null)? 0 :mWifiScanner.getVisibleAPCount();
+    }
+
+    public int getWifiStatus() {
+        return (mWifiScanner == null)? 0 : mWifiScanner.getStatus();
+    }
+
+    public int getCellInfoCount() {
+        return (mCellScanner == null)? 0 :mCellScanner.getCellInfoCount();
+    }
+
+    public int getCurrentCellInfoCount() {
+        return (mCellScanner == null)? 0 :mCellScanner.getCurrentCellInfoCount();
+    }
+
+    public int getLocationCount() {
+        return (mGPSScanner == null)? 0 : mGPSScanner.getLocationCount();
+    }
+
+    public double getLatitude() {
+        return (mGPSScanner == null)? 0.0 : mGPSScanner.getLatitude();
+    }
+
+    public double getLongitude() {
+        return (mGPSScanner == null)? 0.0 : mGPSScanner.getLongitude();
+    }
+
+    public Location getLocation() {
+        return (mGPSScanner == null)? new Location("null") : mGPSScanner.getLocation();
+    }
+
+    public void checkPrefs() {
+        if (mGPSScanner != null) {
+            mGPSScanner.checkPrefs();
+        }
+    }
+
+    public boolean isGeofenced() {
+        return (mGPSScanner == null)? false : mGPSScanner.isGeofenced();
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java
new file mode 100644
index 000000000000..767f31e2a76d
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java
@@ -0,0 +1,220 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.stumblerthread.blocklist.BSSIDBlockList;
+import org.mozilla.mozstumbler.service.stumblerthread.blocklist.SSIDBlockList;
+import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
+import org.mozilla.mozstumbler.service.Prefs;
+import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
+
+public class WifiScanner extends BroadcastReceiver {
+    public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".WifiScanner.";
+    public static final String ACTION_WIFIS_SCANNED = ACTION_BASE + "WIFIS_SCANNED";
+    public static final String ACTION_WIFIS_SCANNED_ARG_RESULTS = "scan_results";
+    public static final String ACTION_WIFIS_SCANNED_ARG_TIME = AppGlobals.ACTION_ARG_TIME;
+
+    public static final int STATUS_IDLE = 0;
+    public static final int STATUS_ACTIVE = 1;
+    public static final int STATUS_WIFI_DISABLED = -1;
+
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + WifiScanner.class.getSimpleName();
+    private static final long WIFI_MIN_UPDATE_TIME = 5000; // milliseconds
+
+    private boolean mStarted;
+    private final Context mContext;
+    private WifiLock mWifiLock;
+    private Timer mWifiScanTimer;
+    private final Set mAPs = Collections.synchronizedSet(new HashSet());
+    private AtomicInteger mVisibleAPs = new AtomicInteger();
+
+    /* Testing */
+    public static boolean sIsTestMode;
+    public List mTestModeFakeScanResults = new ArrayList();
+    public Set getAccessPoints(android.test.AndroidTestCase restrictedAccessor) { return mAPs; }
+    /* ------- */
+
+    public WifiScanner(Context c) {
+        mContext = c;
+    }
+
+    private boolean isWifiEnabled() {
+        return (sIsTestMode) || getWifiManager().isWifiEnabled();
+    }
+
+    private List getScanResults() {
+        return (sIsTestMode)? mTestModeFakeScanResults : getWifiManager().getScanResults();
+    }
+
+
+    public synchronized void start(final ActiveOrPassiveStumbling stumblingMode) {
+        if (mStarted) {
+            return;
+        }
+        mStarted = true;
+
+        boolean scanAlways = Prefs.getInstance().getWifiScanAlways();
+
+        if (scanAlways || isWifiEnabled()) {
+            activatePeriodicScan(stumblingMode);
+        }
+
+        IntentFilter i = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        if (!scanAlways) i.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mContext.registerReceiver(this, i);
+    }
+
+    public synchronized void stop() {
+        if (mStarted) {
+            mContext.unregisterReceiver(this);
+        }
+        deactivatePeriodicScan();
+        mStarted = false;
+    }
+
+    public void onReceive(Context c, Intent intent) {
+        String action = intent.getAction();
+
+        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+            if (isWifiEnabled()) {
+                activatePeriodicScan(ActiveOrPassiveStumbling.ACTIVE_STUMBLING);
+            } else {
+                deactivatePeriodicScan();
+            }
+        } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
+            ArrayList scanResults = new ArrayList();
+            for (ScanResult scanResult : getScanResults()) {
+                scanResult.BSSID = BSSIDBlockList.canonicalizeBSSID(scanResult.BSSID);
+                if (shouldLog(scanResult)) {
+                    scanResults.add(scanResult);
+                    mAPs.add(scanResult.BSSID);
+                }
+            }
+            mVisibleAPs.set(scanResults.size());
+            reportScanResults(scanResults);
+        }
+    }
+
+    public static void setWifiBlockList(WifiBlockListInterface blockList) {
+        BSSIDBlockList.setFilterList(blockList.getBssidOuiList());
+        SSIDBlockList.setFilterLists(blockList.getSsidPrefixList(), blockList.getSsidSuffixList());
+    }
+
+    public int getAPCount() {
+        return mAPs.size();
+    }
+
+    public int getVisibleAPCount() {
+        return mVisibleAPs.get();
+    }
+
+    public synchronized int getStatus() {
+        if (!mStarted) {
+            return STATUS_IDLE;
+        }
+        if (mWifiScanTimer == null) {
+            return STATUS_WIFI_DISABLED;
+        }
+        return STATUS_ACTIVE;
+    }
+
+    private synchronized void activatePeriodicScan(final ActiveOrPassiveStumbling stumblingMode) {
+        if (mWifiScanTimer != null) {
+            return;
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.v(LOG_TAG, "Activate Periodic Scan");
+        }
+
+        mWifiLock = getWifiManager().createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "MozStumbler");
+        mWifiLock.acquire();
+
+        // Ensure that we are constantly scanning for new access points.
+        mWifiScanTimer = new Timer();
+        mWifiScanTimer.schedule(new TimerTask() {
+            int mPassiveScanCount;
+            @Override
+            public void run() {
+                if (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING &&
+                    mPassiveScanCount++ > AppGlobals.PASSIVE_MODE_MAX_SCANS_PER_GPS)
+                {
+                    mPassiveScanCount = 0;
+                    stop(); // set mWifiScanTimer to null
+                    return;
+                }
+                if (AppGlobals.isDebug) {
+                    Log.v(LOG_TAG, "WiFi Scanning Timer fired");
+                }
+                getWifiManager().startScan();
+            }
+        }, 0, WIFI_MIN_UPDATE_TIME);
+    }
+
+    private synchronized void deactivatePeriodicScan() {
+        if (mWifiScanTimer == null) {
+            return;
+        }
+
+        if (AppGlobals.isDebug) {
+            Log.v(LOG_TAG, "Deactivate periodic scan");
+        }
+
+        mWifiLock.release();
+        mWifiLock = null;
+
+        mWifiScanTimer.cancel();
+        mWifiScanTimer = null;
+
+        mVisibleAPs.set(0);
+    }
+
+    public static boolean shouldLog(ScanResult scanResult) {
+        if (BSSIDBlockList.contains(scanResult)) {
+            Log.w(LOG_TAG, "Blocked BSSID: " + scanResult);
+            return false;
+        }
+        if (SSIDBlockList.contains(scanResult)) {
+            Log.w(LOG_TAG, "Blocked SSID: " + scanResult);
+            return false;
+        }
+        return true;
+    }
+
+    private WifiManager getWifiManager() {
+        return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+    }
+
+    private void reportScanResults(ArrayList scanResults) {
+        if (scanResults.isEmpty()) {
+            return;
+        }
+
+        Intent i = new Intent(ACTION_WIFIS_SCANNED);
+        i.putParcelableArrayListExtra(ACTION_WIFIS_SCANNED_ARG_RESULTS, scanResults);
+        i.putExtra(ACTION_WIFIS_SCANNED_ARG_TIME, System.currentTimeMillis());
+        LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(i);
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java
new file mode 100644
index 000000000000..d730490216af
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java
@@ -0,0 +1,389 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner;
+
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.CellLocation;
+import android.telephony.NeighboringCellInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.cdma.CdmaCellLocation;
+import android.telephony.gsm.GsmCellLocation;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.mozstumbler.service.AppGlobals;
+
+public class CellInfo implements Parcelable {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + CellInfo.class.getSimpleName();
+
+    public static final String RADIO_GSM = "gsm";
+    public static final String RADIO_CDMA = "cdma";
+    public static final String RADIO_WCDMA = "wcdma";
+
+    public static final String CELL_RADIO_GSM = "gsm";
+    public static final String CELL_RADIO_UMTS = "umts";
+    public static final String CELL_RADIO_CDMA = "cdma";
+    public static final String CELL_RADIO_LTE = "lte";
+
+    public static final int UNKNOWN_CID = -1;
+    public static final int UNKNOWN_SIGNAL = -1000;
+
+    public static final Parcelable.Creator CREATOR
+            = new Parcelable.Creator() {
+        public CellInfo createFromParcel(Parcel in) {
+            return new CellInfo(in);
+        }
+
+        public CellInfo[] newArray(int size) {
+            return new CellInfo[size];
+        }
+    };
+
+    private String mRadio;
+    private String mCellRadio;
+
+    private int mMcc;
+    private int mMnc;
+    private int mCid;
+    private int mLac;
+    private int mSignal;
+    private int mAsu;
+    private int mTa;
+    private int mPsc;
+
+    public CellInfo(int phoneType) {
+        reset();
+        setRadio(phoneType);
+    }
+
+    private CellInfo(Parcel in) {
+        mRadio = in.readString();
+        mCellRadio = in.readString();
+        mMcc = in.readInt();
+        mMnc = in.readInt();
+        mCid = in.readInt();
+        mLac = in.readInt();
+        mSignal = in.readInt();
+        mAsu = in.readInt();
+        mTa = in.readInt();
+        mPsc = in.readInt();
+    }
+
+    public boolean isCellRadioValid() {
+        return mCellRadio != null && (mCellRadio.length() > 0) && !mCellRadio.equals("0");
+    }
+
+    public String getRadio() {
+        return mRadio;
+    }
+
+    public String getCellRadio() {
+        return mCellRadio;
+    }
+
+    public int getMcc() {
+        return mMcc;
+    }
+
+    public int getMnc() {
+        return mMnc;
+    }
+
+    public int getCid() {
+        return mCid;
+    }
+
+    public int getLac() {
+        return mLac;
+    }
+
+    public int getPsc() {
+        return mPsc;
+    }
+
+    public JSONObject toJSONObject() {
+        final JSONObject obj = new JSONObject();
+
+        try {
+            obj.put("radio", getCellRadio());
+            obj.put("mcc", mMcc);
+            obj.put("mnc", mMnc);
+            if (mLac != UNKNOWN_CID) obj.put("lac", mLac);
+            if (mCid != UNKNOWN_CID) obj.put("cid", mCid);
+            if (mSignal != UNKNOWN_SIGNAL) obj.put("signal", mSignal);
+            if (mAsu != UNKNOWN_SIGNAL) obj.put("asu", mAsu);
+            if (mTa != UNKNOWN_CID) obj.put("ta", mTa);
+            if (mPsc != UNKNOWN_CID) obj.put("psc", mPsc);
+        } catch (JSONException jsonE) {
+            throw new IllegalStateException(jsonE);
+        }
+
+        return obj;
+    }
+
+    public String getCellIdentity() {
+        return getRadio()
+                + " " + getCellRadio()
+                + " " + getMcc()
+                + " " + getMnc()
+                + " " + getLac()
+                + " " + getCid()
+                + " " + getPsc();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mRadio);
+        dest.writeString(mCellRadio);
+        dest.writeInt(mMcc);
+        dest.writeInt(mMnc);
+        dest.writeInt(mCid);
+        dest.writeInt(mLac);
+        dest.writeInt(mSignal);
+        dest.writeInt(mAsu);
+        dest.writeInt(mTa);
+        dest.writeInt(mPsc);
+    }
+
+    void reset() {
+        mRadio = RADIO_GSM;
+        mCellRadio = CELL_RADIO_GSM;
+        mMcc = UNKNOWN_CID;
+        mMnc = UNKNOWN_CID;
+        mLac = UNKNOWN_CID;
+        mCid = UNKNOWN_CID;
+        mSignal = UNKNOWN_SIGNAL;
+        mAsu = UNKNOWN_SIGNAL;
+        mTa = UNKNOWN_CID;
+        mPsc = UNKNOWN_CID;
+    }
+
+    void setRadio(int phoneType) {
+        mRadio = getRadioTypeName(phoneType);
+    }
+
+    void setCellLocation(CellLocation cl,
+                         int networkType,
+                         String networkOperator,
+                         Integer gsmSignalStrength,
+                         Integer cdmaRssi) {
+        if (cl instanceof GsmCellLocation) {
+            final int lac, cid;
+            final GsmCellLocation gcl = (GsmCellLocation) cl;
+
+            reset();
+            mCellRadio = getCellRadioTypeName(networkType);
+            setNetworkOperator(networkOperator);
+
+            lac = gcl.getLac();
+            cid = gcl.getCid();
+            if (lac >= 0) mLac = lac;
+            if (cid >= 0) mCid = cid;
+
+            if (Build.VERSION.SDK_INT >= 9) {
+                final int psc = gcl.getPsc();
+                if (psc >= 0) mPsc = psc;
+            }
+
+            if (gsmSignalStrength != null) {
+                mAsu = gsmSignalStrength;
+            }
+        } else if (cl instanceof CdmaCellLocation) {
+            final CdmaCellLocation cdl = (CdmaCellLocation) cl;
+
+            reset();
+            mCellRadio = getCellRadioTypeName(networkType);
+
+            setNetworkOperator(networkOperator);
+
+            mMnc = cdl.getSystemId();
+
+            mLac = cdl.getNetworkId();
+            mCid = cdl.getBaseStationId();
+
+            if (cdmaRssi != null) {
+                mSignal = cdmaRssi;
+            }
+        } else {
+            throw new IllegalArgumentException("Unexpected CellLocation type: " + cl.getClass().getName());
+        }
+    }
+
+    void setNeighboringCellInfo(NeighboringCellInfo nci, String networkOperator) {
+        final int lac, cid, psc, rssi;
+
+        reset();
+        mCellRadio = getCellRadioTypeName(nci.getNetworkType());
+        setNetworkOperator(networkOperator);
+
+        lac = nci.getLac();
+        cid = nci.getCid();
+        psc = nci.getPsc();
+        rssi = nci.getRssi();
+
+        if (lac >= 0) mLac = lac;
+        if (cid >= 0) mCid = cid;
+        if (psc >= 0) mPsc = psc;
+        if (rssi != NeighboringCellInfo.UNKNOWN_RSSI) mAsu = rssi;
+    }
+
+    void setGsmCellInfo(int mcc, int mnc, int lac, int cid, int asu) {
+        mCellRadio = CELL_RADIO_GSM;
+        mMcc = mcc != Integer.MAX_VALUE ? mcc : UNKNOWN_CID;
+        mMnc = mnc != Integer.MAX_VALUE ? mnc : UNKNOWN_CID;
+        mLac = lac != Integer.MAX_VALUE ? lac : UNKNOWN_CID;
+        mCid = cid != Integer.MAX_VALUE ? cid : UNKNOWN_CID;
+        mAsu = asu;
+    }
+
+    public void setWcmdaCellInfo(int mcc, int mnc, int lac, int cid, int psc, int asu) {
+        mCellRadio = CELL_RADIO_UMTS;
+        mMcc = mcc != Integer.MAX_VALUE ? mcc : UNKNOWN_CID;
+        mMnc = mnc != Integer.MAX_VALUE ? mnc : UNKNOWN_CID;
+        mLac = lac != Integer.MAX_VALUE ? lac : UNKNOWN_CID;
+        mCid = cid != Integer.MAX_VALUE ? cid : UNKNOWN_CID;
+        mPsc = psc != Integer.MAX_VALUE ? psc : UNKNOWN_CID;
+        mAsu = asu;
+    }
+
+    /**
+     * @param mcc Mobile Country Code, Integer.MAX_VALUE if unknown
+     * @param mnc Mobile Network Code, Integer.MAX_VALUE if unknown
+     * @param ci Cell Identity, Integer.MAX_VALUE if unknown
+     * @param pci Physical Cell Id, Integer.MAX_VALUE if unknown
+     * @param tac Tracking Area Code, Integer.MAX_VALUE if unknown
+     * @param asu Arbitrary strength unit
+     * @param ta Timing advance
+     */
+    void setLteCellInfo(int mcc, int mnc, int ci, int pci, int tac, int asu, int ta) {
+        mCellRadio = CELL_RADIO_LTE;
+        mMcc = mcc != Integer.MAX_VALUE ? mcc : UNKNOWN_CID;
+        mMnc = mnc != Integer.MAX_VALUE ? mnc : UNKNOWN_CID;
+        mLac = tac != Integer.MAX_VALUE ? tac : UNKNOWN_CID;
+        mCid = ci != Integer.MAX_VALUE ? ci : UNKNOWN_CID;
+        mPsc = pci != Integer.MAX_VALUE ? pci : UNKNOWN_CID;
+        mAsu = asu;
+        mTa = ta;
+    }
+
+    void setCdmaCellInfo(int baseStationId, int networkId, int systemId, int dbm) {
+        mCellRadio = CELL_RADIO_CDMA;
+        mMnc = systemId != Integer.MAX_VALUE ? systemId : UNKNOWN_CID;
+        mLac = networkId != Integer.MAX_VALUE ? networkId : UNKNOWN_CID;
+        mCid = baseStationId != Integer.MAX_VALUE ? baseStationId : UNKNOWN_CID;
+        mSignal = dbm;
+    }
+
+    void setNetworkOperator(String mccMnc) {
+        if (mccMnc == null || mccMnc.length() < 5 || mccMnc.length() > 8) {
+            throw new IllegalArgumentException("Bad mccMnc: " + mccMnc);
+        }
+        mMcc = Integer.parseInt(mccMnc.substring(0, 3));
+        mMnc = Integer.parseInt(mccMnc.substring(3));
+    }
+
+    static String getCellRadioTypeName(int networkType) {
+        switch (networkType) {
+            // If the network is either GSM or any high-data-rate variant of it, the radio
+            // field should be specified as `gsm`. This includes `GSM`, `EDGE` and `GPRS`.
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+                return CELL_RADIO_GSM;
+
+            // If the network is either UMTS or any high-data-rate variant of it, the radio
+            // field should be specified as `umts`. This includes `UMTS`, `HSPA`, `HSDPA`,
+            // `HSPA+` and `HSUPA`.
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+                return CELL_RADIO_UMTS;
+
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                return CELL_RADIO_LTE;
+
+            // If the network is either CDMA or one of the EVDO variants, the radio
+            // field should be specified as `cdma`. This includes `1xRTT`, `CDMA`, `eHRPD`,
+            // `EVDO_0`, `EVDO_A`, `EVDO_B`, `IS95A` and `IS95B`.
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
+            case TelephonyManager.NETWORK_TYPE_IDEN:
+                return CELL_RADIO_CDMA;
+
+            default:
+                Log.e(LOG_TAG, "", new IllegalArgumentException("Unexpected network type: " + networkType));
+                return String.valueOf(networkType);
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    private static String getRadioTypeName(int phoneType) {
+        switch (phoneType) {
+            case TelephonyManager.PHONE_TYPE_CDMA:
+                return RADIO_CDMA;
+
+            case TelephonyManager.PHONE_TYPE_GSM:
+                return RADIO_GSM;
+
+            default:
+                Log.e(LOG_TAG, "", new IllegalArgumentException("Unexpected phone type: " + phoneType));
+                // fallthrough
+
+            case TelephonyManager.PHONE_TYPE_NONE:
+            case TelephonyManager.PHONE_TYPE_SIP:
+                // These devices have no radio.
+                return "";
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof CellInfo)) {
+            return false;
+        }
+        CellInfo ci = (CellInfo) o;
+        return mRadio.equals(ci.mRadio)
+               && mCellRadio.equals(ci.mCellRadio)
+               && mMcc == ci.mMcc
+               && mMnc == ci.mMnc
+               && mCid == ci.mCid
+               && mLac == ci.mLac
+               && mSignal == ci.mSignal
+               && mAsu == ci.mAsu
+               && mTa == ci.mTa
+               && mPsc == ci.mPsc;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + mRadio.hashCode();
+        result = 31 * result + mCellRadio.hashCode();
+        result = 31 * result + mMcc;
+        result = 31 * result + mMnc;
+        result = 31 * result + mCid;
+        result = 31 * result + mLac;
+        result = 31 * result + mSignal;
+        result = 31 * result + mAsu;
+        result = 31 * result + mTa;
+        result = 31 * result + mPsc;
+        return result;
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java
new file mode 100644
index 000000000000..e332551ce309
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java
@@ -0,0 +1,135 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
+
+
+public class CellScanner {
+    public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".CellScanner.";
+    public static final String ACTION_CELLS_SCANNED = ACTION_BASE + "CELLS_SCANNED";
+    public static final String ACTION_CELLS_SCANNED_ARG_CELLS = "cells";
+    public static final String ACTION_CELLS_SCANNED_ARG_TIME = AppGlobals.ACTION_ARG_TIME;
+
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + CellScanner.class.getSimpleName();
+    private static final long CELL_MIN_UPDATE_TIME = 1000; // milliseconds
+
+    private final Context mContext;
+    private static CellScannerImpl sImpl;
+    private Timer mCellScanTimer;
+    private final Set mCells = new HashSet();
+    private int mCurrentCellInfoCount;
+
+    public ArrayList sTestingModeCellInfoArray;
+
+    public interface CellScannerImpl {
+        public void start();
+
+        public void stop();
+
+        public List getCellInfo();
+    }
+
+    public CellScanner(Context context) {
+        mContext = context;
+    }
+
+    private static synchronized CellScannerImpl getImplementation() {
+        return sImpl;
+    }
+
+    public static synchronized boolean isCellScannerImplSet() {
+        return sImpl != null;
+    }
+
+    /* Fennec doesn't support the apis needed for full scanning, we have different implementations.*/
+    public static synchronized void setCellScannerImpl(CellScannerImpl cellScanner) {
+        sImpl = cellScanner;
+    }
+
+    public void start(final ActiveOrPassiveStumbling stumblingMode) {
+        if (getImplementation() == null) {
+            return;
+        }
+
+        try {
+            getImplementation().start();
+        } catch (UnsupportedOperationException uoe) {
+            Log.e(LOG_TAG, "Cell scanner probe failed", uoe);
+            return;
+        }
+
+        if (mCellScanTimer != null) {
+            return;
+        }
+
+        mCellScanTimer = new Timer();
+
+        mCellScanTimer.schedule(new TimerTask() {
+            int mPassiveScanCount;
+            @Override
+            public void run() {
+                if (getImplementation() == null) {
+                    return;
+                }
+
+                if (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING &&
+                        mPassiveScanCount++ > AppGlobals.PASSIVE_MODE_MAX_SCANS_PER_GPS)
+                {
+                    mPassiveScanCount = 0;
+                    stop();
+                    return;
+                }
+                //if (SharedConstants.isDebug) Log.d(LOG_TAG, "Cell Scanning Timer fired");
+                final long curTime = System.currentTimeMillis();
+
+                ArrayList cells = (sTestingModeCellInfoArray != null)? sTestingModeCellInfoArray :
+                        new ArrayList(getImplementation().getCellInfo());
+
+                mCurrentCellInfoCount = cells.size();
+                if (cells.isEmpty()) {
+                    return;
+                }
+                for (CellInfo cell: cells) mCells.add(cell.getCellIdentity());
+
+                Intent intent = new Intent(ACTION_CELLS_SCANNED);
+                intent.putParcelableArrayListExtra(ACTION_CELLS_SCANNED_ARG_CELLS, cells);
+                intent.putExtra(ACTION_CELLS_SCANNED_ARG_TIME, curTime);
+                LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(intent);
+            }
+        }, 0, CELL_MIN_UPDATE_TIME);
+    }
+
+    public void stop() {
+        if (mCellScanTimer != null) {
+            mCellScanTimer.cancel();
+            mCellScanTimer = null;
+        }
+        if (getImplementation() != null) {
+            getImplementation().stop();
+        }
+    }
+
+    public int getCellInfoCount() {
+        return mCells.size();
+    }
+
+    public int getCurrentCellInfoCount() {
+        return mCurrentCellInfoCount;
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerNoWCDMA.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerNoWCDMA.java
new file mode 100644
index 000000000000..94910a5f755e
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerNoWCDMA.java
@@ -0,0 +1,254 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellLocation;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.NeighboringCellInfo;
+import android.telephony.PhoneStateListener;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import org.mozilla.mozstumbler.service.AppGlobals;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/* Fennec does not yet support the api level for WCDMA import */
+public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
+
+    protected static String LOG_TAG = AppGlobals.LOG_PREFIX + CellScannerNoWCDMA.class.getSimpleName();
+    protected GetAllCellInfoScannerImpl mGetAllInfoCellScanner;
+    protected TelephonyManager mTelephonyManager;
+    protected boolean mIsStarted;
+    protected int mPhoneType;
+    protected final Context mContext;
+    protected volatile int mSignalStrength;
+    protected volatile int mCdmaDbm;
+
+    private PhoneStateListener mPhoneStateListener;
+
+    private static class GetAllCellInfoScannerDummy implements GetAllCellInfoScannerImpl {
+        @Override
+        public List getAllCellInfo(TelephonyManager tm) {
+            return Collections.emptyList();
+        }
+    }
+
+    interface GetAllCellInfoScannerImpl {
+        List getAllCellInfo(TelephonyManager tm);
+    }
+
+    public CellScannerNoWCDMA(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void start() {
+        if (mIsStarted) {
+            return;
+        }
+        mIsStarted = true;
+
+        if (mTelephonyManager == null) {
+            if (Build.VERSION.SDK_INT >= 18 /*Build.VERSION_CODES.JELLY_BEAN_MR2 */) { // Fennec: no Build.VERSION_CODES
+                mGetAllInfoCellScanner = new GetAllCellInfoScannerMr2();
+            } else {
+                mGetAllInfoCellScanner = new GetAllCellInfoScannerDummy();
+            }
+
+            mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+            if (mTelephonyManager == null) {
+                throw new UnsupportedOperationException("TelephonyManager service is not available");
+            }
+
+            mPhoneType = mTelephonyManager.getPhoneType();
+
+            if (mPhoneType != TelephonyManager.PHONE_TYPE_GSM
+                && mPhoneType != TelephonyManager.PHONE_TYPE_CDMA) {
+                throw new UnsupportedOperationException("Unexpected Phone Type: " + mPhoneType);
+            }
+            mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
+            mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
+        }
+
+        mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
+        mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
+
+        mPhoneStateListener = new PhoneStateListener() {
+            @Override
+            public void onSignalStrengthsChanged(SignalStrength ss) {
+                if (ss.isGsm()) {
+                    mSignalStrength = ss.getGsmSignalStrength();
+                } else {
+                    mCdmaDbm = ss.getCdmaDbm();
+                }
+            }
+        };
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+    }
+
+    @Override
+    public void stop() {
+        mIsStarted = false;
+        if (mTelephonyManager != null) {
+            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        }
+        mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
+        mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
+    }
+
+    @Override
+    public List getCellInfo() {
+        List records = new ArrayList();
+
+        List allCells = mGetAllInfoCellScanner.getAllCellInfo(mTelephonyManager);
+        if (allCells.isEmpty()) {
+            CellInfo currentCell = getCurrentCellInfo();
+            if (currentCell == null) {
+                return records;
+            }
+            records.add(currentCell);
+        }else {
+            records.addAll(allCells);
+        }
+
+        // getNeighboringCells() sometimes contains more information than that is already
+        // in getAllCellInfo(). Use the results of both of them.
+        records.addAll(getNeighboringCells());
+        return records;
+    }
+
+    private String getNetworkOperator() {
+        String networkOperator = mTelephonyManager.getNetworkOperator();
+        // getNetworkOperator() may be unreliable on CDMA networks
+        if (networkOperator == null || networkOperator.length() <= 3) {
+            networkOperator = mTelephonyManager.getSimOperator();
+        }
+        return networkOperator;
+    }
+
+    protected CellInfo getCurrentCellInfo() {
+        final CellLocation currentCell = mTelephonyManager.getCellLocation();
+        if (currentCell == null) {
+            return null;
+        }
+
+        try {
+            final CellInfo info = new CellInfo(mPhoneType);
+            final int signalStrength = mSignalStrength;
+            final int cdmaDbm = mCdmaDbm;
+            info.setCellLocation(currentCell,
+                    mTelephonyManager.getNetworkType(),
+                    getNetworkOperator(),
+                    signalStrength == CellInfo.UNKNOWN_SIGNAL ? null : signalStrength,
+                    cdmaDbm == CellInfo.UNKNOWN_SIGNAL ? null : cdmaDbm);
+            return info;
+        } catch (IllegalArgumentException iae) {
+            Log.e(LOG_TAG, "Skip invalid or incomplete CellLocation: " + currentCell, iae);
+        }
+        return null;
+    }
+
+    private List getNeighboringCells() {
+        Collection cells = mTelephonyManager.getNeighboringCellInfo();
+        if (cells == null || cells.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        String networkOperator = getNetworkOperator();
+        List records = new ArrayList(cells.size());
+        for (NeighboringCellInfo nci : cells) {
+            try {
+                final CellInfo record = new CellInfo(mPhoneType);
+                record.setNeighboringCellInfo(nci, networkOperator);
+                if (record.isCellRadioValid()) {
+                    records.add(record);
+                }
+            } catch (IllegalArgumentException iae) {
+                Log.e(LOG_TAG, "Skip invalid or incomplete NeighboringCellInfo: " + nci, iae);
+            }
+        }
+        return records;
+    }
+
+    @TargetApi(18)
+    protected boolean addCellToList(List cells,
+                                 android.telephony.CellInfo observedCell,
+                                 TelephonyManager tm) {
+        boolean added = false;
+        if (observedCell instanceof CellInfoGsm) {
+            CellIdentityGsm ident = ((CellInfoGsm) observedCell).getCellIdentity();
+            if (ident.getMcc() != Integer.MAX_VALUE && ident.getMnc() != Integer.MAX_VALUE) {
+                CellSignalStrengthGsm strength = ((CellInfoGsm) observedCell).getCellSignalStrength();
+                CellInfo cell = new CellInfo(tm.getPhoneType());
+                cell.setGsmCellInfo(ident.getMcc(),
+                        ident.getMnc(),
+                        ident.getLac(),
+                        ident.getCid(),
+                        strength.getAsuLevel());
+                cells.add(cell);
+                added = true;
+            }
+        } else if (observedCell instanceof CellInfoCdma) {
+            CellInfo cell = new CellInfo(tm.getPhoneType());
+            CellIdentityCdma ident = ((CellInfoCdma) observedCell).getCellIdentity();
+            CellSignalStrengthCdma strength = ((CellInfoCdma) observedCell).getCellSignalStrength();
+            cell.setCdmaCellInfo(ident.getBasestationId(),
+                    ident.getNetworkId(),
+                    ident.getSystemId(),
+                    strength.getDbm());
+            cells.add(cell);
+            added = true;
+        } else if (observedCell instanceof CellInfoLte) {
+            CellIdentityLte ident = ((CellInfoLte) observedCell).getCellIdentity();
+            if (ident.getMnc() != Integer.MAX_VALUE && ident.getMcc() != Integer.MAX_VALUE) {
+                CellInfo cell = new CellInfo(tm.getPhoneType());
+                CellSignalStrengthLte strength = ((CellInfoLte) observedCell).getCellSignalStrength();
+                cell.setLteCellInfo(ident.getMcc(),
+                        ident.getMnc(),
+                        ident.getCi(),
+                        ident.getPci(),
+                        ident.getTac(),
+                        strength.getAsuLevel(),
+                        strength.getTimingAdvance());
+               cells.add(cell);
+               added = true;
+            }
+        }
+        return added;
+    }
+
+    @TargetApi(18)
+    private class GetAllCellInfoScannerMr2 implements GetAllCellInfoScannerImpl {
+        @Override
+        public List getAllCellInfo(TelephonyManager tm) {
+            final List observed = tm.getAllCellInfo();
+            if (observed == null || observed.isEmpty()) {
+                return Collections.emptyList();
+            }
+
+            List cells = new ArrayList(observed.size());
+            for (android.telephony.CellInfo observedCell : observed) {
+                if (!addCellToList(cells, observedCell, tm)) {
+                    //Log.i(LOG_TAG, "Skipped CellInfo of unknown class: " + observedCell.toString());
+                }
+            }
+            return cells;
+        }
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java
new file mode 100644
index 000000000000..210b390d929f
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java
@@ -0,0 +1,213 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.uploadthread;
+
+import android.os.AsyncTask;
+import android.util.Log;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.mozilla.mozstumbler.service.Prefs;
+import org.mozilla.mozstumbler.service.utils.AbstractCommunicator;
+import org.mozilla.mozstumbler.service.utils.AbstractCommunicator.SyncSummary;
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
+import org.mozilla.mozstumbler.service.utils.NetworkUtils;
+
+/* Only one at a time may be uploading. If executed while another upload is in progress
+* it will return immediately, and SyncResult is null.
+*
+* Threading:
+* Uploads on a separate thread. ONLY DataStorageManager is thread-safe, do not call
+* preferences, do not call any code that isn't thread-safe. You will cause suffering.
+* An exception is made for AppGlobals.isDebug, a false reading is of no consequence. */
+public class AsyncUploader extends AsyncTask {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + AsyncUploader.class.getSimpleName();
+    private final UploadSettings mSettings;
+    private final Object mListenerLock = new Object();
+    private AsyncUploaderListener mListener;
+    private static AtomicBoolean sIsUploading = new AtomicBoolean();
+    private String mNickname;
+
+    public interface AsyncUploaderListener {
+        public void onUploadComplete(SyncSummary result);
+        public void onUploadProgress();
+    }
+
+    public static class UploadSettings {
+        public final boolean mShouldIgnoreWifiStatus;
+        public final boolean mUseWifiOnly;
+        public UploadSettings(boolean shouldIgnoreWifiStatus, boolean useWifiOnly) {
+            mShouldIgnoreWifiStatus = shouldIgnoreWifiStatus;
+            mUseWifiOnly = useWifiOnly;
+        }
+    }
+
+    public AsyncUploader(UploadSettings settings, AsyncUploaderListener listener) {
+        mListener = listener;
+        mSettings = settings;
+    }
+
+    public void setNickname(String name) {
+        mNickname = name;
+    }
+
+    public void clearListener() {
+        synchronized (mListenerLock) {
+            mListener = null;
+        }
+    }
+
+    public static boolean isUploading() {
+        return sIsUploading.get();
+    }
+
+    @Override
+    protected SyncSummary doInBackground(Void... voids) {
+        if (sIsUploading.get()) {
+            // This if-block is not synchronized, don't care, this is an erroneous usage.
+            Log.d(LOG_TAG, "Usage error: check isUploading first, only one at a time task usage is permitted.");
+            return null;
+        }
+
+        sIsUploading.set(true);
+        SyncSummary result = new SyncSummary();
+        Runnable progressListener = null;
+
+        // no need to lock here, lock is checked again later
+        if (mListener != null) {
+            progressListener = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (mListenerLock) {
+                        if (mListener != null) {
+                            mListener.onUploadProgress();
+                        }
+                    }
+                }
+            };
+        }
+
+        uploadReports(result, progressListener);
+
+        return result;
+    }
+    @Override
+    protected void onPostExecute(SyncSummary result) {
+        sIsUploading.set(false);
+
+        synchronized (mListenerLock) {
+            if (mListener != null) {
+                mListener.onUploadComplete(result);
+            }
+        }
+    }
+    @Override
+    protected void onCancelled(SyncSummary result) {
+        sIsUploading.set(false);
+    }
+
+    private class Submitter extends AbstractCommunicator {
+        private static final String SUBMIT_URL = "https://location.services.mozilla.com/v1/submit";
+
+        public Submitter() {
+            super(Prefs.getInstance().getUserAgent());
+        }
+
+        @Override
+        public String getUrlString() {
+            return SUBMIT_URL;
+        }
+
+        @Override
+        public String getNickname(){
+            return mNickname;
+        }
+
+        @Override
+        public NetworkSendResult cleanSend(byte[] data) {
+            final NetworkSendResult result = new NetworkSendResult();
+            try {
+                result.bytesSent = this.send(data, ZippedState.eAlreadyZipped);
+                result.errorCode = 0;
+            } catch (IOException ex) {
+                String msg = "Error submitting: " + ex;
+                if (ex instanceof HttpErrorException) {
+                    result.errorCode = ((HttpErrorException) ex).responseCode;
+                    msg += " Code:" + result.errorCode;
+                }
+                Log.e(LOG_TAG, msg);
+                AppGlobals.guiLogError(msg);
+            }
+            return result;
+        }
+    }
+
+    private void uploadReports(AbstractCommunicator.SyncSummary syncResult, Runnable progressListener) {
+        long uploadedObservations = 0;
+        long uploadedCells = 0;
+        long uploadedWifis = 0;
+
+        if (!mSettings.mShouldIgnoreWifiStatus && mSettings.mUseWifiOnly && !NetworkUtils.getInstance().isWifiAvailable()) {
+            if (AppGlobals.isDebug) {
+                Log.d(LOG_TAG, "not on WiFi, not sending");
+            }
+            syncResult.numIoExceptions += 1;
+            return;
+        }
+
+        Submitter submitter = new Submitter();
+        DataStorageManager dm = DataStorageManager.getInstance();
+
+        String error = null;
+
+        try {
+            DataStorageManager.ReportBatch batch = dm.getFirstBatch();
+            while (batch != null) {
+                AbstractCommunicator.NetworkSendResult result = submitter.cleanSend(batch.data);
+
+                if (result.errorCode == 0) {
+                    syncResult.totalBytesSent += result.bytesSent;
+
+                    dm.delete(batch.filename);
+
+                    uploadedObservations += batch.reportCount;
+                    uploadedWifis += batch.wifiCount;
+                    uploadedCells += batch.cellCount;
+                } else {
+                    if (result.errorCode / 100 == 4) {
+                        // delete on 4xx, no point in resending
+                        dm.delete(batch.filename);
+                    } else {
+                        DataStorageManager.getInstance().saveCurrentReportsSendBufferToDisk();
+                    }
+                    syncResult.numIoExceptions += 1;
+                }
+
+                if (progressListener != null) {
+                    progressListener.run();
+                }
+
+                batch = dm.getNextBatch();
+            }
+        }
+        catch (IOException ex) {
+            error = ex.toString();
+        }
+
+        try {
+            dm.incrementSyncStats(syncResult.totalBytesSent, uploadedObservations, uploadedCells, uploadedWifis);
+        } catch (IOException ex) {
+            error = ex.toString();
+        } finally {
+            if (error != null) {
+                syncResult.numIoExceptions += 1;
+                Log.d(LOG_TAG, error);
+                AppGlobals.guiLogError(error + " (uploadReports)");
+            }
+            submitter.close();
+        }
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java
new file mode 100644
index 000000000000..20edce83d2b6
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java
@@ -0,0 +1,130 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.uploadthread;
+
+import android.app.AlarmManager;
+import android.app.IntentService;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.Prefs;
+import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
+import org.mozilla.mozstumbler.service.utils.NetworkUtils;
+
+// Only if data is queued and device awake: check network availability and upload.
+// MozStumbler use: this alarm is periodic and repeating.
+// Fennec use: The alarm is single-shot and it is set to run -if there is data in the queue-
+// under these conditions:
+// 1) Fennec start/pause (actually gecko start which is ~4 sec after Fennec start).
+// 2) Changing the pref in Fennec to stumble or not.
+// 3) Boot intent (and SD card app available intent).
+//
+// Threading:
+// - scheduled from the stumbler thread
+// - triggered from the main thread
+// - actual work is done the upload thread (AsyncUploader)
+public class UploadAlarmReceiver extends BroadcastReceiver {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + UploadAlarmReceiver.class.getSimpleName();
+    private static final String EXTRA_IS_REPEATING = "is_repeating";
+    private static boolean sIsAlreadyScheduled;
+
+    public UploadAlarmReceiver() {}
+
+    public static class UploadAlarmService extends IntentService {
+
+        public UploadAlarmService(String name) {
+            super(name);
+        }
+
+        public UploadAlarmService() {
+            super(LOG_TAG);
+        }
+
+        @Override
+        protected void onHandleIntent(Intent intent) {
+            boolean isRepeating = intent.getBooleanExtra(EXTRA_IS_REPEATING, true);
+            if (DataStorageManager.getInstance() == null) {
+                DataStorageManager.createGlobalInstance(this, null);
+            }
+            upload(isRepeating);
+        }
+
+        void upload(boolean isRepeating) {
+            if (!isRepeating) {
+                sIsAlreadyScheduled = false;
+            }
+
+            // Defensive approach: if it is too old, delete all data
+            long oldestMs = DataStorageManager.getInstance().getOldestBatchTimeMs();
+            int maxWeeks = DataStorageManager.getInstance().getMaxWeeksStored();
+            if (oldestMs > 0) {
+                long currentTime = System.currentTimeMillis();
+                long msPerWeek = 604800 * 1000;
+                if (currentTime - oldestMs > maxWeeks * msPerWeek) {
+                    DataStorageManager.getInstance().deleteAll();
+                    UploadAlarmReceiver.cancelAlarm(this, isRepeating);
+                    return;
+                }
+            }
+
+            if (NetworkUtils.getInstance().isWifiAvailable() &&
+                !AsyncUploader.isUploading()) {
+                Log.d(LOG_TAG, "Alarm upload(), call AsyncUploader");
+                AsyncUploader.UploadSettings settings =
+                    new AsyncUploader.UploadSettings(Prefs.getInstance().getWifiScanAlways(), Prefs.getInstance().getUseWifiOnly());
+                AsyncUploader uploader = new AsyncUploader(settings, null);
+                uploader.setNickname(Prefs.getInstance().getNickname());
+                uploader.execute();
+                // we could listen for completion and cancel, instead, cancel on next alarm when db empty
+            }
+        }
+    }
+
+    static PendingIntent createIntent(Context c, boolean isRepeating) {
+        Intent intent = new Intent(c, UploadAlarmReceiver.class);
+        intent.putExtra(EXTRA_IS_REPEATING, isRepeating);
+        PendingIntent pi = PendingIntent.getBroadcast(c, 0, intent, 0);
+        return pi;
+    }
+
+    public static void cancelAlarm(Context c, boolean isRepeating) {
+        Log.d(LOG_TAG, "cancelAlarm");
+        // this is to stop scheduleAlarm from constantly rescheduling, not to guard cancellation.
+        sIsAlreadyScheduled = false;
+        AlarmManager alarmManager = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
+        PendingIntent pi = createIntent(c, isRepeating);
+        alarmManager.cancel(pi);
+    }
+
+    public static void scheduleAlarm(Context c, long secondsToWait, boolean isRepeating) {
+        if (sIsAlreadyScheduled) {
+            return;
+        }
+
+        long intervalMsec = secondsToWait * 1000;
+        Log.d(LOG_TAG, "schedule alarm (ms):" + intervalMsec);
+
+        sIsAlreadyScheduled = true;
+        AlarmManager alarmManager = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
+        PendingIntent pi = createIntent(c, isRepeating);
+
+        long triggerAtMs = System.currentTimeMillis() + intervalMsec;
+        if (isRepeating) {
+            alarmManager.setInexactRepeating(AlarmManager.RTC, triggerAtMs, intervalMsec, pi);
+        } else {
+            alarmManager.set(AlarmManager.RTC, triggerAtMs, pi);
+        }
+    }
+
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        Intent startServiceIntent = new Intent(context, UploadAlarmService.class);
+        context.startService(startServiceIntent);
+    }
+}
\ No newline at end of file
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java
new file mode 100644
index 000000000000..f3708025b5f5
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java
@@ -0,0 +1,156 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.utils;
+
+import android.os.Build;
+import android.util.Log;
+
+import org.mozilla.mozstumbler.service.AppGlobals;
+import org.mozilla.mozstumbler.service.Prefs;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public abstract class AbstractCommunicator {
+
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + AbstractCommunicator.class.getSimpleName();
+    private static final String NICKNAME_HEADER = "X-Nickname";
+    private static final String USER_AGENT_HEADER = "User-Agent";
+    private HttpURLConnection mHttpURLConnection;
+    private final String mUserAgent;
+    private static int sBytesSentTotal = 0;
+    private static String sMozApiKey;
+
+    public abstract String getUrlString();
+
+    public static class HttpErrorException extends IOException {
+        private static final long serialVersionUID = -5404095858043243126L;
+        public final int responseCode;
+
+        public HttpErrorException(int responseCode) {
+            super();
+            this.responseCode = responseCode;
+        }
+
+        public boolean isTemporary() {
+            return responseCode >= 500 && responseCode <= 599;
+        }
+    }
+
+    public static class SyncSummary {
+        public int numIoExceptions;
+        public int totalBytesSent;
+    }
+
+    public static class NetworkSendResult {
+        public int bytesSent;
+        // Zero is no error, for HTTP error cases, set this code to the error
+        public int errorCode = -1;
+    }
+
+    public abstract NetworkSendResult cleanSend(byte[] data);
+
+    public String getNickname() {
+        return null;
+    }
+
+    public AbstractCommunicator(String userAgent) {
+        mUserAgent = userAgent;
+    }
+
+    private void openConnectionAndSetHeaders() {
+        try {
+            if (sMozApiKey == null) {
+                sMozApiKey = Prefs.getInstance().getMozApiKey();
+            }
+            URL url = new URL(getUrlString() + "?key=" + sMozApiKey);
+            mHttpURLConnection = (HttpURLConnection) url.openConnection();
+            mHttpURLConnection.setRequestMethod("POST");
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException(e);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Couldn't open a connection: " + e);
+        }
+        mHttpURLConnection.setDoOutput(true);
+        mHttpURLConnection.setRequestProperty(USER_AGENT_HEADER, mUserAgent);
+        mHttpURLConnection.setRequestProperty("Content-Type", "application/json");
+
+        // Workaround for a bug in Android mHttpURLConnection. When the library
+        // reuses a stale connection, the connection may fail with an EOFException
+        if (Build.VERSION.SDK_INT > 13 && Build.VERSION.SDK_INT < 19) {
+            mHttpURLConnection.setRequestProperty("Connection", "Close");
+        }
+        String nickname = getNickname();
+        if (nickname != null) {
+            mHttpURLConnection.setRequestProperty(NICKNAME_HEADER, nickname);
+        }
+    }
+
+    private byte[] zipData(byte[] data) throws IOException {
+        byte[] output = Zipper.zipData(data);
+        return output;
+    }
+
+    private void sendData(byte[] data) throws IOException{
+        mHttpURLConnection.setFixedLengthStreamingMode(data.length);
+        OutputStream out = new BufferedOutputStream(mHttpURLConnection.getOutputStream());
+        out.write(data);
+        out.flush();
+        int code = mHttpURLConnection.getResponseCode();
+        final boolean isSuccessCode2XX = (code/100 == 2);
+        if (!isSuccessCode2XX) {
+            throw new HttpErrorException(code);
+        }
+    }
+
+    public enum ZippedState { eNotZipped, eAlreadyZipped };
+    /* Return the number of bytes sent. */
+    public int send(byte[] data, ZippedState isAlreadyZipped) throws IOException {
+        openConnectionAndSetHeaders();
+        String logMsg;
+        try {
+            if (isAlreadyZipped != ZippedState.eAlreadyZipped) {
+                data = zipData(data);
+            }
+            mHttpURLConnection.setRequestProperty("Content-Encoding","gzip");
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Couldn't compress and send data, falling back to plain-text: ", e);
+            close();
+        }
+
+        try {
+            sendData(data);
+        } finally {
+            close();
+        }
+        sBytesSentTotal += data.length;
+        logMsg = "Send data: " + String.format("%.2f", data.length / 1024.0) + " kB";
+        logMsg += " Session Total:" + String.format("%.2f", sBytesSentTotal / 1024.0) + " kB";
+        AppGlobals.guiLogInfo(logMsg, "#FFFFCC", true);
+        Log.d(LOG_TAG, logMsg);
+        return data.length;
+    }
+
+    public InputStream getInputStream() {
+        try {
+            return mHttpURLConnection.getInputStream();
+        } catch (IOException e) {
+            return mHttpURLConnection.getErrorStream();
+        }
+    }
+
+    public void close() {
+        if (mHttpURLConnection == null) {
+            return;
+        }
+        mHttpURLConnection.disconnect();
+        mHttpURLConnection = null;
+    }
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java
new file mode 100644
index 000000000000..56dfbe6f262e
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java
@@ -0,0 +1,41 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.utils;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.util.Log;
+import org.mozilla.mozstumbler.service.AppGlobals;
+
+public final class NetworkUtils {
+    private static final String LOG_TAG = AppGlobals.LOG_PREFIX + NetworkUtils.class.getSimpleName();
+
+    ConnectivityManager mConnectivityManager;
+    static NetworkUtils sInstance;
+
+    /* Created at startup by app, or service, using a context. */
+    static public void createGlobalInstance(Context context) {
+        sInstance = new NetworkUtils();
+        sInstance.mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+    }
+
+    /* If accessed before singleton instantiation will abort. */
+    public static NetworkUtils getInstance() {
+        assert(sInstance != null);
+        return sInstance;
+    }
+
+    public synchronized boolean isWifiAvailable() {
+        if (mConnectivityManager == null) {
+            Log.e(LOG_TAG, "ConnectivityManager is null!");
+            return false;
+        }
+
+        NetworkInfo aNet = mConnectivityManager.getActiveNetworkInfo();
+        return (aNet != null && aNet.getType() == ConnectivityManager.TYPE_WIFI);
+    }
+
+}
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java
new file mode 100644
index 000000000000..11e99c5855d1
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java
@@ -0,0 +1,85 @@
+package org.mozilla.mozstumbler.service.utils;
+
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+/* This code is copied from android IntentService, with stopSelf commented out. */
+public abstract class PersistentIntentService extends Service {
+    private volatile Looper mServiceLooper;
+    private volatile ServiceHandler mServiceHandler;
+    private String mName;
+    private boolean mRedelivery;
+
+    private final class ServiceHandler extends Handler {
+        public ServiceHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            onHandleIntent((Intent) msg.obj);
+            // stopSelf(msg.arg1); <-- modified from original file
+        }
+    }
+
+    public PersistentIntentService(String name) {
+        super();
+        mName = name;
+    }
+
+    public void setIntentRedelivery(boolean enabled) {
+        mRedelivery = enabled;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
+        thread.start();
+        mServiceLooper = thread.getLooper();
+        mServiceHandler = new ServiceHandler(mServiceLooper);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Message msg = mServiceHandler.obtainMessage();
+        msg.arg1 = startId;
+        msg.obj = intent;
+        mServiceHandler.sendMessage(msg);
+        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
+    }
+
+    @Override
+    public void onDestroy() {
+        mServiceLooper.quit();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    protected abstract void onHandleIntent(Intent intent);
+}
+
diff --git a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java
new file mode 100644
index 000000000000..90e0ee7f5fb3
--- /dev/null
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/utils/Zipper.java
@@ -0,0 +1,48 @@
+/* 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/. */
+
+package org.mozilla.mozstumbler.service.utils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+public class Zipper {
+    public static byte[] zipData(byte[] data) throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        GZIPOutputStream gstream = new GZIPOutputStream(os);
+        byte[] output;
+        try {
+            gstream.write(data);
+            gstream.finish();
+            output = os.toByteArray();
+        } finally {
+            gstream.close();
+            os.close();
+        }
+        return output;
+    }
+
+    public static String unzipData(byte[] data) throws IOException {
+        StringBuilder result = new StringBuilder();
+        final ByteArrayInputStream bs = new ByteArrayInputStream(data);
+        GZIPInputStream gstream = new GZIPInputStream(bs);
+        try {
+            InputStreamReader reader = new InputStreamReader(gstream);
+            BufferedReader in = new BufferedReader(reader);
+            String read;
+            while ((read = in.readLine()) != null) {
+                result.append(read);
+            }
+        } finally {
+            gstream.close();
+            bs.close();
+        }
+        return result.toString();
+    }
+}
diff --git a/mobile/android/stumbler/manifests/StumblerManifest_services.xml.in b/mobile/android/stumbler/manifests/StumblerManifest_services.xml.in
index f23acd71505a..3ac5748665d6 100644
--- a/mobile/android/stumbler/manifests/StumblerManifest_services.xml.in
+++ b/mobile/android/stumbler/manifests/StumblerManifest_services.xml.in
@@ -1,2 +1,15 @@
-
+
+
+
+
+
+
+
+  
+      
+      
+      
+  
+
diff --git a/mobile/android/stumbler/stumbler_sources.mozbuild b/mobile/android/stumbler/stumbler_sources.mozbuild
index d5c149584180..e721e9df72dc 100644
--- a/mobile/android/stumbler/stumbler_sources.mozbuild
+++ b/mobile/android/stumbler/stumbler_sources.mozbuild
@@ -5,5 +5,28 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 stumbler_sources = [
-    'java/org/mozilla/mozstumbler/PlaceHolder.java',
+    'java/org/mozilla/mozstumbler/service/AppGlobals.java',
+    'java/org/mozilla/mozstumbler/service/mainthread/PassiveServiceReceiver.java',
+    'java/org/mozilla/mozstumbler/service/Prefs.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/BSSIDBlockList.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/SSIDBlockList.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerNoWCDMA.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/WifiScanner.java',
+    'java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java',
+    'java/org/mozilla/mozstumbler/service/uploadthread/AsyncUploader.java',
+    'java/org/mozilla/mozstumbler/service/uploadthread/UploadAlarmReceiver.java',
+    'java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java',
+    'java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java',
+    'java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java',
+    'java/org/mozilla/mozstumbler/service/utils/Zipper.java',
 ]

From 9914f6f5b4d488ab9d2ce90c471a75487d72a187 Mon Sep 17 00:00:00 2001
From: Garvan Keeley 
Date: Thu, 28 Aug 2014 12:52:00 -0700
Subject: [PATCH 105/120] Bug 1038843 - Part 2: Enable stumbler based on
 existing 'app.geo.reportdata' Gecko pref. r=nalexander

---
 mobile/android/base/AppConstants.java.in      |  8 +++++
 mobile/android/base/BrowserApp.java           |  9 ++++++
 mobile/android/base/moz.build                 |  1 +
 .../base/preferences/GeckoPreferences.java    | 30 +++++++++++++++++++
 4 files changed, 48 insertions(+)

diff --git a/mobile/android/base/AppConstants.java.in b/mobile/android/base/AppConstants.java.in
index 66a61daef1ab..8ab98aadc207 100644
--- a/mobile/android/base/AppConstants.java.in
+++ b/mobile/android/base/AppConstants.java.in
@@ -94,6 +94,14 @@ public class AppConstants {
     // add additional quotes we end up with ""x.y"", which is a syntax error.
     public static final String MOZILLA_VERSION = @MOZILLA_VERSION@;
 
+    public static final String MOZ_STUMBLER_API_KEY =
+#ifdef MOZ_ANDROID_MLS_STUMBLER
+    "@MOZ_STUMBLER_API_KEY@";
+#else
+    null;
+#endif
+    public static final boolean MOZ_STUMBLER_BUILD_TIME_ENABLED = (MOZ_STUMBLER_API_KEY != null);
+
     public static final String MOZ_CHILD_PROCESS_NAME = "@MOZ_CHILD_PROCESS_NAME@";
     public static final String MOZ_UPDATE_CHANNEL = "@MOZ_UPDATE_CHANNEL@";
     public static final String OMNIJAR_NAME = "@OMNIJAR_NAME@";
diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 0009bc784840..f07cbd60568b 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -669,6 +669,10 @@ public class BrowserApp extends GeckoApp
         super.onResume();
         EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
             "Prompt:ShowTop");
+        if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
+            // Starts or pings the stumbler lib, see also usage in handleMessage(): Gecko:DelayedStartup.
+            GeckoPreferences.broadcastStumblerPref(this);
+        }
     }
 
     @Override
@@ -1418,6 +1422,11 @@ public class BrowserApp extends GeckoApp
                     }
                 });
 
+                if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
+                    // Start (this acts as ping if started already) the stumbler lib; if the stumbler has queued data it will upload it.
+                    // Stumbler operates on its own thread, and startup impact is further minimized by delaying work (such as upload) a few seconds.
+                    GeckoPreferences.broadcastStumblerPref(this);
+                }
                 super.handleMessage(event, message);
             } else if (event.equals("Gecko:Ready")) {
                 // Handle this message in GeckoApp, but also enable the Settings
diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build
index 6c1a836faf73..9921e96c9aef 100644
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -783,6 +783,7 @@ if CONFIG['MOZ_CRASHREPORTER']:
 if CONFIG['MOZ_ANDROID_MLS_STUMBLER']:
     main.included_projects += ['../FennecStumbler']
     main.referenced_projects += ['../FennecStumbler']
+    DEFINES['MOZ_STUMBLER_API_KEY'] = CONFIG['MOZ_MOZILLA_API_KEY']
 
 if CONFIG['MOZ_ANDROID_SEARCH_ACTIVITY']:
     searchres = add_android_eclipse_library_project('FennecResourcesSearch')
diff --git a/mobile/android/base/preferences/GeckoPreferences.java b/mobile/android/base/preferences/GeckoPreferences.java
index c141c12aaf61..96d2eade53e1 100644
--- a/mobile/android/base/preferences/GeckoPreferences.java
+++ b/mobile/android/base/preferences/GeckoPreferences.java
@@ -115,6 +115,7 @@ OnSharedPreferenceChangeListener
     private static final String PREFS_DEVTOOLS_REMOTE_ENABLED = "devtools.debugger.remote-enabled";
     private static final String PREFS_DISPLAY_REFLOW_ON_ZOOM = "browser.zoom.reflowOnZoom";
     private static final String PREFS_SYNC = NON_PREF_PREFIX + "sync";
+    private static final String PREFS_STUMBLER_ENABLED = AppConstants.ANDROID_PACKAGE_NAME + ".STUMBLER_PREF";
 
     // This isn't a Gecko pref, even if it looks like one.
     private static final String PREFS_BROWSER_LOCALE = "locale";
@@ -849,6 +850,34 @@ OnSharedPreferenceChangeListener
         broadcastAction(context, intent);
     }
 
+    /**
+     * Broadcast the provided value as the value of the
+     * PREFS_STUMBLER_ENABLED pref.
+     */
+    public static void broadcastStumblerPref(final Context context, final boolean value) {
+       Intent intent = new Intent(PREFS_STUMBLER_ENABLED)
+                .putExtra("pref", PREFS_GEO_REPORTING)
+                .putExtra("branch", GeckoSharedPrefs.APP_PREFS_NAME)
+                .putExtra("enabled", value)
+                .putExtra("moz_mozilla_api_key", AppConstants.MOZ_STUMBLER_API_KEY);
+       if (GeckoAppShell.getGeckoInterface() != null) {
+           intent.putExtra("user_agent", GeckoAppShell.getGeckoInterface().getDefaultUAString());
+       }
+       if (!AppConstants.MOZILLA_OFFICIAL) {
+           intent.putExtra("is_debug", true);
+       }
+       broadcastAction(context, intent);
+    }
+
+    /**
+     * Broadcast the current value of the
+     * PREFS_STUMBLER_ENABLED pref.
+     */
+    public static void broadcastStumblerPref(final Context context) {
+        final boolean value = getBooleanPref(context, PREFS_GEO_REPORTING, true);
+        broadcastStumblerPref(context, value);
+    }
+
     /**
      * Return the value of the named preference in the default preferences file.
      *
@@ -1009,6 +1038,7 @@ OnSharedPreferenceChangeListener
             // repeated background upload attempts.
             broadcastHealthReportUploadPref(this, ((Boolean) newValue).booleanValue());
         } else if (PREFS_GEO_REPORTING.equals(prefName)) {
+            broadcastStumblerPref(this, ((Boolean) newValue).booleanValue());
             // Translate boolean value to int for geo reporting pref.
             newValue = ((Boolean) newValue) ? 1 : 0;
         } else if (handlers.containsKey(prefName)) {

From 2f41642ad272282e6de97c02cfaa101dbff9fb36 Mon Sep 17 00:00:00 2001
From: Gijs Kruitbosch 
Date: Thu, 28 Aug 2014 17:24:05 +0100
Subject: [PATCH 106/120] Bug 1050809 - update toolbar/menupanel icons for
 yosemite, r=jaws

---
 browser/themes/osx/Toolbar-yosemite.png       | Bin 0 -> 15264 bytes
 browser/themes/osx/Toolbar-yosemite@2x.png    | Bin 0 -> 35291 bytes
 browser/themes/osx/jar.mn                     |  40 ++++++++++++++++++
 .../themes/osx/loop/menuPanel-yosemite.png    | Bin 0 -> 9689 bytes
 .../themes/osx/loop/menuPanel-yosemite@2x.png | Bin 0 -> 19941 bytes
 browser/themes/osx/loop/toolbar-yosemite.png  | Bin 0 -> 2375 bytes
 .../themes/osx/loop/toolbar-yosemite@2x.png   | Bin 0 -> 4783 bytes
 .../osx/menuPanel-customize-yosemite.png      | Bin 0 -> 219 bytes
 .../osx/menuPanel-customize-yosemite@2x.png   | Bin 0 -> 364 bytes
 .../themes/osx/menuPanel-exit-yosemite.png    | Bin 0 -> 515 bytes
 .../themes/osx/menuPanel-exit-yosemite@2x.png | Bin 0 -> 939 bytes
 .../themes/osx/menuPanel-help-yosemite.png    | Bin 0 -> 1503 bytes
 .../themes/osx/menuPanel-help-yosemite@2x.png | Bin 0 -> 3516 bytes
 .../themes/osx/menuPanel-small-yosemite.png   | Bin 0 -> 1620 bytes
 .../osx/menuPanel-small-yosemite@2x.png       | Bin 0 -> 4221 bytes
 browser/themes/osx/menuPanel-yosemite.png     | Bin 0 -> 19351 bytes
 browser/themes/osx/menuPanel-yosemite@2x.png  | Bin 0 -> 43786 bytes
 .../themes/osx/reload-stop-go-yosemite.png    | Bin 0 -> 923 bytes
 .../themes/osx/reload-stop-go-yosemite@2x.png | Bin 0 -> 1619 bytes
 .../osx/sync-horizontalbar-yosemite.png       | Bin 0 -> 311 bytes
 .../osx/sync-horizontalbar-yosemite@2x.png    | Bin 0 -> 609 bytes
 21 files changed, 40 insertions(+)
 create mode 100644 browser/themes/osx/Toolbar-yosemite.png
 create mode 100644 browser/themes/osx/Toolbar-yosemite@2x.png
 create mode 100644 browser/themes/osx/loop/menuPanel-yosemite.png
 create mode 100644 browser/themes/osx/loop/menuPanel-yosemite@2x.png
 create mode 100644 browser/themes/osx/loop/toolbar-yosemite.png
 create mode 100644 browser/themes/osx/loop/toolbar-yosemite@2x.png
 create mode 100644 browser/themes/osx/menuPanel-customize-yosemite.png
 create mode 100644 browser/themes/osx/menuPanel-customize-yosemite@2x.png
 create mode 100644 browser/themes/osx/menuPanel-exit-yosemite.png
 create mode 100644 browser/themes/osx/menuPanel-exit-yosemite@2x.png
 create mode 100644 browser/themes/osx/menuPanel-help-yosemite.png
 create mode 100644 browser/themes/osx/menuPanel-help-yosemite@2x.png
 create mode 100644 browser/themes/osx/menuPanel-small-yosemite.png
 create mode 100644 browser/themes/osx/menuPanel-small-yosemite@2x.png
 create mode 100644 browser/themes/osx/menuPanel-yosemite.png
 create mode 100644 browser/themes/osx/menuPanel-yosemite@2x.png
 create mode 100644 browser/themes/osx/reload-stop-go-yosemite.png
 create mode 100644 browser/themes/osx/reload-stop-go-yosemite@2x.png
 create mode 100644 browser/themes/osx/sync-horizontalbar-yosemite.png
 create mode 100644 browser/themes/osx/sync-horizontalbar-yosemite@2x.png

diff --git a/browser/themes/osx/Toolbar-yosemite.png b/browser/themes/osx/Toolbar-yosemite.png
new file mode 100644
index 0000000000000000000000000000000000000000..7efda436ada08eae338a0d3845297183b1df69d8
GIT binary patch
literal 15264
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
GL;ep%t)vuloPzdhsQYc#7-JMdb
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 literal 0 HcmV?d00001 diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn index 050866728356..166a0c31fb30 100644 --- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -145,6 +145,10 @@ browser.jar: skin/classic/browser/loop/toolbar@2x.png (loop/toolbar@2x.png) skin/classic/browser/loop/toolbar-inverted.png (loop/toolbar-inverted.png) skin/classic/browser/loop/toolbar-inverted@2x.png (loop/toolbar-inverted@2x.png) + skin/classic/browser/yosemite/loop/menuPanel.png (loop/menuPanel-yosemite.png) + skin/classic/browser/yosemite/loop/menuPanel@2x.png (loop/menuPanel-yosemite@2x.png) + skin/classic/browser/yosemite/loop/toolbar.png (loop/toolbar-yosemite.png) + skin/classic/browser/yosemite/loop/toolbar@2x.png (loop/toolbar-yosemite@2x.png) skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png) skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png) skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png (customizableui/customize-titleBar-toggle@2x.png) @@ -506,6 +510,22 @@ browser.jar: skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon@2x.png (tabbrowser/alltabs-box-bkgnd-icon-lion@2x.png) skin/classic/browser/lion/tabview/tabview.png (tabview/tabview-lion.png) skin/classic/browser/lion/places/toolbar.png (places/toolbar-lion.png) + skin/classic/browser/yosemite/Toolbar.png (Toolbar-yosemite.png) + skin/classic/browser/yosemite/Toolbar@2x.png (Toolbar-yosemite@2x.png) + skin/classic/browser/yosemite/menuPanel.png (menuPanel-yosemite.png) + skin/classic/browser/yosemite/menuPanel@2x.png (menuPanel-yosemite@2x.png) + skin/classic/browser/yosemite/menuPanel-customize.png (menuPanel-customize-yosemite.png) + skin/classic/browser/yosemite/menuPanel-customize@2x.png (menuPanel-customize-yosemite@2x.png) + skin/classic/browser/yosemite/menuPanel-exit.png (menuPanel-exit-yosemite.png) + skin/classic/browser/yosemite/menuPanel-exit@2x.png (menuPanel-exit-yosemite@2x.png) + skin/classic/browser/yosemite/menuPanel-help.png (menuPanel-help-yosemite.png) + skin/classic/browser/yosemite/menuPanel-help@2x.png (menuPanel-help-yosemite@2x.png) + skin/classic/browser/yosemite/menuPanel-small.png (menuPanel-small-yosemite.png) + skin/classic/browser/yosemite/menuPanel-small@2x.png (menuPanel-small-yosemite@2x.png) + skin/classic/browser/yosemite/reload-stop-go.png (reload-stop-go-yosemite.png) + skin/classic/browser/yosemite/reload-stop-go@2x.png (reload-stop-go-yosemite@2x.png) + skin/classic/browser/yosemite/sync-horizontalbar.png (sync-horizontalbar-yosemite.png) + skin/classic/browser/yosemite/sync-horizontalbar@2x.png (sync-horizontalbar-yosemite@2x.png) skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) @@ -525,3 +545,23 @@ browser.jar: % override chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png chrome://browser/skin/lion/tabbrowser/alltabs-box-bkgnd-icon.png os=Darwin osversion>=10.7 % override chrome://browser/skin/tabview/tabview.png chrome://browser/skin/lion/tabview/tabview.png os=Darwin osversion>=10.7 % override chrome://browser/skin/places/toolbar.png chrome://browser/skin/lion/places/toolbar.png os=Darwin osversion>=10.7 +% override chrome://browser/skin/Toolbar.png chrome://browser/skin/yosemite/Toolbar.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/Toolbar@2x.png chrome://browser/skin/yosemite/Toolbar@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel.png chrome://browser/skin/yosemite/menuPanel.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel@2x.png chrome://browser/skin/yosemite/menuPanel@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/loop/menuPanel.png chrome://browser/skin/yosemite/loop/menuPanel.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/loop/menuPanel@2x.png chrome://browser/skin/yosemite/loop/menuPanel@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/loop/toolbar.png chrome://browser/skin/yosemite/loop/toolbar.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/loop/toolbar@2x.png chrome://browser/skin/yosemite/loop/toolbar@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-customize.png chrome://browser/skin/yosemite/menuPanel-customize.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-customize@2x.png chrome://browser/skin/yosemite/menuPanel-customize@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-exit.png chrome://browser/skin/yosemite/menuPanel-exit.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-exit@2x.png chrome://browser/skin/yosemite/menuPanel-exit@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-help.png chrome://browser/skin/yosemite/menuPanel-help.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-help@2x.png chrome://browser/skin/yosemite/menuPanel-help@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/yosemite/menuPanel-small.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/menuPanel-small@2x.png chrome://browser/skin/yosemite/menuPanel-small@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/reload-stop-go.png chrome://browser/skin/yosemite/reload-stop-go.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/reload-stop-go@2x.png chrome://browser/skin/yosemite/reload-stop-go@2x.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/yosemite/sync-horizontalbar.png os=Darwin osversion>=10.10 +% override chrome://browser/skin/sync-horizontalbar@2x.png chrome://browser/skin/yosemite/sync-horizontalbar@2x.png os=Darwin osversion>=10.10 diff --git a/browser/themes/osx/loop/menuPanel-yosemite.png b/browser/themes/osx/loop/menuPanel-yosemite.png new file mode 100644 index 0000000000000000000000000000000000000000..db7f4ac709807d381c91ff2850050579aab17e2c GIT binary patch literal 9689 zcmZ9SbwE?^7w`!Y1aSr_F+!!gL}Dl*A>BCzq#Fq(MkCTKA)V4K-QC?aU`WS+F&NuB zf8T%J_x)qL&pkWmdCq;#bIzXoxi?HrKJb{ayResf3x`)8X zskk}dwoSY2Pu6!C^(Sxf0`LMDa{Ru3rx6RPJn?$Bc01}CDon%sAmt)@S#o@rT40a| z4Do>p3B(V!I6j%oL|+twhz=+X^z|?CEKdW!JjUk>dVIh9G_o8M_W|8sN$c>ILJ*&C znA76U<@#qhit?33YX>!ofv!jDA!Cp~hZ8?$_Q|XNR}=>k^^xOox(|{k{U)pWxAC zKai)HE>s0{p5t?oR6P456)3#O+Ve_GtU0n8G5HFUAEr;aK%^|SJL)DCdX6|9Unv$_V*btc`9TQ~%HAdi*7E zXZ0v*P8dzkfU{pT7|%i}Dk|zz^6AWtfQRAhqeqWK`=fz?Z>Jlb#lL_5{w1@`Za73g zJU5)7OE2KK*0LNG6}2kJ*@m^&7#_(%k~qK@$X5|?W9Sx|8-w8h&(5ykl4e;%ZlPRK-XIRUM7h=_sY!upF%a%97E;^N~m;mT+ZO?dg^M>DDEJKPG;sVO>W+*93@!(J5y`&M-1Y>#60vak*u z4E#Jt-sS)0v+YQb;)#|!Qn%)?>D}v?@|6MiB5$=X3EFL)&_ZKItQQeF;w462Z^E@D z-GR;jR34t@4E1gb2HE2_;qN_nCzNGmWW<=N``K>y+b>jZI{WzCxic9MVL}>~;u8}u z7k_J)Fzu{c9?X?dh7~;v$NNHPqja2F7yW(UdDCDEED~)wE0 z>_rNu&Kuwkp_$9=mulG_eFYY=C9N@hmMlxv)X<1By)*jz(9zmVd3S&2 zDf9bNf8iOmcN3<14>qmn8m-m zwgs`-9V%UQTrpIkAW(OTYszffS1KNn!YCpfd$e$IrsJj|1Yf5Ro5Oa~41F~xBvb-h zAILny?-7E;O8=5sDvASnBW-~U<&h?L1?6q(zvD1Ko^xF262kj;31xhK6CNkQROt8b z-@yr>#Y#ykc{zs1o~FMdA64Y=;l}A#n-9{I(qyAjzX*hDFbMP8+YJ{tF2+*NQ=j`S z{BENu;K$Gb`V;Z?x@(|LiQb^ebPWcdf#PuWL0}bA8JRrL0aUIr2=ok7^uJ)_4fGvO zUcY1Z5p{({fLt)eS}(qG=~mCo%^i0%jepVe!>m@*{4kzkFRh7(NOq6ph&(n-G3ysm zR8*WZwPO+Y1@8MTup=)Mx=!N=yAIs@(cuM0(D+Qdt)bOtcapXD4Gd_>)A zWEe4Gl9%_VlJ6e$Y-3FPLZoi0Eypvw2JTGSh_>6xSv$A5I=meVX;?evxu|7oHHvXa z{q+QP)$eL7Z~5vu=n?o+GMiU)#PD_a!qj7VutNbG8iU|TwI#~qiRMsc-HtX&{ETfI za#OHv1KK|P8$dYqCu*H!f=V7-@3>AMX=LU`@Y-@L9Z%e3sIzxP!G+*2JI1IWC73Vf zl}#73irL}qHJnJfpTc47H!sHLOs7xk26`)ZhJi?(8JRKogq4Wr#DHv+qxfRlO2xpX zF`x@#YW%(7->jzR5T1@t*byDqu~(DIMlK(}!m`2ii1_sDFtyGO-U$CLDc1i)NQdmA z!#%XP&U96;mqZ{msRIpPZS5RH#WPI+S@ z3JZ5hOVjdDsYb3DgpcQggzL5QEYR)Zb!RxxRIi~CcD7;|q3#$02fFl&-O>%o+F=S{ zDA%{==)8K*j?DEL#Q$!ag!>}7LeEc5%4oUKb=L>RY0i?*^p&vRa+a&#+S%Ee#7)Z^ z68ap*Qp?BT>U)k`rQPz$%qU-E{eAt6xl!1%a2*^JD?Ui{-S(}%*9>gE z+=UkpYGAthpbq&eO)(N%UV57i?A!K8`SGC7%N=wEbQg%K{9n1~d(X|yK}SYL@CW$S zbvdtJ-en}sL*MOdm3pb(LN!z#zj{=OcXM1|Y$rQYP=#(p(s%%FD;}Tpw z%07w?bWVa6L`3N9LSDIjgI2KB_mCrYHG5uO>X*URi}ll~G`6IS9+Wwg=?d-Er-FP9 zWpnmmF3=ynb1u%`{PSkLOK=oxPnn@Zf6`uz6}<@d-ie%*a_CGf;<9-0Rh@14|Z zaGpSc{!EQE`Nwpek}QqJ>x!^x#}Bp@lm-z(kI(xQs`Ba+9M+#G$jrHHt@tfz)_Z`{ z;2scky#FnHP=hm!IEs&ef%W zu3k}R$>(8DuX^JZ+lIiVSBHy)jjU}1BoyXC!om*HeFODBEczm-3#tXOxtepZb>mm| z=QFNgSQ7YCP)JCIrQ}U>y-@kbn~^{yYf}C9(pPiIC(G?mAik8PS*5Lf!LCO&d7QA5 zyQQ;@l$pUiTS@CN{ioKN%}Djj62Mxqp;QxvaXVv4%F=kIdloFK(N<`0DLuDNKho4j z1maFaS9`%SRY%~#R#K%e1U}-K+8xgX{vL*=3EAqXo0zOgGNtyz=1IdTdDa*_jEhR0 zB!wD9U5oH{ReA1bee;!HjXP_pWuYrZI&cueRFNf9uuzRt zLHF8`f=pYGSbt~T-szBR^^YW((o|wm->hui6rK)}!lCY$1+a{yH}1>lCI6 zgOmE%ujrBsI~(+dE0}LPMEk^22rx zPxb<~jEAJp>QdJYaAo$P{SDPhV?UP_URVASk3U&HpJq%aU5!SZ_n3uE-6nrR(w=AO zi>|M&Nk${voS&fx*GxC(X@Ti$lhBHJSb2K%phpQ8{N zMo2h1FC+Jb(P$}yPY!o}w^c7#Uc8{SbiW2)aoMi_YwNzqdOg-T* z&*CHo^QU$VcA}RjXMpmCNn&X)xOaO8AM9zAowJY>Vbu!m$C^t&e91x{t0=jQccB4i zUi!9Jm{L)}19oQz_FL`!u`&p{_0`$PQ=nF<+}`lzc~EV}6)Rtx+&D8#fiCYIjAxb_ z@{nzI+U$y?J^uX1$7@i0`nNwAND438PX5=LSJ~99FJLprCF5WBwx2$ z{Iyo9agW9@ zQ)zo9Qs>--qs8sX5Qdwt`ZyqdjGC6z)$cFsBQJAG_8yVX^HU_Oju>P-OKsp{tO`2O zUDaC1MiC7%Vee65c`=9UU1ZokWQQyP>aB-n@*h z$Ph3cxd$s`MJ0?fM*N^P?ps62=;XXS&bSXI6@^&k|y8T{|=lMMih7`il1NgeU4_<1K91n8KLkNJ!7Bi9#PKB>Z=i_R- z1QR-mw#Ci8y2L0nR)E$?UG*Ev^ojnwqZc2%|c=5F6W1&%2$VFDOJ7 zNk>LUS9uUT3c&K3aL=vgw~CXmIX?9ka8;2aaxdRNe3v2|Vq8Q=Rj6XyMT84qsZ<~l zsg!Pk2?MZ~UFLf{RkBkutuVvmB=^9C2VQwyWs*}1Ka=z3QPiC?q#B0~@lGdZKO#9c z-hk_Hn$0|1aLT8@beU0Z)TN{6YeYW+y2&0HHS%;E_r@2JW`V5GRyI?sBGb-(3Fx0F z`90_{-_$JrU%*hqiu7tBkkJlu5xPCzqP$8OvIhcx?FDaiCz%yuKw7&POLQjk<`mNg zTE&tsrHSl9D$c&upDYH9+JZvzHwdjKI?P3Qqwjw1 zg66D+bH&vrNYXn2Q*R&kJbp*@r%U8;cU%&rL$&aKOYvBc)`_3~KO%8LqrLL~DVgvT zQN9iY<^@uHXAI(XBB)0m632YM380*jW}bOVswJJ6Ze!tNY^JHnnFMQM#e*GNQ7*!^ zsOk&avSWE@<|pk6{>LKnC3O}4n6Z3*!<{o9@0&we0BgUz=PfZAGPS#;dEBR*02yPZ zuV|R)y?@FJssx_Cb>Zm`ZPE0Y*z|nw5}ESC_U)CSY6sWkGiyw4y^8=I2@csk0 zxJ(`LIlwi;SM?|I0Afh?^4Ehw9xq0u`3S0vCCf1hpJ1oFpeW!jLGSOg==p;eK!RDU zb|aO6)WNv<#06ckdG$V96Yy^B*~G%jFuMlHLh}CUzd>LXag&O8loC%7)|GQx{>eBe zCRb37BlnZL+m#au+|MGbLQN`yED2VQMw;R#j+5DV=569efVznR&Jsa2O%rwM?^x79 zhFb${qy1es=;+{3&dSYY$l?W5u1V=Sz~YYL?KqLoT+Ri_tgq`^ai@>2Z zg9Bq;o4#lJqnWVg^y~hPNwHG{-9?Qny?T?Y78lXhV*k-A7TffauH{op@3PZtw*DJpkM>)^bRvma1l=3ABNx z>d#R^2o0-N5Fg+M)c$TJGxj8+bF{Qx1@bc38>_292_nxOS9q{gW_`fa;Li3wsbO56 z8>GX!TtW7hM{>6Z|Mf{0?SC2o1g|DhVP=h@HM#fW8DFGyPi zekwoV&GgRr;7h6ngHh&<8n*4#mTr8Md>CkQN@+ox2bj2hgC z(nuLpUi>BA1O$of$#>!Xx*%Mk{iNA=$JC6v*gq|Qj4ohLco%f=WeRvY#L+(lE0ql+;Iw{t&6;Ul(4w%32(dzJ}(iDzqr9mF1OkBC>S<(@s0g+o$rE3Sn7-ZS~%cB63K zkU3UNqx}xvz4~F79<%O?+f=B%p1pw*dUFK$iySc#?C#B8^=`k-Kb~h&vZ`L@_;p1{ zyN6OUf8#3Mj7$c{HXp{1UxYZ^;`{nEeK2p4a=X=CyB^&UMiU!1Q^Hw^M2!tO@HpH3 zY>I+^Y*gMp87a(o`Nh9MaN;G~&dzL-U07b@mz|_mO~YY}AJK#f2i4W1k`UCB+^w^l ze`IL4{9|A3=DywmZzHl~8$|KIQ_3<<*Le!)G#FeDSN9gr`rdVvjtv9l>%vj*_P_k} z6J65OSOM+k#=M0jw#z>cBh%1+_=p!p+ry5iUz=<*ZwV-!O!H`)<6M_mr6dKVdJiHF z6A(A(jgU+6E7`(tOvROd1j}E7B=?Zar5H71_s>~b0(lgfuNNJ{t8AJ3#5<`ttf&tX zo4sY5w@wvU>jbLP3mx!1jTrtuEPhMPB6zrpVcw%GIAGu*Ay@!QIN z!k(SZ;gM^4!gzxJN^`9}8}~PsSiGvg3O!40oS}O%?5o`_T;oL04%GT-F(7*21wQn1@tv>%ME4cr>;SLw% z8fo?qLDB4Ir7P9BUFHC8qbs#E{W!AehjO=`0ymJOT#(7A-^FEcn?c0IS$nV>L|fBO zvbR5~X8+7%eSs5TW-&ni(KITMxuj}bdE@|nwWy}FL&}iNJHW!ab#M0$w?XE7f9>|2 z5U57Di=`OKgcVhoFU_`MUY=_cS9a}g)G>|S;-fdxH4q@5(2{MikFul~z4JQI$?v`N zYV)0(-fxZ$@1h|7@=@caO(OoplhG$QLTa!U-(690M|{UUyeE+%?5y3oOsbU*L5jG< z_wv80DCu7!y!iWCP^+pTulcv$NSjDve7RmM5eAKqJrd z0}e*pcQ{Vai3hnj zfXwrjAMJkcAW{QlE}d%V z1+QT}kw~nFISKC`gBRZ%02Um(>0V(Fc(ep{H|$cF<<0DC5~>omj;R(@m#(J+TT8x@ z%mvX<3f>oOcB!rEnq9&DGsLt=x9XP9TK~e6oi*>sz6_w`8v|doLT^JPGo1S`c1V<_ z1u>FUYHKF7MY-t7%w_akG_p~nKI!|OoG-wtK>8Ple<43krX5r4f z3zIZDBZ>0?S`}#dX{#~acF~V>L9=k4Wk0mk3r`@aGUWxlOD>~lcwx@d5#Vt z=aDYs(rjcE3$?qY+|jsURzx$>&Lg=je0mL9JDh)K51wBVeh{iF8d|GEuo3gNe_8jP zGC%x-8^ZD#o;)7SbMbFAoY+IO231P{bJ#ZUNDiB}VWpGUHiU{>XK=SY;ol1BZ`t|K z2AzL=tk&grw#jKeCzkpA50fU+_t$iGI$NBTI0lQ@oIo>DXUDmg+-9pUcJNA{-20m4 zk!jJ2ezh29HD+Wg5yiIRar02;XFDe-U$6(i_4f4%;19^%bapwj2(~LI_btl zlZM!arwJ#`XOE)BWvb^t>VK55+{2?IUk_EoBX_$b{n|>Ha@=#{Z$ms$H1YZ6fg~gu zA{b^U;h6wP!cLMn$a};m7%6}pSCWqOo}P1E13H~qXDp#s3gmM`>zYMR0Ds+GtCvt6 z{iJfkD!MM%-zU-y_u&GAR!9k~L%t^zjL8*W_=JTgsJO#bIg`HMPg7nC<$UIr9JrZ$ zv7Dkhl+&|46RL;Ez;a#jnYU+`hS{BZ4Ud}GEr-d{QHk1+4nOq*g%Me(*(a$LXnyGp zzC~IzIpD^00oMY}j(noO`}zpr3Eg{fw%Zp{24m4Z7d-+{X^DcxI}ZDG;E+b`vCj}G zvX5cc-6yXaQXx#){@DKxSliRHb<#pUX z@n#pe?w~4Hvsnk^s7D_n)xXsu40r8~y{}$J^BS8?ll}Fh-fz8gI}e$))3Mp)kmQ(# ze4Ap<%cC`<59#Pk3rK)#LjXU)YPD(M(C!MF4DZw6O=0s0y91WD`Jc(nPNSv#?IP@w z$#h3Q%vN7hNRzs{Df@R1aTTUSqswh-s2!u|KtIQ6<}E7PKe(FQ?WMp)a!%I>I9NGW ztLsMj0R2BLTQP%=^N}SmLJ%kr?Wg$#8#RxgZgb$){PROTf4BCDl` zg3>S_NO)qtPBgXxd)vI@s|r4I`t}?|xdCm}Jb~RW8#A@Z5ASwpGaH)3aw={~mkR|Um##eR(}TB@6xfZP_<2YD z-}on>%AxUi88_mwm0WCO=ixB&O9A>$c5n>CaV^xmKn0r?Cds-N4gSKV=Z==@g|q(e zu*Tb8lPP?xc(D)a>Tsy9d-MV>^P5;DR|;RIut~CbrtL_4vdhK;y&USO*lhT;TIh)q zJtSbcHo_u4-jH~;`$B3z%v3h#d{|n3Zq=PEjaq0C5+@~cdVHG2RD29@OB?S`)7$3j zEfmM-z%`YmlL;*BClnwZf$H(+lCo#kahc3*4TtK}4%iL%w&ln_E|>tMTCcT3Hp*c| zf@o0zKyRTs`X~bS+4kh10K_mZ06IC5W*OY6X=c-8)%ucms@9W}*7>R7Y?@ggSF|>$ zhO=W>ZLhO^Q^fgdYSptsz@^sI;2e z?QLf)c{Acm5s1OvEPoA@Dg(LRi#f6%2Mb}edshbrP`PybfbXv|r?fMYCQlF|6R*Jw zwB#vFqSM)EKMxuTMUVB2=XagDsk?+P1>YYxG8R0#BwEqop=)B`yjg7n*`xzgm19Gn zip>F?rphe#23BJyPki~RN4?!>FqCQ}vJ6vXQOiL9dKTHpUu}PhYL+eU8!xPpM>gU* z5hQFhO^|U8XFpe**(R4_lztH?mi4lc?)Ba!C==k;eaqz+y>KA6XP9oMo`_2Toe7KVBh4FCJ|mZ5!SNoTfGP|AFfftNd)~Y!v~w4i2bvjm9%w z(TWXYrkqd?u>RWmQ;%RZcY;3vo9**(C)-XkZ~tQno36t^F+j5y$+1jG&cF#vVcU=H zdGe}19v}W@gC!~kGLoBJm*%-dK225PwA!>Fu^XQnuD&_1Xx=b)q%Ro;N)%s2Xf`q( zulzM<-lFA4vPDaE|0@d7Ya6CdY5uWbOq(>KI(VduKt`z`rMeF}pg3pcy`1rEB`6yEAo%!x6Rqj+9JVQW#~P9^BHk66nhHvn!eRzC|aK9`0}led&hb z-}2F;&8kC^eE#bfqw(a6-pQlKAJn(9GQJx*Ou5bwvo^N;p&ISiZ^p8_d_qHWIw>N385a$uxi=LAYkhG5 z@Km3GMp Z5Y$v=o2j3NePs(rK~_bk{N2ZZ{{sw~t8D-P literal 0 HcmV?d00001 diff --git a/browser/themes/osx/loop/menuPanel-yosemite@2x.png b/browser/themes/osx/loop/menuPanel-yosemite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..23cf6fecce91cef54d494bb1f4aa37052c3639b9 GIT binary patch literal 19941 zcmaHR1yoyIurBWIQlz-MJ1xZ>ihFT)hX5@U+TyOkiWVqPTmlq|yBF8s7Az3R@LlU2mPNWM;nkX3st|IeYJ{#A$0P;bKu?As`^&swgYyA|N34yvPw4XfN-1SZ&n^ z2pT_B6y)^-|DLRcXzK?Qpn776Ni5fx+xc;HFdE}Zc1Rk#1UQor>p&=i95E87**Msu zyod-f7#JAwb%<@`%rweU^lP#R7&-dsoz(^Kh?yu~F(H;9#*e=(4T?qVNIxLxX#^YG z&{guZdx&12cHbF>R?GNt_MTY+pLOo^MV~yWbL%Pp$IEN=)2B~?Q(UTLNL5VIl$b0} zb85Kyia{ju_?Srms+yv(Yj)w}$TMPfC1m03@b1KgDIvmJ_*E1Fe$KmLeYx~fR>s~^ zU~pyR2wNh9GUO3>wT$$?Lr{Ftn(IR2G<8&cm0$rP^@qw#s)}z{Y*9k_fc^9C{}swI ze}wQpZpk;YWn)#OT-!2bUF-1*Yg6v&ph%a_r#_2el`#kqDHat73@g2b(tS6q%;v)y zzvhsxs-K}&>eW|J>|>kLV}UwWT>sJGBTY``!@5aRk)h(~@*+`xXUp{MjkH}#qN1wD zD^xu~O3V^%t?b>B|3=;Fmrb6j%q@)Y#?p844@lX6C65SJrV1b>-%wC3caK6EVb`vK ziW+idDId;hXv>LLiolci(}~&h+cB}&Sl{mhp?!w`rP&*v!$M_QbS33T7p9TP^rc>G`4MDtmGPTe!|P0nuLiG^?MCer62HPk(Fg>e*e zwo(-y9uU1VORL;#4R0?fs*YeUDwb0U_9$;`4knMb^4QtmY?Fxpa+n_mNbM1u{fOW1 zpodF2>&f2+@o;osrfGTBi+Ddgdx#&)7F=QSEGTMD0!o>^|HC&g2e9zfZ-*VYY2(&^ zGC_Ba^sPKJ>TA<9K*IA2emAfkK$%vU~n%lE3*iMjEl-{lUTI-9^N!J zH+P<$ote+*Ja`RK)V)n**PpEGb zo0qb2H_*xnVzHTz1>+^8(NyuGFQk^uy4>dz1>j@%EIqjRN)dw31M zUOrALUwVdj3s`X+VsexjJ#V|{=&5LF*N57ToF7+~vQ|(ua*EF4{R?N*%?$$t4l$g` zsi<-)<(?Iygq@t6nodto+YlNwny218fRlf)ndS``Z!$5Sdl;3 zF{HmeYc_&OMYP`o!*(3{Thg79lEP>|09KOq>VKHINuqO0UPxYO)P27DzH+>I1u687 z`iOO5jeU$l{EBJJdhaf%5Ivn(h-oZx4=lfjf{W>+4Gq#3mw%hJ<^>s&ym;}C`6S+e z;Dcd8L`%CqSdxg`Agf^hY3qks+ttFrS8_|Z4m5h^qdV3&-!2l48rB*Y=8!~2S;ey| zfEAwgoGn(8EIx}^6py10U7}3F5b!z33Qt~50Aw^bSn~EN(=2i1wc{}QV##CRE5GMK z5wjOH&azK5OiG~RLrh|YH-^d8dGx`~^dR9LSnVxJjd8Q9v2fy9$r#`pUtUE;#d)oH zNAsgn;=}XoI3{Dw?99wn!>{gi!-DYb!Yj!4*EOVtrTjuaat3uy0e{HlyM+{{a`M4_ z)j_^=c2MXHfxL_AN1k@kWZ9*^rqsR?YqWaME(Q4Ret+^pM=114#Kj}qs4Ms;MJEHuI#2Y=C?aJ) zmXvWFKE@j*^$)uZY?vShM|Z3KS1XqwQc8o@-v?_|F+0BZd}tYyxq`lX{V(RD_S0Gj zl|pT*0bCF=(Zdkv`Dt%MnU9=|OvLy0WEn1)Zi)2Nm5Z%tayOPO*ztYk!xo`uX4;3+ z#X1Q7H)gSv%aYl1BMvzl?4(WQ_}JC{3y0B48i;Hb8xrKQ{6-riFLfkUu6N7hP>=-WwkCtK*Sev5A+b!cR`!J7&P6uMZ^^7s zEQ1MR^mKHrgO7+4J1QM-&o@8|Gj8iG9+qici;D+zM)ID&YH1`n5u}{0$JbDpeNRKh z2MS;-liXGGvBkU2nqR_DTic`PzZ|X0mM&RDY#0zIBwuQxH?D{#(ki?RGn}qmUk)oH zRv@CI0}%Egi|hk(t$28NYNz$XkCoqVjH361t+o4Y-~@E&>FUa~)WM?4h|{LJogkSA z_NGR6(osaUbs@d`Pa9tD)4oy4>(9Ym<51ZXBk6ql6j?uyCU($kVsv;4MD%N4EKM&$ySI`wy4CTIp}gQea4qG zWF=DY?i92y^tgy|4F@rqGsrV(xjMg^+JHqayX8`zGbYogSdv8*M8$NS0#e*nrxwlk?s3k*T+== zGzeNZnMWU6rVAJ0~O5 z;^ih6Lve(}WT}VoiHTaIB#qfMeW}pV!EkHDEuD`a`0L0@r^J=t|qH~QH9&Mo`~DA?UqfIuPj(mj*C1E%ajLm$hs=QFg9 zu8SB*tnkZg=T9)gtnC%PDgF2F-_Mbkl(`6R@HU9=zkSC)Lc0)b8x=)I2_jCLX<)lY zN0`KKJVO>z)>aKM>pXb|=i%S7#2&~!sWm_oH)3DpieiV{c^D)mw+oZOq@#Q-ZSCQr z@{LDStU)N!@}nFF0w5~({@?&DqTKe%kZA1Y`nnT~en?~Q_sRo4ice^yI%mY7E1Mi3 zDh17BO_kDq4M>X!CK~a41+#5e5)*S3p>0$X4sQjt^ya8 z;;r^f7dH7VPU9I)REkN|TiZK;;dmoI3gPLqbG_?x!vz1Qn+p3)@ zQdA0tYP-+A)+6FKLDK+4d7VgXyE}MOP7+g8)-C|9wQ82CK%n>S<@V{Bq+&1x+xYx5 z(53V@rl?qZVuvm>M0-L7J3fjA+pFJZHa6R&2*d7wDcFB|MTwgV{A6puP!)K^A%WC0 z>bjPW^8NDAu=)}BXs1jjufKu+Lc-$vN?!%SrR3fR*g$T$qAG&VaRgo_5{6=oqI0wU zHe+?zhf`kv?rd$v+5_<_e%BH?c3K;e_Lp`9D6`|FsVCYLQ}rkaQj?0%Ili!_to`?? zBcSFCux?mnidp<%J@jx6A3nEfCQ=aggnLMGkz1`8L{*&KZaDZKLzZ-0nPZR65d4So zrHKD2i!h>`$Wy=SbI5+CnzC{$l2uy_)=%G7e59m?73~O26y~*1X0RXvNXRsRTwVto zn7jsGvy5gTP)M_+=E;TIYN;d1E0hN>n2f`1t7IbSi_2%P8$x);^GcNIV;$Z3|80O0 z42Eq(#xRd|WT_v!=gk+QJp)u6J%YbOsmAU^$gD`@Rm@FiCXln7n$Hkls{gj{rTSWK zMkMkIb(Tgfxo~|g^%t4$uG>l&u4nr9B^=hsLDE`?6YLA&JA!GC1o>x~&Ec6u`r;;+ z#b(5zH1@=HYYX`x^d2l+(#?76Zi-f7x%QXZBa=V8^f4v*2EwLFqn{RW+8k|@i9a0P z!ZY?lj(PywL4Zf`H;l0rt3Q{WpUYw zbnUL_Sh8H4omJqq={Eiw?b&36Pkt3c~^{9Q}Mjn_7aS6^M> zz^)L)FWVCkgzz|P(e<k*h>8}Vd)fFg%@C0#?rPc4wyY*H=-aXI@_TbFU zPShRgF=pGwoWm^-foo6aXRZub%~Nv4F|COQ{H#t9AatTH@$p?TC!9Z^-#!a==Fk;e zFR7*8b%c$pWsvPmI-pGtH$#O1x^(W9pT>&EoQS5It}PlF>@rsseT_KaP0|_((WG~j>Hoh zujx&FZoyu?Qi4m2(SQH`EfbSR?&M#>nkpzLpn(O6ex2VHXT(rer5(>HVO4`nE=GP4 zmzUGMdT&=)z<7LRIm3gCl#){2o^G%Q|Da&{5;#z)<->}@)7#Ds^%8n|_GG)Hn-3B3 z`zWu_gjFjM-Pb#zXdt8m@{FsJWp=d3Z}<22YYZOYb-0&&n-VgQqYJ`4*~B^aL*D|K zD;=N2`i`Jlt&#zKy(3V?&J=xHA=f4eIP=;J=5o8;KZezVWe1J$S4eI^KIw+FSi_Vr zH!3FB%cvic6p71#jEoj491EOI6dxi?T0M)*RB^Q{^;sBT5-tV%5g{>XI9_iLgBhq; zx6$tR2*A9PMANJnc}>8ZC0@Dp>s$4P%t1(~5Vuj9&23<}NBL%0uHY`YktjTr`8{tk zox)Di7j*M?zej*8U5W)Y*esRWcN@Q+;c$w0Sj{*M6KPQTH~Nmf9N;_eS6IxILm>*k zsgZ@`hNVbthEtfwL+|by8j_`C9VYS$dSy6SSoWopML^`eVoSI^UiUtd4d{4aNX`>d zne>~TpKX*Db8UCCoS!~p!-F&t0B5l4M%T{4?jn7M_a-?SGIqJH;+p1@L#*% z6ToUqLGBL8tWtU{P`D8ke7>NbOSY_{OF*#5JmhW;9di16?aRQ9F~rhKVFdS_=U^A= zX>^z@*hk+qT(Gz74u$si%D7x^5BLR!DSpD`vy1(V0KQxX2(C`*qjOa>_z5~E{xwk! z-TBCu_1kofwyUOx7FRpq!KD{wYRKyRvAVleG%;^2zxfy8-sG{dsh=^O`b2GSmhcIz zyZ&#LQ!SV#Nhq)@48n=Hrzgvru8aYoClHRip%&~+K3FMuKdE8=i(OSod zl{ahJj(bog5!~9uJ2wU6H+Xyk$2_*VQ8R|Rt$oX?I+~1Q!+Lhu+`@nWLu$>k-9C58 z3S;hX{B2*NIDKTMiWOAr2APdd4_$2>t$~kE#(6;wPq9~kP_uK%Fg0@V#)vKn*T>jN z8Q5Qag>JzKV)4f4Oec~L5m>mm+PW-vs;&rMeeHxr|*)5 zKygzzOeEyw<(rKm->xC18PRDnij4K7&DAcfgc@`w9T(4uk*;W;O>waXhW3GVf;ZOR zE#Hr`f_LBgnL|rPEay7DU#m_Ecx#SUwt)isp&yCc)ykEehAD&G=XEusb&|sFNs9|- zvK^TwhOkNSoqRte6%@#jf|DQe>Jb$c6*I23-dZhv=HByelbncdz67#%N}I4-42rix zpD?Z>K3#;gK)}xoRxo8y$z$%X%JK8DqsI4oGnQjg@(O2fg?dCIT)&6u^$&r8bzg3= z^%4!xubGRB#B#ajn{~j3HX5q_Wd^;N=D!sgo5)S9kr8!s!9{~J1QUP zABT?2q&4z=k{@g-6(;N3Au612<|HmIuKFkIFz)3i zXdt=>$SX;tzkoO3=4hTN{Az>ZG{BEWIo3t-ZGAKum-6(bgf6O}9C}M20OtsK<4DiP=`a3R!Fx$a9~A?g&0^OSSl?3SO>M zdz>C^p)4y|eCA-ApvE1@MzPa#A%ELUiOlfeq_3YgW1K@b5ynqSN{Wuc2~f;=YCBzN zv4lnb{^9a!3ieDj6N%OsaBhJL3?l`cdCWmJ2rQGY`WXe>4&F)vy+aY;oU zLzg>n^bB~i;M04P;jM3jO8~XGo-7zWad|^x^$?Ph$lj>4+xhE*uen+I^{#8Ia@7}I zb3h%LxeWsKEf1#$v_y^BE5S=&MIYT#&Bf3Za~fEHRU7X<5;iWA$BjEPNq$3At)3t8 z42n?g|7y{Sm?@>uGwGJz)z-E=3p49^O&3lfrvmFB#cL2tQFopR>x|T;U4f!M z=jw*1sldr@p`yCLKg||I)aUtKe|~L;ci56A$UE|oe$c^*i`OEf6zpbxOhAPH5a&+H zvU*om`}5}or%WgbXm@@;dX&xp3-tJKb8JbZb3y+>m^P!=^kNlb&;)Hc<7%h9{}K5X zmJyLFeN{5u8foA=?op6f+al+52bB%qn8f`hXOr?^6<4cc=z0gkV(I_aF!|}wWXaTj zT=qiz3Fr6Q6uWvIDlq$Hx-r z#s_vOk2;u^eP9q$oJz>Sh{-I)I6Uq#yg<&zTfV8tz`>O=6^8X8mNh9W?bf4C*wf8_ zQr1Uu2a}0~lQ_QVNK-RuEnJv4Rq7>GH^h0F!=idhWLMwG*n>;OwZQ}$HBoeM^zXWp ztS4{}MnQeRH~5+5HW=7zaDdcMh<~&tvKr08hZ|6L*B6aFjC_TTbqhP0Mwmp1lON3s zT3b^}J&}a>p&5YzXv#Rc$CuDnPP=_L^O9pUAN=VqCeY*R6=`Vv%j@Hiz zv7v_qEY8nIZ-dtgX-cAHTz!3gbsQYPwTK7W0%cR6vYJ#$h3R#xbiB6Zrp(}sf6wExA6P267jA%{(Wed|E&j#Hwj4V zQP_*JEYE;D-q_z7I^y)=*9k}$y4*{fwfF3yxWJZ}lUoQr@4B1Y57DW$=xYDdxhRtI z7`W}u!);_|oRXUx@(I)&uavvVeSb+I3=)le^_q>XVtnDkWRPo%cf4_qT5c;ZjS6{;XC5`wo*|guTQVU;OzKFe?C$TnK;E4 z9rdxIlNjTR&X+Fm+I%`UB~y07rTfK3JD4VPfR*66+X`D$=ls`sQG>3!da2|~?#V<> z=q!igeYYK*cCyo3HPjB!E~epj11v{|5#&Dyy$)>V06(| zY3IXXT3oUF^R$G2oQF$RJRV&*smXv%nZ{D_OCok9+E;yw-bXU%+t?@*|MkL@D5c#c z{+^h?nx@6AY~BnwXvOn#?5ohrCOT*;bYcP)Sb$3{l9o+gx0&)q5mM9-I?>2JU&~HP zq8A0OJdE~{Mb2NK2Zn#+l>y<{;;u4vpiknA8CL3tcx-g%{{+CFNB2P}n^8eE!Wy#l z^o66a^PO8CZ`d6=DwJ`H=DwqTEHUQS!bsVG-;al%?RQsu=i{=Up$_h=VvaHni%mX; z77q9A4R~A@PL@=wO9{tVk_MsLi%^{17}t4`(L_&z=x8Rwvmq;4d9vc`naHgrPhYr zlZ3xSvl)Mg^h%G=I%>|ysD0}4)+~d88p)zwUu=<^;ut`#nNHkE%ntDF^@mi~uy_RU%RU zI8C2iN8!$YwQ#0iHD#2Vz3saa)62oEQPPpi^%~bG-Y6Dg4a5xJBE3Mn?`2t%P}d>A z65OJTUTluDKTibR9c=yn%)6N&E*UfOphF#lf4Mr^l3BxZVxoKh}}O4IYu*${nng$0O!UI8{d< zjgZ`1b}Lzd)jd4YBW33AFKzup(lH`NKr}&E0l0^CoTEat935S@k4IHl)EN+sQ{Phg zvs*3d<(wD7Fl99s;=!s_pe`uuC+8VBL2f~0p@2!e6|jle*h@zSL9&(!>;?4JS$BQ} zHeYb9J{L(_KxzgB1O>IQ@TT1(M7PQ>kYJ+sy;Pj6(m1e9*)3G`0WftT7oj8HewXOe zC9zW;$;&Qq?jb^UI9V`@6-`@GG9gv-JO)DK*8%_*`heo4C%eM(M7MkW}-(SPOrZ2!Aw1!2~@ z&r+o{DPWHvlityb?Jj4tGtZa}_K0tuAg3T3MZReln106#o8;~Bu^HZwc)O1%q`h(y z^ia!f`ZY_^P8SFe0?FYQMotKEO@oC8Nh@*FQzjExz=%RgDdshGyF_0k+Ne~(cL`fk z5okG}%vmMi)|U|~m6Vq|OPWb5hs@pf=AqS8Uw@hBl7ACFOyshKa(1iJJm_V|kM)~x z1*Mn#w+AYAg>i+{zURgK0Df}*=sV-)K$;BtQ-Ok)_8tqDGYT_ul@Fw(}Uq1mfB0k z`${h{gd{V3k5emQFkDsZ2bG59Xwoc=7xS+Jti$FEZ74J8cM9Xfgvg(W>QOyQOGX~4 z!zA1oU9?hL=gcI=S#XYudMrUvcJ@OU{a5e4-nW4kns0DDiBOyaPH)S~J)fuVS>&yB z)H+26rNf|*HvAV&IG{h5@wRg0yepSQezO4QN~GTQb%&6Pyog3r5Aq%b@|n{sWD=x= z&liXtt&LlYQD1An=fNGKQd^QY@$0TWY~}zA!(T4{MG9qKgw?Hxr`+v6~78+l*ro&G<>qe^ZDDs(uabrMEfVU$1L)%6roz}Bl1 zG`jomC|4kqubX;9QIAt-IKccZK=&jF&dwE;S;_~`8T;XNA@S+A4qJp$A?h~&6y|&q zqSq$6rYw9QQE;&Lm;g_y2!S?|EOtQqE2 zXPqege^sXc7yWNs^-NqTv=TWwibC}3DO`z2_X1j+DQp~ypiJv_-?ZA?h7_pEmIU)9uL3_#8(Y z5>k!1*g#G!q{}`G8=G&J-P*}|D2Q4l@8snP-x0o|NT8HEqon9}9C`#jdBET6L9nGa zamKCqxum*)bsrACkpgQO@va zk>tysv~6+eFbD2=3-iRWQQb#%PTe@^xeJU-Nxylp(u~9aR)iE7q_C zTb}pgO+im5QuZZl;rQs)W-B;B7WSE9p5YTXEPiUW5<@o}Ro=6f7#>E&00D2728(Zh zU1V%?B|md6{x?L+)ON@}v!Q>p6fNK?ZGh2|ud04G-e)wqLh+Liw+p=9!`fK;c4}uu z|Jtt$@v~hEpO*%jnF#04TPqnP&5cFg-(oiYqcoq-w%=V9>PBH8UWZ}vapF<Lf-+;`FyA%QH}%|KTU>ZDwoy*B?i9?Ptz*GjMeAhx zp{GvFhZsoFw>Y(#=YxlDw2GFDyi;?&em{u%^!VJW=ZCWm)f-~CqU$nRC@@G#pvQ>k z{di7DTJ~d70odkrAj8?T9K)kFSX?8%L~M$431gpI>HAVAUBg5p?@5nrl#PLtILFy; zPoz2x75WK9qc4z+=K6q-urwVT;z=p=Lo)?d#%^zn)^T2N9)l*5%00yYz-|7;F{DhR20*(#{@q5w zEVpd|Xd-CU^b-LQ7S1^A)IYKi;-9wIIGYs_~eoZ4fLIJbo!+R}m zCsSoyX(r|ymuOg+N@ZqOg0l%<2n~Cs2Pf%9TX}!dy57}%I z8Ea>GRv}&;Si*!0py{{DnWjuoYJjq7)a#1Um}T;JnZe^fxo`IFUZ}AFw$3=lDR|Um zdTKuFp7@bo-*3zYSIKxlhHT077n(>iQaGK><$L0^=>8ju(u>mqAqbneBYd65E_Uzkg5W!WvU?Z0x%9kPH8I((<9DXOM=4@&xPPm9SCVQDcP~r}@45*x_Z&+TqNx9NBV~ zT26M1FGqs0AP{YDP^!s$gjBJ+5oBi^9=u~YBM%8|6f_)VcI-a#*%KP{c?Mt06 zV5c(6T6#HW0N=(UF#1-w$o34x^?6v~*RuRYvVnpW68H`p}*oj-) zEiA07gYv3FdF{qRS-ov_e8KDEIo+>$4V}kzA;)#um1{9 z;TBB%X}dlTiKKGXpitnbwY(C-NkG@o*KAP4Wrn zlwY9=OwR;p7--XOK*TyVPTfybt_XaAx>!{=H#2%?+U&f{TG$A~>sM#F_A;Y0RpjrX zEK^SyY7W4?Y;V;-)nDtguYmjBs&%kmrS(=4RCawZpRC*b_YENx#jj>}(cTdDP#Qc0{`P30Xs%zKivlpL!`&*dL`QFlTHAd)6edaDbXg zl*Bx%NIsHp5RUw@8Glm2tW96m5KXWx;vOJu-gr2F4D&c?G}CnDsGXlqLv8)zJfd}d zf9YYj8J@pc&ycCF0)W91X- z0b}<`+^coy+J|AGL|?>=1_Y>&R!z^W+91SFSO@WefT!~JrjH$xl#xIN5B-|jpm4yy z=7y>dgzv@Bi%?U!*9RV-C2FCS5GAv!i`OWB(yb4!It~s~+%NAHsuEnzocoZjU!Sxg zUtlCcoP?F_JuSI+0@uwq zR@_XiFd$1}q4kPcprVt|lN@=;#7Wbd7_YOP0Ybycr#xbv*! zN*^FMb@f*%ALlVNH+<7w0Q>BtFO=xd7Mf(d#3KXFX1b@HBTcfiu&e4{MGv0qPZ~xw zR&A@zR4z!~wce+bS%omy3K>4)pNRxAH3Pvv#0*2yT|Ay?5ge5aZ)k58jVRr$y@pT9 zhh%>gNm`PrTc2-Px{-`}$UHS^VB=YLYtfVkV;wuPg?OnfFO_qF{L@s~eD4TU2dc2N z`E5u9nooU$zFfH|Rep+)NR2%xY$ECNFj>{KuF8R5of+xh6nlRWV(gpEY{nsyWDr{)Sqso*hBo{HQ9F^ z&!A1y{Ii&QA-8Y%`w_7+MrOT(LFe5uSlXOq^neLlf&4P320WUeT4U5eS$l~s^=FGf zOIobDQ9J{O4>LmJ!z=QW!i@;!#52OLxzgBoZT%R0$en6;XZLfE+IA!JHq$1g`*< zcVIlKunxRvn%T$M7(6!(_*#_%CK{Bb>iqUj zCun*Tn1xWc%AdY-YPc$TH?$`IRD9zAHppYB!SF-IsJ{cGUM=D|&3)QxECX;?MAT&9 z0-hqdBrIR+8no#+nGfem@a5J`2*YsX8X9c*o4z;z1R@6|?Q24e${z7zs` zkG~jgpYIE~3N6_#&g7552LXTYUv@F=;fO=MHQ#=4{#nOFyw4674n4fnwD*50&PLL^ zFkax#f;_4BSE&uGWu^H}Hc-FUX|AjNSDt*8jA7{JJ0>AQd>%bd^DY{a2W(`R=?A8}L0 z09-nfi5COyQrE_XNvPc<53RFux|GIK^l09X z#I>9oXfZZ`l<+G};7c6wB9@`&9u24fMmU|3e~{M5gh%duGbSp95Kl}Jow4fuXDzmmA;Yf$81|pQy5C(wo zD^=l3S%T!-Fa68o#ua#>CDSa;{@Be(`1((`>nOua+K(H4HB56lTgzd;(CMDe0aU?m zep5vEb4fAH&SzcJia71iL_b5Np^-G;N&E=#akG=<9RxdJ4amVs8wpg|cR+OR#7iqY z?|Wq&1Rs^-@3_X$lWRO7y6CkI3YvZTaZQVGpn$K!*@C35(vi<470H$ikd)?=@~>|> zm!a*@<|6z`1H))7irM4dM0c{>{tIXE3-wc1cZdpJaAh;5D)XP5*dkoKydmCyLVhy1 zn75ssM{hkdInYFU+JU&Sc*4yXa9re6s z)?EbdIVfFph~OQkDvf*@tlUb0LTK|^7!@)n6l{lujKw`2yi1_Q;r^d`MR(e==UK-W!?p(shlH5uMSy5uc8OP!vOn^2gSSFen}BF62VU4XXeUEY3_@t=Cl{ z;pKQ(=#vXBH;TS&*DoIn1(fNJ7a70W-Gpx0uHGs{-%(djDzSsoVCqvq|R!A~9;`M!y| z4}Iqkj>f^4HGd%B#eojXx@XkE(R{ng9Z8XDY96`#j=Li7jA+#ii-W%bO}2>pJ!{g0 z2b5e|yq(LSOKAkY&sCLX?)NiRmG`>)K&oL&yFjzQr(-0vkng0VRv1p#f)`=EM6Wwu zy2WIB&uxL|??T9CQ0*Sg#~={z#`Q;I@OV9)39sLiaYQZQvdhn8yVs)K>?O<)uth#?K}99NGDI2r19(VU44aOh+3eKWsM2iUv93Ht(4D z0kQupKBsC9H?=EgQQE(^(yJ;taaE?`&IY22K~2WV6dL(VJS^hbG@D&784!B zGHSBI_6nv{N~v#bJu-GO$H|j@e3`_}{*-2;n)%kxm*Plu6OJcr)_XYeff6;uD8nU0-S< zJwy*_CDOc`c{yY=R}~4gZ8_Mncp_)0?BW+<{U$mQ_bskYPurkVak$rYpJ~cf8S9>l zMLIFs0uBFoSt>l0Wflectkzxb$hicLI|-lA%T>(b*H?Nple-?hiK2goCi;4;U!F05 z`18OGF}J5KsXN-OXe6ky3n%zSmfGtr-z9kaBZzfF|oXHpA+5F%N3`|Kjk{EGP@ks8ZNVGg_1g+E0?oaEBV~kcn-~oMns<*fwekI` z@x-P;zqkYcb6x$#RY>lUay7_3obp1L|M6In%<6M-5H?-q$!B?Rvx|red=pMqqmHGz zYf#BI$*M}Qp8OzBqi@Yx(3=Er&F&T+`m0{W^qQS5;nsX8AL=tn2`&^#GGF%z z2g}6@LI9Rp;Xy5wC8%Wrd!YLZ1ksW;>|dzIdt;zH*jwsl-?4d>@7A z8vW)4Y|H0*n^@IzZ4r(Y#s^_pKgsimWwiWjtsDoK$6FW-aZ3qOX%Rcq)UyW((2(T1Vm$T2=D1@p4pj!LyTAkZrnj5AJ6s4RY&o{}awF{;u@~Qlm0Huhp zmX6DI6(8?y3^j=&SUv=q#rnyGKi`$5y#lB~< zIil#pr)K!c(A4-3?5Dgw%b7dIuguSIs4%dmD95D69@F4+ZlGY~I4Wu#DvtGd1-S32110GqMsrwyqe?vd8)+ zhfR7zQ43z^*l;=i5L_FES4)V?MiQhQg{`ZJ;x>CIAO10^x_C~%Ee~8q+7Wl+mU6oB z*l_eYn(#BHnOy3UsaT8Cedg?53SgFhGS-#k3yW8+yA!d@W8EY)Tc(`B=rv8DijiyJ zl#p*HDRamMR>&wX;Vm19MilAds*o>{o{V1vI>p#1_omYqnCIE?>(K$pl!mKv-sKII z-Ti{F;kF#FSr`@R&^d6(xb$mjcCfh@sI)X`*)Y`y5ateVB+H9JYvvyMIEaq75IYlu zH>7QgVUxJ3P2bLuqn>Cy2niQ>93v&iS}Mvf#QYg$+7F}(o^816dKza8=k-)ZoI*JvV%~-~ z-KKw_v4UQ!sdZID$BXcUA^tC1$J?A|IcycbA7Z+PSVv=9-iz+H95Jg90PK6c#q~|}%i5jsQR1TyU~Ph0 z+?$@ug`R zD-HaG@9stC-iM1_vlhArEqw~5uRF2K5;NLah}C@%za&%>y_AYkP1%qtjU)la^2lyK zTzpj(%ihpm2h;IS4AsW=?qiEJPZ@r~CVOK#he*K863NC+84JuM<2jq29A(zqYKfGsvnYSvz!h z$4oB&MLmjBmIyZ}4Q-q~mYW=zcyOfI;3t*iR!LT64LUb8quE5YXTrffE4=l0`LyW|k<6{L{y}BJ*(DVKhrO3)K%zd}C zZgmA-_4&^3jmQz2dvWHEY-cJhH^95y#I|4iSNv)5?Ov^8@3sl7{!aiK4CM2r@caoi zftPc{%R$}9==7GjhuA76Kbd{;uDh2xTc3iu!47GcjI)bSNOpQ1c%6H2c@D}(-Ed5j zNWSpcr`S3mpEcJ=`|wpcxFYkOt5?8&GJG((+fVpYv!>nIA+DFgXp!hlf z04CCfJW&_<;ha~|cq6+Vly2|m3hasfigW;ZZrmezl{~KvS^^{vS&B?V z-hPSjCLoKD80x<#=|GxkL%xl_rswe9A8Qy&UWX_0uA=gHad|8Ro~&65jT~FGAkTtT zHDT=ZUCL;G6d((Mv0H%rQ}BevJklP=QhZd_^1W3w-!~6HkqmD z{3yU~76NNxC14XKRtrr1%d3XzIVdtaU4SeEzAXT7N>dM5(bZKSPMf8iIv_v9MMxte zP$l?yqkB956MLEnP7;88s=(~SkQSsB5fFF>1V@wS{uqBBihNK0O+=v;X{WvR2XY%J zM6Mt;l=skSLmt!f6TRLw8@I($^1D-deu@&{xvsP{5YC#da`D|`*>r>&m?tW${Ye3y zt7^@H_&bZ>M2(wDi7s{RSP;fmYJQa8IqU&KzGO9Akoc&S^cJs;zHA*M29IR|n)BM_Q3KRf-Sq z!cv!zmdzb)z}`*??}iLi@I2gVLm zzT_yk4gg>sW#yqj*)%_CsX2KrIhnH1gJ3=Km6BFqUPU?)0Rb`ZR&@R5B^-u)Op#Y7 z@`nsPWFgW-B7D_*aeK$33kAh_R!+-)pndBZqm2A0zd%(Ee^yy@TB3~@Ib+98->HiB zuW8E(L?FFxBgEZtQ#yxATv}EivdbA^FheEzQGS64Tz$SxCE`nd?AfyAymQV-BO|5f zNBIRJu=WTFaND0s$9l_?mT4YoIm0H|DK9%+fOQavKwu$&D_8l<`K7JJIE0(?!BiF0 z0lA>#K1Bep1)rKwhWDaOzE)a(ndr62Dm)a60Pp5fj;k!QmaN`*klfq$Up69E$Ul@M zKQl_NPC((YY~qt0f$(u9A%1<9YXl|#7KEj&{3yPGh(L5c0fe^pAmrG-mRn4Y;P6aF z?ga~0Wj*%Vh}UGH5h-JGgy&6}MGL+(jvb7-Rn`7?+HwaXf{KEe!q}h=Fd?n;P z_kAr1k30n-iLSY^w-#4sb@_;i*JJ>t=L^3IJcWDn<`>!fv0?}5sw6+kPdX40Bos-( zemfz+*JJg4qd?z-n``D@UWr>2#Kdc|@h3397YYqm6c*_+H)GqY=(CS3Idw1)5v1P# z|KZPh+}GpybCbX%G$WT2T~+ClA{G;`$wayoW}j&mGWK3B8s{3M+ByJ$wJ#9>eR!^c z*et)yFX#~EVnc{U8uklU{z%N(ok`@TUA%lPpV+XC!-&_BlK=LmGA>-oK6w1>dAtW_ zEM;K}m2VJJA8VfW)-HSKGJ8|a+ z+s5I-7PZLFyCGeNK=}D?utNd91eBIUY8FslF@_!TLiWMBhM}LCu8ErLdMwevD>L6@ z?e!bx>nf`l8)|DA8~A*S_0=_|{g;p@u0vqY^;b*F zHN9KPIaFCOVSea~buh*-bd=rNsA)K7XBwWJZ~as04V#$iD*NLPYVA+d@oi)8*02wj zmofGh6&r3!;OcqoiTiMxn$!URypJ@H0uUe#bchfABwj8L=fn2UF4z|_L*|jz4v~>y zWF=yQd`92frsUpV`>W)Iz150+2Tz>+WU@ur%kmKSCMBe{d|gOPVE7Nm3D$>193>Xh z5U>AhlG)4t?JBb2-&1ye6rT>#(v^}5O>>=l6d#{u({XP9E!ymM*{ZV{6NK18V zCY-y!3{Ksh4|I-|yLEjRH|x?DEMu+9kK)roS{_RCp`hCj^16M2PDbbQuANzKm!>$F zX;pp{pAOQJdQA#0dkFy|G;jlY*9@QhOCRem(w6LW`RO1n#Nro^YydYNLc=BbX_v*W z-!6S>u7z~~0Q)H`7aOP$J-D!ahvJE+4$y|@T#=FVO_a!RT?U$B*(@WDg_ zty&Tp9!UC_5^r?|bl9{N$MM;iTzWnIGjBgTVGgDcJ4kegQ@xpReZ! zA=b#y|Iv~H06t{?Hmdk=3&I^7%1xbS?XsIz2P=`UU$q^9xHlas#Zkxvl5xcEOK zOa7-^o&^G3iAnI-aV|8W^!O~>&NC*=Le>{XKWTgWqxdWksA}cG*?UV-dhT$n%&jvp z-my@Bj;Yq?NAX!8P%q7ei`{F1kX}Z|^3L5kZiU9~mfD;jJxG5?p;)yddhP&ksK<#j*~ebyi%yaNiKn78xW zyz>a&7qyUAu3iBb++arc8i8)Q$Hy$@+v|PLBs+XS*Qjb7W z!1{KsxpnF4sb=vyqx9d1_P>impGZ9d8T{b(u;e+VjseX0p`X7Q`5T}>2dPKkigrY79O}{BE9q+I=e(-25{_La6uO4)edIYu>E-C05A%1#h#AMkTKIkX`#PGSjdN36q%ks4Y`jGmQCHg|H#ihEXoN$ zEa>xcS|mVS#68|W(0<6MX>VNnqxf_Y_dTbB><5q5f8+9__;eBXsFX1K_ujDlC_Y`p zebvrP`$4*I-e(^vKwZS$FZxZb11!WCED}KJ;?73KQZ`*{d;a%nlea;L8!~~cgZ}pK z&)=WFKYM>2XlVuLklou)Xv2GNO8&*jdSo6lg)%AI-~Rpi`}6l_@2`XY(qH;Zf9Ws% drN3xa`9EVOLfYX26OI4?002ovPDHLkV1oTxln(#^ literal 0 HcmV?d00001 diff --git a/browser/themes/osx/loop/toolbar-yosemite.png b/browser/themes/osx/loop/toolbar-yosemite.png new file mode 100644 index 0000000000000000000000000000000000000000..05204920e9bb84bfe17baa0e77627c95ff4b5625 GIT binary patch literal 2375 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 literal 0 HcmV?d00001 diff --git a/browser/themes/osx/menuPanel-customize-yosemite.png b/browser/themes/osx/menuPanel-customize-yosemite.png new file mode 100644 index 0000000000000000000000000000000000000000..93b6606928039af13895a3bb66ac27806a733671 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^20$#p!2%?IEjO_OQj0uY978G?uU;|aYB7*-d3fjb zexG+z8$|`XMYjpqv?Wek*`iY!roATE?n85jC%?_kl+v)GQ`>F5R%{m1bUoFywC1++ zhU1O9uJ$sNGu;uqu&^0KOWxS3{D7~antet0z3Z6no zM{T_%xbw2$&d=sEOobo#HCQt}ujpghA^d>v!2EwFOJ?%cF_!In!^UiXkA2sYh+Q+7 SHe~}{%i!ti=d#Wzp$Py{C0Ky~ literal 0 HcmV?d00001 diff --git a/browser/themes/osx/menuPanel-customize-yosemite@2x.png b/browser/themes/osx/menuPanel-customize-yosemite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..43cde4a68273f05a025b9a3f369e8c644ff0ab06 GIT binary patch literal 364 zcmV-y0h9iTP)1%S|a!eE-q4szJY^Nhbz>kkrsS{UL|KU zo5m&*MMUCK8cZo|nX7Pti9>XLi*=~lsnXC$L{2A_<8;j$x_3J#Er-Wj|M;4S9| z7`-$2J$Ae}K5<*P&az*>nV*e&4lp>vSKqy|`>gVr>Ql5l?FIJw z09)D%?BfZ9_O(s?FwKTEwsE)T`X+Ao`X+vv=8FGv7k_;11hT`%x#d?qv(HtZ*L=Ez ze;a)huN~Xw&-w#BvoBR&*1Y;Q`t(lK^-25NsKvVm|0bSO#sBX;5EofoWXAhIxy0kk zf}UCZqVfyH$2+kUuat3sf$3EJL?0I zRM`{S^^Tc2@7$G2Cge>ZuceEDHvm83Bh2x529QXuG{Y^et|c;mjG#C)w7Q1HYp80T zyQNhXHA|n$(h5i*Yxbg?KE=`sAi$cvD5oDGu>!=q>>VW}l#LSijKDyvjf8wT#7230 zMqr@D2BDJmmH5^O+-cQE-~E z*xUn3#JsgQS!w1ADN~$An)yP?(U;YBjf^jp*n0F^Yda;j9{twZPKmxp-}h|ipgOXU z7dgm|IdQ`&m=>ag1zvE#jyZvk2lS$YAtwBFSO=y5ici8bTfn#>Ep7k+002ovPDHLk FV1k9L_*nn| literal 0 HcmV?d00001 diff --git a/browser/themes/osx/menuPanel-exit-yosemite@2x.png b/browser/themes/osx/menuPanel-exit-yosemite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..af3160621c36d2c8b067cec4d4b05acb339881c7 GIT binary patch literal 939 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 FV1hjLZL*}w*UfxaK}qQ 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 Th!Q8r00000NkvXXu0mjfJP9M@ literal 0 HcmV?d00001 diff --git a/browser/themes/osx/menuPanel-yosemite.png b/browser/themes/osx/menuPanel-yosemite.png new file mode 100644 index 0000000000000000000000000000000000000000..0e3e4f7a8c2a2c6ad22b6b5a5ce8cc6058884ccd GIT binary patch literal 19351 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 literal 0 HcmV?d00001 diff --git a/browser/themes/osx/reload-stop-go-yosemite@2x.png b/browser/themes/osx/reload-stop-go-yosemite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b681f8930eaf310687a5c6211ace93f4115f04ff GIT binary patch literal 1619 zcmV-Z2CVssP)`K?ee0mSXzTAmiFcy{S7hK_5XZgPip3~9I_O}04vX+n z?1w(KU=x0gA7U#i*5I-TcR?BHDcm&5|BER4oJcQQ}Vgs-cm*802pc*gXM;JFp4Ha`C zZbFD0bSTHTva+%%L|rJQ)Sr6^Zng=!(s0{U;&Qx$CN^S;T~Pa|)-j_;9m0`UUS2+> zsi~=isGjy;=HvD-LHpww?1PF;xDeZ8EiSdX<)cTvtYTVSHPNGvtEi}W=Gd`gi?pZ` zi}C%t1)Zmr{|O&Sa%HZ@<<>t#qeuM@ds@eg9(6EBUOQ0(oQ1W?f*!(WQ85!gKojNK zyPj=O`>4=CF(q~cKF+{B?FBuL!%;C1TTrJIS0UI2O+Bg}(_v5*bvo`f1-*sc5n|Wz zUUbQ1{K{~f2RIG)ra@4NZ{T~Tpw|*2-ohT}1oOMO`O0t@ROaXBZ{^d#hPKb*7?x4^bBLH>qCSa@m6n~27Zg- z&_CO1F+)b(g>x{#sJw>N=vl`!1XWQ7aU4N{8BtHzLle#T6t*DPMGYBKk6POSF?-<& z9AO{R98{0GA19#=4fwoGOpPb-2ee@#9>oAtqM)E)QbR+-LErcL+Q&2p)o=fjHv3{S zuHstUhCXH-e4L7NJYHX4|4?0B-R21sChX*o&E}Z4LA9`bIHq6`K86D@2AA2F(V2@ROVCIhJHx z6d|H-n|RSN8)OiK-8QYq#V9hYW@_7}vGq5S2lRs|+olb;2qAn>FDLGF+r(>4ecLql z5T$!%7P5PZVo1;4Nw&{W0f5jB?cHm;$L{!i5wn>jF6Ym(iZPVzw)`Y9mceZU3 zIdR9^CXFD_{?Ht9+cdiNs=7K|Z<~nfx!pEt$Uwfzu@mE=w@ssV{i%Yc#kNVrh1+eD zhLkZqYVvK<$eNb6pnke+n~3Ul+O|nTr*4~atFEXkG_AHx!V{UfZOVO@A59S4_S0(H zB!uXkZIkHaZPSSDm(=Ia%-uFQ2&%_ah~Zl=sG#YwZIYe3ZL-G`FYt9Y<``pYh+&(~ ztDx?;O;UE|w#gpPdzr6w7&pc=Ack%@r-HiOHU%=RwoM`~jN2xBJ;{Ye(6wjP@379c zP12X?v~41$r?yQNF#*Joir-=iqIUVVNd_{lwoP1_>Q_#ym~!Ll;%3|A%e2@w z5mVbX*~C;qSN^JBF;2EklBh1XO~ll;O?ELAV$h0HrrXfXw#ku+*m=P)6Y@6IO9>2lmSc5hYbZK)eDM8G^w#hktu@!A0=;9YH zAO?7A`b_pc=zG`qweKt6lMXCcl=x)({)fUz3=IC}zPEjYk)-|7;L`v7LPL3cp8{F` z{34*z{<6N`pwh2=|9h$VIQV`A^FH{AgBAETLiMJ3$^eycF)(-;_3n+aBM5u%_8 zVw|5fI7E(msrd%`{sD`1K=g?Fet;P08|=yF`_uQC?>{jAr=JSU#!!$BzsG^Xz6FRN z^C?9R>OkLP0SZ9F-@`*RA6ty1`W^>b_s{p2?^C}ep`1j;GyvvImP{g#5Xk@l002ov JPDHLkV1mXEkM{ro literal 0 HcmV?d00001 diff --git a/browser/themes/osx/sync-horizontalbar-yosemite@2x.png b/browser/themes/osx/sync-horizontalbar-yosemite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c9472b70e23627aca606fc9389502fdd41aacb31 GIT binary patch literal 609 zcmV-n0-pVeP)kdg0006gNklLGxNPYVch}4LCn4CsK1bNQV|320;N>KJ^tAv-^mAE6~k5-p`1M^d>DA^ZSIcn!X^ z>f3^(@&!WpGeX#}5}yGmvGo^Wz!xOpJiG>EAgTP0FyIMN*iOcq;in@R@El7K6$lB2tPFQ&1ASpK@mfenN<2vv-} z*HEO6BaHCf0^~OWgU<}b`Tu?Iqm)j-vH&Hk_&xRwgXA~gXQ0IGJID7onu-S0uwwK% zik2Urdh#(acp2cx0H1Jd$K5ifaQ@r6aZ zUo)0US96SdQZ3Hj|%6&Kc v-UpV}peX#}`x=;94*D(eZ46KtOcgQ!TnIy0yWF7I00000NkvXXu0mjfTBsBz literal 0 HcmV?d00001 From 5babe6a55dac6b7a62bbf41545f596962b216d81 Mon Sep 17 00:00:00 2001 From: Henrik Skupin Date: Fri, 29 Aug 2014 22:37:44 +0200 Subject: [PATCH 107/120] Backout of 7cb26c341a4e due to new TPS sync failures --- services/sync/tps/extensions/tps/resource/tps.jsm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/services/sync/tps/extensions/tps/resource/tps.jsm b/services/sync/tps/extensions/tps/resource/tps.jsm index 243aff202648..6ca526e9a967 100644 --- a/services/sync/tps/extensions/tps/resource/tps.jsm +++ b/services/sync/tps/extensions/tps/resource/tps.jsm @@ -300,7 +300,12 @@ let TPS = { Logger.logInfo("tab for " + taburi + " finished loading"); if (that._tabsFinished == that._tabsAdded) { Logger.logInfo("all tabs loaded, continuing..."); - that.FinishAsyncOperation(); + + // Wait a second before continuing to be sure tabs can be synced, + // otherwise we can get 'error locating tab' + Utils.namedTimer(function () { + that.FinishAsyncOperation(); + }, 1000, this, "postTabsOpening"); } }); break; @@ -890,13 +895,7 @@ let TPS = { this._triggeredSync = true; this.StartAsyncOperation(); - - // Bug 682446 - // We wait a little before we trigger the Sync call to be sure elements are - // ready to be synced - Utils.namedTimer(function () { - Weave.Service.sync(); - }, 2500, this, "beforeSyncDelay"); + Weave.Service.sync(); }, WipeServer: function TPS__WipeServer() { From 5295e2e05ce11801d23b679f3317549e1ebcc24d Mon Sep 17 00:00:00 2001 From: David Major Date: Sat, 30 Aug 2014 17:21:18 +1200 Subject: [PATCH 108/120] Bug 1007534 - Part 3: Submit about:memory data from the native crash client. r=ted --- .../crashreporter/client/crashreporter.cpp | 38 ++++++-- toolkit/crashreporter/nsExceptionHandler.cpp | 95 ++++++++++++++++++- 2 files changed, 122 insertions(+), 11 deletions(-) diff --git a/toolkit/crashreporter/client/crashreporter.cpp b/toolkit/crashreporter/client/crashreporter.cpp index eb740a7948ec..1d93a7151829 100644 --- a/toolkit/crashreporter/client/crashreporter.cpp +++ b/toolkit/crashreporter/client/crashreporter.cpp @@ -41,8 +41,10 @@ enum SubmissionResult {Succeeded, Failed}; static auto_ptr gLogStream(nullptr); static string gReporterDumpFile; static string gExtraFile; +static string gMemoryFile; -static string kExtraDataExtension = ".extra"; +static const char kExtraDataExtension[] = ".extra"; +static const char kMemoryReportExtension[] = ".memory.json.gz"; void UIError(const string& message) { @@ -257,20 +259,22 @@ static bool ReadConfig() return true; } -static string GetExtraDataFilename(const string& dumpfile) +static string +GetAdditionalFilename(const string& dumpfile, const char* extension) { string filename(dumpfile); int dot = filename.rfind('.'); if (dot < 0) return ""; - filename.replace(dot, filename.length() - dot, kExtraDataExtension); + filename.replace(dot, filename.length() - dot, extension); return filename; } static bool MoveCrashData(const string& toDir, string& dumpfile, - string& extrafile) + string& extrafile, + string& memoryfile) { if (!UIEnsurePathExists(toDir)) { UIError(gStrings[ST_ERROR_CREATEDUMPDIR]); @@ -279,6 +283,7 @@ static bool MoveCrashData(const string& toDir, string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile); string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile); + string newMemory = toDir + UI_DIR_SEPARATOR + Basename(memoryfile); if (!UIMoveFile(dumpfile, newDump)) { UIError(gStrings[ST_ERROR_DUMPFILEMOVE]); @@ -290,6 +295,15 @@ static bool MoveCrashData(const string& toDir, return false; } + if (!memoryfile.empty()) { + // Ignore errors from moving the memory file + if (!UIMoveFile(memoryfile, newMemory)) { + UIDeleteFile(memoryfile); + newMemory.erase(); + } + memoryfile = newMemory; + } + dumpfile = newDump; extrafile = newExtra; @@ -369,6 +383,8 @@ void DeleteDump() UIDeleteFile(gReporterDumpFile); if (!gExtraFile.empty()) UIDeleteFile(gExtraFile); + if (!gMemoryFile.empty()) + UIDeleteFile(gMemoryFile); } } @@ -498,7 +514,7 @@ int main(int argc, char** argv) // no dump file specified, run the default UI UIShowDefaultUI(); } else { - gExtraFile = GetExtraDataFilename(gReporterDumpFile); + gExtraFile = GetAdditionalFilename(gReporterDumpFile, kExtraDataExtension); if (gExtraFile.empty()) { UIError(gStrings[ST_ERROR_BADARGUMENTS]); return 0; @@ -509,6 +525,12 @@ int main(int argc, char** argv) return 0; } + gMemoryFile = GetAdditionalFilename(gReporterDumpFile, + kMemoryReportExtension); + if (!UIFileExists(gMemoryFile)) { + gMemoryFile.erase(); + } + StringTable queryParameters; if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) { UIError(gStrings[ST_ERROR_EXTRAFILEREAD]); @@ -582,7 +604,8 @@ int main(int argc, char** argv) } string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending"; - if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile)) { + if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile, + gMemoryFile)) { return 0; } @@ -639,6 +662,9 @@ int main(int argc, char** argv) StringTable files; files["upload_file_minidump"] = gReporterDumpFile; + if (!gMemoryFile.empty()) { + files["memory_report"] = gMemoryFile; + } if (!UIShowCrashUI(files, queryParameters, sendURL, restartArgs)) DeleteDump(); diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index e270175bd00c..b15161100479 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -107,6 +107,7 @@ namespace CrashReporter { #ifdef XP_WIN32 typedef wchar_t XP_CHAR; typedef std::wstring xpstring; +#define XP_TEXT(x) L##x #define CONVERT_XP_CHAR_TO_UTF16(x) x #define XP_STRLEN(x) wcslen(x) #define my_strlen strlen @@ -126,6 +127,7 @@ typedef std::wstring xpstring; #else typedef char XP_CHAR; typedef std::string xpstring; +#define XP_TEXT(x) x #define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x) #define CRASH_REPORTER_FILENAME "crashreporter" #define PATH_SEPARATOR "/" @@ -143,17 +145,17 @@ typedef std::string xpstring; #define sys_close close #define sys_fork fork #define sys_open open +#define sys_read read #define sys_write write #endif #endif // XP_WIN32 #ifndef XP_LINUX -static const XP_CHAR dumpFileExtension[] = {'.', 'd', 'm', 'p', - '\0'}; // .dmp +static const XP_CHAR dumpFileExtension[] = XP_TEXT(".dmp"); #endif -static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't', - 'r', 'a', '\0'}; // .extra +static const XP_CHAR extraFileExtension[] = XP_TEXT(".extra"); +static const XP_CHAR memoryReportExtension[] = XP_TEXT(".memory.json.gz"); static const char kCrashMainID[] = "crash.main.1\n"; @@ -209,7 +211,6 @@ static const char kOOMAllocationSizeParameter[] = "OOMAllocationSize="; static const int kOOMAllocationSizeParameterLen = sizeof(kOOMAllocationSizeParameter)-1; - #ifdef XP_WIN32 static const char kSysMemoryParameter[] = "SystemMemoryUsePercentage="; static const int kSysMemoryParameterLen = sizeof(kSysMemoryParameter)-1; @@ -257,6 +258,10 @@ static const int kBreakpadReserveSizeParameterLen = sizeof(kBreakpadReserveSizeParameter)-1; #endif +static const char kMemoryReportParameter[] = "ContainsMemoryReport=1\n"; +static const int kMemoryReportParameterLen = + sizeof(kMemoryReportParameter)-1; + // this holds additional data sent via the API static Mutex* crashReporterAPILock; static Mutex* notesFieldLock; @@ -463,6 +468,56 @@ void AnnotateOOMAllocationSize(size_t size) gOOMAllocationSize = size; } +#ifndef XP_WIN +// Like Windows CopyFile for *nix +bool copy_file(const char* from, const char* to) +{ + const int kBufSize = 4096; + int fdfrom = sys_open(from, O_RDONLY, 0); + if (fdfrom < 0) { + return false; + } + + bool ok = false; + + int fdto = sys_open(to, O_WRONLY | O_CREAT, 0666); + if (fdto < 0) { + sys_close(fdfrom); + return false; + } + + char buf[kBufSize]; + while (true) { + int r = sys_read(fdfrom, buf, kBufSize); + if (r == 0) { + ok = true; + break; + } + if (r < 0) { + break; + } + char* wbuf = buf; + while (r) { + int w = sys_write(fdto, wbuf, r); + if (w > 0) { + r -= w; + wbuf += w; + } else if (errno != EINTR) { + break; + } + } + if (r) { + break; + } + } + + sys_close(fdfrom); + sys_close(fdto); + + return ok; +} +#endif + bool MinidumpCallback( #ifdef XP_LINUX const MinidumpDescriptor& descriptor, @@ -504,6 +559,27 @@ bool MinidumpCallback( #endif Concat(p, extraFileExtension, &size); + static XP_CHAR memoryReportLocalPath[XP_PATH_MAX]; + size = XP_PATH_MAX; +#ifndef XP_LINUX + p = Concat(memoryReportLocalPath, dump_path, &size); + p = Concat(p, XP_PATH_SEPARATOR, &size); + p = Concat(p, minidump_id, &size); +#else + p = Concat(memoryReportLocalPath, descriptor.path(), &size); + // Skip back past the .dmp extension + p -= 4; +#endif + Concat(p, memoryReportExtension, &size); + + if (memoryReportPath) { +#ifdef XP_WIN + CopyFile(memoryReportPath, memoryReportLocalPath, false); +#else + copy_file(memoryReportPath, memoryReportLocalPath); +#endif + } + if (headlessClient) { // Leave a marker indicating that there was a crash. #if defined(XP_WIN32) @@ -721,6 +797,11 @@ bool MinidumpCallback( &nBytes, nullptr); WriteFile(hFile, "\n", 1, &nBytes, nullptr); } + + if (memoryReportPath) { + WriteFile(hFile, kMemoryReportParameter, + kMemoryReportParameterLen, &nBytes, nullptr); + } CloseHandle(hFile); } } @@ -793,6 +874,10 @@ bool MinidumpCallback( oomAllocationSizeBufferLen); unused << sys_write(fd, "\n", 1); } + if (memoryReportPath) { + unused << sys_write(fd, kMemoryReportParameter, + kMemoryReportParameterLen); + } sys_close(fd); } } From 0509508150c9fde07fbec902bb2ed09d7bc3a8cd Mon Sep 17 00:00:00 2001 From: David Major Date: Sat, 30 Aug 2014 17:21:22 +1200 Subject: [PATCH 109/120] Bug 1007534 - Part 4: Save a memory report when close to OOM. r=bsmedberg --- xpcom/threads/nsThread.cpp | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index d96114e1fcb9..2951ceb1e6ca 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -30,6 +30,11 @@ #include "nsXPCOMPrivate.h" #include "mozilla/ChaosMode.h" +#ifdef MOZ_CRASHREPORTER +#include "nsServiceManagerUtils.h" +#include "nsICrashReporter.h" +#endif + #ifdef XP_LINUX #include #include @@ -386,6 +391,34 @@ nsThread::ThreadFunc(void* aArg) //----------------------------------------------------------------------------- +#ifdef MOZ_CRASHREPORTER +// Tell the crash reporter to save a memory report if our heuristics determine +// that an OOM failure is likely to occur soon. +static bool SaveMemoryReportNearOOM() +{ + bool needMemoryReport = false; + +#ifdef XP_WIN // XXX implement on other platforms as needed + const size_t LOWMEM_THRESHOLD_VIRTUAL = 200 * 1024 * 1024; + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + if (GlobalMemoryStatusEx(&statex)) { + if (statex.ullAvailVirtual < LOWMEM_THRESHOLD_VIRTUAL) { + needMemoryReport = true; + } + } +#endif + + if (needMemoryReport) { + nsCOMPtr cr = + do_GetService("@mozilla.org/toolkit/crash-reporter;1"); + cr->SaveMemoryReport(); + } + + return needMemoryReport; +} +#endif + #ifdef MOZ_CANARY int sCanaryOutputFD = -1; #endif @@ -729,6 +762,27 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) } } +#ifdef MOZ_CRASHREPORTER + if (MAIN_THREAD == mIsMainThread && !ShuttingDown()) { + // Keep an eye on memory usage (cheap, ~7ms) somewhat frequently, + // but save memory reports (expensive, ~75ms) less frequently. + const size_t LOW_MEMORY_CHECK_SECONDS = 30; + const size_t LOW_MEMORY_SAVE_SECONDS = 3 * 60; + + static TimeStamp nextCheck = TimeStamp::NowLoRes() + + TimeDuration::FromSeconds(LOW_MEMORY_CHECK_SECONDS); + + TimeStamp now = TimeStamp::NowLoRes(); + if (now >= nextCheck) { + if (SaveMemoryReportNearOOM()) { + nextCheck = now + TimeDuration::FromSeconds(LOW_MEMORY_SAVE_SECONDS); + } else { + nextCheck = now + TimeDuration::FromSeconds(LOW_MEMORY_CHECK_SECONDS); + } + } + } +#endif + bool notifyMainThreadObserver = (MAIN_THREAD == mIsMainThread) && sMainThreadObserver; if (notifyMainThreadObserver) { From 8cb88f5b6be6d852d58c216a5195ccb63a39dee2 Mon Sep 17 00:00:00 2001 From: David Major Date: Sat, 30 Aug 2014 17:21:25 +1200 Subject: [PATCH 110/120] Bug 1007534 - Part 5: Support memory files in CrashSubmit.jsm. r=ted --- toolkit/crashreporter/CrashSubmit.jsm | 43 +++++++++++++++---- .../browser/browser_aboutCrashesResubmit.js | 3 ++ toolkit/crashreporter/test/browser/head.js | 4 ++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/toolkit/crashreporter/CrashSubmit.jsm b/toolkit/crashreporter/CrashSubmit.jsm index 74ca1cb01ff6..605cce36eecf 100644 --- a/toolkit/crashreporter/CrashSubmit.jsm +++ b/toolkit/crashreporter/CrashSubmit.jsm @@ -101,9 +101,11 @@ function getPendingMinidump(id) { let pendingDir = getDir("pending"); let dump = pendingDir.clone(); let extra = pendingDir.clone(); + let memory = pendingDir.clone(); dump.append(id + ".dmp"); extra.append(id + ".extra"); - return [dump, extra]; + memory.append(id + ".memory.json.gz"); + return [dump, extra, memory]; } function getAllPendingMinidumpsIDs() { @@ -162,6 +164,13 @@ function pruneSavedDumps() { let dump = extra.clone(); dump.leafName = matches[1] + '.dmp'; dump.remove(false); + + let memory = extra.clone(); + memory.leafName = matches[1] + '.memory.json.gz'; + if (memory.exists()) { + memory.remove(false); + } + extra.remove(false); } } @@ -206,6 +215,11 @@ Submitter.prototype = { try { this.dump.remove(false); this.extra.remove(false); + + if (this.memory) { + this.memory.remove(false); + } + for (let i of this.additionalDumps) { i.dump.remove(false); } @@ -225,6 +239,7 @@ Submitter.prototype = { this.iframe = null; this.dump = null; this.extra = null; + this.memory = null; this.additionalDumps = null; // remove this object from the list of active submissions let idx = CrashSubmit._activeSubmissions.indexOf(this); @@ -271,6 +286,9 @@ Submitter.prototype = { } // add the minidumps formData.append("upload_file_minidump", File(this.dump.path)); + if (this.memory) { + formData.append("memory_report", File(this.memory.path)); + } if (this.additionalDumps.length > 0) { let names = []; for (let i of this.additionalDumps) { @@ -353,12 +371,20 @@ Submitter.prototype = { submit: function Submitter_submit() { - let [dump, extra] = getPendingMinidump(this.id); + let [dump, extra, memory] = getPendingMinidump(this.id); + if (!dump.exists() || !extra.exists()) { this.notifyStatus(FAILED); this.cleanup(); return false; } + this.dump = dump; + this.extra = extra; + + // The memory file may or may not exist + if (memory.exists()) { + this.memory = memory; + } let extraKeyVals = parseKeyValuePairsFromFile(extra); for (let key in extraKeyVals) { @@ -371,7 +397,7 @@ Submitter.prototype = { if ("additional_minidumps" in this.extraKeyVals) { let names = this.extraKeyVals.additional_minidumps.split(','); for (let name of names) { - let [dump, extra] = getPendingMinidump(this.id + "-" + name); + let [dump, extra, memory] = getPendingMinidump(this.id + "-" + name); if (!dump.exists()) { this.notifyStatus(FAILED); this.cleanup(); @@ -383,8 +409,6 @@ Submitter.prototype = { this.notifyStatus(SUBMITTING); - this.dump = dump; - this.extra = extra; this.additionalDumps = additionalDumps; if (!this.submitForm()) { @@ -467,9 +491,12 @@ this.CrashSubmit = { * Filename (minus .dmp extension) of the minidump to delete. */ delete: function CrashSubmit_delete(id) { - let [dump, extra] = getPendingMinidump(id); - dump.QueryInterface(Ci.nsIFile).remove(false); - extra.QueryInterface(Ci.nsIFile).remove(false); + let [dump, extra, memory] = getPendingMinidump(id); + dump.remove(false); + extra.remove(false); + if (memory.exists()) { + memory.remove(false); + } }, /** diff --git a/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js b/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js index 6152c4a2e50e..d9421faa6eb2 100644 --- a/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js +++ b/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js @@ -56,10 +56,13 @@ function check_submit_pending(tab, crashes) { // check the JSON content vs. what we submitted let result = JSON.parse(browser.contentDocument.documentElement.textContent); is(result.upload_file_minidump, "MDMP", "minidump file sent properly"); + is(result.memory_report, "Let's pretend this is a memory report", + "memory report sent properly"); is(result.Throttleable, 0, "correctly sent as non-throttleable"); // we checked these, they're set by the submission process, // so they won't be in the "extra" data. delete result.upload_file_minidump; + delete result.memory_report; delete result.Throttleable; // Likewise, this is discarded before it gets to the server delete SubmittedCrash.extra.ServerURL; diff --git a/toolkit/crashreporter/test/browser/head.js b/toolkit/crashreporter/test/browser/head.js index c3cebea3b117..1a1411896ff3 100644 --- a/toolkit/crashreporter/test/browser/head.js +++ b/toolkit/crashreporter/test/browser/head.js @@ -129,7 +129,11 @@ function addPendingCrashreport(crD, date, extra) { extradata += x + "=" + extra[x] + "\n"; } writeDataToFile(extrafile, extradata); + let memoryfile = pendingdir.clone(); + memoryfile.append(uuid + ".memory.json.gz"); + writeDataToFile(memoryfile, "Let's pretend this is a memory report"); dumpfile.lastModifiedTime = date; extrafile.lastModifiedTime = date; + memoryfile.lastModifiedTime = date; return {'id': uuid, 'date': date, 'pending': true, 'extra': extra}; } From 73981dd8342f54f4466eb611617eda2c53afd7b9 Mon Sep 17 00:00:00 2001 From: David Major Date: Sat, 30 Aug 2014 17:22:14 +1200 Subject: [PATCH 111/120] Bug 1007534 - Part 6: xpcshell test for memory data in crash reporter. r=ted --- .../test/unit/head_crashreporter.js | 7 +++ .../unit/test_crash_with_memory_report.js | 52 +++++++++++++++++++ toolkit/crashreporter/test/unit/xpcshell.ini | 3 +- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 toolkit/crashreporter/test/unit/test_crash_with_memory_report.js diff --git a/toolkit/crashreporter/test/unit/head_crashreporter.js b/toolkit/crashreporter/test/unit/head_crashreporter.js index cd420177730e..040b270bacd5 100644 --- a/toolkit/crashreporter/test/unit/head_crashreporter.js +++ b/toolkit/crashreporter/test/unit/head_crashreporter.js @@ -108,12 +108,17 @@ function handleMinidump(callback) let extrafile = minidump.clone(); extrafile.leafName = extrafile.leafName.slice(0, -4) + ".extra"; + let memoryfile = minidump.clone(); + memoryfile.leafName = memoryfile.leafName.slice(0, -4) + ".memory.json.gz"; + // Just in case, don't let these files linger. do_register_cleanup(function() { if (minidump.exists()) minidump.remove(false); if (extrafile.exists()) extrafile.remove(false); + if (memoryfile.exists()) + memoryfile.remove(false); }); do_check_true(extrafile.exists()); let extra = parseKeyValuePairsFromFile(extrafile); @@ -125,6 +130,8 @@ function handleMinidump(callback) minidump.remove(false); if (extrafile.exists()) extrafile.remove(false); + if (memoryfile.exists()) + memoryfile.remove(false); } function do_content_crash(setup, callback) diff --git a/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js b/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js new file mode 100644 index 000000000000..fa323067d933 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js @@ -0,0 +1,52 @@ +function run_test() +{ + if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) { + dump("INFO | test_crash_oom.js | Can't test crashreporter in a non-libxul build.\n"); + return; + } + + // This was shamelessly copied and stripped down from do_get_profile() in + // head.js so that nsICrashReporter::saveMemoryReport can use a profile + // within the crasher subprocess. + + do_crash( + function() { + let Cc = Components.classes; + let Ci = Components.interfaces; + + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + let profd = env.get("XPCSHELL_TEST_PROFILE_DIR"); + let file = Cc["@mozilla.org/file/local;1"] + .createInstance(Ci.nsILocalFile); + file.initWithPath(profd); + + let dirSvc = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties); + let provider = { + getFile: function(prop, persistent) { + persistent.value = true; + if (prop == "ProfD" || prop == "ProfLD" || prop == "ProfDS" || + prop == "ProfLDS" || prop == "TmpD") { + return file.clone(); + } + throw Components.results.NS_ERROR_FAILURE; + }, + QueryInterface: function(iid) { + if (iid.equals(Ci.nsIDirectoryServiceProvider) || + iid.equals(Ci.nsISupports)) { + return this; + } + throw Components.results.NS_ERROR_NO_INTERFACE; + } + }; + dirSvc.QueryInterface(Ci.nsIDirectoryService) + .registerProvider(provider); + + crashReporter.saveMemoryReport(); + }, + function(mdump, extra) { + do_check_eq(extra.ContainsMemoryReport, "1"); + }, + true); +} diff --git a/toolkit/crashreporter/test/unit/xpcshell.ini b/toolkit/crashreporter/test/unit/xpcshell.ini index 54f7b5fec310..83eac0fa5e4f 100644 --- a/toolkit/crashreporter/test/unit/xpcshell.ini +++ b/toolkit/crashreporter/test/unit/xpcshell.ini @@ -14,11 +14,10 @@ support-files = [test_crash_after_js_large_allocation_failure.js] [test_crash_after_js_large_allocation_failure_reporting.js] [test_crash_oom.js] -skip-if = os == 'win' && debug - [test_crash_abort.js] skip-if = os == 'win' +[test_crash_with_memory_report.js] [test_crashreporter.js] [test_crashreporter_crash.js] [test_crashreporter_crash_profile_lock.js] From 1f33b1a7b91b58c2a4605968ded64d15d8114c2a Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sat, 30 Aug 2014 02:11:56 -0400 Subject: [PATCH 112/120] Bug 1033114 Part 1: Update AnimationPlayer to spec changes r=birtles, r=bz --- dom/animation/AnimationPlayer.cpp | 18 ++++++++++-------- dom/animation/AnimationPlayer.h | 4 ++-- dom/webidl/AnimationPlayer.webidl | 25 ++++++++++++++++++++----- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/dom/animation/AnimationPlayer.cpp b/dom/animation/AnimationPlayer.cpp index f213c44f9f9b..2360a2b2c8cf 100644 --- a/dom/animation/AnimationPlayer.cpp +++ b/dom/animation/AnimationPlayer.cpp @@ -20,16 +20,16 @@ AnimationPlayer::WrapObject(JSContext* aCx) return dom::AnimationPlayerBinding::Wrap(aCx, this); } -double -AnimationPlayer::StartTime() const +Nullable +AnimationPlayer::GetStartTime() const { - Nullable startTime = mTimeline->ToTimelineTime(mStartTime); - return startTime.IsNull() ? 0.0 : startTime.Value(); + return mTimeline->ToTimelineTime(mStartTime); } -double -AnimationPlayer::CurrentTime() const +Nullable +AnimationPlayer::GetCurrentTime() const { + Nullable result; Nullable currentTime = GetCurrentTimeDuration(); // The current time is currently only going to be null when don't have a @@ -44,10 +44,12 @@ AnimationPlayer::CurrentTime() const // timestamps and return the appropriate current time when the timeline time // is null. if (currentTime.IsNull()) { - return 0.0; + result.SetValue(0.0); + } else { + result.SetValue(currentTime.Value().ToMilliseconds()); } - return currentTime.Value().ToMilliseconds(); + return result; } void diff --git a/dom/animation/AnimationPlayer.h b/dom/animation/AnimationPlayer.h index f03ba97cbac5..f19e82a4b75e 100644 --- a/dom/animation/AnimationPlayer.h +++ b/dom/animation/AnimationPlayer.h @@ -48,8 +48,8 @@ public: // AnimationPlayer methods Animation* GetSource() const { return mSource; } AnimationTimeline* Timeline() const { return mTimeline; } - double StartTime() const; - double CurrentTime() const; + Nullable GetStartTime() const; + Nullable GetCurrentTime() const; bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; } void SetSource(Animation* aSource); diff --git a/dom/webidl/AnimationPlayer.webidl b/dom/webidl/AnimationPlayer.webidl index b22c05253052..ba0e98d08677 100644 --- a/dom/webidl/AnimationPlayer.webidl +++ b/dom/webidl/AnimationPlayer.webidl @@ -4,7 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/fxtf/web-animations/#the-animationtimeline-interface + * http://dev.w3.org/fxtf/web-animations/#idl-def-AnimationPlayer * * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. @@ -12,11 +12,26 @@ [Pref="dom.animations-api.core.enabled"] interface AnimationPlayer { - // Bug 1049975: Per spec, this should be a writeable AnimationNode? member - [Pure] readonly attribute Animation? source; + // Bug 1049975 + // attribute AnimationNode? source; + [Pure] + readonly attribute Animation? source; readonly attribute AnimationTimeline timeline; - [Pure] readonly attribute double startTime; - readonly attribute double currentTime; + [Pure] + readonly attribute double? startTime; + readonly attribute double? currentTime; + + /* Not yet implemented + attribute double playbackRate; + readonly attribute AnimationPlayState playState; + readonly attribute Promise ready; + readonly attribute Promise finished; + void cancel (); + void finish (); + void play (); + void pause (); + void reverse (); + */ }; // Non-standard extensions From 846226f7fd3f7c29465172bc84c2a0ffc1ff8548 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sat, 30 Aug 2014 02:11:56 -0400 Subject: [PATCH 113/120] Bug 1033114 Part 2: Rename mPauseStart to mHoldTime to match spec r=birtles --- dom/animation/AnimationPlayer.h | 8 ++++---- layout/style/nsAnimationManager.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dom/animation/AnimationPlayer.h b/dom/animation/AnimationPlayer.h index f19e82a4b75e..be5bfd1c516f 100644 --- a/dom/animation/AnimationPlayer.h +++ b/dom/animation/AnimationPlayer.h @@ -76,20 +76,20 @@ public: // FIXME: In order to support arbitrary timelines we will need to fix // the pause logic to handle the timeline time going backwards. MOZ_ASSERT(timelineTime.IsNull() || !IsPaused() || - timelineTime >= mPauseStart, + timelineTime >= mHoldTime, "if paused, any non-null value of aTime must be at least" - " mPauseStart"); + " mHoldTime"); Nullable result; // Initializes to null if (!timelineTime.IsNull() && !mStartTime.IsNull()) { - result.SetValue((IsPaused() ? mPauseStart : timelineTime) - mStartTime); + result.SetValue((IsPaused() ? mHoldTime : timelineTime) - mStartTime); } return result; } // The beginning of the delay period. TimeStamp mStartTime; - TimeStamp mPauseStart; + TimeStamp mHoldTime; uint8_t mPlayState; bool mIsRunningOnCompositor; diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 6618ab71df81..035a8cbe34d1 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -309,7 +309,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, // Handle changes in play state. if (!oldPlayer->IsPaused() && newPlayer->IsPaused()) { // Start pause at current time. - oldPlayer->mPauseStart = timeline->GetCurrentTimeStamp(); + oldPlayer->mHoldTime = timeline->GetCurrentTimeStamp(); } else if (oldPlayer->IsPaused() && !newPlayer->IsPaused()) { const TimeStamp& now = timeline->GetCurrentTimeStamp(); if (!now.IsNull()) { @@ -318,9 +318,9 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, // start time to something more appropriate when now IsNull. // Handle change in pause state by adjusting start time to // unpause. - oldPlayer->mStartTime += now - oldPlayer->mPauseStart; + oldPlayer->mStartTime += now - oldPlayer->mHoldTime; } - oldPlayer->mPauseStart = TimeStamp(); + oldPlayer->mHoldTime = TimeStamp(); } oldPlayer->mPlayState = newPlayer->mPlayState; @@ -457,9 +457,9 @@ nsAnimationManager::BuildAnimations(nsStyleContext* aStyleContext, dest->mStartTime = now; dest->mPlayState = src.GetPlayState(); if (dest->IsPaused()) { - dest->mPauseStart = now; + dest->mHoldTime = now; } else { - dest->mPauseStart = TimeStamp(); + dest->mHoldTime = TimeStamp(); } // While current drafts of css3-animations say that later keyframes From cbd65c781b5cebb3da541f1fe7c91452d2a2b55c Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sat, 30 Aug 2014 02:11:57 -0400 Subject: [PATCH 114/120] Bug 1033114 Part 3: Make mStartTime a nullable TimeDuration r=birtles --- dom/animation/AnimationPlayer.cpp | 3 ++- dom/animation/AnimationPlayer.h | 14 ++++--------- dom/animation/AnimationTimeline.cpp | 30 +++++++++++++++++++++++----- dom/animation/AnimationTimeline.h | 11 +++++++--- dom/animation/AnimationUtils.h | 29 +++++++++++++++++++++++++++ layout/base/nsDisplayList.cpp | 2 +- layout/style/nsAnimationManager.cpp | 4 ++-- layout/style/nsTransitionManager.cpp | 2 +- 8 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 dom/animation/AnimationUtils.h diff --git a/dom/animation/AnimationPlayer.cpp b/dom/animation/AnimationPlayer.cpp index 2360a2b2c8cf..05fd536634e3 100644 --- a/dom/animation/AnimationPlayer.cpp +++ b/dom/animation/AnimationPlayer.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AnimationPlayer.h" +#include "AnimationUtils.h" #include "mozilla/dom/AnimationPlayerBinding.h" namespace mozilla { @@ -23,7 +24,7 @@ AnimationPlayer::WrapObject(JSContext* aCx) Nullable AnimationPlayer::GetStartTime() const { - return mTimeline->ToTimelineTime(mStartTime); + return AnimationUtils::TimeDurationToDouble(mStartTime); } Nullable diff --git a/dom/animation/AnimationPlayer.h b/dom/animation/AnimationPlayer.h index be5bfd1c516f..8d26f051bc27 100644 --- a/dom/animation/AnimationPlayer.h +++ b/dom/animation/AnimationPlayer.h @@ -72,23 +72,17 @@ public: // current timestamp that is null or if the start time of this object is // null. Nullable GetCurrentTimeDuration() const { - const TimeStamp& timelineTime = mTimeline->GetCurrentTimeStamp(); - // FIXME: In order to support arbitrary timelines we will need to fix - // the pause logic to handle the timeline time going backwards. - MOZ_ASSERT(timelineTime.IsNull() || !IsPaused() || - timelineTime >= mHoldTime, - "if paused, any non-null value of aTime must be at least" - " mHoldTime"); - + Nullable timelineTime = mTimeline->GetCurrentTimeDuration(); + Nullable holdDuration = mTimeline->ToTimelineTime(mHoldTime); Nullable result; // Initializes to null if (!timelineTime.IsNull() && !mStartTime.IsNull()) { - result.SetValue((IsPaused() ? mHoldTime : timelineTime) - mStartTime); + result.SetValue((IsPaused() ? holdDuration.Value() : timelineTime.Value()) - mStartTime.Value()); } return result; } // The beginning of the delay period. - TimeStamp mStartTime; + Nullable mStartTime; TimeStamp mHoldTime; uint8_t mPlayState; bool mIsRunningOnCompositor; diff --git a/dom/animation/AnimationTimeline.cpp b/dom/animation/AnimationTimeline.cpp index 15bc3f23a22b..a22db6c96591 100644 --- a/dom/animation/AnimationTimeline.cpp +++ b/dom/animation/AnimationTimeline.cpp @@ -5,6 +5,7 @@ #include "AnimationTimeline.h" #include "mozilla/dom/AnimationTimelineBinding.h" +#include "AnimationUtils.h" #include "nsContentUtils.h" #include "nsIPresShell.h" #include "nsPresContext.h" @@ -28,7 +29,7 @@ AnimationTimeline::WrapObject(JSContext* aCx) Nullable AnimationTimeline::GetCurrentTime() const { - return ToTimelineTime(GetCurrentTimeStamp()); + return AnimationUtils::TimeDurationToDouble(GetCurrentTimeDuration()); } TimeStamp @@ -67,10 +68,16 @@ AnimationTimeline::GetCurrentTimeStamp() const return result; } -Nullable -AnimationTimeline::ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const +Nullable +AnimationTimeline::GetCurrentTimeDuration() const { - Nullable result; // Initializes to null + return ToTimelineTime(GetCurrentTimeStamp()); +} + +Nullable +AnimationTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const +{ + Nullable result; // Initializes to null if (aTimeStamp.IsNull()) { return result; } @@ -80,7 +87,20 @@ AnimationTimeline::ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const return result; } - result.SetValue(timing->TimeStampToDOMHighRes(aTimeStamp)); + result.SetValue(aTimeStamp - timing->GetNavigationStartTimeStamp()); + return result; +} + +TimeStamp +AnimationTimeline::ToTimeStamp(const TimeDuration& aTimeDuration) const +{ + TimeStamp result; + nsRefPtr timing = mDocument->GetNavigationTiming(); + if (MOZ_UNLIKELY(!timing)) { + return result; + } + + result = timing->GetNavigationStartTimeStamp() + aTimeDuration; return result; } diff --git a/dom/animation/AnimationTimeline.h b/dom/animation/AnimationTimeline.h index 37d0adaae2f8..3fdc1c2eb40f 100644 --- a/dom/animation/AnimationTimeline.h +++ b/dom/animation/AnimationTimeline.h @@ -33,10 +33,15 @@ public: nsISupports* GetParentObject() const { return mDocument; } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + // WebIDL API Nullable GetCurrentTime() const; - mozilla::TimeStamp GetCurrentTimeStamp() const; - Nullable ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const; + Nullable GetCurrentTimeDuration() const; + + Nullable ToTimelineTime(const TimeStamp& aTimeStamp) const; + TimeStamp ToTimeStamp(const TimeDuration& aTimelineTime) const; + + TimeStamp GetCurrentTimeStamp() const; protected: virtual ~AnimationTimeline() { } @@ -46,7 +51,7 @@ protected: // Store the most recently returned value of current time. This is used // in cases where we don't have a refresh driver (e.g. because we are in // a display:none iframe). - mutable mozilla::TimeStamp mLastCurrentTime; + mutable TimeStamp mLastCurrentTime; }; } // namespace dom diff --git a/dom/animation/AnimationUtils.h b/dom/animation/AnimationUtils.h new file mode 100644 index 000000000000..5a56a36ec162 --- /dev/null +++ b/dom/animation/AnimationUtils.h @@ -0,0 +1,29 @@ +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ +/* 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 "mozilla/TimeStamp.h" +#include "mozilla/dom/Nullable.h" + +namespace mozilla { +namespace dom { + +class AnimationUtils +{ +public: + static Nullable + TimeDurationToDouble(const Nullable& aTime) + { + Nullable result; + + if (!aTime.IsNull()) { + result.SetValue(aTime.Value().ToMilliseconds()); + } + + return result; + } +}; + +} // namespace dom +} // namespace mozilla diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index cc4d99c827cc..603695501e15 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -351,7 +351,7 @@ AddAnimationForProperty(nsIFrame* aFrame, nsCSSProperty aProperty, aLayer->AddAnimation(); const AnimationTiming& timing = aPlayer->GetSource()->Timing(); - animation->startTime() = aPlayer->mStartTime + timing.mDelay; + animation->startTime() = aPlayer->Timeline()->ToTimeStamp(aPlayer->mStartTime.Value() + timing.mDelay); animation->duration() = timing.mIterationDuration; animation->iterationCount() = timing.mIterationCount; animation->direction() = timing.mDirection; diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 035a8cbe34d1..e040bf601e7a 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -318,7 +318,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, // start time to something more appropriate when now IsNull. // Handle change in pause state by adjusting start time to // unpause. - oldPlayer->mStartTime += now - oldPlayer->mHoldTime; + oldPlayer->mStartTime.SetValue(now + oldPlayer->mStartTime.Value() - oldPlayer->mHoldTime); } oldPlayer->mHoldTime = TimeStamp(); } @@ -454,7 +454,7 @@ nsAnimationManager::BuildAnimations(nsStyleContext* aStyleContext, new Animation(mPresContext->Document(), timing, src.GetName()); dest->SetSource(destAnim); - dest->mStartTime = now; + dest->mStartTime = aTimeline->GetCurrentTimeDuration(); dest->mPlayState = src.GetPlayState(); if (dest->IsPaused()) { dest->mHoldTime = now; diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 2ee3cba39994..983704832dd3 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -530,7 +530,7 @@ nsTransitionManager::ConsiderStartingTransition( segment.mTimingFunction.Init(tf); nsRefPtr player = new dom::AnimationPlayer(timeline); - player->mStartTime = timeline->GetCurrentTimeStamp(); + player->mStartTime = timeline->GetCurrentTimeDuration(); player->SetSource(pt); if (!aElementTransitions) { From 13da8bae553c3a1d6b015d1d90ab7c5ac9750661 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sat, 30 Aug 2014 02:11:57 -0400 Subject: [PATCH 115/120] Bug 1033114 Part 4: Make mStartTime a nullable TimeDuration r=birtles --- dom/animation/AnimationPlayer.cpp | 37 +++++++++++++---------------- dom/animation/AnimationPlayer.h | 17 +++---------- dom/animation/AnimationTimeline.h | 2 +- layout/style/nsAnimationManager.cpp | 26 ++++++++++---------- 4 files changed, 32 insertions(+), 50 deletions(-) diff --git a/dom/animation/AnimationPlayer.cpp b/dom/animation/AnimationPlayer.cpp index 05fd536634e3..6a20ecd1f27e 100644 --- a/dom/animation/AnimationPlayer.cpp +++ b/dom/animation/AnimationPlayer.cpp @@ -30,27 +30,7 @@ AnimationPlayer::GetStartTime() const Nullable AnimationPlayer::GetCurrentTime() const { - Nullable result; - Nullable currentTime = GetCurrentTimeDuration(); - - // The current time is currently only going to be null when don't have a - // refresh driver (e.g. because we are in a display:none iframe). - // - // Web Animations says that in this case we should use a timeline time of - // 0 (the "effective timeline time") and calculate the current time from that. - // Doing that, however, requires storing the start time as an offset rather - // than a timestamp so for now we just return 0. - // - // FIXME: Store player start time and pause start as offsets rather than - // timestamps and return the appropriate current time when the timeline time - // is null. - if (currentTime.IsNull()) { - result.SetValue(0.0); - } else { - result.SetValue(currentTime.Value().ToMilliseconds()); - } - - return result; + return AnimationUtils::TimeDurationToDouble(GetCurrentTimeDuration()); } void @@ -90,5 +70,20 @@ AnimationPlayer::IsCurrent() const return GetSource() && GetSource()->IsCurrent(); } +Nullable +AnimationPlayer::GetCurrentTimeDuration() const +{ + Nullable result; + if (!mHoldTime.IsNull()) { + result = mHoldTime; + } else { + Nullable timelineTime = mTimeline->GetCurrentTimeDuration(); + if (!timelineTime.IsNull() && !mStartTime.IsNull()) { + result.SetValue(timelineTime.Value() - mStartTime.Value()); + } + } + return result; +} + } // namespace dom } // namespace mozilla diff --git a/dom/animation/AnimationPlayer.h b/dom/animation/AnimationPlayer.h index 8d26f051bc27..663ed5a8420c 100644 --- a/dom/animation/AnimationPlayer.h +++ b/dom/animation/AnimationPlayer.h @@ -67,23 +67,12 @@ public: bool IsCurrent() const; // Return the duration since the start time of the player, taking into - // account the pause state. May be negative. - // Returns a null value if the timeline associated with this object has a - // current timestamp that is null or if the start time of this object is - // null. - Nullable GetCurrentTimeDuration() const { - Nullable timelineTime = mTimeline->GetCurrentTimeDuration(); - Nullable holdDuration = mTimeline->ToTimelineTime(mHoldTime); - Nullable result; // Initializes to null - if (!timelineTime.IsNull() && !mStartTime.IsNull()) { - result.SetValue((IsPaused() ? holdDuration.Value() : timelineTime.Value()) - mStartTime.Value()); - } - return result; - } + // account the pause state. May be negative or null. + Nullable GetCurrentTimeDuration() const; // The beginning of the delay period. Nullable mStartTime; - TimeStamp mHoldTime; + Nullable mHoldTime; uint8_t mPlayState; bool mIsRunningOnCompositor; diff --git a/dom/animation/AnimationTimeline.h b/dom/animation/AnimationTimeline.h index 3fdc1c2eb40f..dd26ccf41325 100644 --- a/dom/animation/AnimationTimeline.h +++ b/dom/animation/AnimationTimeline.h @@ -41,9 +41,9 @@ public: Nullable ToTimelineTime(const TimeStamp& aTimeStamp) const; TimeStamp ToTimeStamp(const TimeDuration& aTimelineTime) const; +protected: TimeStamp GetCurrentTimeStamp() const; -protected: virtual ~AnimationTimeline() { } nsCOMPtr mDocument; diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index e040bf601e7a..8c7178d4b50d 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -272,6 +272,9 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, // (or potentially optimize BuildAnimations to avoid rebuilding it // in the first place). if (!collection->mPlayers.IsEmpty()) { + + Nullable now = timeline->GetCurrentTimeDuration(); + for (size_t newIdx = newPlayers.Length(); newIdx-- != 0;) { AnimationPlayer* newPlayer = newPlayers[newIdx]; @@ -309,18 +312,15 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, // Handle changes in play state. if (!oldPlayer->IsPaused() && newPlayer->IsPaused()) { // Start pause at current time. - oldPlayer->mHoldTime = timeline->GetCurrentTimeStamp(); + oldPlayer->mHoldTime = oldPlayer->GetCurrentTimeDuration(); } else if (oldPlayer->IsPaused() && !newPlayer->IsPaused()) { - const TimeStamp& now = timeline->GetCurrentTimeStamp(); - if (!now.IsNull()) { - // FIXME: Once we store the start time and pause start as - // offsets (not timestamps) we should be able to update the - // start time to something more appropriate when now IsNull. - // Handle change in pause state by adjusting start time to - // unpause. - oldPlayer->mStartTime.SetValue(now + oldPlayer->mStartTime.Value() - oldPlayer->mHoldTime); + if (now.IsNull()) { + oldPlayer->mStartTime.SetNull(); + } else { + oldPlayer->mStartTime.SetValue(now.Value() - + oldPlayer->mHoldTime.Value()); } - oldPlayer->mHoldTime = TimeStamp(); + oldPlayer->mHoldTime.SetNull(); } oldPlayer->mPlayState = newPlayer->mPlayState; @@ -419,7 +419,7 @@ nsAnimationManager::BuildAnimations(nsStyleContext* aStyleContext, ResolvedStyleCache resolvedStyles; const nsStyleDisplay *disp = aStyleContext->StyleDisplay(); - TimeStamp now = aTimeline->GetCurrentTimeStamp(); + Nullable now = aTimeline->GetCurrentTimeDuration(); for (size_t animIdx = 0, animEnd = disp->mAnimationNameCount; animIdx != animEnd; ++animIdx) { @@ -454,12 +454,10 @@ nsAnimationManager::BuildAnimations(nsStyleContext* aStyleContext, new Animation(mPresContext->Document(), timing, src.GetName()); dest->SetSource(destAnim); - dest->mStartTime = aTimeline->GetCurrentTimeDuration(); + dest->mStartTime = now; dest->mPlayState = src.GetPlayState(); if (dest->IsPaused()) { dest->mHoldTime = now; - } else { - dest->mHoldTime = TimeStamp(); } // While current drafts of css3-animations say that later keyframes From c4cf1d93c6bee26c75fb2d45de6181391e65dc4c Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Sat, 30 Aug 2014 09:15:35 +0100 Subject: [PATCH 116/120] Bug 1054632 - constructor init list in wrong order in CrashGenerationServer r=ted --- .../client/mac/crash_generation/crash_generation_server.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_server.cc b/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_server.cc index b3eb403ffb6a..c228025797a5 100644 --- a/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_server.cc +++ b/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_server.cc @@ -45,9 +45,9 @@ CrashGenerationServer::CrashGenerationServer( void *exit_context, bool generate_dumps, const std::string &dump_path) - : dump_callback_(dump_callback), - filter_(filter), + : filter_(filter), filter_context_(filter_context), + dump_callback_(dump_callback), dump_context_(dump_context), exit_callback_(exit_callback), exit_context_(exit_context), From ea9d818f0dbcb4a03cb0f12f8a85e748da45ce57 Mon Sep 17 00:00:00 2001 From: ffxbld Date: Sat, 30 Aug 2014 03:22:59 -0700 Subject: [PATCH 117/120] No bug, Automated HSTS preload list update from host bld-linux64-spot-456 - a=hsts-update --- security/manager/boot/src/nsSTSPreloadList.errors | 15 ++++++--------- security/manager/boot/src/nsSTSPreloadList.inc | 6 +++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/security/manager/boot/src/nsSTSPreloadList.errors b/security/manager/boot/src/nsSTSPreloadList.errors index b54b033bd2d0..63ca8f0d6881 100644 --- a/security/manager/boot/src/nsSTSPreloadList.errors +++ b/security/manager/boot/src/nsSTSPreloadList.errors @@ -1,8 +1,7 @@ -accelerated.de: did not receive HSTS header +accounts.firefox.com: did not receive HSTS header admin.google.com: did not receive HSTS header (error ignored - included regardless) adsfund.org: could not connect to host airbnb.com: did not receive HSTS header -ansdell.net: did not receive HSTS header api.lookout.com: could not connect to host api.mega.co.nz: could not connect to host api.recurly.com: did not receive HSTS header @@ -20,7 +19,6 @@ braintreegateway.com: did not receive HSTS header braintreepayments.com: did not receive HSTS header browserid.org: did not receive HSTS header business.medbank.com.mt: did not receive HSTS header -ca.gparent.org: could not connect to host calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no] carlolly.co.uk: did not receive HSTS header cartucce24.it: could not connect to host @@ -39,7 +37,6 @@ csawctf.poly.edu: did not receive HSTS header discovery.lookout.com: did not receive HSTS header dl.google.com: did not receive HSTS header (error ignored - included regardless) docs.google.com: did not receive HSTS header (error ignored - included regardless) -domains.google.com: did not receive HSTS header (error ignored - included regardless) donmez.ws: did not receive HSTS header drive.google.com: did not receive HSTS header (error ignored - included regardless) dropbox.com: max-age too low: 2592000 @@ -59,7 +56,7 @@ googlemail.com: did not receive HSTS header (error ignored - included regardless googleplex.com: could not connect to host googleplex.com: could not connect to host (error ignored - included regardless) goto.google.com: did not receive HSTS header (error ignored - included regardless) -gparent.org: could not connect to host +gparent.org: did not receive HSTS header greplin.com: did not receive HSTS header groups.google.com: did not receive HSTS header (error ignored - included regardless) hackerone-user-content.com: could not connect to host @@ -81,7 +78,7 @@ liberty.lavabit.com: could not connect to host lifeguard.aecom.com: did not receive HSTS header lists.mayfirst.org: did not receive HSTS header loenshotel.de: could not connect to host -login.corp.google.com: could not connect to host (error ignored - included regardless) +login.corp.google.com: max-age too low: 7776000 (error ignored - included regardless) logotype.se: did not receive HSTS header ludwig.im: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no] lumi.do: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no] @@ -96,11 +93,12 @@ mykolab.com: did not receive HSTS header nachsenden.info: did not receive HSTS header neonisi.com: could not connect to host nexth.de: could not connect to host -nexth.net: did not receive HSTS header +nexth.net: could not connect to host nexth.us: could not connect to host noexpect.org: could not connect to host openshift.redhat.com: did not receive HSTS header ottospora.nl: could not connect to host +passwd.io: could not connect to host passwordbox.com: did not receive HSTS header paypal.com: max-age too low: 14400 payroll.xero.com: max-age too low: 3600 @@ -140,8 +138,6 @@ translate.googleapis.com: did not receive HSTS header (error ignored - included uprotect.it: could not connect to host wallet.google.com: did not receive HSTS header (error ignored - included regardless) webmail.mayfirst.org: did not receive HSTS header -wf-training-master.appspot.com: could not connect to host -wf-training-master.appspot.com: could not connect to host (error ignored - included regardless) whonix.org: did not receive HSTS header www.calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no] www.cueup.com: could not connect to host @@ -152,6 +148,7 @@ www.gmail.com: did not receive HSTS header (error ignored - included regardless) www.googlemail.com: did not receive HSTS header (error ignored - included regardless) www.greplin.com: did not receive HSTS header www.jitsi.org: did not receive HSTS header +www.lastpass.com: did not receive HSTS header www.ledgerscope.net: did not receive HSTS header www.logentries.com: did not receive HSTS header www.moneybookers.com: did not receive HSTS header diff --git a/security/manager/boot/src/nsSTSPreloadList.inc b/security/manager/boot/src/nsSTSPreloadList.inc index 8a52b230c70b..0a5a4f4152e7 100644 --- a/security/manager/boot/src/nsSTSPreloadList.inc +++ b/security/manager/boot/src/nsSTSPreloadList.inc @@ -8,7 +8,7 @@ /*****************************************************************************/ #include -const PRTime gPreloadListExpirationTime = INT64_C(1419675456115000); +const PRTime gPreloadListExpirationTime = INT64_C(1420280117245000); class nsSTSPreload { @@ -18,7 +18,6 @@ class nsSTSPreload }; static const nsSTSPreload kSTSPreloadList[] = { - { "accounts.firefox.com", true }, { "accounts.google.com", true }, { "aclu.org", false }, { "activiti.alfresco.com", false }, @@ -30,6 +29,7 @@ static const nsSTSPreload kSTSPreloadList[] = { { "aladdinschools.appspot.com", false }, { "alexsexton.com", true }, { "alpha.irccloud.com", false }, + { "ansdell.net", true }, { "anycoin.me", true }, { "apadvantage.com", true }, { "api.intercom.io", false }, @@ -79,6 +79,7 @@ static const nsSTSPreload kSTSPreloadList[] = { { "bugzilla.mozilla.org", true }, { "business.lookout.com", false }, { "bytepark.de", true }, + { "ca.gparent.org", false }, { "carezone.com", false }, { "cartouche24.eu", true }, { "celltek-server.de", true }, @@ -496,7 +497,6 @@ static const nsSTSPreload kSTSPreloadList[] = { { "www.heliosnet.com", true }, { "www.intercom.io", false }, { "www.irccloud.com", false }, - { "www.lastpass.com", false }, { "www.linode.com", false }, { "www.lookout.com", false }, { "www.makeyourlaws.org", true }, From 61a875d894b03569800fe65d356e6151eeb1b2fb Mon Sep 17 00:00:00 2001 From: ffxbld Date: Sat, 30 Aug 2014 03:23:01 -0700 Subject: [PATCH 118/120] No bug, Automated HPKP preload list update from host bld-linux64-spot-456 - a=hpkp-update --- security/manager/boot/src/StaticHPKPins.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/manager/boot/src/StaticHPKPins.h b/security/manager/boot/src/StaticHPKPins.h index db1472c850c0..07b6ed0c44f5 100644 --- a/security/manager/boot/src/StaticHPKPins.h +++ b/security/manager/boot/src/StaticHPKPins.h @@ -1086,4 +1086,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = { static const int32_t kUnknownId = -1; -static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1417640422391000); +static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1417860919825000); From 2fa9fe49355e9a242c9beb6db33b428b27a445c1 Mon Sep 17 00:00:00 2001 From: ffxbld Date: Sat, 30 Aug 2014 03:23:03 -0700 Subject: [PATCH 119/120] No bug, Automated blocklist update from host bld-linux64-spot-456 - a=blocklist-update --- browser/app/blocklist.xml | 2479 ------------------------------------- 1 file changed, 2479 deletions(-) diff --git a/browser/app/blocklist.xml b/browser/app/blocklist.xml index f0ea80c9384b..e69de29bb2d1 100644 --- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -1,2479 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - browser.search.defaultenginename - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - browser.startup.homepage - browser.search.defaultenginename - - - - - - - - - - - - - - - - - - - - - - - - - - - - - browser.search.defaultenginename - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - browser.startup.homepage - browser.search.defaultenginename - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - browser.startup.homepage - browser.search.defaultenginename - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - browser.startup.homepage - browser.search.defaultenginename - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - https://get.adobe.com/flashplayer/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WINNT 6.1 0x10de - 0x0a6c - - DIRECT2D BLOCKED_DRIVER_VERSION 8.17.12.5896 LESS_THAN_OR_EQUAL - WINNT 6.1 0x10de - 0x0a6c - - DIRECT3D_9_LAYERS BLOCKED_DRIVER_VERSION 8.17.12.5896 LESS_THAN_OR_EQUAL - WINNT 5.1 0x10de DIRECT3D_9_LAYERS BLOCKED_DRIVER_VERSION 7.0.0.0 GREATER_THAN_OR_EQUAL - All 0x1002 DIRECT2D BLOCKED_DRIVER_VERSION 8.982.0.0 EQUAL - All 0x1022 DIRECT2D BLOCKED_DRIVER_VERSION 8.982.0.0 EQUAL - All 0x1022 DIRECT3D_9_LAYERS BLOCKED_DRIVER_VERSION 8.982.0.0 EQUAL - All 0x1002 DIRECT3D_9_LAYERS BLOCKED_DRIVER_VERSION 8.982.0.0 EQUAL - WINNT 6.2 0x1002 DIRECT2D BLOCKED_DRIVER_VERSION 9.10.8.0 LESS_THAN_OR_EQUAL - WINNT 6.2 0x1022 DIRECT2D BLOCKED_DRIVER_VERSION 9.10.8.0 LESS_THAN_OR_EQUAL - Darwin 10 0x10de WEBGL_MSAA BLOCKED_DEVICE - Darwin 11 0x10de WEBGL_MSAA BLOCKED_DEVICE - Darwin 12 0x10de WEBGL_MSAA BLOCKED_DEVICE - Darwin 10 0x8086 WEBGL_MSAA BLOCKED_DEVICE - Darwin 11 0x8086 WEBGL_MSAA BLOCKED_DEVICE - Darwin 12 0x8086 WEBGL_MSAA BLOCKED_DEVICE - Darwin 10 0x1002 WEBGL_MSAA BLOCKED_DEVICE - Darwin 11 0x1002 WEBGL_MSAA BLOCKED_DEVICE - Darwin 12 0x1002 WEBGL_MSAA BLOCKED_DEVICE - WINNT 6.1 0x1002 - 0x9802 - 0x9803 - 0x9803 - 0x9804 - 0x9805 - 0x9806 - 0x9807 - - DIRECT2D BLOCKED_DEVICE - WINNT 6.1 0x1002 - 0x9802 - 0x9803 - 0x9803 - 0x9804 - 0x9805 - 0x9806 - 0x9807 - - DIRECT3D_9_LAYERS BLOCKED_DEVICE - WINNT 5.1 0x8086 DIRECT3D_9_LAYERS, WEBGL_ANGLE BLOCKED_DRIVER_VERSION 6.14.10.5218 LESS_THAN - - - - \ No newline at end of file From 3bd8e95f82ceca5938869fdccc629fcdec7794e6 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 30 Aug 2014 13:34:09 +0200 Subject: [PATCH 120/120] Bug 1060342 - Optimize TypeOfV codegen. r=bhackett --- js/src/jit/CodeGenerator.cpp | 149 ++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 48 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 38b7b754f92b..d4f56f53a4c3 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7837,62 +7837,115 @@ CodeGenerator::visitTypeOfV(LTypeOfV *lir) const JSAtomState &names = GetIonContext()->runtime->names(); Label done; - OutOfLineTypeOfV *ool = nullptr; - if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) { - // The input may be a callable object (result is "function") or may - // emulate undefined (result is "undefined"). Use an OOL path. - ool = new(alloc()) OutOfLineTypeOfV(lir); - if (!addOutOfLineCode(ool, lir->mir())) - return false; + MDefinition *input = lir->mir()->input(); - masm.branchTestObject(Assembler::Equal, tag, ool->entry()); - } else { - // Input is not callable and does not emulate undefined, so if - // it's an object the result is always "object". - Label notObject; - masm.branchTestObject(Assembler::NotEqual, tag, ¬Object); - masm.movePtr(ImmGCPtr(names.object), output); - masm.jump(&done); - masm.bind(¬Object); + bool testObject = input->mightBeType(MIRType_Object); + bool testNumber = input->mightBeType(MIRType_Int32) || input->mightBeType(MIRType_Double); + bool testBoolean = input->mightBeType(MIRType_Boolean); + bool testUndefined = input->mightBeType(MIRType_Undefined); + bool testNull = input->mightBeType(MIRType_Null); + bool testString = input->mightBeType(MIRType_String); + bool testSymbol = input->mightBeType(MIRType_Symbol); + + unsigned numTests = unsigned(testObject) + unsigned(testNumber) + unsigned(testBoolean) + + unsigned(testUndefined) + unsigned(testNull) + unsigned(testString) + unsigned(testSymbol); + + MOZ_ASSERT_IF(!input->emptyResultTypeSet(), numTests > 0); + + OutOfLineTypeOfV *ool = nullptr; + if (testObject) { + if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) { + // The input may be a callable object (result is "function") or may + // emulate undefined (result is "undefined"). Use an OOL path. + ool = new(alloc()) OutOfLineTypeOfV(lir); + if (!addOutOfLineCode(ool, lir->mir())) + return false; + + if (numTests > 1) + masm.branchTestObject(Assembler::Equal, tag, ool->entry()); + else + masm.jump(ool->entry()); + } else { + // Input is not callable and does not emulate undefined, so if + // it's an object the result is always "object". + Label notObject; + if (numTests > 1) + masm.branchTestObject(Assembler::NotEqual, tag, ¬Object); + masm.movePtr(ImmGCPtr(names.object), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬Object); + } + numTests--; } - Label notNumber; - masm.branchTestNumber(Assembler::NotEqual, tag, ¬Number); - masm.movePtr(ImmGCPtr(names.number), output); - masm.jump(&done); - masm.bind(¬Number); + if (testNumber) { + Label notNumber; + if (numTests > 1) + masm.branchTestNumber(Assembler::NotEqual, tag, ¬Number); + masm.movePtr(ImmGCPtr(names.number), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬Number); + numTests--; + } - Label notUndefined; - masm.branchTestUndefined(Assembler::NotEqual, tag, ¬Undefined); - masm.movePtr(ImmGCPtr(names.undefined), output); - masm.jump(&done); - masm.bind(¬Undefined); + if (testUndefined) { + Label notUndefined; + if (numTests > 1) + masm.branchTestUndefined(Assembler::NotEqual, tag, ¬Undefined); + masm.movePtr(ImmGCPtr(names.undefined), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬Undefined); + numTests--; + } - Label notNull; - masm.branchTestNull(Assembler::NotEqual, tag, ¬Null); - masm.movePtr(ImmGCPtr(names.object), output); - masm.jump(&done); - masm.bind(¬Null); + if (testNull) { + Label notNull; + if (numTests > 1) + masm.branchTestNull(Assembler::NotEqual, tag, ¬Null); + masm.movePtr(ImmGCPtr(names.object), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬Null); + numTests--; + } - Label notBoolean; - masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean); - masm.movePtr(ImmGCPtr(names.boolean), output); - masm.jump(&done); - masm.bind(¬Boolean); + if (testBoolean) { + Label notBoolean; + if (numTests > 1) + masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean); + masm.movePtr(ImmGCPtr(names.boolean), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬Boolean); + numTests--; + } - Label notString; - masm.branchTestString(Assembler::NotEqual, tag, ¬String); - masm.movePtr(ImmGCPtr(names.string), output); - masm.jump(&done); - masm.bind(¬String); + if (testString) { + Label notString; + if (numTests > 1) + masm.branchTestString(Assembler::NotEqual, tag, ¬String); + masm.movePtr(ImmGCPtr(names.string), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬String); + numTests--; + } -#ifdef DEBUG - Label isSymbol; - masm.branchTestSymbol(Assembler::Equal, tag, &isSymbol); - masm.assumeUnreachable("Unexpected type for TypeOfV"); - masm.bind(&isSymbol); -#endif - masm.movePtr(ImmGCPtr(names.symbol), output); + if (testSymbol) { + Label notSymbol; + if (numTests > 1) + masm.branchTestSymbol(Assembler::NotEqual, tag, ¬Symbol); + masm.movePtr(ImmGCPtr(names.symbol), output); + if (numTests > 1) + masm.jump(&done); + masm.bind(¬Symbol); + numTests--; + } + + MOZ_ASSERT(numTests == 0); masm.bind(&done); if (ool)