From f9d213c7cb5787fff03dac97c4d2066dc17a65af Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 4 Jun 2012 13:01:00 +0200 Subject: [PATCH 01/53] Bug 761089 - Missing Opus export in glmedias.dll in mingw builds r=kinetik --- layout/media/symbols.def.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index d222985bd5cc..e3df89aa5ebc 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -132,6 +132,8 @@ opus_decoder_ctl opus_decoder_get_nb_samples opus_decode opus_decode_float +opus_packet_get_nb_frames +opus_packet_get_samples_per_frame #endif ShInitialize ShFinalize From 61502911db84cd4ce44dedb7df662389d6a321be Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 4 Jun 2012 13:02:02 +0200 Subject: [PATCH 02/53] Bug 756996 - GCC warnings in gfx/2d r=bas --- gfx/2d/DrawTargetD2D.cpp | 15 +++++++----- gfx/2d/HelpersD2D.h | 34 +++++++++++++++------------- gfx/2d/ImageScalingSSE2.cpp | 6 ----- gfx/2d/PathD2D.cpp | 2 -- gfx/layers/d3d10/ImageLayerD3D10.cpp | 2 +- 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/gfx/2d/DrawTargetD2D.cpp b/gfx/2d/DrawTargetD2D.cpp index 0091545b2ea2..3428dd6a8653 100644 --- a/gfx/2d/DrawTargetD2D.cpp +++ b/gfx/2d/DrawTargetD2D.cpp @@ -129,8 +129,7 @@ public: RefPtr sink; invClippedArea->Open(byRef(sink)); - HRESULT hr = rectGeom->CombineWithGeometry(mClippedArea, D2D1_COMBINE_MODE_EXCLUDE, - NULL, sink); + rectGeom->CombineWithGeometry(mClippedArea, D2D1_COMBINE_MODE_EXCLUDE, NULL, sink); sink->Close(); RefPtr brush; @@ -293,6 +292,8 @@ DrawTargetD2D::DrawSurface(SourceSurface *aSurface, srcRect.y -= (uint32_t)aSource.y; } break; + default: + break; } rt->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(srcRect)); @@ -699,6 +700,8 @@ DrawTargetD2D::CopySurface(SourceSurface *aSurface, AddDependencyOnSource(srcSurf); } break; + default: + return; } if (!bitmap) { @@ -2009,6 +2012,8 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) } } break; + default: + break; } mRT->CreateBitmapBrush(bitmap, @@ -2276,8 +2281,6 @@ DrawTargetD2D::CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix if (uploadRect.width <= mRT->GetMaximumBitmapSize() && uploadRect.height <= mRT->GetMaximumBitmapSize()) { - - int Bpp = BytesPerPixel(aSurface->GetFormat()); // A partial upload will suffice. mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)), @@ -2311,13 +2314,13 @@ DrawTargetD2D::CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix scaleSize.width = max(Distance(topRight, topLeft), Distance(bottomRight, bottomLeft)); scaleSize.height = max(Distance(topRight, bottomRight), Distance(topLeft, bottomLeft)); - if (scaleSize.width > mRT->GetMaximumBitmapSize()) { + if (unsigned(scaleSize.width) > mRT->GetMaximumBitmapSize()) { // Ok, in this case we'd really want a downscale of a part of the bitmap, // perhaps we can do this later but for simplicity let's do something // different here and assume it's good enough, this should be rare! scaleSize.width = 4095; } - if (scaleSize.height > mRT->GetMaximumBitmapSize()) { + if (unsigned(scaleSize.height) > mRT->GetMaximumBitmapSize()) { scaleSize.height = 4095; } diff --git a/gfx/2d/HelpersD2D.h b/gfx/2d/HelpersD2D.h index c32095e1925d..4386c0eebdea 100644 --- a/gfx/2d/HelpersD2D.h +++ b/gfx/2d/HelpersD2D.h @@ -32,7 +32,7 @@ static inline D2D1_RECT_F D2DRect(const Rect &aRect) static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode) { - D2D1_EXTEND_MODE extend = D2D1_EXTEND_MODE_CLAMP; + D2D1_EXTEND_MODE extend; switch (aExtendMode) { case EXTEND_REPEAT: extend = D2D1_EXTEND_MODE_WRAP; @@ -40,6 +40,8 @@ static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode) case EXTEND_REFLECT: extend = D2D1_EXTEND_MODE_MIRROR; break; + default: + extend = D2D1_EXTEND_MODE_CLAMP; } return extend; @@ -50,9 +52,9 @@ static inline D2D1_BITMAP_INTERPOLATION_MODE D2DFilter(const Filter &aFilter) switch (aFilter) { case FILTER_POINT: return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + default: + return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR; } - - return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR; } static inline D2D1_ANTIALIAS_MODE D2DAAMode(AntialiasMode aMode) @@ -60,9 +62,9 @@ static inline D2D1_ANTIALIAS_MODE D2DAAMode(AntialiasMode aMode) switch (aMode) { case AA_NONE: return D2D1_ANTIALIAS_MODE_ALIASED; + default: + return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; } - - return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; } static inline D2D1_MATRIX_3X2_F D2DMatrix(const Matrix &aTransform) @@ -93,9 +95,9 @@ static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT &aFormat) } else { return FORMAT_B8G8R8A8; } + default: + return FORMAT_B8G8R8A8; } - - return FORMAT_B8G8R8A8; } static inline Rect ToRect(const D2D1_RECT_F &aRect) @@ -112,9 +114,9 @@ static inline DXGI_FORMAT DXGIFormat(SurfaceFormat aFormat) return DXGI_FORMAT_B8G8R8A8_UNORM; case FORMAT_A8: return DXGI_FORMAT_A8_UNORM; + default: + return DXGI_FORMAT_UNKNOWN; } - - return DXGI_FORMAT_UNKNOWN; } static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat) @@ -122,9 +124,9 @@ static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat) switch (aFormat) { case FORMAT_B8G8R8X8: return D2D1_ALPHA_MODE_IGNORE; + default: + return D2D1_ALPHA_MODE_PREMULTIPLIED; } - - return D2D1_ALPHA_MODE_PREMULTIPLIED; } static inline D2D1_PIXEL_FORMAT D2DPixelFormat(SurfaceFormat aFormat) @@ -132,7 +134,7 @@ static inline D2D1_PIXEL_FORMAT D2DPixelFormat(SurfaceFormat aFormat) return D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat)); } -static bool IsPatternSupportedByD2D(const Pattern &aPattern) +static inline bool IsPatternSupportedByD2D(const Pattern &aPattern) { if (aPattern.GetType() != PATTERN_RADIAL_GRADIENT) { return false; @@ -173,7 +175,7 @@ struct ShaderConstantRectD3D10 operator float* () { return &mX; } }; -static DWRITE_MATRIX +static inline DWRITE_MATRIX DWriteMatrixFromMatrix(Matrix &aMatrix) { DWRITE_MATRIX mat; @@ -188,7 +190,7 @@ DWriteMatrixFromMatrix(Matrix &aMatrix) class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN { - static const int kNumAutoGlyphs = 256; + static const unsigned kNumAutoGlyphs = 256; public: AutoDWriteGlyphRun() { @@ -203,7 +205,7 @@ public: } } - void allocate(int aNumGlyphs) { + void allocate(unsigned aNumGlyphs) { glyphCount = aNumGlyphs; if (aNumGlyphs <= kNumAutoGlyphs) { glyphIndices = &mAutoIndices[0]; @@ -222,7 +224,7 @@ private: UINT16 mAutoIndices[kNumAutoGlyphs]; }; -static void +static inline void DWriteGlyphRunFromGlyphs(const GlyphBuffer &aGlyphs, ScaledFontDWrite *aFont, AutoDWriteGlyphRun *run) { run->allocate(aGlyphs.mNumGlyphs); diff --git a/gfx/2d/ImageScalingSSE2.cpp b/gfx/2d/ImageScalingSSE2.cpp index 390b370c7efc..334fce60d97d 100644 --- a/gfx/2d/ImageScalingSSE2.cpp +++ b/gfx/2d/ImageScalingSSE2.cpp @@ -89,8 +89,6 @@ MOZ_ALWAYS_INLINE __m128i avg_sse2_8x2(__m128i *a, __m128i *b, __m128i *c, __m12 __m128i carry = _mm_or_si128(_mm_and_si128(*a, *b), _mm_or_si128(_mm_and_si128(*a, *c), _mm_and_si128(*b, *c))); - __m128i minusone = _mm_set1_epi32(0xffffffff); - sum = _mm_avg_epu8(_mm_not_si128(sum), _mm_not_si128(*d)); return _mm_not_si128(_mm_avg_epu8(sum, _mm_not_si128(carry))); @@ -98,8 +96,6 @@ MOZ_ALWAYS_INLINE __m128i avg_sse2_8x2(__m128i *a, __m128i *b, __m128i *c, __m12 MOZ_ALWAYS_INLINE __m128i avg_sse2_4x2_4x1(__m128i a, __m128i b) { - __m128i minusone = _mm_set1_epi32(0xffffffff); - return _mm_not_si128(_mm_avg_epu8(_mm_not_si128(a), _mm_not_si128(b))); } @@ -109,8 +105,6 @@ MOZ_ALWAYS_INLINE __m128i avg_sse2_8x1_4x1(__m128i a, __m128i b) b = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(a), _MM_SHUFFLE(2, 0, 2, 0))); a = t; - __m128i minusone = _mm_set1_epi32(0xffffffff); - return _mm_not_si128(_mm_avg_epu8(_mm_not_si128(a), _mm_not_si128(b))); } diff --git a/gfx/2d/PathD2D.cpp b/gfx/2d/PathD2D.cpp index 5ff6eb83f78c..41681fcf9a6a 100644 --- a/gfx/2d/PathD2D.cpp +++ b/gfx/2d/PathD2D.cpp @@ -3,8 +3,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#pragma once - #include "PathD2D.h" #include "HelpersD2D.h" #include diff --git a/gfx/layers/d3d10/ImageLayerD3D10.cpp b/gfx/layers/d3d10/ImageLayerD3D10.cpp index 0a392787aa12..fb13993893e7 100644 --- a/gfx/layers/d3d10/ImageLayerD3D10.cpp +++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp @@ -484,7 +484,7 @@ RemoteDXGITextureImage::GetD3D10TextureBackendData(ID3D10Device *aDevice) return nsnull; } - nsAutoPtr data = new TextureD3D10BackendData(); + nsAutoPtr data(new TextureD3D10BackendData()); data->mTexture = texture; From ae8e9aa9f0771e76109813cebdfa18bab815a828 Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Mon, 4 Jun 2012 08:32:29 -0400 Subject: [PATCH 03/53] Bug 760463 - de-ns-ify nsBaseWidgetAccessible, r=surkov --HG-- rename : accessible/src/base/nsBaseWidgetAccessible.cpp => accessible/src/generic/BaseAccessibles.cpp rename : accessible/src/base/nsBaseWidgetAccessible.h => accessible/src/generic/BaseAccessibles.h --- accessible/src/base/Makefile.in | 1 - .../src/base/nsAccessibilityService.cpp | 19 ++--- .../BaseAccessibles.cpp} | 73 +++++++++---------- .../BaseAccessibles.h} | 36 +++++---- .../src/generic/FormControlAccessible.cpp | 20 ++--- .../src/generic/FormControlAccessible.h | 8 +- accessible/src/generic/ImageAccessible.cpp | 14 ++-- accessible/src/generic/ImageAccessible.h | 4 +- accessible/src/generic/Makefile.in | 1 + accessible/src/generic/TextLeafAccessible.cpp | 2 +- accessible/src/generic/TextLeafAccessible.h | 4 +- accessible/src/html/HTMLElementAccessibles.h | 10 +-- .../src/html/HTMLFormControlAccessible.cpp | 4 +- .../src/html/HTMLFormControlAccessible.h | 2 +- accessible/src/html/HTMLListAccessible.cpp | 2 +- accessible/src/html/HTMLListAccessible.h | 6 +- .../src/msaa/nsHTMLWin32ObjectAccessible.cpp | 4 +- .../src/msaa/nsHTMLWin32ObjectAccessible.h | 6 +- .../src/xforms/nsXFormsWidgetsAccessible.cpp | 2 +- .../src/xforms/nsXFormsWidgetsAccessible.h | 4 +- .../src/xul/XULFormControlAccessible.cpp | 10 +-- accessible/src/xul/XULFormControlAccessible.h | 8 +- accessible/src/xul/nsXULListboxAccessible.cpp | 2 +- accessible/src/xul/nsXULListboxAccessible.h | 5 +- accessible/src/xul/nsXULTabAccessible.h | 1 - accessible/src/xul/nsXULTextAccessible.cpp | 6 +- accessible/src/xul/nsXULTextAccessible.h | 4 +- .../src/xul/nsXULTreeGridAccessible.cpp | 14 ++-- accessible/src/xul/nsXULTreeGridAccessible.h | 14 ++-- 29 files changed, 143 insertions(+), 143 deletions(-) rename accessible/src/{base/nsBaseWidgetAccessible.cpp => generic/BaseAccessibles.cpp} (72%) rename accessible/src/{base/nsBaseWidgetAccessible.h => generic/BaseAccessibles.h} (77%) diff --git a/accessible/src/base/Makefile.in b/accessible/src/base/Makefile.in index cd63f150b931..d302f68d8488 100644 --- a/accessible/src/base/Makefile.in +++ b/accessible/src/base/Makefile.in @@ -31,7 +31,6 @@ CPPSRCS = \ nsAccessibilityService.cpp \ nsAccessiblePivot.cpp \ nsAccTreeWalker.cpp \ - nsBaseWidgetAccessible.cpp \ nsEventShell.cpp \ nsCaretAccessible.cpp \ nsTextEquivUtils.cpp \ diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index a49db190b677..1f9b4d61cd41 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -296,8 +296,8 @@ nsAccessibilityService::CreateHTMLMediaAccessible(nsIContent* aContent, nsIPresShell* aPresShell) { Accessible* accessible = - new nsEnumRoleAccessible(aContent, GetDocAccessible(aPresShell), - roles::GROUPING); + new EnumRoleAccessible(aContent, GetDocAccessible(aPresShell), + roles::GROUPING); NS_ADDREF(accessible); return accessible; } @@ -405,7 +405,7 @@ nsAccessibilityService::CreateHTMLTableRowAccessible(nsIContent* aContent, nsIPresShell* aPresShell) { Accessible* accessible = - new nsEnumRoleAccessible(aContent, GetDocAccessible(aPresShell), roles::ROW); + new EnumRoleAccessible(aContent, GetDocAccessible(aPresShell), roles::ROW); NS_ADDREF(accessible); return accessible; } @@ -1173,12 +1173,10 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode, if (!newAcc) { // Create generic accessibles for SVG and MathML nodes. if (content->IsSVG(nsGkAtoms::svg)) { - newAcc = new nsEnumRoleAccessible(content, docAcc, - roles::DIAGRAM); + newAcc = new EnumRoleAccessible(content, docAcc, roles::DIAGRAM); } else if (content->IsMathML(nsGkAtoms::math)) { - newAcc = new nsEnumRoleAccessible(content, docAcc, - roles::EQUATION); + newAcc = new EnumRoleAccessible(content, docAcc, roles::EQUATION); } } @@ -1419,8 +1417,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent, break; case nsIAccessibleProvider::XULPane: - accessible = new nsEnumRoleAccessible(aContent, aDoc, - roles::PANE); + accessible = new EnumRoleAccessible(aContent, aDoc, roles::PANE); break; case nsIAccessibleProvider::XULProgressMeter: @@ -1786,8 +1783,8 @@ nsAccessibilityService::CreateAccessibleForDeckChild(nsIFrame* aFrame, return accessible; } #endif - Accessible* accessible = new nsEnumRoleAccessible(aContent, aDoc, - roles::PROPERTYPAGE); + Accessible* accessible = new EnumRoleAccessible(aContent, aDoc, + roles::PROPERTYPAGE); NS_IF_ADDREF(accessible); return accessible; } diff --git a/accessible/src/base/nsBaseWidgetAccessible.cpp b/accessible/src/generic/BaseAccessibles.cpp similarity index 72% rename from accessible/src/base/nsBaseWidgetAccessible.cpp rename to accessible/src/generic/BaseAccessibles.cpp index 4624eb4f18c9..45a3521f36a0 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.cpp +++ b/accessible/src/generic/BaseAccessibles.cpp @@ -3,7 +3,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/. */ -#include "nsBaseWidgetAccessible.h" +#include "BaseAccessibles.h" #include "Accessible-inl.h" #include "HyperTextAccessibleWrap.h" @@ -22,44 +22,44 @@ using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// -// nsLeafAccessible +// LeafAccessible //////////////////////////////////////////////////////////////////////////////// -nsLeafAccessible:: - nsLeafAccessible(nsIContent* aContent, DocAccessible* aDoc) : +LeafAccessible:: + LeafAccessible(nsIContent* aContent, DocAccessible* aDoc) : AccessibleWrap(aContent, aDoc) { } -NS_IMPL_ISUPPORTS_INHERITED0(nsLeafAccessible, Accessible) +NS_IMPL_ISUPPORTS_INHERITED0(LeafAccessible, Accessible) //////////////////////////////////////////////////////////////////////////////// -// nsLeafAccessible: Accessible public +// LeafAccessible: Accessible public Accessible* -nsLeafAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, - EWhichChildAtPoint aWhichChild) +LeafAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, + EWhichChildAtPoint aWhichChild) { // Don't walk into leaf accessibles. return this; } //////////////////////////////////////////////////////////////////////////////// -// nsLeafAccessible: Accessible private +// LeafAccessible: Accessible private void -nsLeafAccessible::CacheChildren() +LeafAccessible::CacheChildren() { // No children for leaf accessible. } //////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible +// LinkableAccessible //////////////////////////////////////////////////////////////////////////////// -nsLinkableAccessible:: - nsLinkableAccessible(nsIContent* aContent, DocAccessible* aDoc) : +LinkableAccessible:: + LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc) : AccessibleWrap(aContent, aDoc), mActionAcc(nsnull), mIsLink(false), @@ -67,19 +67,19 @@ nsLinkableAccessible:: { } -NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, AccessibleWrap) +NS_IMPL_ISUPPORTS_INHERITED0(LinkableAccessible, AccessibleWrap) //////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible. nsIAccessible +// LinkableAccessible. nsIAccessible NS_IMETHODIMP -nsLinkableAccessible::TakeFocus() +LinkableAccessible::TakeFocus() { return mActionAcc ? mActionAcc->TakeFocus() : AccessibleWrap::TakeFocus(); } PRUint64 -nsLinkableAccessible::NativeLinkState() const +LinkableAccessible::NativeLinkState() const { if (mIsLink) return states::LINKED | (mActionAcc->LinkState() & states::TRAVERSED); @@ -88,7 +88,7 @@ nsLinkableAccessible::NativeLinkState() const } void -nsLinkableAccessible::Value(nsString& aValue) +LinkableAccessible::Value(nsString& aValue) { aValue.Truncate(); @@ -102,18 +102,18 @@ nsLinkableAccessible::Value(nsString& aValue) PRUint8 -nsLinkableAccessible::ActionCount() +LinkableAccessible::ActionCount() { return (mIsOnclick || mIsLink) ? 1 : 0; } NS_IMETHODIMP -nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) +LinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) { aName.Truncate(); // Action 0 (default action): Jump to link - if (aIndex == eAction_Jump) { + if (aIndex == eAction_Jump) { if (mIsLink) { aName.AssignLiteral("jump"); return NS_OK; @@ -128,7 +128,7 @@ nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) } NS_IMETHODIMP -nsLinkableAccessible::DoAction(PRUint8 aIndex) +LinkableAccessible::DoAction(PRUint8 aIndex) { if (aIndex != eAction_Jump) return NS_ERROR_INVALID_ARG; @@ -138,17 +138,17 @@ nsLinkableAccessible::DoAction(PRUint8 aIndex) } KeyBinding -nsLinkableAccessible::AccessKey() const +LinkableAccessible::AccessKey() const { return mActionAcc ? mActionAcc->AccessKey() : Accessible::AccessKey(); } //////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible. nsAccessNode +// LinkableAccessible. nsAccessNode void -nsLinkableAccessible::Shutdown() +LinkableAccessible::Shutdown() { mIsLink = false; mIsOnclick = false; @@ -157,10 +157,10 @@ nsLinkableAccessible::Shutdown() } //////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible: HyperLinkAccessible +// LinkableAccessible: HyperLinkAccessible already_AddRefed -nsLinkableAccessible::AnchorURIAt(PRUint32 aAnchorIndex) +LinkableAccessible::AnchorURIAt(PRUint32 aAnchorIndex) { if (mIsLink) { NS_ASSERTION(mActionAcc->IsLink(), @@ -174,11 +174,11 @@ nsLinkableAccessible::AnchorURIAt(PRUint32 aAnchorIndex) } //////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible: Accessible protected +// LinkableAccessible: Accessible protected void -nsLinkableAccessible::BindToParent(Accessible* aParent, - PRUint32 aIndexInParent) +LinkableAccessible::BindToParent(Accessible* aParent, + PRUint32 aIndexInParent) { AccessibleWrap::BindToParent(aParent, aIndexInParent); @@ -212,7 +212,7 @@ nsLinkableAccessible::BindToParent(Accessible* aParent, } void -nsLinkableAccessible::UnbindFromParent() +LinkableAccessible::UnbindFromParent() { mActionAcc = nsnull; mIsLink = false; @@ -222,20 +222,19 @@ nsLinkableAccessible::UnbindFromParent() } //////////////////////////////////////////////////////////////////////////////// -// nsEnumRoleAccessible +// EnumRoleAccessible //////////////////////////////////////////////////////////////////////////////// -nsEnumRoleAccessible:: - nsEnumRoleAccessible(nsIContent* aNode, DocAccessible* aDoc, - roles::Role aRole) : +EnumRoleAccessible:: + EnumRoleAccessible(nsIContent* aNode, DocAccessible* aDoc, roles::Role aRole) : AccessibleWrap(aNode, aDoc), mRole(aRole) { } -NS_IMPL_ISUPPORTS_INHERITED0(nsEnumRoleAccessible, Accessible) +NS_IMPL_ISUPPORTS_INHERITED0(EnumRoleAccessible, Accessible) role -nsEnumRoleAccessible::NativeRole() +EnumRoleAccessible::NativeRole() { return mRole; } diff --git a/accessible/src/base/nsBaseWidgetAccessible.h b/accessible/src/generic/BaseAccessibles.h similarity index 77% rename from accessible/src/base/nsBaseWidgetAccessible.h rename to accessible/src/generic/BaseAccessibles.h index 5bdbb8b7d68c..67d2343850cb 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.h +++ b/accessible/src/generic/BaseAccessibles.h @@ -3,8 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef _nsBaseWidgetAccessible_H_ -#define _nsBaseWidgetAccessible_H_ +#ifndef mozilla_a11y_BaseAccessibles_h__ +#define mozilla_a11y_BaseAccessibles_h__ #include "AccessibleWrap.h" #include "HyperTextAccessibleWrap.h" @@ -16,14 +16,17 @@ * the HTML and XUL widget sets. --jgaunt */ -/** +namespace mozilla { +namespace a11y { + +/** * Leaf version of DOM Accessible -- has no children */ -class nsLeafAccessible : public AccessibleWrap +class LeafAccessible : public AccessibleWrap { public: - nsLeafAccessible(nsIContent* aContent, DocAccessible* aDoc); + LeafAccessible(nsIContent* aContent, DocAccessible* aDoc); // nsISupports NS_DECL_ISUPPORTS_INHERITED @@ -44,12 +47,12 @@ protected: * report the state of the host link (traveled or not) and can activate (click) * the host accessible programmatically. */ -class nsLinkableAccessible : public AccessibleWrap +class LinkableAccessible : public AccessibleWrap { public: enum { eAction_Jump = 0 }; - nsLinkableAccessible(nsIContent* aContent, DocAccessible* aDoc); + LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc); NS_DECL_ISUPPORTS_INHERITED @@ -87,21 +90,24 @@ protected: /** * A simple accessible that gets its enumerated role passed into constructor. - */ -class nsEnumRoleAccessible : public AccessibleWrap + */ +class EnumRoleAccessible : public AccessibleWrap { public: - nsEnumRoleAccessible(nsIContent* aContent, DocAccessible* aDoc, - mozilla::a11y::role aRole); - virtual ~nsEnumRoleAccessible() { } + EnumRoleAccessible(nsIContent* aContent, DocAccessible* aDoc, + a11y::role aRole); + virtual ~EnumRoleAccessible() { } NS_DECL_ISUPPORTS_INHERITED // Accessible - virtual mozilla::a11y::role NativeRole(); + virtual a11y::role NativeRole(); protected: - mozilla::a11y::role mRole; + a11y::role mRole; }; -#endif +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/src/generic/FormControlAccessible.cpp b/accessible/src/generic/FormControlAccessible.cpp index 42e1df7f92df..43a22e22b916 100644 --- a/accessible/src/generic/FormControlAccessible.cpp +++ b/accessible/src/generic/FormControlAccessible.cpp @@ -26,14 +26,14 @@ template class mozilla::a11y::ProgressMeterAccessible<100>; // nsISupports template -NS_IMPL_ADDREF_INHERITED(ProgressMeterAccessible, nsLeafAccessible) +NS_IMPL_ADDREF_INHERITED(ProgressMeterAccessible, LeafAccessible) template -NS_IMPL_RELEASE_INHERITED(ProgressMeterAccessible, nsLeafAccessible) +NS_IMPL_RELEASE_INHERITED(ProgressMeterAccessible, LeafAccessible) template NS_IMPL_QUERY_INTERFACE_INHERITED1(ProgressMeterAccessible, - nsLeafAccessible, + LeafAccessible, nsIAccessibleValue) //////////////////////////////////////////////////////////////////////////////// @@ -50,7 +50,7 @@ template PRUint64 ProgressMeterAccessible::NativeState() { - PRUint64 state = nsLeafAccessible::NativeState(); + PRUint64 state = LeafAccessible::NativeState(); // An undetermined progressbar (i.e. without a value) has a mixed state. nsAutoString attrValue; @@ -79,7 +79,7 @@ template void ProgressMeterAccessible::Value(nsString& aValue) { - nsLeafAccessible::Value(aValue); + LeafAccessible::Value(aValue); if (!aValue.IsEmpty()) return; @@ -105,7 +105,7 @@ template NS_IMETHODIMP ProgressMeterAccessible::GetMaximumValue(double* aMaximumValue) { - nsresult rv = nsLeafAccessible::GetMaximumValue(aMaximumValue); + nsresult rv = LeafAccessible::GetMaximumValue(aMaximumValue); if (rv != NS_OK_NO_ARIA_VALUE) return rv; @@ -124,7 +124,7 @@ template NS_IMETHODIMP ProgressMeterAccessible::GetMinimumValue(double* aMinimumValue) { - nsresult rv = nsLeafAccessible::GetMinimumValue(aMinimumValue); + nsresult rv = LeafAccessible::GetMinimumValue(aMinimumValue); if (rv != NS_OK_NO_ARIA_VALUE) return rv; @@ -136,7 +136,7 @@ template NS_IMETHODIMP ProgressMeterAccessible::GetMinimumIncrement(double* aMinimumIncrement) { - nsresult rv = nsLeafAccessible::GetMinimumIncrement(aMinimumIncrement); + nsresult rv = LeafAccessible::GetMinimumIncrement(aMinimumIncrement); if (rv != NS_OK_NO_ARIA_VALUE) return rv; @@ -148,7 +148,7 @@ template NS_IMETHODIMP ProgressMeterAccessible::GetCurrentValue(double* aCurrentValue) { - nsresult rv = nsLeafAccessible::GetCurrentValue(aCurrentValue); + nsresult rv = LeafAccessible::GetCurrentValue(aCurrentValue); if (rv != NS_OK_NO_ARIA_VALUE) return rv; @@ -181,7 +181,7 @@ ProgressMeterAccessible::SetCurrentValue(double aValue) RadioButtonAccessible:: RadioButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } diff --git a/accessible/src/generic/FormControlAccessible.h b/accessible/src/generic/FormControlAccessible.h index df105548d3d2..6ff685621280 100644 --- a/accessible/src/generic/FormControlAccessible.h +++ b/accessible/src/generic/FormControlAccessible.h @@ -6,7 +6,7 @@ #ifndef MOZILLA_A11Y_FormControlAccessible_H_ #define MOZILLA_A11Y_FormControlAccessible_H_ -#include "nsBaseWidgetAccessible.h" +#include "BaseAccessibles.h" namespace mozilla { namespace a11y { @@ -15,11 +15,11 @@ namespace a11y { * Generic class used for progress meters. */ template -class ProgressMeterAccessible : public nsLeafAccessible +class ProgressMeterAccessible : public LeafAccessible { public: ProgressMeterAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } @@ -38,7 +38,7 @@ public: /** * Generic class used for radio buttons. */ -class RadioButtonAccessible : public nsLeafAccessible +class RadioButtonAccessible : public LeafAccessible { public: diff --git a/accessible/src/generic/ImageAccessible.cpp b/accessible/src/generic/ImageAccessible.cpp index 2672d46337bf..bcc0f5a7513a 100644 --- a/accessible/src/generic/ImageAccessible.cpp +++ b/accessible/src/generic/ImageAccessible.cpp @@ -30,7 +30,7 @@ using namespace mozilla::a11y; ImageAccessible:: ImageAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLinkableAccessible(aContent, aDoc) + LinkableAccessible(aContent, aDoc) { mFlags |= eImageAccessible; } @@ -47,7 +47,7 @@ ImageAccessible::NativeState() // The state is a bitfield, get our inherited state, then logically OR it with // states::ANIMATED if this is an animated image. - PRUint64 state = nsLinkableAccessible::NativeState(); + PRUint64 state = LinkableAccessible::NativeState(); nsCOMPtr content(do_QueryInterface(mContent)); nsCOMPtr imageRequest; @@ -104,7 +104,7 @@ ImageAccessible::NativeRole() PRUint8 ImageAccessible::ActionCount() { - PRUint8 actionCount = nsLinkableAccessible::ActionCount(); + PRUint8 actionCount = LinkableAccessible::ActionCount(); return HasLongDesc() ? actionCount + 1 : actionCount; } @@ -120,7 +120,7 @@ ImageAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) aName.AssignLiteral("showlongdesc"); return NS_OK; } - return nsLinkableAccessible::GetActionName(aIndex, aName); + return LinkableAccessible::GetActionName(aIndex, aName); } NS_IMETHODIMP @@ -131,7 +131,7 @@ ImageAccessible::DoAction(PRUint8 aIndex) // Get the long description uri and open in a new window. if (!IsLongDescIndex(aIndex)) - return nsLinkableAccessible::DoAction(aIndex); + return LinkableAccessible::DoAction(aIndex); nsCOMPtr uri = GetLongDescURI(); if (!uri) @@ -179,7 +179,7 @@ ImageAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes) if (IsDefunct()) return NS_ERROR_FAILURE; - nsresult rv = nsLinkableAccessible::GetAttributesInternal(aAttributes); + nsresult rv = LinkableAccessible::GetAttributesInternal(aAttributes); NS_ENSURE_SUCCESS(rv, rv); nsAutoString src; @@ -228,6 +228,6 @@ ImageAccessible::GetLongDescURI() const bool ImageAccessible::IsLongDescIndex(PRUint8 aIndex) { - return aIndex == nsLinkableAccessible::ActionCount(); + return aIndex == LinkableAccessible::ActionCount(); } diff --git a/accessible/src/generic/ImageAccessible.h b/accessible/src/generic/ImageAccessible.h index 2b2d8a59757a..6d1a1a324e0d 100644 --- a/accessible/src/generic/ImageAccessible.h +++ b/accessible/src/generic/ImageAccessible.h @@ -6,7 +6,7 @@ #ifndef mozilla_a11y_ImageAccessible_h__ #define mozilla_a11y_ImageAccessible_h__ -#include "nsBaseWidgetAccessible.h" +#include "BaseAccessibles.h" #include "nsIAccessibleImage.h" class nsGenericHTMLElement; @@ -19,7 +19,7 @@ namespace a11y { * - gets name, role * - support basic state */ -class ImageAccessible : public nsLinkableAccessible, +class ImageAccessible : public LinkableAccessible, public nsIAccessibleImage { public: diff --git a/accessible/src/generic/Makefile.in b/accessible/src/generic/Makefile.in index 3ab03031d832..7cd539288f2f 100644 --- a/accessible/src/generic/Makefile.in +++ b/accessible/src/generic/Makefile.in @@ -18,6 +18,7 @@ CPPSRCS = \ Accessible.cpp \ ApplicationAccessible.cpp \ ARIAGridAccessible.cpp \ + BaseAccessibles.cpp \ DocAccessible.cpp \ FormControlAccessible.cpp \ HyperTextAccessible.cpp \ diff --git a/accessible/src/generic/TextLeafAccessible.cpp b/accessible/src/generic/TextLeafAccessible.cpp index 37e6ffca98eb..f7108861e14d 100644 --- a/accessible/src/generic/TextLeafAccessible.cpp +++ b/accessible/src/generic/TextLeafAccessible.cpp @@ -17,7 +17,7 @@ using namespace mozilla::a11y; TextLeafAccessible:: TextLeafAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLinkableAccessible(aContent, aDoc) + LinkableAccessible(aContent, aDoc) { mFlags |= eTextLeafAccessible; } diff --git a/accessible/src/generic/TextLeafAccessible.h b/accessible/src/generic/TextLeafAccessible.h index ef7bd531efb4..4327dbbf08fb 100644 --- a/accessible/src/generic/TextLeafAccessible.h +++ b/accessible/src/generic/TextLeafAccessible.h @@ -6,7 +6,7 @@ #ifndef mozilla_a11y_TextLeafAccessible_h__ #define mozilla_a11y_TextLeafAccessible_h__ -#include "nsBaseWidgetAccessible.h" +#include "BaseAccessibles.h" namespace mozilla { namespace a11y { @@ -14,7 +14,7 @@ namespace a11y { /** * Generic class used for text nodes. */ -class TextLeafAccessible : public nsLinkableAccessible +class TextLeafAccessible : public LinkableAccessible { public: TextLeafAccessible(nsIContent* aContent, DocAccessible* aDoc); diff --git a/accessible/src/html/HTMLElementAccessibles.h b/accessible/src/html/HTMLElementAccessibles.h index ad41e491ed4c..f7ec7e35fc61 100644 --- a/accessible/src/html/HTMLElementAccessibles.h +++ b/accessible/src/html/HTMLElementAccessibles.h @@ -6,8 +6,8 @@ #ifndef mozilla_a11y_HTMLElementAccessibles_h__ #define mozilla_a11y_HTMLElementAccessibles_h__ +#include "BaseAccessibles.h" #include "nsAutoPtr.h" -#include "nsBaseWidgetAccessible.h" namespace mozilla { namespace a11y { @@ -15,12 +15,12 @@ namespace a11y { /** * Used for HTML hr element. */ -class HTMLHRAccessible : public nsLeafAccessible +class HTMLHRAccessible : public LeafAccessible { public: HTMLHRAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) {}; + LeafAccessible(aContent, aDoc) {}; // Accessible virtual a11y::role NativeRole(); @@ -29,12 +29,12 @@ public: /** * Used for HTML br element. */ -class HTMLBRAccessible : public nsLeafAccessible +class HTMLBRAccessible : public LeafAccessible { public: HTMLBRAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) {}; + LeafAccessible(aContent, aDoc) {}; // Accessible virtual nsresult GetNameInternal(nsAString& aName); diff --git a/accessible/src/html/HTMLFormControlAccessible.cpp b/accessible/src/html/HTMLFormControlAccessible.cpp index 0853943c898b..f51f0c372012 100644 --- a/accessible/src/html/HTMLFormControlAccessible.cpp +++ b/accessible/src/html/HTMLFormControlAccessible.cpp @@ -43,7 +43,7 @@ using namespace mozilla::a11y; HTMLCheckboxAccessible:: HTMLCheckboxAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } @@ -91,7 +91,7 @@ HTMLCheckboxAccessible::DoAction(PRUint8 aIndex) PRUint64 HTMLCheckboxAccessible::NativeState() { - PRUint64 state = nsLeafAccessible::NativeState(); + PRUint64 state = LeafAccessible::NativeState(); state |= states::CHECKABLE; bool checkState = false; // Radio buttons and check boxes can be checked or mixed diff --git a/accessible/src/html/HTMLFormControlAccessible.h b/accessible/src/html/HTMLFormControlAccessible.h index 21f9f6329ffd..d8a638e7733a 100644 --- a/accessible/src/html/HTMLFormControlAccessible.h +++ b/accessible/src/html/HTMLFormControlAccessible.h @@ -20,7 +20,7 @@ typedef ProgressMeterAccessible<1> HTMLProgressMeterAccessible; /** * Accessible for HTML input@type="checkbox". */ -class HTMLCheckboxAccessible : public nsLeafAccessible +class HTMLCheckboxAccessible : public LeafAccessible { public: diff --git a/accessible/src/html/HTMLListAccessible.cpp b/accessible/src/html/HTMLListAccessible.cpp index 003a1b81e7d6..6d5211f98cf9 100644 --- a/accessible/src/html/HTMLListAccessible.cpp +++ b/accessible/src/html/HTMLListAccessible.cpp @@ -188,7 +188,7 @@ HTMLListBulletAccessible::NativeRole() PRUint64 HTMLListBulletAccessible::NativeState() { - return nsLeafAccessible::NativeState() | states::READONLY; + return LeafAccessible::NativeState() | states::READONLY; } void diff --git a/accessible/src/html/HTMLListAccessible.h b/accessible/src/html/HTMLListAccessible.h index fb4e3ad32f2e..a913cf32ca59 100644 --- a/accessible/src/html/HTMLListAccessible.h +++ b/accessible/src/html/HTMLListAccessible.h @@ -7,8 +7,8 @@ #ifndef mozilla_a11y_HTMLListAccessible_h__ #define mozilla_a11y_HTMLListAccessible_h__ +#include "BaseAccessibles.h" #include "HyperTextAccessibleWrap.h" -#include "nsBaseWidgetAccessible.h" namespace mozilla { namespace a11y { @@ -72,11 +72,11 @@ private: /** * Used for bullet of HTML list item element (for example, HTML li). */ -class HTMLListBulletAccessible : public nsLeafAccessible +class HTMLListBulletAccessible : public LeafAccessible { public: HTMLListBulletAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) { } + LeafAccessible(aContent, aDoc) { } virtual ~HTMLListBulletAccessible() { } // nsAccessNode diff --git a/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp b/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp index f839c36933a7..18fd7b7fb738 100644 --- a/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp +++ b/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp @@ -65,8 +65,8 @@ nsHTMLWin32ObjectOwnerAccessible::CacheChildren() // nsHTMLWin32ObjectAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLWin32ObjectAccessible::nsHTMLWin32ObjectAccessible(void* aHwnd): -nsLeafAccessible(nsnull, nsnull) +nsHTMLWin32ObjectAccessible::nsHTMLWin32ObjectAccessible(void* aHwnd) : + LeafAccessible(nsnull, nsnull) { // XXX: Mark it as defunct to make sure no single Accessible method is // running on it. We need to allow accessible without DOM nodes. diff --git a/accessible/src/msaa/nsHTMLWin32ObjectAccessible.h b/accessible/src/msaa/nsHTMLWin32ObjectAccessible.h index 69e0d55cade5..1f20ff5e48fb 100644 --- a/accessible/src/msaa/nsHTMLWin32ObjectAccessible.h +++ b/accessible/src/msaa/nsHTMLWin32ObjectAccessible.h @@ -6,7 +6,7 @@ #ifndef _nsHTMLWin32ObjectAccessible_H_ #define _nsHTMLWin32ObjectAccessible_H_ -#include "nsBaseWidgetAccessible.h" +#include "BaseAccessibles.h" struct IAccessible; @@ -48,11 +48,11 @@ protected: * object returned by us in Accessible::NewAccessible() that gets the IAccessible * from the windows system from the window handle. */ -class nsHTMLWin32ObjectAccessible : public nsLeafAccessible +class nsHTMLWin32ObjectAccessible : public mozilla::a11y::LeafAccessible { public: - nsHTMLWin32ObjectAccessible(void *aHwnd); + nsHTMLWin32ObjectAccessible(void* aHwnd); virtual ~nsHTMLWin32ObjectAccessible() {} NS_DECL_ISUPPORTS_INHERITED diff --git a/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp b/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp index c66f76cc5426..e701934c9e59 100644 --- a/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp +++ b/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp @@ -17,7 +17,7 @@ using namespace mozilla::a11y; nsXFormsDropmarkerWidgetAccessible:: nsXFormsDropmarkerWidgetAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } diff --git a/accessible/src/xforms/nsXFormsWidgetsAccessible.h b/accessible/src/xforms/nsXFormsWidgetsAccessible.h index 4673bfbe7e32..807dfc95380f 100644 --- a/accessible/src/xforms/nsXFormsWidgetsAccessible.h +++ b/accessible/src/xforms/nsXFormsWidgetsAccessible.h @@ -6,15 +6,15 @@ #ifndef _nsXFormsWidgetsAccessible_H_ #define _nsXFormsWidgetsAccessible_H_ +#include "BaseAccessibles.h" #include "nsXFormsAccessible.h" -#include "nsBaseWidgetAccessible.h" /** * Accessible object for dropmarker widget that is used inside xforms elements * of combobox representation. For example, these are xforms:select1, * xforms:input[type="xsd:date"]. */ -class nsXFormsDropmarkerWidgetAccessible : public nsLeafAccessible, +class nsXFormsDropmarkerWidgetAccessible : public mozilla::a11y::LeafAccessible, public nsXFormsAccessibleBase { public: diff --git a/accessible/src/xul/XULFormControlAccessible.cpp b/accessible/src/xul/XULFormControlAccessible.cpp index 6315c0bc8658..071c98090e94 100644 --- a/accessible/src/xul/XULFormControlAccessible.cpp +++ b/accessible/src/xul/XULFormControlAccessible.cpp @@ -239,7 +239,7 @@ XULButtonAccessible::ContainsMenu() XULDropmarkerAccessible:: XULDropmarkerAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } @@ -323,7 +323,7 @@ XULDropmarkerAccessible::NativeState() XULCheckboxAccessible:: XULCheckboxAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } @@ -376,7 +376,7 @@ XULCheckboxAccessible::NativeState() { // Possible states: focused, focusable, unavailable(disabled), checked // Get focus and disable status from base class - PRUint64 state = nsLeafAccessible::NativeState(); + PRUint64 state = LeafAccessible::NativeState(); state |= states::CHECKABLE; @@ -468,7 +468,7 @@ XULRadioButtonAccessible:: PRUint64 XULRadioButtonAccessible::NativeState() { - PRUint64 state = nsLeafAccessible::NativeState(); + PRUint64 state = LeafAccessible::NativeState(); state |= states::CHECKABLE; nsCOMPtr radioButton = @@ -659,7 +659,7 @@ XULToolbarAccessible::GetNameInternal(nsAString& aName) XULToolbarSeparatorAccessible:: XULToolbarSeparatorAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } diff --git a/accessible/src/xul/XULFormControlAccessible.h b/accessible/src/xul/XULFormControlAccessible.h index 195945e7f065..e07db17d189f 100644 --- a/accessible/src/xul/XULFormControlAccessible.h +++ b/accessible/src/xul/XULFormControlAccessible.h @@ -23,7 +23,7 @@ typedef ProgressMeterAccessible<100> XULProgressMeterAccessible; /** * Used for XUL button. * - * @note Don't inherit from nsLeafAccessible - it doesn't allow children + * @note Don't inherit from LeafAccessible - it doesn't allow children * and a button can have a dropmarker child. */ class XULButtonAccessible : public AccessibleWrap @@ -65,7 +65,7 @@ protected: /** * Used for XUL checkbox element. */ -class XULCheckboxAccessible : public nsLeafAccessible +class XULCheckboxAccessible : public LeafAccessible { public: enum { eAction_Click = 0 }; @@ -86,7 +86,7 @@ public: /** * Used for XUL dropmarker element. */ -class XULDropmarkerAccessible : public nsLeafAccessible +class XULDropmarkerAccessible : public LeafAccessible { public: enum { eAction_Click = 0 }; @@ -200,7 +200,7 @@ public: /** * Used for XUL toolbarseparator element. */ -class XULToolbarSeparatorAccessible : public nsLeafAccessible +class XULToolbarSeparatorAccessible : public LeafAccessible { public: XULToolbarSeparatorAccessible(nsIContent* aContent, diff --git a/accessible/src/xul/nsXULListboxAccessible.cpp b/accessible/src/xul/nsXULListboxAccessible.cpp index 76a88527c425..da1f1093c98c 100644 --- a/accessible/src/xul/nsXULListboxAccessible.cpp +++ b/accessible/src/xul/nsXULListboxAccessible.cpp @@ -52,7 +52,7 @@ nsXULColumAccessible::NativeState() nsXULColumnItemAccessible:: nsXULColumnItemAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } diff --git a/accessible/src/xul/nsXULListboxAccessible.h b/accessible/src/xul/nsXULListboxAccessible.h index 655ee504464d..84dec8d67318 100644 --- a/accessible/src/xul/nsXULListboxAccessible.h +++ b/accessible/src/xul/nsXULListboxAccessible.h @@ -5,9 +5,8 @@ #ifndef __nsXULListboxAccessible_h__ #define __nsXULListboxAccessible_h__ -#include "nsCOMPtr.h" +#include "BaseAccessibles.h" #include "nsXULMenuAccessible.h" -#include "nsBaseWidgetAccessible.h" #include "nsIAccessibleTable.h" #include "TableAccessible.h" #include "xpcAccessibleTable.h" @@ -33,7 +32,7 @@ public: * nsXULColumnAccessible are accessibles for list and tree column elements * (xul:listcol and xul:treecol). */ -class nsXULColumnItemAccessible : public nsLeafAccessible +class nsXULColumnItemAccessible : public mozilla::a11y::LeafAccessible { public: nsXULColumnItemAccessible(nsIContent* aContent, DocAccessible* aDoc); diff --git a/accessible/src/xul/nsXULTabAccessible.h b/accessible/src/xul/nsXULTabAccessible.h index 9e8fb925eb95..e350664941d0 100644 --- a/accessible/src/xul/nsXULTabAccessible.h +++ b/accessible/src/xul/nsXULTabAccessible.h @@ -7,7 +7,6 @@ #define _nsXULTabAccessible_H_ // NOTE: alphabetically ordered -#include "nsBaseWidgetAccessible.h" #include "nsXULMenuAccessible.h" #include "XULSelectControlAccessible.h" diff --git a/accessible/src/xul/nsXULTextAccessible.cpp b/accessible/src/xul/nsXULTextAccessible.cpp index 0f115467aec0..d8cc8f973e16 100644 --- a/accessible/src/xul/nsXULTextAccessible.cpp +++ b/accessible/src/xul/nsXULTextAccessible.cpp @@ -7,8 +7,8 @@ #include "nsXULTextAccessible.h" #include "Accessible-inl.h" +#include "BaseAccessibles.h" #include "nsAccUtils.h" -#include "nsBaseWidgetAccessible.h" #include "nsCoreUtils.h" #include "nsTextEquivUtils.h" #include "Relation.h" @@ -80,14 +80,14 @@ nsXULTextAccessible::RelationByType(PRUint32 aType) nsXULTooltipAccessible:: nsXULTooltipAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) + LeafAccessible(aContent, aDoc) { } PRUint64 nsXULTooltipAccessible::NativeState() { - return nsLeafAccessible::NativeState() | states::READONLY; + return LeafAccessible::NativeState() | states::READONLY; } role diff --git a/accessible/src/xul/nsXULTextAccessible.h b/accessible/src/xul/nsXULTextAccessible.h index 1d83ca3621a4..3479f5eef7cf 100644 --- a/accessible/src/xul/nsXULTextAccessible.h +++ b/accessible/src/xul/nsXULTextAccessible.h @@ -6,8 +6,8 @@ #ifndef _nsXULTextAccessible_H_ #define _nsXULTextAccessible_H_ +#include "BaseAccessibles.h" #include "HyperTextAccessibleWrap.h" -#include "nsBaseWidgetAccessible.h" /** * Used for XUL description and label elements. @@ -27,7 +27,7 @@ public: /** * Used for XUL tooltip element. */ -class nsXULTooltipAccessible : public nsLeafAccessible +class nsXULTooltipAccessible : public mozilla::a11y::LeafAccessible { public: diff --git a/accessible/src/xul/nsXULTreeGridAccessible.cpp b/accessible/src/xul/nsXULTreeGridAccessible.cpp index 19a33f4d75b8..eba2470d177c 100644 --- a/accessible/src/xul/nsXULTreeGridAccessible.cpp +++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp @@ -719,7 +719,7 @@ nsXULTreeGridCellAccessible:: nsXULTreeGridRowAccessible* aRowAcc, nsITreeBoxObject* aTree, nsITreeView* aTreeView, PRInt32 aRow, nsITreeColumn* aColumn) : - nsLeafAccessible(aContent, aDoc), mTree(aTree), + LeafAccessible(aContent, aDoc), mTree(aTree), mTreeView(aTreeView), mRow(aRow), mColumn(aColumn) { mParent = aRowAcc; @@ -731,13 +731,13 @@ nsXULTreeGridCellAccessible:: NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeGridCellAccessible) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeGridCellAccessible, - nsLeafAccessible) + LeafAccessible) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTree) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mColumn) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeGridCellAccessible, - nsLeafAccessible) + LeafAccessible) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTree) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mColumn) NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -746,9 +746,9 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULTreeGridCellAccessible) NS_INTERFACE_TABLE_INHERITED2(nsXULTreeGridCellAccessible, nsIAccessibleTableCell, nsXULTreeGridCellAccessible) -NS_INTERFACE_TABLE_TAIL_INHERITING(nsLeafAccessible) -NS_IMPL_ADDREF_INHERITED(nsXULTreeGridCellAccessible, nsLeafAccessible) -NS_IMPL_RELEASE_INHERITED(nsXULTreeGridCellAccessible, nsLeafAccessible) +NS_INTERFACE_TABLE_TAIL_INHERITING(LeafAccessible) +NS_IMPL_ADDREF_INHERITED(nsXULTreeGridCellAccessible, LeafAccessible) +NS_IMPL_RELEASE_INHERITED(nsXULTreeGridCellAccessible, LeafAccessible) //////////////////////////////////////////////////////////////////////////////// // nsXULTreeGridCellAccessible: nsIAccessible implementation @@ -1029,7 +1029,7 @@ nsXULTreeGridCellAccessible::IsSelected(bool *aIsSelected) bool nsXULTreeGridCellAccessible::Init() { - if (!nsLeafAccessible::Init() || !mTreeView) + if (!LeafAccessible::Init() || !mTreeView) return false; PRInt16 type; diff --git a/accessible/src/xul/nsXULTreeGridAccessible.h b/accessible/src/xul/nsXULTreeGridAccessible.h index 1cf8ce250369..a46f56befd62 100644 --- a/accessible/src/xul/nsXULTreeGridAccessible.h +++ b/accessible/src/xul/nsXULTreeGridAccessible.h @@ -104,7 +104,7 @@ protected: { 0xa9, 0x32, 0x4c, 0x5c, 0xa5, 0xde, 0x5d, 0xff } \ } -class nsXULTreeGridCellAccessible : public nsLeafAccessible, +class nsXULTreeGridCellAccessible : public mozilla::a11y::LeafAccessible, public nsIAccessibleTableCell { public: @@ -117,12 +117,12 @@ public: // nsISupports NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeGridCellAccessible, - nsLeafAccessible) + LeafAccessible) // nsIAccessible - NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY, - PRInt32 *aWidth, PRInt32 *aHeight); + NS_IMETHOD GetBounds(PRInt32* aX, PRInt32* aY, + PRInt32* aWidth, PRInt32* aHeight); NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); NS_IMETHOD DoAction(PRUint8 aIndex); @@ -137,7 +137,7 @@ public: // Accessible virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual Accessible* FocusedChild(); - virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); + virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes); virtual PRInt32 IndexInParent() const; virtual Relation RelationByType(PRUint32 aType); virtual mozilla::a11y::role NativeRole(); @@ -164,8 +164,8 @@ public: protected: // Accessible virtual Accessible* GetSiblingAtOffset(PRInt32 aOffset, - nsresult *aError = nsnull) const; - virtual void DispatchClickEvent(nsIContent *aContent, PRUint32 aActionIndex); + nsresult* aError = nsnull) const; + virtual void DispatchClickEvent(nsIContent* aContent, PRUint32 aActionIndex); // nsXULTreeGridCellAccessible From 9add19ecba65a4fa00ed7e18862a174a949793e0 Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Mon, 4 Jun 2012 08:32:34 -0400 Subject: [PATCH 04/53] Bug 760755 - de-ns-ify nsHTMLImageMapAccessible, r=surkov --HG-- rename : accessible/src/html/nsHTMLImageMapAccessible.cpp => accessible/src/html/HTMLImageMapAccessible.cpp rename : accessible/src/html/nsHTMLImageMapAccessible.h => accessible/src/html/HTMLImageMapAccessible.h --- .../src/base/nsAccessibilityService.cpp | 10 +-- accessible/src/generic/Accessible.h | 6 +- ...essible.cpp => HTMLImageMapAccessible.cpp} | 66 +++++++++---------- ...pAccessible.h => HTMLImageMapAccessible.h} | 44 +++++++------ accessible/src/html/Makefile.in | 2 +- 5 files changed, 66 insertions(+), 62 deletions(-) rename accessible/src/html/{nsHTMLImageMapAccessible.cpp => HTMLImageMapAccessible.cpp} (78%) rename accessible/src/html/{nsHTMLImageMapAccessible.h => HTMLImageMapAccessible.h} (73%) diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 1f9b4d61cd41..9767d2a12d27 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -15,6 +15,7 @@ #include "DocAccessible-inl.h" #include "FocusManager.h" #include "HTMLElementAccessibles.h" +#include "HTMLImageMapAccessible.h" #include "HTMLListAccessible.h" #include "HyperTextAccessibleWrap.h" #include "nsAccessiblePivot.h" @@ -22,7 +23,6 @@ #include "nsARIAMap.h" #include "nsIAccessibleProvider.h" #include "nsHTMLCanvasAccessible.h" -#include "nsHTMLImageMapAccessible.h" #include "nsHTMLLinkAccessible.h" #include "nsHTMLSelectAccessible.h" #include "nsHTMLTableAccessibleWrap.h" @@ -170,7 +170,7 @@ nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell, } return nsnull; } - + already_AddRefed nsAccessibilityService::CreateOuterDocAccessible(nsIContent* aContent, nsIPresShell* aPresShell) @@ -266,7 +266,7 @@ nsAccessibilityService::CreateHTMLImageMapAccessible(nsIContent* aContent, nsIPresShell* aPresShell) { Accessible* accessible = - new nsHTMLImageMapAccessible(aContent, GetDocAccessible(aPresShell)); + new HTMLImageMapAccessible(aContent, GetDocAccessible(aPresShell)); NS_ADDREF(accessible); return accessible; } @@ -562,7 +562,7 @@ nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame) Accessible* accessible = document->GetAccessible(aImageFrame->GetContent()); if (accessible) { - nsHTMLImageMapAccessible* imageMap = accessible->AsImageMap(); + HTMLImageMapAccessible* imageMap = accessible->AsImageMap(); if (imageMap) { imageMap->UpdateChildAreas(); return; @@ -1015,7 +1015,7 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode, // map rect is empty then it is used for links grouping. Otherwise it should // be used in conjunction with HTML image element and in this case we don't // create any accessible for it and don't walk into it. The accessibles for - // HTML area (nsHTMLAreaAccessible) the map contains are attached as + // HTML area (HTMLAreaAccessible) the map contains are attached as // children of the appropriate accessible for HTML image // (ImageAccessible). if (nsLayoutUtils::GetAllInFlowRectsUnion(weakFrame, diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index 7510b44aee2d..7e6619ca40b3 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -27,13 +27,13 @@ class EmbeddedObjCollector; class KeyBinding; class Accessible; class HyperTextAccessible; -class nsHTMLImageMapAccessible; struct nsRoleMapEntry; class Relation; namespace mozilla { namespace a11y { +class HTMLImageMapAccessible; class HTMLLIAccessible; class ImageAccessible; class TableAccessible; @@ -504,7 +504,7 @@ public: mozilla::a11y::ImageAccessible* AsImage(); bool IsImageMapAccessible() const { return mFlags & eImageMapAccessible; } - nsHTMLImageMapAccessible* AsImageMap(); + mozilla::a11y::HTMLImageMapAccessible* AsImageMap(); inline bool IsXULTree() const { return mFlags & eXULTreeAccessible; } nsXULTreeAccessible* AsXULTree(); @@ -879,7 +879,7 @@ protected: nsAutoPtr mGroupInfo; friend class AccGroupInfo; - + /** * Non-null indicates author-supplied role; possibly state & value as well */ diff --git a/accessible/src/html/nsHTMLImageMapAccessible.cpp b/accessible/src/html/HTMLImageMapAccessible.cpp similarity index 78% rename from accessible/src/html/nsHTMLImageMapAccessible.cpp rename to accessible/src/html/HTMLImageMapAccessible.cpp index 45af987f8c0e..d90bb1625aa7 100644 --- a/accessible/src/html/nsHTMLImageMapAccessible.cpp +++ b/accessible/src/html/HTMLImageMapAccessible.cpp @@ -3,7 +3,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/. */ -#include "nsHTMLImageMapAccessible.h" +#include "HTMLImageMapAccessible.h" #include "nsAccUtils.h" #include "nsARIAMap.h" @@ -21,47 +21,47 @@ using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible +// HTMLImageMapAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLImageMapAccessible:: - nsHTMLImageMapAccessible(nsIContent* aContent, DocAccessible* aDoc) : +HTMLImageMapAccessible:: + HTMLImageMapAccessible(nsIContent* aContent, DocAccessible* aDoc) : ImageAccessibleWrap(aContent, aDoc) { mFlags |= eImageMapAccessible; } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: nsISupports +// HTMLImageMapAccessible: nsISupports -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLImageMapAccessible, ImageAccessible) +NS_IMPL_ISUPPORTS_INHERITED0(HTMLImageMapAccessible, ImageAccessible) //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: Accessible public +// HTMLImageMapAccessible: Accessible public role -nsHTMLImageMapAccessible::NativeRole() +HTMLImageMapAccessible::NativeRole() { return roles::IMAGE_MAP; } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: HyperLinkAccessible +// HTMLImageMapAccessible: HyperLinkAccessible PRUint32 -nsHTMLImageMapAccessible::AnchorCount() +HTMLImageMapAccessible::AnchorCount() { return ChildCount(); } Accessible* -nsHTMLImageMapAccessible::AnchorAt(PRUint32 aAnchorIndex) +HTMLImageMapAccessible::AnchorAt(PRUint32 aAnchorIndex) { return GetChildAt(aAnchorIndex); } already_AddRefed -nsHTMLImageMapAccessible::AnchorURIAt(PRUint32 aAnchorIndex) +HTMLImageMapAccessible::AnchorURIAt(PRUint32 aAnchorIndex) { Accessible* area = GetChildAt(aAnchorIndex); if (!area) @@ -72,10 +72,10 @@ nsHTMLImageMapAccessible::AnchorURIAt(PRUint32 aAnchorIndex) } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: public +// HTMLImageMapAccessible: public void -nsHTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) +HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) { nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame()); @@ -108,7 +108,7 @@ nsHTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) Accessible* area = mChildren.SafeElementAt(idx); if (!area || area->GetContent() != areaContent) { - nsRefPtr area = new nsHTMLAreaAccessible(areaContent, mDoc); + nsRefPtr area = new HTMLAreaAccessible(areaContent, mDoc); if (!mDoc->BindToDocument(area, aria::GetRoleMap(areaContent))) break; @@ -135,30 +135,30 @@ nsHTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: Accessible protected +// HTMLImageMapAccessible: Accessible protected void -nsHTMLImageMapAccessible::CacheChildren() +HTMLImageMapAccessible::CacheChildren() { UpdateChildAreas(false); } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLAreaAccessible +// HTMLAreaAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLAreaAccessible:: - nsHTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc) : +HTMLAreaAccessible:: + HTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc) : nsHTMLLinkAccessible(aContent, aDoc) { } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLAreaAccessible: nsIAccessible +// HTMLAreaAccessible: nsIAccessible nsresult -nsHTMLAreaAccessible::GetNameInternal(nsAString & aName) +HTMLAreaAccessible::GetNameInternal(nsAString & aName) { nsresult rv = Accessible::GetNameInternal(aName); NS_ENSURE_SUCCESS(rv, rv); @@ -173,7 +173,7 @@ nsHTMLAreaAccessible::GetNameInternal(nsAString & aName) } void -nsHTMLAreaAccessible::Description(nsString& aDescription) +HTMLAreaAccessible::Description(nsString& aDescription) { aDescription.Truncate(); @@ -184,10 +184,10 @@ nsHTMLAreaAccessible::Description(nsString& aDescription) } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLAreaAccessible: nsAccessNode public +// HTMLAreaAccessible: nsAccessNode public bool -nsHTMLAreaAccessible::IsPrimaryForNode() const +HTMLAreaAccessible::IsPrimaryForNode() const { // Make HTML area DOM element not accessible. HTML image map accessible // manages its tree itself. @@ -195,10 +195,10 @@ nsHTMLAreaAccessible::IsPrimaryForNode() const } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLAreaAccessible: Accessible public +// HTMLAreaAccessible: Accessible public Accessible* -nsHTMLAreaAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, +HTMLAreaAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, EWhichChildAtPoint aWhichChild) { // Don't walk into area accessibles. @@ -206,10 +206,10 @@ nsHTMLAreaAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: HyperLinkAccessible +// HTMLImageMapAccessible: HyperLinkAccessible PRUint32 -nsHTMLAreaAccessible::StartOffset() +HTMLAreaAccessible::StartOffset() { // Image map accessible is not hypertext accessible therefore // StartOffset/EndOffset implementations of Accessible doesn't work here. @@ -220,22 +220,22 @@ nsHTMLAreaAccessible::StartOffset() } PRUint32 -nsHTMLAreaAccessible::EndOffset() +HTMLAreaAccessible::EndOffset() { return IndexInParent() + 1; } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLAreaAccessible: Accessible protected +// HTMLAreaAccessible: Accessible protected void -nsHTMLAreaAccessible::CacheChildren() +HTMLAreaAccessible::CacheChildren() { // No children for aria accessible. } void -nsHTMLAreaAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame) +HTMLAreaAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame) { nsIFrame* frame = GetFrame(); if (!frame) diff --git a/accessible/src/html/nsHTMLImageMapAccessible.h b/accessible/src/html/HTMLImageMapAccessible.h similarity index 73% rename from accessible/src/html/nsHTMLImageMapAccessible.h rename to accessible/src/html/HTMLImageMapAccessible.h index 8c9a30c20e02..e730418a2c72 100644 --- a/accessible/src/html/nsHTMLImageMapAccessible.h +++ b/accessible/src/html/HTMLImageMapAccessible.h @@ -3,28 +3,30 @@ * 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 _nsHTMLAreaAccessible_H_ -#define _nsHTMLAreaAccessible_H_ +#ifndef mozilla_a11y_HTMLImageMapAccessible_h__ +#define mozilla_a11y_HTMLImageMapAccessible_h__ #include "ImageAccessibleWrap.h" #include "nsHTMLLinkAccessible.h" - #include "nsIDOMHTMLMapElement.h" +namespace mozilla { +namespace a11y { + /** * Used for HTML image maps. */ -class nsHTMLImageMapAccessible : public mozilla::a11y::ImageAccessibleWrap +class HTMLImageMapAccessible : public ImageAccessibleWrap { public: - nsHTMLImageMapAccessible(nsIContent* aContent, DocAccessible* aDoc); - virtual ~nsHTMLImageMapAccessible() { } + HTMLImageMapAccessible(nsIContent* aContent, DocAccessible* aDoc); + virtual ~HTMLImageMapAccessible() { } // nsISupports and cycle collector NS_DECL_ISUPPORTS_INHERITED // Accessible - virtual mozilla::a11y::role NativeRole(); + virtual a11y::role NativeRole(); // HyperLinkAccessible virtual PRUint32 AnchorCount(); @@ -42,25 +44,14 @@ protected: virtual void CacheChildren(); }; -//////////////////////////////////////////////////////////////////////////////// -// Accessible downcasting method - -inline nsHTMLImageMapAccessible* -Accessible::AsImageMap() -{ - return IsImageMapAccessible() ? - static_cast(this) : nsnull; -} - - /** * Accessible for image map areas - must be child of image. */ -class nsHTMLAreaAccessible : public nsHTMLLinkAccessible +class HTMLAreaAccessible : public nsHTMLLinkAccessible { public: - nsHTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc); + HTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc); // nsAccessNode virtual bool IsPrimaryForNode() const; @@ -82,4 +73,17 @@ protected: virtual void CacheChildren(); }; +} // namespace a11y +} // namespace mozilla + +//////////////////////////////////////////////////////////////////////////////// +// Accessible downcasting method + +inline mozilla::a11y::HTMLImageMapAccessible* +Accessible::AsImageMap() +{ + return IsImageMapAccessible() ? + static_cast(this) : nsnull; +} + #endif diff --git a/accessible/src/html/Makefile.in b/accessible/src/html/Makefile.in index b239d02be8ca..b3e1905a2278 100644 --- a/accessible/src/html/Makefile.in +++ b/accessible/src/html/Makefile.in @@ -19,9 +19,9 @@ LIBXUL_LIBRARY = 1 CPPSRCS = \ HTMLElementAccessibles.cpp \ HTMLFormControlAccessible.cpp \ + HTMLImageMapAccessible.cpp \ HTMLListAccessible.cpp \ nsHTMLCanvasAccessible.cpp \ - nsHTMLImageMapAccessible.cpp \ nsHTMLLinkAccessible.cpp \ nsHTMLSelectAccessible.cpp \ nsHTMLTableAccessible.cpp \ From fcec1569ca6630e62b13383d12bdab01fc7cfe3f Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Mon, 4 Jun 2012 08:32:38 -0400 Subject: [PATCH 05/53] Bug 760756 - de-ns-ify nsHTMLLinkAccessible, r=surkov --HG-- rename : accessible/src/html/nsHTMLLinkAccessible.cpp => accessible/src/html/HTMLLinkAccessible.cpp rename : accessible/src/html/nsHTMLLinkAccessible.h => accessible/src/html/HTMLLinkAccessible.h --- .../src/base/nsAccessibilityService.cpp | 10 +++--- .../src/html/HTMLImageMapAccessible.cpp | 6 ++-- accessible/src/html/HTMLImageMapAccessible.h | 4 +-- ...kAccessible.cpp => HTMLLinkAccessible.cpp} | 32 +++++++++---------- ...LLinkAccessible.h => HTMLLinkAccessible.h} | 18 +++++++---- accessible/src/html/Makefile.in | 2 +- .../tests/mochitest/states/test_aria.html | 2 +- .../tests/mochitest/value/test_general.html | 4 +-- 8 files changed, 42 insertions(+), 36 deletions(-) rename accessible/src/html/{nsHTMLLinkAccessible.cpp => HTMLLinkAccessible.cpp} (82%) rename accessible/src/html/{nsHTMLLinkAccessible.h => HTMLLinkAccessible.h} (74%) diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 9767d2a12d27..2eb59ebe1c78 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -16,6 +16,7 @@ #include "FocusManager.h" #include "HTMLElementAccessibles.h" #include "HTMLImageMapAccessible.h" +#include "HTMLLinkAccessible.h" #include "HTMLListAccessible.h" #include "HyperTextAccessibleWrap.h" #include "nsAccessiblePivot.h" @@ -23,7 +24,6 @@ #include "nsARIAMap.h" #include "nsIAccessibleProvider.h" #include "nsHTMLCanvasAccessible.h" -#include "nsHTMLLinkAccessible.h" #include "nsHTMLSelectAccessible.h" #include "nsHTMLTableAccessibleWrap.h" #include "nsXFormsFormControlsAccessible.h" @@ -1187,9 +1187,9 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode, // If no accessible, see if we need to create a generic accessible because // of some property that makes this object interesting - // We don't do this for , , , etc. which + // We don't do this for , , , etc. which // correspond to the doc accessible and will be created in any case - if (!newAcc && content->Tag() != nsGkAtoms::body && content->GetParent() && + if (!newAcc && content->Tag() != nsGkAtoms::body && content->GetParent() && ((weakFrame.GetFrame() && weakFrame.GetFrame()->IsFocusable()) || (isHTML && nsCoreUtils::HasClickListener(content)) || HasUniversalAriaProperty(content) || roleMapEntry || @@ -1623,7 +1623,7 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, } if (tag == nsGkAtoms::a) { - // Only some roles truly enjoy life as nsHTMLLinkAccessibles, for details + // Only some roles truly enjoy life as HTMLLinkAccessibles, for details // see closed bug 494807. nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent); if (roleMapEntry && roleMapEntry->role != roles::NOTHING && @@ -1633,7 +1633,7 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, return accessible; } - Accessible* accessible = new nsHTMLLinkAccessible(aContent, aDoc); + Accessible* accessible = new HTMLLinkAccessible(aContent, aDoc); NS_IF_ADDREF(accessible); return accessible; } diff --git a/accessible/src/html/HTMLImageMapAccessible.cpp b/accessible/src/html/HTMLImageMapAccessible.cpp index d90bb1625aa7..13e1178baefd 100644 --- a/accessible/src/html/HTMLImageMapAccessible.cpp +++ b/accessible/src/html/HTMLImageMapAccessible.cpp @@ -150,7 +150,7 @@ HTMLImageMapAccessible::CacheChildren() HTMLAreaAccessible:: HTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc) : - nsHTMLLinkAccessible(aContent, aDoc) + HTMLLinkAccessible(aContent, aDoc) { } @@ -158,7 +158,7 @@ HTMLAreaAccessible:: // HTMLAreaAccessible: nsIAccessible nsresult -HTMLAreaAccessible::GetNameInternal(nsAString & aName) +HTMLAreaAccessible::GetNameInternal(nsAString& aName) { nsresult rv = Accessible::GetNameInternal(aName); NS_ENSURE_SUCCESS(rv, rv); @@ -199,7 +199,7 @@ HTMLAreaAccessible::IsPrimaryForNode() const Accessible* HTMLAreaAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, - EWhichChildAtPoint aWhichChild) + EWhichChildAtPoint aWhichChild) { // Don't walk into area accessibles. return this; diff --git a/accessible/src/html/HTMLImageMapAccessible.h b/accessible/src/html/HTMLImageMapAccessible.h index e730418a2c72..d5da3f3f508d 100644 --- a/accessible/src/html/HTMLImageMapAccessible.h +++ b/accessible/src/html/HTMLImageMapAccessible.h @@ -6,8 +6,8 @@ #ifndef mozilla_a11y_HTMLImageMapAccessible_h__ #define mozilla_a11y_HTMLImageMapAccessible_h__ +#include "HTMLLinkAccessible.h" #include "ImageAccessibleWrap.h" -#include "nsHTMLLinkAccessible.h" #include "nsIDOMHTMLMapElement.h" namespace mozilla { @@ -47,7 +47,7 @@ protected: /** * Accessible for image map areas - must be child of image. */ -class HTMLAreaAccessible : public nsHTMLLinkAccessible +class HTMLAreaAccessible : public HTMLLinkAccessible { public: diff --git a/accessible/src/html/nsHTMLLinkAccessible.cpp b/accessible/src/html/HTMLLinkAccessible.cpp similarity index 82% rename from accessible/src/html/nsHTMLLinkAccessible.cpp rename to accessible/src/html/HTMLLinkAccessible.cpp index 0f8a58164fe3..0633a04a348d 100644 --- a/accessible/src/html/nsHTMLLinkAccessible.cpp +++ b/accessible/src/html/HTMLLinkAccessible.cpp @@ -3,7 +3,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/. */ -#include "nsHTMLLinkAccessible.h" +#include "HTMLLinkAccessible.h" #include "nsCoreUtils.h" #include "DocAccessible.h" @@ -17,36 +17,36 @@ using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// -// nsHTMLLinkAccessible +// HTMLLinkAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLLinkAccessible:: - nsHTMLLinkAccessible(nsIContent* aContent, DocAccessible* aDoc) : +HTMLLinkAccessible:: + HTMLLinkAccessible(nsIContent* aContent, DocAccessible* aDoc) : HyperTextAccessibleWrap(aContent, aDoc) { } // Expose nsIAccessibleHyperLink unconditionally -NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLLinkAccessible, HyperTextAccessibleWrap, +NS_IMPL_ISUPPORTS_INHERITED1(HTMLLinkAccessible, HyperTextAccessibleWrap, nsIAccessibleHyperLink) //////////////////////////////////////////////////////////////////////////////// // nsIAccessible role -nsHTMLLinkAccessible::NativeRole() +HTMLLinkAccessible::NativeRole() { return roles::LINK; } PRUint64 -nsHTMLLinkAccessible::NativeState() +HTMLLinkAccessible::NativeState() { return HyperTextAccessibleWrap::NativeState() & ~states::READONLY; } PRUint64 -nsHTMLLinkAccessible::NativeLinkState() const +HTMLLinkAccessible::NativeLinkState() const { nsEventStates eventState = mContent->AsElement()->State(); if (eventState.HasState(NS_EVENT_STATE_UNVISITED)) @@ -62,7 +62,7 @@ nsHTMLLinkAccessible::NativeLinkState() const } PRUint64 -nsHTMLLinkAccessible::NativeInteractiveState() const +HTMLLinkAccessible::NativeInteractiveState() const { PRUint64 state = HyperTextAccessibleWrap::NativeInteractiveState(); @@ -76,7 +76,7 @@ nsHTMLLinkAccessible::NativeInteractiveState() const } void -nsHTMLLinkAccessible::Value(nsString& aValue) +HTMLLinkAccessible::Value(nsString& aValue) { aValue.Truncate(); @@ -86,13 +86,13 @@ nsHTMLLinkAccessible::Value(nsString& aValue) } PRUint8 -nsHTMLLinkAccessible::ActionCount() +HTMLLinkAccessible::ActionCount() { return IsLinked() ? 1 : HyperTextAccessible::ActionCount(); } NS_IMETHODIMP -nsHTMLLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) +HTMLLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) { aName.Truncate(); @@ -108,7 +108,7 @@ nsHTMLLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) } NS_IMETHODIMP -nsHTMLLinkAccessible::DoAction(PRUint8 aIndex) +HTMLLinkAccessible::DoAction(PRUint8 aIndex) { if (!IsLinked()) return HyperTextAccessible::DoAction(aIndex); @@ -128,14 +128,14 @@ nsHTMLLinkAccessible::DoAction(PRUint8 aIndex) // HyperLinkAccessible bool -nsHTMLLinkAccessible::IsLink() +HTMLLinkAccessible::IsLink() { // Expose HyperLinkAccessible unconditionally. return true; } already_AddRefed -nsHTMLLinkAccessible::AnchorURIAt(PRUint32 aAnchorIndex) +HTMLLinkAccessible::AnchorURIAt(PRUint32 aAnchorIndex) { return aAnchorIndex == 0 ? mContent->GetHrefURI() : nsnull; } @@ -144,7 +144,7 @@ nsHTMLLinkAccessible::AnchorURIAt(PRUint32 aAnchorIndex) // Protected members bool -nsHTMLLinkAccessible::IsLinked() +HTMLLinkAccessible::IsLinked() { if (IsDefunct()) return false; diff --git a/accessible/src/html/nsHTMLLinkAccessible.h b/accessible/src/html/HTMLLinkAccessible.h similarity index 74% rename from accessible/src/html/nsHTMLLinkAccessible.h rename to accessible/src/html/HTMLLinkAccessible.h index 08984101e2e1..aa13bff49075 100644 --- a/accessible/src/html/nsHTMLLinkAccessible.h +++ b/accessible/src/html/HTMLLinkAccessible.h @@ -3,15 +3,18 @@ * 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 _nsHTMLLinkAccessible_H_ -#define _nsHTMLLinkAccessible_H_ +#ifndef mozilla_a11y_HTMLLinkAccessible_h__ +#define mozilla_a11y_HTMLLinkAccessible_h__ #include "HyperTextAccessibleWrap.h" -class nsHTMLLinkAccessible : public HyperTextAccessibleWrap +namespace mozilla { +namespace a11y { + +class HTMLLinkAccessible : public HyperTextAccessibleWrap { public: - nsHTMLLinkAccessible(nsIContent* aContent, DocAccessible* aDoc); + HTMLLinkAccessible(nsIContent* aContent, DocAccessible* aDoc); NS_DECL_ISUPPORTS_INHERITED @@ -21,7 +24,7 @@ public: // Accessible virtual void Value(nsString& aValue); - virtual mozilla::a11y::role NativeRole(); + virtual a11y::role NativeRole(); virtual PRUint64 NativeState(); virtual PRUint64 NativeLinkState() const; virtual PRUint64 NativeInteractiveState() const; @@ -42,4 +45,7 @@ protected: bool IsLinked(); }; -#endif +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/src/html/Makefile.in b/accessible/src/html/Makefile.in index b3e1905a2278..56d9a9c909c5 100644 --- a/accessible/src/html/Makefile.in +++ b/accessible/src/html/Makefile.in @@ -20,9 +20,9 @@ CPPSRCS = \ HTMLElementAccessibles.cpp \ HTMLFormControlAccessible.cpp \ HTMLImageMapAccessible.cpp \ + HTMLLinkAccessible.cpp \ HTMLListAccessible.cpp \ nsHTMLCanvasAccessible.cpp \ - nsHTMLLinkAccessible.cpp \ nsHTMLSelectAccessible.cpp \ nsHTMLTableAccessible.cpp \ $(NULL) diff --git a/accessible/tests/mochitest/states/test_aria.html b/accessible/tests/mochitest/states/test_aria.html index 08c1c7014d5c..b891931fa004 100644 --- a/accessible/tests/mochitest/states/test_aria.html +++ b/accessible/tests/mochitest/states/test_aria.html @@ -130,7 +130,7 @@ // // This section tests aria roles on links/anchors for underlying - // nsHTMLLinkAccessible creation. (see closed bug 494807) + // HTMLLinkAccessible creation. (see closed bug 494807) // // strong roles diff --git a/accessible/tests/mochitest/value/test_general.html b/accessible/tests/mochitest/value/test_general.html index 352cf679ed64..439c56afdda7 100644 --- a/accessible/tests/mochitest/value/test_general.html +++ b/accessible/tests/mochitest/value/test_general.html @@ -39,13 +39,13 @@ var rootDir = getRootDirectory(window.location.href); var href = getRootDirectory(window.location.href) + "foo"; - // roles that can't live as nsHTMLLinkAccessibles + // roles that can't live as HTMLLinkAccessibles testValue("aria_menuitem_link", ""); testValue("aria_button_link", ""); testValue("aria_checkbox_link", ""); testValue("aria_application_link", ""); - // roles that can live as nsHTMLLinkAccessibles + // roles that can live as HTMLLinkAccessibles testValue("aria_link_link", href); testValue("aria_main_link", href); testValue("aria_navigation_link", href); From 8afc14fa3f3a788a4d28b10f742c2298ab98b239 Mon Sep 17 00:00:00 2001 From: Lucas Rocha Date: Mon, 4 Jun 2012 16:32:38 +0200 Subject: [PATCH 06/53] Bug 761131 - Add reader button to all browser_toolbar.xml files (r=mfinkle) --- .../base/resources/layout-land-v14/browser_toolbar.xml | 7 +++++++ .../base/resources/layout-sw600dp/browser_toolbar.xml | 7 +++++++ .../base/resources/layout-xlarge/browser_toolbar.xml | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml b/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml index 459c79d716b5..217be33aa30d 100644 --- a/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml +++ b/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml @@ -93,6 +93,13 @@ android:layout_alignRight="@id/awesome_bar" android:orientation="horizontal"> + + + + + + Date: Mon, 4 Jun 2012 16:58:54 +0200 Subject: [PATCH 07/53] Bug 760152 - Start library decompression earlier. r=blassey --- mobile/android/base/GeckoApp.java | 11 ++++++++--- mobile/android/base/GeckoThread.java | 20 ++++++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 2757c7b75fc7..7e4444d1db40 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -1773,6 +1773,11 @@ abstract public class GeckoApp } GeckoAppShell.loadMozGlue(); + sGeckoThread = new GeckoThread(); + String uri = getURIFromIntent(getIntent()); + if (uri != null && uri.length() > 0 && !uri.equals("about:home")) + sGeckoThread.start(); + mMainHandler = new Handler(); Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onCreate"); @@ -1871,17 +1876,17 @@ abstract public class GeckoApp passedUri = "about:empty"; } - sGeckoThread = new GeckoThread(intent, passedUri, mRestoreMode); + sGeckoThread.init(intent, passedUri, mRestoreMode); if (!ACTION_DEBUG.equals(action) && checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched)) { - sGeckoThread.start(); + sGeckoThread.reallyStart(); } else if (ACTION_DEBUG.equals(action) && checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitForDebugger)) { mMainHandler.postDelayed(new Runnable() { public void run() { Log.i(LOGTAG, "Launching from debug intent after 5s wait"); setLaunchState(LaunchState.Launching); - sGeckoThread.start(); + sGeckoThread.reallyStart(); } }, 1000 * 5 /* 5 seconds */); Log.i(LOGTAG, "Intent : ACTION_DEBUG - waiting 5s before launching"); diff --git a/mobile/android/base/GeckoThread.java b/mobile/android/base/GeckoThread.java index 732b9958b22d..5ced67ff03ed 100644 --- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -18,6 +18,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.Date; import java.util.Locale; +import java.util.concurrent.CountDownLatch; public class GeckoThread extends Thread { private static final String LOGTAG = "GeckoThread"; @@ -25,13 +26,23 @@ public class GeckoThread extends Thread { Intent mIntent; String mUri; int mRestoreMode; + CountDownLatch mStartSignal; - GeckoThread(Intent intent, String uri, int restoreMode) { + GeckoThread() { + mStartSignal = new CountDownLatch(1); + setName("Gecko"); + } + + public void init(Intent intent, String uri, int restoreMode) { mIntent = intent; mUri = uri; mRestoreMode = restoreMode; + } - setName("Gecko"); + public void reallyStart() { + mStartSignal.countDown(); + if (getState() == Thread.State.NEW) + start(); } public void run() { @@ -48,6 +59,11 @@ public class GeckoThread extends Thread { GeckoAppShell.loadGeckoLibs(resourcePath); Locale.setDefault(locale); + + try { + mStartSignal.await(); + } catch (Exception e) { } + Resources res = app.getBaseContext().getResources(); Configuration config = res.getConfiguration(); config.locale = locale; From 0fae7833d2732ef267188df0badbf32806af1a0b Mon Sep 17 00:00:00 2001 From: Lucas Rocha Date: Mon, 4 Jun 2012 11:07:04 -0400 Subject: [PATCH 08/53] Bug 761132 - Don't try to fetch display column on history items (r=margaret) --- mobile/android/base/AwesomeBarTabs.java | 1 - 1 file changed, 1 deletion(-) diff --git a/mobile/android/base/AwesomeBarTabs.java b/mobile/android/base/AwesomeBarTabs.java index faaf8ece0c88..8769ea525d95 100644 --- a/mobile/android/base/AwesomeBarTabs.java +++ b/mobile/android/base/AwesomeBarTabs.java @@ -481,7 +481,6 @@ public class AwesomeBarTabs extends TabHost { byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON)); Integer bookmarkId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID)); Integer historyId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.HISTORY_ID)); - Integer display = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.DISPLAY)); // Use the URL instead of an empty title for consistency with the normal URL // bar view - this is the equivalent of getDisplayTitle() in Tab.java From 48a750f4f920e355f63688a4ab8e6466c90bfdd5 Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Fri, 1 Jun 2012 13:19:08 -0700 Subject: [PATCH 09/53] Bug 760643 - Device Storage - Delete isn't working. r=sicking --- dom/devicestorage/nsDeviceStorage.cpp | 226 ++++++++++++++------------ 1 file changed, 123 insertions(+), 103 deletions(-) diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index cf81089b5216..039ea1eaac43 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -23,22 +23,70 @@ using namespace mozilla::dom; class DeviceStorageFile : public nsISupports { public: - DeviceStorageFile(nsIFile* aFile, const nsAString& aPath) - : mFile(aFile) - , mPath(aPath) - { - NS_ASSERTION(aFile, "Must not create a DeviceStorageFile with a null nsIFile"); - NormalizeFilePath(); - } - DeviceStorageFile(nsIFile* aFile) - : mFile(aFile) - { - NS_ASSERTION(aFile, "Must not create a DeviceStorageFile with a null nsIFile"); - } - nsCOMPtr mFile; - nsString mPath; - NS_DECL_ISUPPORTS + nsCOMPtr mFile; + nsString mPath; + + DeviceStorageFile(nsIFile* aFile, const nsAString& aPath) + : mPath(aPath) + { + NS_ASSERTION(aFile, "Must not create a DeviceStorageFile with a null nsIFile"); + // always take a clone + nsCOMPtr file; + aFile->Clone(getter_AddRefs(mFile)); + + AppendRelativePath(); + + NormalizeFilePath(); + } + + DeviceStorageFile(nsIFile* aFile) + { + NS_ASSERTION(aFile, "Must not create a DeviceStorageFile with a null nsIFile"); + // always take a clone + nsCOMPtr file; + aFile->Clone(getter_AddRefs(mFile)); + } + + void + setPath(const nsAString& aPath) { + mPath.Assign(aPath); + NormalizeFilePath(); + } + + NS_DECL_ISUPPORTS + + // we want to make sure that the names of file can't reach + // outside of the type of storage the user asked for. + bool + isSafePath() + { + nsAString::const_iterator start, end; + mPath.BeginReading(start); + mPath.EndReading(end); + + // if the path has a ~ or \ in it, return false. + NS_NAMED_LITERAL_STRING(tilde, "~"); + NS_NAMED_LITERAL_STRING(bslash, "\\"); + if (FindInReadable(tilde, start, end) || + FindInReadable(bslash, start, end)) { + return false; + } + + // split on /. if any token is "", ., or .., return false. + NS_ConvertUTF16toUTF8 cname(mPath); + char* buffer = cname.BeginWriting(); + const char* token; + + while ((token = nsCRT::strtok(buffer, "/", &buffer))) { + if (PL_strcmp(token, "") == 0 || + PL_strcmp(token, ".") == 0 || + PL_strcmp(token, "..") == 0 ) { + return false; + } + } + return true; + } private: void NormalizeFilePath() { @@ -52,62 +100,30 @@ private: #endif } + void AppendRelativePath() { +#if defined(XP_WIN) + // replace forward slashes with backslashes, + // since nsLocalFileWin chokes on them + nsString temp; + temp.Assign(mPath); + + PRUnichar* cur = temp.BeginWriting(); + PRUnichar* end = temp.EndWriting(); + + for (; cur < end; ++cur) { + if (PRUnichar('/') == *cur) + *cur = PRUnichar('\\'); + } + mFile->AppendRelativePath(temp); +#else + mFile->AppendRelativePath(mPath); +#endif + } + }; NS_IMPL_THREADSAFE_ISUPPORTS0(DeviceStorageFile) -// we want to make sure that the names of file can't reach -// outside of the type of storage the user asked for. -bool -isSafePath(const nsAString& aPath) -{ - nsAString::const_iterator start, end; - aPath.BeginReading(start); - aPath.EndReading(end); - - // if the path has a ~ or \ in it, return false. - NS_NAMED_LITERAL_STRING(tilde, "~"); - NS_NAMED_LITERAL_STRING(bslash, "\\"); - if (FindInReadable(tilde, start, end) || - FindInReadable(bslash, start, end)) { - return false; - } - - // split on /. if any token is "", ., or .., return false. - NS_ConvertUTF16toUTF8 cname(aPath); - char* buffer = cname.BeginWriting(); - const char* token; - - while ((token = nsCRT::strtok(buffer, "/", &buffer))) { - if (PL_strcmp(token, "") == 0 || - PL_strcmp(token, ".") == 0 || - PL_strcmp(token, "..") == 0 ) { - return false; - } - } - return true; -} - -static void AppendRelativePath(nsIFile* file, const nsAString& aPath) { - -#if defined(XP_WIN) - // replace forward slashes with backslashes, - // since nsLocalFileWin chokes on them - nsString temp; - temp.Assign(aPath); - - PRUnichar* cur = temp.BeginWriting(); - PRUnichar* end = temp.EndWriting(); - - for (; cur < end; ++cur) { - if (PRUnichar('/') == *cur) - *cur = PRUnichar('\\'); - } - file->AppendRelativePath(temp); -#else - file->AppendRelativePath(aPath); -#endif -} // TODO - eventually, we will want to factor this method // out into different system specific subclasses (or @@ -471,9 +487,7 @@ public: return NS_OK; } - nsString fullpath; - mFile->mFile->GetPath(fullpath); - collectFiles(fullpath, mFile); + collectFiles(mFile); nsCOMPtr event = new ContinueCursorEvent(mRequest); NS_DispatchToMainThread(event); @@ -481,7 +495,7 @@ public: return NS_OK; } - void collectFiles(const nsString& aInitialFullPath, DeviceStorageFile* aFile) + void collectFiles(DeviceStorageFile* aFile) { // TODO - we may want to do this incrementally. if (!aFile) @@ -503,17 +517,21 @@ public: nsString fullpath; f->GetPath(fullpath); - nsAString::size_type len = aInitialFullPath.Length() + 1; // +1 for the trailing / - nsDependentSubstring newPath = Substring(fullpath, len); + nsString rootPath; + mFile->mFile->GetPath(rootPath); - if (!StringBeginsWith(fullpath, aInitialFullPath)) { + if (!StringBeginsWith(fullpath, rootPath)) { NS_WARNING("collectFiles returned a path that does not belong!"); continue; } - nsRefPtr dsf = new DeviceStorageFile(f, newPath); + nsAString::size_type len = rootPath.Length() + 1; // +1 for the trailing / + nsDependentSubstring newPath = Substring(fullpath, len); + nsRefPtr dsf = new DeviceStorageFile(f); + dsf->setPath(newPath); + if (isDir) { - collectFiles(aInitialFullPath, dsf); + collectFiles(dsf); } else if (isFile) { nsDOMDeviceStorageCursor* cursor = static_cast(mRequest.get()); @@ -597,7 +615,7 @@ nsDOMDeviceStorageCursor::Cancel() NS_IMETHODIMP nsDOMDeviceStorageCursor::Allow() { - if (!isSafePath(mFile->mPath)) { + if (!mFile->isSafePath()) { nsCOMPtr r = new PostErrorEvent(this, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, mFile); @@ -605,8 +623,6 @@ nsDOMDeviceStorageCursor::Allow() return NS_OK; } - AppendRelativePath(mFile->mFile, mFile->mPath); - nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); NS_ASSERTION(target, "Must have stream transport service"); @@ -833,8 +849,18 @@ public: NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); mFile->mFile->Remove(true); - nsCOMPtr event = new PostResultEvent(mRequest, mFile->mPath); - NS_DispatchToMainThread(event); + + nsRefPtr r; + + bool check = false; + mFile->mFile->Exists(&check); + if (check) { + r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_UNKNOWN, mFile); + } + else { + r = new PostResultEvent(mRequest, mFile->mPath); + } + NS_DispatchToMainThread(r); return NS_OK; } @@ -1113,13 +1139,9 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob, nsCOMPtr r; - nsCOMPtr file; - mFile->Clone(getter_AddRefs(file)); - AppendRelativePath(file, aPath); + nsRefPtr dsf = new DeviceStorageFile(mFile, aPath); - nsRefPtr dsf = new DeviceStorageFile(file, aPath); - - if (!isSafePath(aPath)) { + if (!dsf->isSafePath()) { r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf); } else { @@ -1169,17 +1191,15 @@ nsDOMDeviceStorage::GetInternal(const JS::Value & aPath, r = new PostErrorEvent(request, POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED, dsf); - } else if (!isSafePath(path)) { - nsRefPtr dsf = new DeviceStorageFile(mFile, path); + NS_DispatchToMainThread(r); + return NS_OK; + } + + nsRefPtr dsf = new DeviceStorageFile(mFile, path); + + if (!dsf->isSafePath()) { r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf); } else { - - nsCOMPtr file; - mFile->Clone(getter_AddRefs(file)); - AppendRelativePath(file, path); - - nsRefPtr dsf = new DeviceStorageFile(file, path); - r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_READ, win, mURI, dsf, request, aEditable); } @@ -1205,16 +1225,16 @@ nsDOMDeviceStorage::Delete(const JS::Value & aPath, JSContext* aCx, nsIDOMDOMReq if (!path.init(aCx, jsstr)) { nsRefPtr dsf = new DeviceStorageFile(mFile); r = new PostErrorEvent(request, POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED, dsf); - } else if (!isSafePath(path)) { - nsRefPtr dsf = new DeviceStorageFile(mFile, path); + NS_DispatchToMainThread(r); + return NS_OK; + } + + nsRefPtr dsf = new DeviceStorageFile(mFile, path); + + if (!dsf->isSafePath()) { r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf); } else { - nsCOMPtr file; - mFile->Clone(getter_AddRefs(file)); - AppendRelativePath(file, path); - - nsRefPtr dsf = new DeviceStorageFile(file, path); r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_DELETE, win, mURI, dsf, request, true); } From d95080757d708b31583aca8622fcbe9895d907dc Mon Sep 17 00:00:00 2001 From: Sid Stamm Date: Wed, 23 May 2012 16:35:37 -0700 Subject: [PATCH 10/53] Bug 634773 - fix CSPSourceList.equals so 'none' and * are not equal. r=jst --- content/base/src/CSPUtils.jsm | 5 +++++ content/base/test/unit/test_csputils.js | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/content/base/src/CSPUtils.jsm b/content/base/src/CSPUtils.jsm index 1512c64017f1..a6589a434101 100644 --- a/content/base/src/CSPUtils.jsm +++ b/content/base/src/CSPUtils.jsm @@ -626,6 +626,11 @@ CSPSourceList.prototype = { */ equals: function(that) { + // special case to default-src * and 'none' to look different + // (both have a ._sources.length of 0). + if (that._permitAllSources != this._permitAllSources) { + return false; + } if (that._sources.length != this._sources.length) { return false; } diff --git a/content/base/test/unit/test_csputils.js b/content/base/test/unit/test_csputils.js index c87c9a9d5eb5..2f0c9be88b87 100644 --- a/content/base/test/unit/test_csputils.js +++ b/content/base/test/unit/test_csputils.js @@ -599,6 +599,29 @@ test( }); +test( + function test_bug634773_noneAndStarAreDifferent() { + /** + * Bug 634773 is that allow * and allow 'none' end up "equal" via + * CSPSourceList.prototype.equals(), which is wrong. This tests that + * doesn't happen. + */ + + var p_none = CSPSourceList.fromString("'none'", "http://foo.com", false); + var p_all = CSPSourceList.fromString("*", "http://foo.com", false); + var p_one = CSPSourceList.fromString("bar.com", "http://foo.com", false); + + do_check_false(p_none.equals(p_all)); + do_check_false(p_none.equals(p_one)); + do_check_false(p_all.equals(p_none)); + do_check_false(p_all.equals(p_one)); + + do_check_true(p_all.permits("http://bar.com")); + do_check_true(p_one.permits("http://bar.com")); + do_check_false(p_none.permits("http://bar.com")); + }); + + /* test(function test_CSPRep_fromPolicyURI_failswhenmixed() { From 629833639ff4808c1649f507fe8bb8b7c09d11f1 Mon Sep 17 00:00:00 2001 From: Yury Date: Mon, 4 Jun 2012 08:56:04 -0700 Subject: [PATCH 11/53] Bug 742099 - Registers pdf.js resources and adds chrome.properties. r=Pike --- .../locales/en-US/pdfviewer/chrome.properties | 3 + .../locales/en-US/pdfviewer/viewer.properties | 71 ++++++++++++------- browser/locales/jar.mn | 3 + 3 files changed, 52 insertions(+), 25 deletions(-) create mode 100644 browser/locales/en-US/pdfviewer/chrome.properties diff --git a/browser/locales/en-US/pdfviewer/chrome.properties b/browser/locales/en-US/pdfviewer/chrome.properties new file mode 100644 index 000000000000..1885e60362ea --- /dev/null +++ b/browser/locales/en-US/pdfviewer/chrome.properties @@ -0,0 +1,3 @@ +# Chrome notification bar messages and buttons +unsupported_feature=This PDF document might not be displayed correctly. +open_with_different_viewer=Open With Different Viewer diff --git a/browser/locales/en-US/pdfviewer/viewer.properties b/browser/locales/en-US/pdfviewer/viewer.properties index 0922062a6cda..25abd9275aed 100644 --- a/browser/locales/en-US/pdfviewer/viewer.properties +++ b/browser/locales/en-US/pdfviewer/viewer.properties @@ -1,10 +1,46 @@ -bookmark.title=Current view (copy or open in new window) +# Main toolbar buttons (tooltips and alt text for images) previous.title=Previous Page +previous_label=Previous next.title=Next Page -print.title=Print -download.title=Download +next_label=Next +page_label=Page: +page_of=of {{pageCount}} zoom_out.title=Zoom Out +zoom_out_label=Zoom Out zoom_in.title=Zoom In +zoom_in_label=Zoom In +zoom.title=Zoom +print.title=Print +print_label=Print +open_file.title=Open File +open_file_label=Open +download.title=Download +download_label=Download +bookmark.title=Current view (copy or open in new window) +bookmark_label=Current View + +# Side panel toolbar buttons (tooltips and alt text for images) +toggle_slider.title=Toggle Slider +toggle_slider_label=Toggle Slider +outline.title=Show Document Outline +outline_label=Document Outline +thumbs.title=Show Thumbnails +thumbs_label=Thumbnails +search_panel.title=Search Document +search_panel_label=Search + +# Document outline messages +no_outline=No Outline Available + +# Thumbnails panel item (tooltip and alt text for images) +thumb_page_title=Page {{page}} +thumb_page_canvas=Thumbnail of Page {{page}} + +# Search panel button title and messages +search=Find +search_terms_not_found=(Not found) + +# Error panel labels error_more_info=More Information error_less_info=Less Information error_close=Close @@ -13,34 +49,19 @@ error_message=Message: {{message}} error_stack=Stack: {{stack}} error_file=File: {{file}} error_line=Line: {{line}} +rendering_error=An error occurred while rendering the page. + +# Predefined zoom values page_scale_width=Page Width page_scale_fit=Page Fit page_scale_auto=Automatic Zoom page_scale_actual=Actual Size -toggle_slider.title=Toggle Slider -thumbs.title=Show Thumbnails -outline.title=Show Document Outline + +# Loading indicator messages loading=Loading... {{percent}}% loading_error_indicator=Error loading_error=An error occurred while loading the PDF. -rendering_error=An error occurred while rendering the page. -page_label=Page: -page_of=of {{pageCount}} -no_outline=No Outline Available -open_file.title=Open File + +# Misc labels and messages text_annotation_type=[{{type}} Annotation] -toggle_slider_label=Toggle Slider -thumbs_label=Thumbnails -outline_label=Document Outline -bookmark_label=Current View -previous_label=Previous -next_label=Next -print_label=Print -download_label=Download -zoom_out_label=Zoom Out -zoom_in_label=Zoom In -zoom.title=Zoom -thumb_page_title=Page {{page}} -thumb_page_canvas=Thumbnail of Page {{page}} request_password=PDF is protected by a password: -open_file_label=Open diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn index ef3e43eb7d43..74dab2558c0f 100644 --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -116,6 +116,9 @@ % locale testpilot @AB_CD@ %locale/feedback/ locale/feedback/main.dtd (%feedback/main.dtd) locale/feedback/main.properties (%feedback/main.properties) +% locale pdf.js @AB_CD@ %locale/pdfviewer/ + locale/pdfviewer/viewer.properties (%pdfviewer/viewer.properties) + locale/pdfviewer/chrome.properties (%pdfviewer/chrome.properties) #ifdef MOZ_WEBAPP_RUNTIME % locale webapprt @AB_CD@ %locale/webapprt/ locale/webapprt/webapp.dtd (%webapprt/webapp.dtd) From 84b2bdb7842a5dc818cd8d84629320a037b06268 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Sat, 2 Jun 2012 09:56:24 -0700 Subject: [PATCH 12/53] Bug 752676: Add pdf.js as an internal handler for pdfjs (1/2); r=mak77 --- browser/app/profile/firefox.js | 12 ++ browser/components/nsBrowserGlue.js | 5 + .../components/preferences/applications.js | 82 +++++++++- .../preferences/in-content/applications.js | 82 +++++++++- browser/extensions/pdfjs/README.mozilla | 2 +- .../pdfjs/components/PdfStreamConverter.js | 80 ++++++++-- browser/extensions/pdfjs/content/PdfJs.jsm | 142 ++++++++++++++++++ .../extensions/pdfjs/content/web/viewer.html | 2 +- .../pdfjs/test/browser_pdfjs_main.js | 20 ++- .../pdfjs/test/browser_pdfjs_savedialog.js | 65 ++++++++ .../preferences/preferences.properties | 1 + uriloader/exthandler/nsHandlerService.js | 2 +- 12 files changed, 473 insertions(+), 22 deletions(-) mode change 100644 => 100755 browser/components/preferences/in-content/applications.js create mode 100644 browser/extensions/pdfjs/content/PdfJs.jsm create mode 100644 browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 6ae76de3b881..d9990cac0a31 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1160,6 +1160,18 @@ pref("full-screen-api.approval-required", true); // (this pref has no effect if more than 6 hours have passed since the last crash) pref("toolkit.startup.max_resumed_crashes", 3); +// Completely disable pdf.js as an option to preview pdfs within firefox. +// Note: if this is not disabled it does not necessarily mean pdf.js is the pdf +// handler just that it is an option. +pref("pdfjs.disabled", false); +// Used by pdf.js to know the first time firefox is run with it installed so it +// can become the default pdf viewer. +pref("pdfjs.firstRun", true); +// The values of preferredAction and alwaysAskBeforeHandling before pdf.js +// became the default. +pref("pdfjs.previousHandler.preferredAction", 0); +pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false); + // The maximum amount of decoded image data we'll willingly keep around (we // might keep around more than this, but we'll try to get down to this value). // (This is intentionally on the high side; see bug 746055.) diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 12bf42215cb3..5ebe789ff5c8 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -31,6 +31,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", "resource:///modules/PageThumbs.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PdfJs", + "resource://pdf.js/PdfJs.jsm"); + const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -329,6 +332,8 @@ BrowserGlue.prototype = { PageThumbs.init(); + PdfJs.init(); + Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, diff --git a/browser/components/preferences/applications.js b/browser/components/preferences/applications.js index 1fab69a791d3..8f3b1d83cbdd 100644 --- a/browser/components/preferences/applications.js +++ b/browser/components/preferences/applications.js @@ -17,10 +17,15 @@ var Cr = Components.results; /* #endif */ +Components.utils.import('resource://gre/modules/Services.jsm'); const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed"; const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed"; const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed"; +const TYPE_PDF = "application/pdf"; + +const PREF_PDFJS_DISABLED = "pdfjs.disabled"; +const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged"; const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types"; @@ -810,6 +815,46 @@ var audioFeedHandlerInfo = { _appPrefLabel: "audioPodcastFeed" } +/** + * InternalHandlerInfoWrapper provides a basic mechanism to create an internal + * mime type handler that can be enabled/disabled in the applications preference + * menu. + */ +function InternalHandlerInfoWrapper(aMIMEType) { + var mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + var handlerInfo = mimeSvc.getFromTypeAndExtension(aMIMEType, null); + + HandlerInfoWrapper.call(this, aMIMEType, handlerInfo); +} + +InternalHandlerInfoWrapper.prototype = { + __proto__: HandlerInfoWrapper.prototype, + + // Override store so we so we can notify any code listening for registration + // or unregistration of this handler. + store: function() { + HandlerInfoWrapper.prototype.store.call(this); + Services.obs.notifyObservers(null, this._handlerChanged, null); + }, + + get enabled() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + get description() { + return this.element("bundlePreferences").getString(this._appPrefLabel); + } +}; + +var pdfHandlerInfo = { + __proto__: new InternalHandlerInfoWrapper(TYPE_PDF), + _handlerChanged: TOPIC_PDFJS_HANDLER_CHANGED, + _appPrefLabel: "portableDocumentFormat", + get enabled() { + return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED); + }, +}; + //****************************************************************************// // Prefpane Controller @@ -999,6 +1044,7 @@ var gApplicationsPane = { _loadData: function() { this._loadFeedHandler(); + this._loadInternalHandlers(); this._loadPluginHandlers(); this._loadApplicationHandlers(); }, @@ -1014,6 +1060,19 @@ var gApplicationsPane = { audioFeedHandlerInfo.handledOnlyByPlugin = false; }, + /** + * Load higher level internal handlers so they can be turned on/off in the + * applications menu. + */ + _loadInternalHandlers: function() { + var internalHandlers = [pdfHandlerInfo]; + for (let internalHandler of internalHandlers) { + if (internalHandler.enabled) { + this._handledTypes[internalHandler.type] = internalHandler; + } + } + }, + /** * Load the set of handlers defined by plugins. * @@ -1216,9 +1275,15 @@ var gApplicationsPane = { case Ci.nsIHandlerInfo.handleInternally: // For the feed type, handleInternally means live bookmarks. - if (isFeedType(aHandlerInfo.type)) + if (isFeedType(aHandlerInfo.type)) { return this._prefsBundle.getFormattedString("addLiveBookmarksInApp", [this._brandShortName]); + } + + if (aHandlerInfo instanceof InternalHandlerInfoWrapper) { + return this._prefsBundle.getFormattedString("previewInApp", + [this._brandShortName]); + } // For other types, handleInternally looks like either useHelperApp // or useSystemDefault depending on whether or not there's a preferred @@ -1319,6 +1384,18 @@ var gApplicationsPane = { while (menuPopup.hasChildNodes()) menuPopup.removeChild(menuPopup.lastChild); + // Add the "Preview in Firefox" option for optional internal handlers. + if (handlerInfo instanceof InternalHandlerInfoWrapper) { + var internalMenuItem = document.createElement("menuitem"); + internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally); + let label = this._prefsBundle.getFormattedString("previewInApp", + [this._brandShortName]); + internalMenuItem.setAttribute("label", label); + internalMenuItem.setAttribute("tooltiptext", label); + internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask"); + menuPopup.appendChild(internalMenuItem); + } + { var askMenuItem = document.createElement("menuitem"); askMenuItem.setAttribute("alwaysAsk", "true"); @@ -1739,6 +1816,9 @@ var gApplicationsPane = { if (isFeedType(aHandlerInfo.type)) { aElement.setAttribute(APP_ICON_ATTR_NAME, "feed"); return true; + } else if (aHandlerInfo instanceof InternalHandlerInfoWrapper) { + aElement.setAttribute(APP_ICON_ATTR_NAME, "ask"); + return true; } break; diff --git a/browser/components/preferences/in-content/applications.js b/browser/components/preferences/in-content/applications.js old mode 100644 new mode 100755 index 03c8065979f5..13e2d39d41e8 --- a/browser/components/preferences/in-content/applications.js +++ b/browser/components/preferences/in-content/applications.js @@ -5,9 +5,14 @@ //****************************************************************************// // Constants & Enumeration Values +Components.utils.import('resource://gre/modules/Services.jsm'); const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed"; const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed"; const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed"; +const TYPE_PDF = "application/pdf"; + +const PREF_PDFJS_DISABLED = "pdfjs.disabled"; +const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged"; const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types"; @@ -797,6 +802,46 @@ var audioFeedHandlerInfo = { _appPrefLabel: "audioPodcastFeed" } +/** + * InternalHandlerInfoWrapper provides a basic mechanism to create an internal + * mime type handler that can be enabled/disabled in the applications preference + * menu. + */ +function InternalHandlerInfoWrapper(aMIMEType) { + var mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + var handlerInfo = mimeSvc.getFromTypeAndExtension(aMIMEType, null); + + HandlerInfoWrapper.call(this, aMIMEType, handlerInfo); +} + +InternalHandlerInfoWrapper.prototype = { + __proto__: HandlerInfoWrapper.prototype, + + // Override store so we so we can notify any code listening for registration + // or unregistration of this handler. + store: function() { + HandlerInfoWrapper.prototype.store.call(this); + Services.obs.notifyObservers(null, this._handlerChanged, null); + }, + + get enabled() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + get description() { + return this.element("bundlePreferences").getString(this._appPrefLabel); + } +}; + +var pdfHandlerInfo = { + __proto__: new InternalHandlerInfoWrapper(TYPE_PDF), + _handlerChanged: TOPIC_PDFJS_HANDLER_CHANGED, + _appPrefLabel: "portableDocumentFormat", + get enabled() { + return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED); + }, +}; + //****************************************************************************// // Prefpane Controller @@ -986,6 +1031,7 @@ var gApplicationsPane = { _loadData: function() { this._loadFeedHandler(); + this._loadInternalHandlers(); this._loadPluginHandlers(); this._loadApplicationHandlers(); }, @@ -1001,6 +1047,19 @@ var gApplicationsPane = { audioFeedHandlerInfo.handledOnlyByPlugin = false; }, + /** + * Load higher level internal handlers so they can be turned on/off in the + * applications menu. + */ + _loadInternalHandlers: function() { + var internalHandlers = [pdfHandlerInfo]; + for (let internalHandler of internalHandlers) { + if (internalHandler.enabled) { + this._handledTypes[internalHandler.type] = internalHandler; + } + } + }, + /** * Load the set of handlers defined by plugins. * @@ -1203,9 +1262,15 @@ var gApplicationsPane = { case Ci.nsIHandlerInfo.handleInternally: // For the feed type, handleInternally means live bookmarks. - if (isFeedType(aHandlerInfo.type)) + if (isFeedType(aHandlerInfo.type)) { return this._prefsBundle.getFormattedString("addLiveBookmarksInApp", [this._brandShortName]); + } + + if (aHandlerInfo instanceof InternalHandlerInfoWrapper) { + return this._prefsBundle.getFormattedString("previewInApp", + [this._brandShortName]); + } // For other types, handleInternally looks like either useHelperApp // or useSystemDefault depending on whether or not there's a preferred @@ -1306,6 +1371,18 @@ var gApplicationsPane = { while (menuPopup.hasChildNodes()) menuPopup.removeChild(menuPopup.lastChild); + // Add the "Preview in Firefox" option for optional internal handlers. + if (handlerInfo instanceof InternalHandlerInfoWrapper) { + var internalMenuItem = document.createElement("menuitem"); + internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally); + let label = this._prefsBundle.getFormattedString("previewInApp", + [this._brandShortName]); + internalMenuItem.setAttribute("label", label); + internalMenuItem.setAttribute("tooltiptext", label); + internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask"); + menuPopup.appendChild(internalMenuItem); + } + { var askMenuItem = document.createElement("menuitem"); askMenuItem.setAttribute("alwaysAsk", "true"); @@ -1726,6 +1803,9 @@ var gApplicationsPane = { if (isFeedType(aHandlerInfo.type)) { aElement.setAttribute(APP_ICON_ATTR_NAME, "feed"); return true; + } else if (aHandlerInfo instanceof InternalHandlerInfoWrapper) { + aElement.setAttribute(APP_ICON_ATTR_NAME, "ask"); + return true; } break; diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index 5efc31e09723..7e2fb644616a 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,4 +1,4 @@ This is the pdf.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 0.3.266 +Current extension version is: 0.3.345 diff --git a/browser/extensions/pdfjs/components/PdfStreamConverter.js b/browser/extensions/pdfjs/components/PdfStreamConverter.js index 1bcccbe22ad4..857c85a8a6e1 100644 --- a/browser/extensions/pdfjs/components/PdfStreamConverter.js +++ b/browser/extensions/pdfjs/components/PdfStreamConverter.js @@ -9,9 +9,11 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; const Cu = Components.utils; +// True only if this is the version of pdf.js that is included with firefox. +const MOZ_CENTRAL = true; const PDFJS_EVENT_ID = 'pdf.js.message'; const PDF_CONTENT_TYPE = 'application/pdf'; -const EXT_PREFIX = 'extensions.uriloader@pdf.js'; +const PREF_PREFIX = 'pdfjs'; const MAX_DATABASE_LENGTH = 4096; const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'; const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'; @@ -20,9 +22,14 @@ Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/NetUtil.jsm'); + let appInfo = Cc['@mozilla.org/xre/app-info;1'] .getService(Ci.nsIXULAppInfo); let privateBrowsing, inPrivateBrowsing; +let Svc = {}; +XPCOMUtils.defineLazyServiceGetter(Svc, 'mime', + '@mozilla.org/mime;1', + 'nsIMIMEService'); if (appInfo.ID === FIREFOX_ID) { privateBrowsing = Cc['@mozilla.org/privatebrowsing;1'] @@ -57,7 +64,7 @@ function getStringPref(pref, def) { } function log(aMsg) { - if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false)) + if (!getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false)) return; let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg); Services.console.logStringMessage(msg); @@ -70,6 +77,23 @@ function getDOMWindow(aChannel) { return win; } +function isEnabled() { + if (MOZ_CENTRAL) { + var disabled = getBoolPref(PREF_PREFIX + '.disabled', false); + if (disabled) + return false; + // To also be considered enabled the "Preview in Firefox" option must be + // selected in the Application preferences. + var handlerInfo = Svc.mime + .getFromTypeAndExtension('application/pdf', 'pdf'); + return handlerInfo.alwaysAskBeforeHandling == false && + handlerInfo.preferredAction == Ci.nsIHandlerInfo.handleInternally; + } + // Always returns true for the extension since enabling/disabling is handled + // by the add-on manager. + return true; +} + function getLocalizedStrings(path) { var stringBundle = Cc['@mozilla.org/intl/stringbundle;1']. getService(Ci.nsIStringBundleService). @@ -91,16 +115,22 @@ function getLocalizedStrings(path) { } return map; } +function getLocalizedString(strings, id, property) { + property = property || 'textContent'; + if (id in strings) + return strings[id][property]; + return id; +} // All the priviledged actions. -function ChromeActions() { +function ChromeActions(domWindow) { + this.domWindow = domWindow; } ChromeActions.prototype = { download: function(data) { - let mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService); - var handlerInfo = mimeService. - getFromTypeAndExtension('application/pdf', 'pdf'); + var handlerInfo = Svc.mime + .getFromTypeAndExtension('application/pdf', 'pdf'); var uri = NetUtil.newURI(data); var extHelperAppSvc = @@ -136,12 +166,12 @@ ChromeActions.prototype = { // Protect against something sending tons of data to setDatabase. if (data.length > MAX_DATABASE_LENGTH) return; - setStringPref(EXT_PREFIX + '.database', data); + setStringPref(PREF_PREFIX + '.database', data); }, getDatabase: function() { if (inPrivateBrowsing) return '{}'; - return getStringPref(EXT_PREFIX + '.database', '{}'); + return getStringPref(PREF_PREFIX + '.database', '{}'); }, getLocale: function() { return getStringPref('general.useragent.locale', 'en-US'); @@ -160,11 +190,34 @@ ChromeActions.prototype = { } }, pdfBugEnabled: function() { - return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false); + return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false); + }, + searchEnabled: function() { + return getBoolPref(PREF_PREFIX + '.searchEnabled', false); + }, + fallback: function(url) { + var self = this; + var domWindow = this.domWindow; + var strings = getLocalizedStrings('chrome.properties'); + var message = getLocalizedString(strings, 'unsupported_feature'); + + var win = Services.wm.getMostRecentWindow('navigator:browser'); + var browser = win.gBrowser.getBrowserForDocument(domWindow.top.document); + var notificationBox = win.gBrowser.getNotificationBox(browser); + var buttons = [{ + label: getLocalizedString(strings, 'open_with_different_viewer'), + accessKey: getLocalizedString(strings, 'open_with_different_viewer', + 'accessKey'), + callback: function() { + self.download(url); + } + }]; + notificationBox.appendNotification(message, 'pdfjs-fallback', null, + notificationBox.PRIORITY_WARNING_LOW, + buttons); } }; - // Event listener to trigger chrome privedged code. function RequestListener(actions) { this.actions = actions; @@ -190,7 +243,7 @@ function PdfStreamConverter() { PdfStreamConverter.prototype = { // properties required for XPCOM registration: - classID: Components.ID('{6457a96b-2d68-439a-bcfa-44465fbcdbb1}'), + classID: Components.ID('{d0c5195d-e798-49d4-b1d3-9324328b2291}'), classDescription: 'pdf.js Component', contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*', @@ -218,6 +271,8 @@ PdfStreamConverter.prototype = { // nsIStreamConverter::asyncConvertData asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { + if (!isEnabled()) + throw Cr.NS_ERROR_NOT_IMPLEMENTED; // Ignoring HTTP POST requests -- pdf.js has to repeat the request. var skipConversion = false; try { @@ -267,7 +322,8 @@ PdfStreamConverter.prototype = { var domWindow = getDOMWindow(channel); // Double check the url is still the correct one. if (domWindow.document.documentURIObject.equals(aRequest.URI)) { - let requestListener = new RequestListener(new ChromeActions); + let requestListener = new RequestListener( + new ChromeActions(domWindow)); domWindow.addEventListener(PDFJS_EVENT_ID, function(event) { requestListener.receive(event); }, false, true); diff --git a/browser/extensions/pdfjs/content/PdfJs.jsm b/browser/extensions/pdfjs/content/PdfJs.jsm new file mode 100644 index 000000000000..9d112f5b2b85 --- /dev/null +++ b/browser/extensions/pdfjs/content/PdfJs.jsm @@ -0,0 +1,142 @@ +var EXPORTED_SYMBOLS = ["PdfJs"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cm = Components.manager; +const Cu = Components.utils; + +const PREF_PREFIX = 'pdfjs'; +const PREF_DISABLED = PREF_PREFIX + '.disabled'; +const PREF_FIRST_RUN = PREF_PREFIX + '.firstRun'; +const PREF_PREVIOUS_ACTION = PREF_PREFIX + '.previousHandler.preferredAction'; +const PREF_PREVIOUS_ASK = PREF_PREFIX + '.previousHandler.alwaysAskBeforeHandling'; +const TOPIC_PDFJS_HANDLER_CHANGED = 'pdfjs:handlerChanged'; + +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import('resource://pdf.js.components/PdfStreamConverter.js'); + +let Svc = {}; +XPCOMUtils.defineLazyServiceGetter(Svc, 'mime', + '@mozilla.org/mime;1', + 'nsIMIMEService'); + +function getBoolPref(aPref, aDefaultValue) { + try { + return Services.prefs.getBoolPref(aPref); + } catch (ex) { + return aDefaultValue; + } +} + +// Register/unregister a constructor as a component. +let Factory = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]), + _targetConstructor: null, + + register: function register(targetConstructor) { + this._targetConstructor = targetConstructor; + var proto = targetConstructor.prototype; + var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); + registrar.registerFactory(proto.classID, proto.classDescription, + proto.contractID, this); + }, + + unregister: function unregister() { + var proto = this._targetConstructor.prototype; + var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); + registrar.unregisterFactory(proto.classID, this); + this._targetConstructor = null; + }, + + // nsIFactory + createInstance: function createInstance(aOuter, iid) { + if (aOuter !== null) + throw Cr.NS_ERROR_NO_AGGREGATION; + return (new (this._targetConstructor)).QueryInterface(iid); + }, + + // nsIFactory + lockFactory: function lockFactory(lock) { + // No longer used as of gecko 1.7. + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + } +}; + +let PdfJs = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + _registered: false, + + init: function init() { + // On first run make pdf.js the default handler. + if (!getBoolPref(PREF_DISABLED, true) && getBoolPref(PREF_FIRST_RUN, false)) { + Services.prefs.setBoolPref(PREF_FIRST_RUN, false); + + let handlerInfo = Svc.mime.getFromTypeAndExtension('application/pdf', 'pdf'); + // Store the previous settings of preferredAction and + // alwaysAskBeforeHandling in case we need to revert them in a hotfix that + // would turn pdf.js off. + Services.prefs.setIntPref(PREF_PREVIOUS_ACTION, handlerInfo.preferredAction); + Services.prefs.setBoolPref(PREF_PREVIOUS_ASK, handlerInfo.alwaysAskBeforeHandling); + + let handlerService = Cc['@mozilla.org/uriloader/handler-service;1']. + getService(Ci.nsIHandlerService); + + // Change and save mime handler settings. + handlerInfo.alwaysAskBeforeHandling = false; + handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally; + handlerService.store(handlerInfo); + } + + if (this.enabled) + this._ensureRegistered(); + else + this._ensureUnregistered(); + + // Listen for when pdf.js is completely disabled or a different pdf handler + // is chosen. + Services.prefs.addObserver(PREF_DISABLED, this, false); + Services.obs.addObserver(this, TOPIC_PDFJS_HANDLER_CHANGED, false); + }, + + // nsIObserver + observe: function observe(aSubject, aTopic, aData) { + if (this.enabled) + this._ensureRegistered(); + else + this._ensureUnregistered(); + }, + + /** + * pdf.js is only enabled if it is both selected as the pdf viewer and if the + * global switch enabling it is true. + * @return {boolean} Wether or not it's enabled. + */ + get enabled() { + var disabled = getBoolPref(PREF_DISABLED, true); + if (disabled) + return false; + + var handlerInfo = Svc.mime. + getFromTypeAndExtension('application/pdf', 'pdf'); + return handlerInfo.alwaysAskBeforeHandling == false && + handlerInfo.preferredAction == Ci.nsIHandlerInfo.handleInternally; + }, + + _ensureRegistered: function _ensureRegistered() { + if (this._registered) + return; + + Factory.register(PdfStreamConverter); + this._registered = true; + }, + + _ensureUnregistered: function _ensureUnregistered() { + if (!this._registered) + return; + + Factory.unregister(); + this._registered = false; + } +}; diff --git a/browser/extensions/pdfjs/content/web/viewer.html b/browser/extensions/pdfjs/content/web/viewer.html index dddf01f49268..afbf553ba8ce 100644 --- a/browser/extensions/pdfjs/content/web/viewer.html +++ b/browser/extensions/pdfjs/content/web/viewer.html @@ -22,7 +22,7 @@ var PDFJS = {}; // Use strict in our context only - users might not want it 'use strict'; - PDFJS.build = '5ac7513'; + PDFJS.build = '121040a'; // Files are inserted below - see Makefile /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_main.js b/browser/extensions/pdfjs/test/browser_pdfjs_main.js index 884650892d2c..e3d7c8babca1 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_main.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_main.js @@ -1,6 +1,5 @@ /* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ + * http://creativecommons.org/publicdomain/zero/1.0/ */ const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; @@ -8,6 +7,16 @@ const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; function test() { var tab; + let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); + let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); + + // Make sure pdf.js is the default handler. + is(handlerInfo.alwaysAskBeforeHandling, false, 'pdf handler defaults to always-ask is false'); + is(handlerInfo.preferredAction, Ci.nsIHandlerInfo.handleInternally, 'pdf handler defaults to internal'); + + info('Pref action: ' + handlerInfo.preferredAction); + waitForExplicitFinish(); registerCleanupFunction(function() { gBrowser.removeTab(tab); @@ -23,13 +32,14 @@ function test() { // Runs tests after all 'load' event handlers have fired off setTimeout(function() { - runTests(document, window); + runTests(document, window, finish); }, 0); }, true); } -function runTests(document, window) { +function runTests(document, window, callback) { + // // Overall sanity tests // @@ -67,5 +77,5 @@ function runTests(document, window) { viewBookmark.click(); ok(viewBookmark.href.length > 0, 'viewBookmark button has href'); - finish(); + callback(); } diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js b/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js new file mode 100644 index 000000000000..a6564e59199b --- /dev/null +++ b/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js @@ -0,0 +1,65 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; +const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; + +function test() { + var oldAction = changeMimeHandler(Ci.nsIHandlerInfo.useSystemDefault, true); + var tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); + // + // Test: "Open with" dialog comes up when pdf.js is not selected as the default + // handler. + // + addWindowListener('chrome://mozapps/content/downloads/unknownContentType.xul', finish); + + waitForExplicitFinish(); + registerCleanupFunction(function() { + changeMimeHandler(oldAction[0], oldAction[1]); + gBrowser.removeTab(tab); + }); +} + +function changeMimeHandler(preferredAction, alwaysAskBeforeHandling) { + let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); + let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); + var oldAction = [handlerInfo.preferredAction, handlerInfo.alwaysAskBeforeHandling]; + + // Change and save mime handler settings + handlerInfo.alwaysAskBeforeHandling = alwaysAskBeforeHandling; + handlerInfo.preferredAction = preferredAction; + handlerService.store(handlerInfo); + + Services.obs.notifyObservers(null, 'pdfjs:handlerChanged', null); + + // Refresh data + handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); + + // + // Test: Mime handler was updated + // + is(handlerInfo.alwaysAskBeforeHandling, alwaysAskBeforeHandling, 'always-ask prompt change successful'); + is(handlerInfo.preferredAction, preferredAction, 'mime handler change successful'); + + return oldAction; +} + +function addWindowListener(aURL, aCallback) { + Services.wm.addListener({ + onOpenWindow: function(aXULWindow) { + info("window opened, waiting for focus"); + Services.wm.removeListener(this); + + var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + waitForFocus(function() { + is(domwindow.document.location.href, aURL, "should have seen the right window open"); + domwindow.close(); + aCallback(); + }, domwindow); + }, + onCloseWindow: function(aXULWindow) { }, + onWindowTitleChange: function(aXULWindow, aNewTitle) { } + }); +} diff --git a/browser/locales/en-US/chrome/browser/preferences/preferences.properties b/browser/locales/en-US/chrome/browser/preferences/preferences.properties index 850e3250773d..b9e0663211de 100644 --- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties +++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties @@ -63,6 +63,7 @@ webFeed=Web Feed videoPodcastFeed=Video Podcast audioPodcastFeed=Podcast alwaysAsk=Always ask +portableDocumentFormat=Portable Document Format (PDF) # LOCALIZATION NOTE (usePluginIn): # %1$S = plugin name (for example "QuickTime Plugin-in 7.2") diff --git a/uriloader/exthandler/nsHandlerService.js b/uriloader/exthandler/nsHandlerService.js index 4856edeb38c1..d437b2807cdb 100644 --- a/uriloader/exthandler/nsHandlerService.js +++ b/uriloader/exthandler/nsHandlerService.js @@ -489,7 +489,7 @@ HandlerService.prototype = { return Ci.nsIHandlerInfo.useSystemDefault; if (this._getValue(aInfoID, NC_HANDLE_INTERNALLY) == "true") - return Ci.nsIHandlerInfo.handleInternal; + return Ci.nsIHandlerInfo.handleInternally; return Ci.nsIHandlerInfo.useHelperApp; }, From 69ade17295363cc6701e9b8ee73c10077cf7102d Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Fri, 1 Jun 2012 21:41:22 -0700 Subject: [PATCH 13/53] Bug 752676: Add pdf.js as an internal handler for pdfs (2/2); r=mak77 --- browser/extensions/pdfjs/chrome.manifest | 8 +- .../extensions/pdfjs/content/web/viewer.css | 81 ++ .../extensions/pdfjs/content/web/viewer.html | 1098 ++++++++++++++++- .../extensions/pdfjs/content/web/viewer.js | 212 +++- browser/extensions/pdfjs/extension-files | 5 +- browser/extensions/pdfjs/test/Makefile.in | 1 + 6 files changed, 1293 insertions(+), 112 deletions(-) diff --git a/browser/extensions/pdfjs/chrome.manifest b/browser/extensions/pdfjs/chrome.manifest index 8348f377ed8b..1c7abc845c3e 100644 --- a/browser/extensions/pdfjs/chrome.manifest +++ b/browser/extensions/pdfjs/chrome.manifest @@ -1,8 +1,2 @@ resource pdf.js content/ -component {6457a96b-2d68-439a-bcfa-44465fbcdbb1} components/PdfStreamConverter.js -contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {6457a96b-2d68-439a-bcfa-44465fbcdbb1} - -# Additional resources for pdf.js - -# PDFJS_SUPPORTED_LOCALES - +resource pdf.js.components components/ diff --git a/browser/extensions/pdfjs/content/web/viewer.css b/browser/extensions/pdfjs/content/web/viewer.css index d0a7be9a0203..2d2864551033 100644 --- a/browser/extensions/pdfjs/content/web/viewer.css +++ b/browser/extensions/pdfjs/content/web/viewer.css @@ -238,6 +238,10 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton { opacity: .5; } +.toolbarButton.group { + margin-right:0; +} + .splitToolbarButton:hover > .toolbarButton, .splitToolbarButton:focus > .toolbarButton, .splitToolbarButton.toggled > .toolbarButton { @@ -533,6 +537,12 @@ html[dir='rtl'] .toolbarButton.pageDown::before { content: url(images/toolbarButton-viewOutline.png); } +#viewSearch.toolbarButton::before { + display: inline-block; + content: url(images/toolbarButton-search.png); +} + + .toolbarField { min-width: 16px; width: 32px; @@ -697,6 +707,53 @@ a:focus > .thumbnail > .thumbnailSelectionRing, color: hsla(0,0%,100%,.9); } +#searchScrollView { + position: absolute; + top: 10px; + bottom: 10px; + left: 10px; + width: 280px; +} + +#searchToolbar { + padding-left: 0px; + right: 0px; + padding-top: 0px; + padding-bottom: 5px; +} + +#searchToolbar > input { + margin-left: 8px; + width: 130px; +} + +#searchResults { + overflow: auto; + background-color: #fff; + position: absolute; + top: 30px; + bottom: 0px; + left: 0px; + right: 0; + font-size: smaller; + opacity: 0.7; +} + +#searchResults a { + display: block; + white-space: pre; + text-decoration: none; + color: black; +} + +#sidebarControls { + position:absolute; + width: 180px; + height: 32px; + left: 15px; + bottom: 35px; +} + .outlineItem.selected { background-color: hsla(0,0%,100%,.08); background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); @@ -937,6 +994,30 @@ canvas { font-size: 10px; } +@media print { + #sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer { + display: none; + } + + #mainContainer, #viewerContainer, .page, .page canvas { + position: static; + padding: 0; + margin: 0; + } + + .page { + float: left; + display: none; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + } + + .page[data-loaded] { + display: block; + } +} + @media all and (max-width: 950px) { html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter, html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter { diff --git a/browser/extensions/pdfjs/content/web/viewer.html b/browser/extensions/pdfjs/content/web/viewer.html index afbf553ba8ce..776fbec2ec74 100644 --- a/browser/extensions/pdfjs/content/web/viewer.html +++ b/browser/extensions/pdfjs/content/web/viewer.html @@ -34,7 +34,7 @@ var globalScope = (typeof window === 'undefined') ? this : window; var isWorker = (typeof window == 'undefined'); -var ERRORS = 0, WARNINGS = 1, TODOS = 5; +var ERRORS = 0, WARNINGS = 1, INFOS = 5; var verbosity = WARNINGS; // The global PDFJS object exposes the API @@ -178,6 +178,7 @@ var Page = (function PageClosure() { // fetching items var streams = []; var i, n = content.length; + var streams = []; for (i = 0; i < n; ++i) streams.push(xref.fetchIfRef(content[i])); content = new StreamsSequenceStream(streams); @@ -193,7 +194,48 @@ var Page = (function PageClosure() { return pe.getOperatorList(content, resources, dependency); }, + extractTextContent: function Page_extractTextContent() { + var handler = { + on: function nullHandlerOn() {}, + send: function nullHandlerSend() {} + }; + var xref = this.xref; + var content = xref.fetchIfRef(this.content); + var resources = xref.fetchIfRef(this.resources); + if (isArray(content)) { + // fetching items + var i, n = content.length; + var streams = []; + for (i = 0; i < n; ++i) + streams.push(xref.fetchIfRef(content[i])); + content = new StreamsSequenceStream(streams); + } else if (isStream(content)) { + content.reset(); + } + + var pe = new PartialEvaluator( + xref, handler, 'p' + this.pageNumber + '_'); + return pe.getTextContent(content, resources); + }, + + ensureFonts: function Page_ensureFonts(fonts, callback) { + this.stats.time('Font Loading'); + // Convert the font names to the corresponding font obj. + for (var i = 0, ii = fonts.length; i < ii; i++) { + fonts[i] = this.objs.objs[fonts[i]].data; + } + + // Load all the fonts + FontLoader.bind( + fonts, + function pageEnsureFontsFontObjs(fontObjs) { + this.stats.timeEnd('Font Loading'); + + callback.call(this); + }.bind(this) + ); + }, getLinks: function Page_getLinks() { var links = []; var annotations = pageGetAnnotations(); @@ -508,11 +550,14 @@ var PDFDocument = (function PDFDocumentClosure() { return PDFDocument; })(); + /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 'use strict'; +// Use only for debugging purposes. This should not be used in any code that is +// in mozilla master. function log(msg) { if (console && console.log) console.log(msg); @@ -520,9 +565,36 @@ function log(msg) { print(msg); } +// A notice for devs that will not trigger the fallback UI. These are good +// for things that are helpful to devs, such as warning that Workers were +// disabled, which is important to devs but not end users. +function info(msg) { + if (verbosity >= INFOS) { + log('Info: ' + msg); + PDFJS.LogManager.notify('info', msg); + } +} + +// Non-fatal warnings that should trigger the fallback UI. function warn(msg) { - if (verbosity >= WARNINGS) + if (verbosity >= WARNINGS) { log('Warning: ' + msg); + PDFJS.LogManager.notify('warn', msg); + } +} + +// Fatal errors that should trigger the fallback UI and halt execution by +// throwing an exception. +function error(msg) { + log('Error: ' + msg); + log(backtrace()); + PDFJS.LogManager.notify('error', msg); + throw new Error(msg); +} + +// Missing features that should trigger the fallback UI. +function TODO(what) { + warn('TODO: ' + what); } function backtrace() { @@ -533,21 +605,6 @@ function backtrace() { } } -function error(msg) { - log('Error: ' + msg); - log(backtrace()); - throw new Error(msg); -} - -function TODO(what) { - if (verbosity >= TODOS) - log('TODO: ' + what); -} - -function malformed(msg) { - error('Malformed PDF: ' + msg); -} - function assert(cond, msg) { if (!cond) error(msg); @@ -557,9 +614,25 @@ function assert(cond, msg) { // behavior is undefined. function assertWellFormed(cond, msg) { if (!cond) - malformed(msg); + error(msg); } +var LogManager = PDFJS.LogManager = (function LogManagerClosure() { + var loggers = []; + return { + addLogger: function logManager_addLogger(logger) { + loggers.push(logger); + }, + notify: function(type, message) { + for (var i = 0, ii = loggers.length; i < ii; i++) { + var logger = loggers[i]; + if (logger[type]) + logger[type](message); + } + } + }; +})(); + function shadow(obj, prop, value) { Object.defineProperty(obj, prop, { value: value, enumerable: true, @@ -812,6 +885,10 @@ function stringToPDFString(str) { return str2; } +function stringToUTF8String(str) { + return decodeURIComponent(escape(str)); +} + function isBool(v) { return typeof v == 'boolean'; } @@ -1453,12 +1530,18 @@ var PDFPageProxy = (function PDFPageProxyClosure() { next(); }, /** - * Stub for future feature. + * @return {Promise} That is resolved with the a {string} that is the text + * content from the page. */ getTextContent: function PDFPageProxy_getTextContent() { var promise = new PDFJS.Promise(); - var textContent = 'page text'; // not implemented - promise.resolve(textContent); + this.transport.messageHandler.send('GetTextContent', { + pageIndex: this.pageNumber - 1 + }, + function textContentCallback(textContent) { + promise.resolve(textContent); + } + ); return promise; }, /** @@ -1544,7 +1627,7 @@ var WorkerTransport = (function WorkerTransportClosure() { messageHandler.send('test', testObj); return; } catch (e) { - warn('The worker has been disabled.'); + info('The worker has been disabled.'); } } // Either workers are disabled, not supported or have thrown an exception. @@ -2066,10 +2149,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.ctx.webkitLineDashOffset = dashPhase; }, setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) { - TODO('set rendering intent: ' + intent); + // Maybe if we one day fully support color spaces this will be important + // for now we can ignore. + // TODO set rendering intent? }, setFlatness: function CanvasGraphics_setFlatness(flatness) { - TODO('set flatness: ' + flatness); + // There's no way to control this with canvas, but we can safely ignore. + // TODO set flatness? }, setGState: function CanvasGraphics_setGState(states) { for (var i = 0, ii = states.length; i < ii; i++) { @@ -2564,7 +2650,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { text.length += shownText.length; } } else { - malformed('TJ array element ' + e + ' is not string or num'); + error('TJ array element ' + e + ' is not string or num'); } } @@ -3102,7 +3188,14 @@ var Catalog = (function CatalogClosure() { Catalog.prototype = { get metadata() { - var stream = this.catDict.get('Metadata'); + var streamRef = this.catDict.getRaw('Metadata'); + if (!isRef(streamRef)) + return shadow(this, 'metadata', null); + + var encryptMetadata = !this.xref.encrypt ? false : + this.xref.encrypt.encryptMetadata; + + var stream = this.xref.fetch(streamRef, !encryptMetadata); var metadata; if (stream && isDict(stream.dict)) { var type = stream.dict.get('Type'); @@ -3110,7 +3203,16 @@ var Catalog = (function CatalogClosure() { if (isName(type) && isName(subtype) && type.name === 'Metadata' && subtype.name === 'XML') { - metadata = stringToPDFString(bytesToString(stream.getBytes())); + // XXX: This should examine the charset the XML document defines, + // however since there are currently no real means to decode + // arbitrary charsets, let's just hope that the author of the PDF + // was reasonable enough to stick with the XML default charset, + // which is UTF-8. + try { + metadata = stringToUTF8String(bytesToString(stream.getBytes())); + } catch (e) { + info('Skipping invalid metadata.'); + } } } @@ -12155,12 +12257,12 @@ var LabCS = (function LabCSClosure() { error('Invalid WhitePoint components, no fallback available'); if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - warn('Invalid BlackPoint, falling back to default'); + info('Invalid BlackPoint, falling back to default'); this.XB = this.YB = this.ZB = 0; } if (this.amin > this.amax || this.bmin > this.bmax) { - warn('Invalid Range, falling back to defaults'); + info('Invalid Range, falling back to defaults'); this.amin = -100; this.amax = 100; this.bmin = -100; @@ -12783,8 +12885,10 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var userPassword = stringToBytes(dict.get('U')); var flags = dict.get('P'); var revision = dict.get('R'); - var encryptMetadata = + var encryptMetadata = algorithm == 4 && // meaningful when V is 4 dict.get('EncryptMetadata') !== false; // makes true as default value + this.encryptMetadata = encryptMetadata; + var fileIdBytes = stringToBytes(fileId); var passwordBytes; if (password) @@ -13040,8 +13144,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { font = xref.fetchIfRef(font) || fontRes.get(fontName); assertWellFormed(isDict(font)); + ++self.objIdCounter; - if (!font.translated) { + if (!font.loadedName) { font.translated = self.translateFont(font, xref, resources, dependency); if (font.translated) { @@ -13304,6 +13409,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { value[1] ]); break; + case 'BM': + // We support the default so don't trigger the TODO. + if (!isName(value) || value.name != 'Normal') + TODO('graphic state operator ' + key); + break; + case 'SMask': + // We support the default so don't trigger the TODO. + if (!isName(value) || value.name != 'None') + TODO('graphic state operator ' + key); + break; + // Only generate info log messages for the following since + // they are unlikey to have a big impact on the rendering. case 'OP': case 'op': case 'OPM': @@ -13316,14 +13433,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { case 'HT': case 'SM': case 'SA': - case 'BM': - case 'SMask': case 'AIS': case 'TK': - TODO('graphic state operator ' + key); + // TODO implement these operators. + info('graphic state operator ' + key); break; default: - warn('Unknown graphic state operator ' + key); + info('Unknown graphic state operator ' + key); break; } } @@ -13344,6 +13460,81 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return queue; }, + getTextContent: function partialEvaluatorGetIRQueue(stream, resources) { + + var self = this; + var xref = this.xref; + + function handleSetFont(fontName, fontRef) { + var fontRes = resources.get('Font'); + + // TODO: TOASK: Is it possible to get here? If so, what does + // args[0].name should be like??? + assert(fontRes, 'fontRes not available'); + + fontRes = xref.fetchIfRef(fontRes); + fontRef = fontRef || fontRes.get(fontName); + var font = xref.fetchIfRef(fontRef), tra; + assertWellFormed(isDict(font)); + if (!font.translated) { + font.translated = self.translateFont(font, xref, resources); + } + return font; + } + + resources = xref.fetchIfRef(resources) || new Dict(); + + var parser = new Parser(new Lexer(stream), false); + var res = resources; + var args = [], obj; + + var text = ''; + var chunk = ''; + var font = null; + while (!isEOF(obj = parser.getObj())) { + if (isCmd(obj)) { + var cmd = obj.cmd; + switch (cmd) { + case 'Tf': + font = handleSetFont(args[0].name); + break; + case 'TJ': + var items = args[0]; + for (var j = 0, jj = items.length; j < jj; j++) { + if (typeof items[j] === 'string') { + chunk += items[j]; + } else if (items[j] < 0) { + // making all negative offsets a space - better to have + // a space in incorrect place than not have them at all + chunk += ' '; + } + } + break; + case 'Tj': + chunk += args[0]; + break; + case "'": + chunk += args[0] + ' '; + break; + case '"': + chunk += args[2] + ' '; + break; + } // switch + if (chunk !== '') { + text += fontCharsToUnicode(chunk, font.translated.properties); + chunk = ''; + } + + args = []; + } else if (obj != null) { + assertWellFormed(args.length <= 33, 'Too many arguments'); + args.push(obj); + } + } + + return text; + }, + extractDataStructures: function partialEvaluatorExtractDataStructures(dict, baseDict, xref, properties) { @@ -13497,8 +13688,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } } else if (octet == 0x3E) { if (token.length) { - // XXX guessing chars size by checking number size in the CMap - if (token.length <= 2 && properties.composite) + // Heuristic: guessing chars size by checking numbers sizes + // in the CMap entries. + if (token.length == 2 && properties.composite) properties.wideChars = false; if (token.length <= 4) { @@ -14538,6 +14730,736 @@ function isSpecialUnicode(unicode) { unicode < kCmapGlyphOffset + kSizeOfGlyphArea); } +// The normalization table is obtained by filtering the Unicode characters +// database with entries. +var NormalizedUnicodes = { + '\u00A8': '\u0020\u0308', + '\u00AF': '\u0020\u0304', + '\u00B4': '\u0020\u0301', + '\u00B5': '\u03BC', + '\u00B8': '\u0020\u0327', + '\u0132': '\u0049\u004A', + '\u0133': '\u0069\u006A', + '\u013F': '\u004C\u00B7', + '\u0140': '\u006C\u00B7', + '\u0149': '\u02BC\u006E', + '\u017F': '\u0073', + '\u01C4': '\u0044\u017D', + '\u01C5': '\u0044\u017E', + '\u01C6': '\u0064\u017E', + '\u01C7': '\u004C\u004A', + '\u01C8': '\u004C\u006A', + '\u01C9': '\u006C\u006A', + '\u01CA': '\u004E\u004A', + '\u01CB': '\u004E\u006A', + '\u01CC': '\u006E\u006A', + '\u01F1': '\u0044\u005A', + '\u01F2': '\u0044\u007A', + '\u01F3': '\u0064\u007A', + '\u02D8': '\u0020\u0306', + '\u02D9': '\u0020\u0307', + '\u02DA': '\u0020\u030A', + '\u02DB': '\u0020\u0328', + '\u02DC': '\u0020\u0303', + '\u02DD': '\u0020\u030B', + '\u037A': '\u0020\u0345', + '\u0384': '\u0020\u0301', + '\u03D0': '\u03B2', + '\u03D1': '\u03B8', + '\u03D2': '\u03A5', + '\u03D5': '\u03C6', + '\u03D6': '\u03C0', + '\u03F0': '\u03BA', + '\u03F1': '\u03C1', + '\u03F2': '\u03C2', + '\u03F4': '\u0398', + '\u03F5': '\u03B5', + '\u03F9': '\u03A3', + '\u0587': '\u0565\u0582', + '\u0675': '\u0627\u0674', + '\u0676': '\u0648\u0674', + '\u0677': '\u06C7\u0674', + '\u0678': '\u064A\u0674', + '\u0E33': '\u0E4D\u0E32', + '\u0EB3': '\u0ECD\u0EB2', + '\u0EDC': '\u0EAB\u0E99', + '\u0EDD': '\u0EAB\u0EA1', + '\u0F77': '\u0FB2\u0F81', + '\u0F79': '\u0FB3\u0F81', + '\u1E9A': '\u0061\u02BE', + '\u1FBD': '\u0020\u0313', + '\u1FBF': '\u0020\u0313', + '\u1FC0': '\u0020\u0342', + '\u1FFE': '\u0020\u0314', + '\u2002': '\u0020', + '\u2003': '\u0020', + '\u2004': '\u0020', + '\u2005': '\u0020', + '\u2006': '\u0020', + '\u2008': '\u0020', + '\u2009': '\u0020', + '\u200A': '\u0020', + '\u2017': '\u0020\u0333', + '\u2024': '\u002E', + '\u2025': '\u002E\u002E', + '\u2026': '\u002E\u002E\u002E', + '\u2033': '\u2032\u2032', + '\u2034': '\u2032\u2032\u2032', + '\u2036': '\u2035\u2035', + '\u2037': '\u2035\u2035\u2035', + '\u203C': '\u0021\u0021', + '\u203E': '\u0020\u0305', + '\u2047': '\u003F\u003F', + '\u2048': '\u003F\u0021', + '\u2049': '\u0021\u003F', + '\u2057': '\u2032\u2032\u2032\u2032', + '\u205F': '\u0020', + '\u20A8': '\u0052\u0073', + '\u2100': '\u0061\u002F\u0063', + '\u2101': '\u0061\u002F\u0073', + '\u2103': '\u00B0\u0043', + '\u2105': '\u0063\u002F\u006F', + '\u2106': '\u0063\u002F\u0075', + '\u2107': '\u0190', + '\u2109': '\u00B0\u0046', + '\u2116': '\u004E\u006F', + '\u2121': '\u0054\u0045\u004C', + '\u2135': '\u05D0', + '\u2136': '\u05D1', + '\u2137': '\u05D2', + '\u2138': '\u05D3', + '\u213B': '\u0046\u0041\u0058', + '\u2160': '\u0049', + '\u2161': '\u0049\u0049', + '\u2162': '\u0049\u0049\u0049', + '\u2163': '\u0049\u0056', + '\u2164': '\u0056', + '\u2165': '\u0056\u0049', + '\u2166': '\u0056\u0049\u0049', + '\u2167': '\u0056\u0049\u0049\u0049', + '\u2168': '\u0049\u0058', + '\u2169': '\u0058', + '\u216A': '\u0058\u0049', + '\u216B': '\u0058\u0049\u0049', + '\u216C': '\u004C', + '\u216D': '\u0043', + '\u216E': '\u0044', + '\u216F': '\u004D', + '\u2170': '\u0069', + '\u2171': '\u0069\u0069', + '\u2172': '\u0069\u0069\u0069', + '\u2173': '\u0069\u0076', + '\u2174': '\u0076', + '\u2175': '\u0076\u0069', + '\u2176': '\u0076\u0069\u0069', + '\u2177': '\u0076\u0069\u0069\u0069', + '\u2178': '\u0069\u0078', + '\u2179': '\u0078', + '\u217A': '\u0078\u0069', + '\u217B': '\u0078\u0069\u0069', + '\u217C': '\u006C', + '\u217D': '\u0063', + '\u217E': '\u0064', + '\u217F': '\u006D', + '\u222C': '\u222B\u222B', + '\u222D': '\u222B\u222B\u222B', + '\u222F': '\u222E\u222E', + '\u2230': '\u222E\u222E\u222E', + '\u2474': '\u0028\u0031\u0029', + '\u2475': '\u0028\u0032\u0029', + '\u2476': '\u0028\u0033\u0029', + '\u2477': '\u0028\u0034\u0029', + '\u2478': '\u0028\u0035\u0029', + '\u2479': '\u0028\u0036\u0029', + '\u247A': '\u0028\u0037\u0029', + '\u247B': '\u0028\u0038\u0029', + '\u247C': '\u0028\u0039\u0029', + '\u247D': '\u0028\u0031\u0030\u0029', + '\u247E': '\u0028\u0031\u0031\u0029', + '\u247F': '\u0028\u0031\u0032\u0029', + '\u2480': '\u0028\u0031\u0033\u0029', + '\u2481': '\u0028\u0031\u0034\u0029', + '\u2482': '\u0028\u0031\u0035\u0029', + '\u2483': '\u0028\u0031\u0036\u0029', + '\u2484': '\u0028\u0031\u0037\u0029', + '\u2485': '\u0028\u0031\u0038\u0029', + '\u2486': '\u0028\u0031\u0039\u0029', + '\u2487': '\u0028\u0032\u0030\u0029', + '\u2488': '\u0031\u002E', + '\u2489': '\u0032\u002E', + '\u248A': '\u0033\u002E', + '\u248B': '\u0034\u002E', + '\u248C': '\u0035\u002E', + '\u248D': '\u0036\u002E', + '\u248E': '\u0037\u002E', + '\u248F': '\u0038\u002E', + '\u2490': '\u0039\u002E', + '\u2491': '\u0031\u0030\u002E', + '\u2492': '\u0031\u0031\u002E', + '\u2493': '\u0031\u0032\u002E', + '\u2494': '\u0031\u0033\u002E', + '\u2495': '\u0031\u0034\u002E', + '\u2496': '\u0031\u0035\u002E', + '\u2497': '\u0031\u0036\u002E', + '\u2498': '\u0031\u0037\u002E', + '\u2499': '\u0031\u0038\u002E', + '\u249A': '\u0031\u0039\u002E', + '\u249B': '\u0032\u0030\u002E', + '\u249C': '\u0028\u0061\u0029', + '\u249D': '\u0028\u0062\u0029', + '\u249E': '\u0028\u0063\u0029', + '\u249F': '\u0028\u0064\u0029', + '\u24A0': '\u0028\u0065\u0029', + '\u24A1': '\u0028\u0066\u0029', + '\u24A2': '\u0028\u0067\u0029', + '\u24A3': '\u0028\u0068\u0029', + '\u24A4': '\u0028\u0069\u0029', + '\u24A5': '\u0028\u006A\u0029', + '\u24A6': '\u0028\u006B\u0029', + '\u24A7': '\u0028\u006C\u0029', + '\u24A8': '\u0028\u006D\u0029', + '\u24A9': '\u0028\u006E\u0029', + '\u24AA': '\u0028\u006F\u0029', + '\u24AB': '\u0028\u0070\u0029', + '\u24AC': '\u0028\u0071\u0029', + '\u24AD': '\u0028\u0072\u0029', + '\u24AE': '\u0028\u0073\u0029', + '\u24AF': '\u0028\u0074\u0029', + '\u24B0': '\u0028\u0075\u0029', + '\u24B1': '\u0028\u0076\u0029', + '\u24B2': '\u0028\u0077\u0029', + '\u24B3': '\u0028\u0078\u0029', + '\u24B4': '\u0028\u0079\u0029', + '\u24B5': '\u0028\u007A\u0029', + '\u2A0C': '\u222B\u222B\u222B\u222B', + '\u2A74': '\u003A\u003A\u003D', + '\u2A75': '\u003D\u003D', + '\u2A76': '\u003D\u003D\u003D', + '\u2E9F': '\u6BCD', + '\u2EF3': '\u9F9F', + '\u2F00': '\u4E00', + '\u2F01': '\u4E28', + '\u2F02': '\u4E36', + '\u2F03': '\u4E3F', + '\u2F04': '\u4E59', + '\u2F05': '\u4E85', + '\u2F06': '\u4E8C', + '\u2F07': '\u4EA0', + '\u2F08': '\u4EBA', + '\u2F09': '\u513F', + '\u2F0A': '\u5165', + '\u2F0B': '\u516B', + '\u2F0C': '\u5182', + '\u2F0D': '\u5196', + '\u2F0E': '\u51AB', + '\u2F0F': '\u51E0', + '\u2F10': '\u51F5', + '\u2F11': '\u5200', + '\u2F12': '\u529B', + '\u2F13': '\u52F9', + '\u2F14': '\u5315', + '\u2F15': '\u531A', + '\u2F16': '\u5338', + '\u2F17': '\u5341', + '\u2F18': '\u535C', + '\u2F19': '\u5369', + '\u2F1A': '\u5382', + '\u2F1B': '\u53B6', + '\u2F1C': '\u53C8', + '\u2F1D': '\u53E3', + '\u2F1E': '\u56D7', + '\u2F1F': '\u571F', + '\u2F20': '\u58EB', + '\u2F21': '\u5902', + '\u2F22': '\u590A', + '\u2F23': '\u5915', + '\u2F24': '\u5927', + '\u2F25': '\u5973', + '\u2F26': '\u5B50', + '\u2F27': '\u5B80', + '\u2F28': '\u5BF8', + '\u2F29': '\u5C0F', + '\u2F2A': '\u5C22', + '\u2F2B': '\u5C38', + '\u2F2C': '\u5C6E', + '\u2F2D': '\u5C71', + '\u2F2E': '\u5DDB', + '\u2F2F': '\u5DE5', + '\u2F30': '\u5DF1', + '\u2F31': '\u5DFE', + '\u2F32': '\u5E72', + '\u2F33': '\u5E7A', + '\u2F34': '\u5E7F', + '\u2F35': '\u5EF4', + '\u2F36': '\u5EFE', + '\u2F37': '\u5F0B', + '\u2F38': '\u5F13', + '\u2F39': '\u5F50', + '\u2F3A': '\u5F61', + '\u2F3B': '\u5F73', + '\u2F3C': '\u5FC3', + '\u2F3D': '\u6208', + '\u2F3E': '\u6236', + '\u2F3F': '\u624B', + '\u2F40': '\u652F', + '\u2F41': '\u6534', + '\u2F42': '\u6587', + '\u2F43': '\u6597', + '\u2F44': '\u65A4', + '\u2F45': '\u65B9', + '\u2F46': '\u65E0', + '\u2F47': '\u65E5', + '\u2F48': '\u66F0', + '\u2F49': '\u6708', + '\u2F4A': '\u6728', + '\u2F4B': '\u6B20', + '\u2F4C': '\u6B62', + '\u2F4D': '\u6B79', + '\u2F4E': '\u6BB3', + '\u2F4F': '\u6BCB', + '\u2F50': '\u6BD4', + '\u2F51': '\u6BDB', + '\u2F52': '\u6C0F', + '\u2F53': '\u6C14', + '\u2F54': '\u6C34', + '\u2F55': '\u706B', + '\u2F56': '\u722A', + '\u2F57': '\u7236', + '\u2F58': '\u723B', + '\u2F59': '\u723F', + '\u2F5A': '\u7247', + '\u2F5B': '\u7259', + '\u2F5C': '\u725B', + '\u2F5D': '\u72AC', + '\u2F5E': '\u7384', + '\u2F5F': '\u7389', + '\u2F60': '\u74DC', + '\u2F61': '\u74E6', + '\u2F62': '\u7518', + '\u2F63': '\u751F', + '\u2F64': '\u7528', + '\u2F65': '\u7530', + '\u2F66': '\u758B', + '\u2F67': '\u7592', + '\u2F68': '\u7676', + '\u2F69': '\u767D', + '\u2F6A': '\u76AE', + '\u2F6B': '\u76BF', + '\u2F6C': '\u76EE', + '\u2F6D': '\u77DB', + '\u2F6E': '\u77E2', + '\u2F6F': '\u77F3', + '\u2F70': '\u793A', + '\u2F71': '\u79B8', + '\u2F72': '\u79BE', + '\u2F73': '\u7A74', + '\u2F74': '\u7ACB', + '\u2F75': '\u7AF9', + '\u2F76': '\u7C73', + '\u2F77': '\u7CF8', + '\u2F78': '\u7F36', + '\u2F79': '\u7F51', + '\u2F7A': '\u7F8A', + '\u2F7B': '\u7FBD', + '\u2F7C': '\u8001', + '\u2F7D': '\u800C', + '\u2F7E': '\u8012', + '\u2F7F': '\u8033', + '\u2F80': '\u807F', + '\u2F81': '\u8089', + '\u2F82': '\u81E3', + '\u2F83': '\u81EA', + '\u2F84': '\u81F3', + '\u2F85': '\u81FC', + '\u2F86': '\u820C', + '\u2F87': '\u821B', + '\u2F88': '\u821F', + '\u2F89': '\u826E', + '\u2F8A': '\u8272', + '\u2F8B': '\u8278', + '\u2F8C': '\u864D', + '\u2F8D': '\u866B', + '\u2F8E': '\u8840', + '\u2F8F': '\u884C', + '\u2F90': '\u8863', + '\u2F91': '\u897E', + '\u2F92': '\u898B', + '\u2F93': '\u89D2', + '\u2F94': '\u8A00', + '\u2F95': '\u8C37', + '\u2F96': '\u8C46', + '\u2F97': '\u8C55', + '\u2F98': '\u8C78', + '\u2F99': '\u8C9D', + '\u2F9A': '\u8D64', + '\u2F9B': '\u8D70', + '\u2F9C': '\u8DB3', + '\u2F9D': '\u8EAB', + '\u2F9E': '\u8ECA', + '\u2F9F': '\u8F9B', + '\u2FA0': '\u8FB0', + '\u2FA1': '\u8FB5', + '\u2FA2': '\u9091', + '\u2FA3': '\u9149', + '\u2FA4': '\u91C6', + '\u2FA5': '\u91CC', + '\u2FA6': '\u91D1', + '\u2FA7': '\u9577', + '\u2FA8': '\u9580', + '\u2FA9': '\u961C', + '\u2FAA': '\u96B6', + '\u2FAB': '\u96B9', + '\u2FAC': '\u96E8', + '\u2FAD': '\u9751', + '\u2FAE': '\u975E', + '\u2FAF': '\u9762', + '\u2FB0': '\u9769', + '\u2FB1': '\u97CB', + '\u2FB2': '\u97ED', + '\u2FB3': '\u97F3', + '\u2FB4': '\u9801', + '\u2FB5': '\u98A8', + '\u2FB6': '\u98DB', + '\u2FB7': '\u98DF', + '\u2FB8': '\u9996', + '\u2FB9': '\u9999', + '\u2FBA': '\u99AC', + '\u2FBB': '\u9AA8', + '\u2FBC': '\u9AD8', + '\u2FBD': '\u9ADF', + '\u2FBE': '\u9B25', + '\u2FBF': '\u9B2F', + '\u2FC0': '\u9B32', + '\u2FC1': '\u9B3C', + '\u2FC2': '\u9B5A', + '\u2FC3': '\u9CE5', + '\u2FC4': '\u9E75', + '\u2FC5': '\u9E7F', + '\u2FC6': '\u9EA5', + '\u2FC7': '\u9EBB', + '\u2FC8': '\u9EC3', + '\u2FC9': '\u9ECD', + '\u2FCA': '\u9ED1', + '\u2FCB': '\u9EF9', + '\u2FCC': '\u9EFD', + '\u2FCD': '\u9F0E', + '\u2FCE': '\u9F13', + '\u2FCF': '\u9F20', + '\u2FD0': '\u9F3B', + '\u2FD1': '\u9F4A', + '\u2FD2': '\u9F52', + '\u2FD3': '\u9F8D', + '\u2FD4': '\u9F9C', + '\u2FD5': '\u9FA0', + '\u3036': '\u3012', + '\u3038': '\u5341', + '\u3039': '\u5344', + '\u303A': '\u5345', + '\u309B': '\u0020\u3099', + '\u309C': '\u0020\u309A', + '\u3131': '\u1100', + '\u3132': '\u1101', + '\u3133': '\u11AA', + '\u3134': '\u1102', + '\u3135': '\u11AC', + '\u3136': '\u11AD', + '\u3137': '\u1103', + '\u3138': '\u1104', + '\u3139': '\u1105', + '\u313A': '\u11B0', + '\u313B': '\u11B1', + '\u313C': '\u11B2', + '\u313D': '\u11B3', + '\u313E': '\u11B4', + '\u313F': '\u11B5', + '\u3140': '\u111A', + '\u3141': '\u1106', + '\u3142': '\u1107', + '\u3143': '\u1108', + '\u3144': '\u1121', + '\u3145': '\u1109', + '\u3146': '\u110A', + '\u3147': '\u110B', + '\u3148': '\u110C', + '\u3149': '\u110D', + '\u314A': '\u110E', + '\u314B': '\u110F', + '\u314C': '\u1110', + '\u314D': '\u1111', + '\u314E': '\u1112', + '\u314F': '\u1161', + '\u3150': '\u1162', + '\u3151': '\u1163', + '\u3152': '\u1164', + '\u3153': '\u1165', + '\u3154': '\u1166', + '\u3155': '\u1167', + '\u3156': '\u1168', + '\u3157': '\u1169', + '\u3158': '\u116A', + '\u3159': '\u116B', + '\u315A': '\u116C', + '\u315B': '\u116D', + '\u315C': '\u116E', + '\u315D': '\u116F', + '\u315E': '\u1170', + '\u315F': '\u1171', + '\u3160': '\u1172', + '\u3161': '\u1173', + '\u3162': '\u1174', + '\u3163': '\u1175', + '\u3164': '\u1160', + '\u3165': '\u1114', + '\u3166': '\u1115', + '\u3167': '\u11C7', + '\u3168': '\u11C8', + '\u3169': '\u11CC', + '\u316A': '\u11CE', + '\u316B': '\u11D3', + '\u316C': '\u11D7', + '\u316D': '\u11D9', + '\u316E': '\u111C', + '\u316F': '\u11DD', + '\u3170': '\u11DF', + '\u3171': '\u111D', + '\u3172': '\u111E', + '\u3173': '\u1120', + '\u3174': '\u1122', + '\u3175': '\u1123', + '\u3176': '\u1127', + '\u3177': '\u1129', + '\u3178': '\u112B', + '\u3179': '\u112C', + '\u317A': '\u112D', + '\u317B': '\u112E', + '\u317C': '\u112F', + '\u317D': '\u1132', + '\u317E': '\u1136', + '\u317F': '\u1140', + '\u3180': '\u1147', + '\u3181': '\u114C', + '\u3182': '\u11F1', + '\u3183': '\u11F2', + '\u3184': '\u1157', + '\u3185': '\u1158', + '\u3186': '\u1159', + '\u3187': '\u1184', + '\u3188': '\u1185', + '\u3189': '\u1188', + '\u318A': '\u1191', + '\u318B': '\u1192', + '\u318C': '\u1194', + '\u318D': '\u119E', + '\u318E': '\u11A1', + '\u3200': '\u0028\u1100\u0029', + '\u3201': '\u0028\u1102\u0029', + '\u3202': '\u0028\u1103\u0029', + '\u3203': '\u0028\u1105\u0029', + '\u3204': '\u0028\u1106\u0029', + '\u3205': '\u0028\u1107\u0029', + '\u3206': '\u0028\u1109\u0029', + '\u3207': '\u0028\u110B\u0029', + '\u3208': '\u0028\u110C\u0029', + '\u3209': '\u0028\u110E\u0029', + '\u320A': '\u0028\u110F\u0029', + '\u320B': '\u0028\u1110\u0029', + '\u320C': '\u0028\u1111\u0029', + '\u320D': '\u0028\u1112\u0029', + '\u320E': '\u0028\u1100\u1161\u0029', + '\u320F': '\u0028\u1102\u1161\u0029', + '\u3210': '\u0028\u1103\u1161\u0029', + '\u3211': '\u0028\u1105\u1161\u0029', + '\u3212': '\u0028\u1106\u1161\u0029', + '\u3213': '\u0028\u1107\u1161\u0029', + '\u3214': '\u0028\u1109\u1161\u0029', + '\u3215': '\u0028\u110B\u1161\u0029', + '\u3216': '\u0028\u110C\u1161\u0029', + '\u3217': '\u0028\u110E\u1161\u0029', + '\u3218': '\u0028\u110F\u1161\u0029', + '\u3219': '\u0028\u1110\u1161\u0029', + '\u321A': '\u0028\u1111\u1161\u0029', + '\u321B': '\u0028\u1112\u1161\u0029', + '\u321C': '\u0028\u110C\u116E\u0029', + '\u321D': '\u0028\u110B\u1169\u110C\u1165\u11AB\u0029', + '\u321E': '\u0028\u110B\u1169\u1112\u116E\u0029', + '\u3220': '\u0028\u4E00\u0029', + '\u3221': '\u0028\u4E8C\u0029', + '\u3222': '\u0028\u4E09\u0029', + '\u3223': '\u0028\u56DB\u0029', + '\u3224': '\u0028\u4E94\u0029', + '\u3225': '\u0028\u516D\u0029', + '\u3226': '\u0028\u4E03\u0029', + '\u3227': '\u0028\u516B\u0029', + '\u3228': '\u0028\u4E5D\u0029', + '\u3229': '\u0028\u5341\u0029', + '\u322A': '\u0028\u6708\u0029', + '\u322B': '\u0028\u706B\u0029', + '\u322C': '\u0028\u6C34\u0029', + '\u322D': '\u0028\u6728\u0029', + '\u322E': '\u0028\u91D1\u0029', + '\u322F': '\u0028\u571F\u0029', + '\u3230': '\u0028\u65E5\u0029', + '\u3231': '\u0028\u682A\u0029', + '\u3232': '\u0028\u6709\u0029', + '\u3233': '\u0028\u793E\u0029', + '\u3234': '\u0028\u540D\u0029', + '\u3235': '\u0028\u7279\u0029', + '\u3236': '\u0028\u8CA1\u0029', + '\u3237': '\u0028\u795D\u0029', + '\u3238': '\u0028\u52B4\u0029', + '\u3239': '\u0028\u4EE3\u0029', + '\u323A': '\u0028\u547C\u0029', + '\u323B': '\u0028\u5B66\u0029', + '\u323C': '\u0028\u76E3\u0029', + '\u323D': '\u0028\u4F01\u0029', + '\u323E': '\u0028\u8CC7\u0029', + '\u323F': '\u0028\u5354\u0029', + '\u3240': '\u0028\u796D\u0029', + '\u3241': '\u0028\u4F11\u0029', + '\u3242': '\u0028\u81EA\u0029', + '\u3243': '\u0028\u81F3\u0029', + '\u32C0': '\u0031\u6708', + '\u32C1': '\u0032\u6708', + '\u32C2': '\u0033\u6708', + '\u32C3': '\u0034\u6708', + '\u32C4': '\u0035\u6708', + '\u32C5': '\u0036\u6708', + '\u32C6': '\u0037\u6708', + '\u32C7': '\u0038\u6708', + '\u32C8': '\u0039\u6708', + '\u32C9': '\u0031\u0030\u6708', + '\u32CA': '\u0031\u0031\u6708', + '\u32CB': '\u0031\u0032\u6708', + '\u3358': '\u0030\u70B9', + '\u3359': '\u0031\u70B9', + '\u335A': '\u0032\u70B9', + '\u335B': '\u0033\u70B9', + '\u335C': '\u0034\u70B9', + '\u335D': '\u0035\u70B9', + '\u335E': '\u0036\u70B9', + '\u335F': '\u0037\u70B9', + '\u3360': '\u0038\u70B9', + '\u3361': '\u0039\u70B9', + '\u3362': '\u0031\u0030\u70B9', + '\u3363': '\u0031\u0031\u70B9', + '\u3364': '\u0031\u0032\u70B9', + '\u3365': '\u0031\u0033\u70B9', + '\u3366': '\u0031\u0034\u70B9', + '\u3367': '\u0031\u0035\u70B9', + '\u3368': '\u0031\u0036\u70B9', + '\u3369': '\u0031\u0037\u70B9', + '\u336A': '\u0031\u0038\u70B9', + '\u336B': '\u0031\u0039\u70B9', + '\u336C': '\u0032\u0030\u70B9', + '\u336D': '\u0032\u0031\u70B9', + '\u336E': '\u0032\u0032\u70B9', + '\u336F': '\u0032\u0033\u70B9', + '\u3370': '\u0032\u0034\u70B9', + '\u33E0': '\u0031\u65E5', + '\u33E1': '\u0032\u65E5', + '\u33E2': '\u0033\u65E5', + '\u33E3': '\u0034\u65E5', + '\u33E4': '\u0035\u65E5', + '\u33E5': '\u0036\u65E5', + '\u33E6': '\u0037\u65E5', + '\u33E7': '\u0038\u65E5', + '\u33E8': '\u0039\u65E5', + '\u33E9': '\u0031\u0030\u65E5', + '\u33EA': '\u0031\u0031\u65E5', + '\u33EB': '\u0031\u0032\u65E5', + '\u33EC': '\u0031\u0033\u65E5', + '\u33ED': '\u0031\u0034\u65E5', + '\u33EE': '\u0031\u0035\u65E5', + '\u33EF': '\u0031\u0036\u65E5', + '\u33F0': '\u0031\u0037\u65E5', + '\u33F1': '\u0031\u0038\u65E5', + '\u33F2': '\u0031\u0039\u65E5', + '\u33F3': '\u0032\u0030\u65E5', + '\u33F4': '\u0032\u0031\u65E5', + '\u33F5': '\u0032\u0032\u65E5', + '\u33F6': '\u0032\u0033\u65E5', + '\u33F7': '\u0032\u0034\u65E5', + '\u33F8': '\u0032\u0035\u65E5', + '\u33F9': '\u0032\u0036\u65E5', + '\u33FA': '\u0032\u0037\u65E5', + '\u33FB': '\u0032\u0038\u65E5', + '\u33FC': '\u0032\u0039\u65E5', + '\u33FD': '\u0033\u0030\u65E5', + '\u33FE': '\u0033\u0031\u65E5', + '\uFB00': '\u0066\u0066', + '\uFB01': '\u0066\u0069', + '\uFB02': '\u0066\u006C', + '\uFB03': '\u0066\u0066\u0069', + '\uFB04': '\u0066\u0066\u006C', + '\uFB05': '\u017F\u0074', + '\uFB06': '\u0073\u0074', + '\uFB13': '\u0574\u0576', + '\uFB14': '\u0574\u0565', + '\uFB15': '\u0574\u056B', + '\uFB16': '\u057E\u0576', + '\uFB17': '\u0574\u056D', + '\uFB4F': '\u05D0\u05DC', + '\uFE49': '\u203E', + '\uFE4A': '\u203E', + '\uFE4B': '\u203E', + '\uFE4C': '\u203E', + '\uFE4D': '\u005F', + '\uFE4E': '\u005F', + '\uFE4F': '\u005F' +}; + +function fontCharsToUnicode(charCodes, fontProperties) { + var toUnicode = fontProperties.toUnicode; + var composite = fontProperties.composite; + var encoding, differences, cidToUnicode; + var result = ''; + if (composite) { + cidToUnicode = fontProperties.cidToUnicode; + for (var i = 0, ii = charCodes.length; i < ii; i += 2) { + var charCode = (charCodes.charCodeAt(i) << 8) | + charCodes.charCodeAt(i + 1); + if (toUnicode && charCode in toUnicode) { + var unicode = toUnicode[charCode]; + result += typeof unicode !== 'number' ? unicode : + String.fromCharCode(unicode); + continue; + } + result += String.fromCharCode(!cidToUnicode ? charCode : + cidToUnicode[charCode] || charCode); + } + } else { + differences = fontProperties.differences; + encoding = fontProperties.baseEncoding; + for (var i = 0, ii = charCodes.length; i < ii; i++) { + var charCode = charCodes.charCodeAt(i); + var unicode; + if (toUnicode && charCode in toUnicode) { + var unicode = toUnicode[charCode]; + result += typeof unicode !== 'number' ? unicode : + String.fromCharCode(unicode); + continue; + } + + var glyphName = charCode in differences ? differences[charCode] : + encoding[charCode]; + if (glyphName in GlyphsUnicode) { + result += String.fromCharCode(GlyphsUnicode[glyphName]); + continue; + } + result += String.fromCharCode(charCode); + } + } + // normalizing the unicode characters + for (var i = 0, ii = result.length; i < ii; i++) { + if (!(result[i] in NormalizedUnicodes)) + continue; + result = result.substring(0, i) + NormalizedUnicodes[result[i]] + + result.substring(i + 1); + ii = result.length; + } + return result; +} + /** * 'Font' is the class the outside world should use, it encapsulate all the font * decoding logics whatever type it is (assuming the font type is supported). @@ -15761,9 +16683,9 @@ var Font = (function FontClosure() { this.isSymbolicFont = false; } - // heuristics: if removed more than 2 glyphs encoding WinAnsiEncoding - // does not set properly - if (glyphsRemoved > 2) { + // heuristics: if removed more than 10 glyphs encoding WinAnsiEncoding + // does not set properly (broken PDFs have about 100 removed glyphs) + if (glyphsRemoved > 10) { warn('Switching TrueType encoding to MacRomanEncoding for ' + this.name + ' font'); encoding = Encodings.MacRomanEncoding; @@ -16263,6 +17185,7 @@ var Font = (function FontClosure() { } // MacRoman encoding address by re-encoding the cmap table + fontCharCode = glyphName in this.glyphNameMap ? this.glyphNameMap[glyphName] : GlyphsUnicode[glyphName]; break; @@ -17433,7 +18356,7 @@ var CFFParser = (function CFFParserClosure() { ++offset; if (offset != 0) { - warn('cff data is shifted'); + info('cff data is shifted'); bytes = bytes.subarray(offset); this.bytes = bytes; } @@ -28669,7 +29592,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (a1 > codingLine[codingPos]) { if (a1 > this.columns) { - warn('row is wrong length'); + info('row is wrong length'); this.err = true; a1 = this.columns; } @@ -28689,7 +29612,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (a1 > codingLine[codingPos]) { if (a1 > this.columns) { - warn('row is wrong length'); + info('row is wrong length'); this.err = true; a1 = this.columns; } @@ -28699,7 +29622,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { codingLine[codingPos] = a1; } else if (a1 < codingLine[codingPos]) { if (a1 < 0) { - warn('invalid code'); + info('invalid code'); this.err = true; a1 = 0; } @@ -28861,7 +29784,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { this.eof = true; break; default: - warn('bad 2d code'); + info('bad 2d code'); this.addPixels(columns, 0); this.err = true; } @@ -28924,7 +29847,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) - warn('bad rtc code: ' + code1); + info('bad rtc code: ' + code1); this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); @@ -29047,7 +29970,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (result[0] && result[2]) return result[1]; } - warn('Bad two dim code'); + info('Bad two dim code'); return EOF; }; @@ -29080,7 +30003,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (result[0]) return result[1]; } - warn('bad white code'); + info('bad white code'); this.eatBits(1); return 1; }; @@ -29117,7 +30040,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (result[0]) return result[1]; } - warn('bad black code'); + info('bad black code'); this.eatBits(1); return 1; }; @@ -29288,10 +30211,13 @@ function MessageHandler(name, comObj) { var ah = this.actionHandler = {}; ah['console_log'] = [function ahConsoleLog(data) { - console.log.apply(console, data); + console.log.apply(console, data); }]; ah['console_error'] = [function ahConsoleError(data) { - console.error.apply(console, data); + console.error.apply(console, data); + }]; + ah['_warn'] = [function ah_Warn(data) { + warn(data); }]; comObj.onmessage = function messageHandlerComObjOnMessage(event) { @@ -29421,7 +30347,6 @@ var WorkerMessageHandler = { handler.on('RenderPageRequest', function wphSetupRenderPage(data) { var pageNum = data.pageIndex + 1; - // The following code does quite the same as // Page.prototype.startRendering, but stops at one point and sends the // result back to the main thread. @@ -29481,6 +30406,24 @@ var WorkerMessageHandler = { depFonts: Object.keys(fonts) }); }, this); + + handler.on('GetTextContent', function wphExtractText(data, promise) { + var pageNum = data.pageIndex + 1; + var start = Date.now(); + + var textContent = ''; + try { + var page = pdfModel.getPage(pageNum); + textContent = page.extractTextContent(); + promise.resolve(textContent); + } catch (e) { + // Skip errored pages + promise.reject(e); + } + + console.log('text indexing: page=%d - time=%dms', + pageNum, Date.now() - start); + }); } }; @@ -29521,6 +30464,17 @@ var workerConsole = { if (typeof window === 'undefined') { globalScope.console = workerConsole; + // Add a logger so we can pass warnings on to the main thread, errors will + // throw an exception which will be forwarded on automatically. + PDFJS.LogManager.addLogger({ + warn: function(msg) { + postMessage({ + action: '_warn', + data: msg + }); + } + }); + var handler = new MessageHandler('worker_processor', this); WorkerMessageHandler.setup(handler); } @@ -32846,20 +33800,28 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
-
- - -
+ + +
+
@@ -32869,27 +33831,27 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
-
-
-
- +
- @@ -32908,16 +33870,16 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
-
-
- diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index f616b02c9c26..8cb3647ecdf3 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -219,8 +219,11 @@ var PDFView = { currentScale: kUnknownScale, currentScaleValue: null, initialBookmark: document.location.hash.substring(1), + startedTextExtraction: false, + pageText: [], container: null, initialized: false, + fellback: false, // called once when the document is loaded initialize: function pdfViewInitialize() { this.container = document.getElementById('viewerContainer'); @@ -390,6 +393,18 @@ var PDFView = { } }, + fallback: function pdfViewFallback() { + if (!PDFJS.isFirefoxExtension) + return; + // Only trigger the fallback once so we don't spam the user with messages + // for one PDF. + if (this.fellback) + return; + this.fellback = true; + var url = this.url.split('#')[0]; + FirefoxCom.request('fallback', url); + }, + navigateTo: function pdfViewNavigateTo(dest) { if (typeof dest === 'string') dest = this.destinations[dest]; @@ -452,6 +467,34 @@ var PDFView = { * and optionally a 'stack' property. */ error: function pdfViewError(message, moreInfo) { + var moreInfoText = mozL10n.get('error_build', {build: PDFJS.build}, + 'PDF.JS Build: {{build}}') + '\n'; + if (moreInfo) { + moreInfoText += + mozL10n.get('error_message', {message: moreInfo.message}, + 'Message: {{message}}'); + if (moreInfo.stack) { + moreInfoText += '\n' + + mozL10n.get('error_stack', {stack: moreInfo.stack}, + 'Stack: {{stack}}'); + } else { + if (moreInfo.filename) { + moreInfoText += '\n' + + mozL10n.get('error_file', {file: moreInfo.filename}, + 'File: {{file}}'); + } + if (moreInfo.lineNumber) { + moreInfoText += '\n' + + mozL10n.get('error_line', {line: moreInfo.lineNumber}, + 'Line: {{line}}'); + } + } + } + if (PDFJS.isFirefoxExtension) { + console.error(message + '\n' + moreInfoText); + this.fallback(); + return; + } var errorWrapper = document.getElementById('errorWrapper'); errorWrapper.removeAttribute('hidden'); @@ -478,32 +521,9 @@ var PDFView = { }; moreInfoButton.removeAttribute('hidden'); lessInfoButton.setAttribute('hidden', 'true'); - errorMoreInfo.value = - mozL10n.get('error_build', {build: PDFJS.build}, - 'PDF.JS Build: {{build}}') + '\n'; + errorMoreInfo.value = moreInfoText; - if (moreInfo) { - errorMoreInfo.value += - mozL10n.get('error_message', {message: moreInfo.message}, - 'Message: {{message}}'); - if (moreInfo.stack) { - errorMoreInfo.value += '\n' + - mozL10n.get('error_stack', {stack: moreInfo.stack}, - 'Stack: {{stack}}'); - } else { - if (moreInfo.filename) { - errorMoreInfo.value += '\n' + - mozL10n.get('error_file', {file: moreInfo.filename}, - 'File: {{file}}'); - } - if (moreInfo.lineNumber) { - errorMoreInfo.value += '\n' + - mozL10n.get('error_line', {line: moreInfo.lineNumber}, - 'Line: {{line}}'); - } - } - } - errorMoreInfo.rows = errorMoreInfo.value.split('\n').length - 1; + errorMoreInfo.rows = moreInfoText.split('\n').length - 1; }, progress: function pdfViewProgress(level) { @@ -561,6 +581,8 @@ var PDFView = { } var pages = this.pages = []; + this.pageText = []; + this.startedTextExtraction = false; var pagesRefMap = {}; var thumbnails = this.thumbnails = []; var pagePromises = []; @@ -641,6 +663,67 @@ var PDFView = { } }, + search: function pdfViewStartSearch() { + // Limit this function to run every ms. + var SEARCH_TIMEOUT = 250; + var lastSeach = this.lastSearch; + var now = Date.now(); + if (lastSeach && (now - lastSeach) < SEARCH_TIMEOUT) { + if (!this.searchTimer) { + this.searchTimer = setTimeout(function resumeSearch() { + PDFView.search(); + }, + SEARCH_TIMEOUT - (now - lastSeach) + ); + } + return; + } + this.searchTimer = null; + this.lastSearch = now; + + function bindLink(link, pageNumber) { + link.href = '#' + pageNumber; + link.onclick = function searchBindLink() { + PDFView.page = pageNumber; + return false; + }; + } + + var searchResults = document.getElementById('searchResults'); + + var searchTermsInput = document.getElementById('searchTermsInput'); + searchResults.removeAttribute('hidden'); + searchResults.textContent = ''; + + var terms = searchTermsInput.value; + + if (!terms) + return; + + // simple search: removing spaces and hyphens, then scanning every + terms = terms.replace(/\s-/g, '').toLowerCase(); + var index = PDFView.pageText; + var pageFound = false; + for (var i = 0, ii = index.length; i < ii; i++) { + var pageText = index[i].replace(/\s-/g, '').toLowerCase(); + var j = pageText.indexOf(terms); + if (j < 0) + continue; + + var pageNumber = i + 1; + var textSample = index[i].substr(j, 50); + var link = document.createElement('a'); + bindLink(link, pageNumber); + link.textContent = 'Page ' + pageNumber + ': ' + textSample; + searchResults.appendChild(link); + + pageFound = true; + } + if (!pageFound) { + searchResults.textContent = '(Not found)'; + } + }, + setHash: function pdfViewSetHash(hash) { if (!hash) return; @@ -683,26 +766,70 @@ var PDFView = { switchSidebarView: function pdfViewSwitchSidebarView(view) { var thumbsView = document.getElementById('thumbnailView'); var outlineView = document.getElementById('outlineView'); - var thumbsSwitchButton = document.getElementById('viewThumbnail'); - var outlineSwitchButton = document.getElementById('viewOutline'); + var searchView = document.getElementById('searchView'); - if (outlineSwitchButton.getAttribute('disabled')) - return; - - thumbsView.classList.toggle('hidden'); - outlineView.classList.toggle('hidden'); - document.getElementById('viewThumbnail').classList.toggle('toggled'); - document.getElementById('viewOutline').classList.toggle('toggled'); + var thumbsButton = document.getElementById('viewThumbnail'); + var outlineButton = document.getElementById('viewOutline'); + var searchButton = document.getElementById('viewSearch'); switch (view) { case 'thumbs': + thumbsButton.classList.add('toggled'); + outlineButton.classList.remove('toggled'); + searchButton.classList.remove('toggled'); + thumbsView.classList.remove('hidden'); + outlineView.classList.add('hidden'); + searchView.classList.add('hidden'); + updateThumbViewArea(); break; + case 'outline': + thumbsButton.classList.remove('toggled'); + outlineButton.classList.add('toggled'); + searchButton.classList.remove('toggled'); + thumbsView.classList.add('hidden'); + outlineView.classList.remove('hidden'); + searchView.classList.add('hidden'); + + if (outlineButton.getAttribute('disabled')) + return; + break; + + case 'search': + thumbsButton.classList.remove('toggled'); + outlineButton.classList.remove('toggled'); + searchButton.classList.add('toggled'); + thumbsView.classList.add('hidden'); + outlineView.classList.add('hidden'); + searchView.classList.remove('hidden'); + + var searchTermsInput = document.getElementById('searchTermsInput'); + searchTermsInput.focus(); + // Start text extraction as soon as the search gets displayed. + this.extractText(); break; } }, + extractText: function() { + if (this.startedTextExtraction) + return; + this.startedTextExtraction = true; + var self = this; + function extractPageText(pageIndex) { + self.pages[pageIndex].pdfPage.getTextContent().then( + function textContentResolved(textContent) { + self.pageText[pageIndex] = textContent; + self.search(); + if ((pageIndex + 1) < self.pages.length) + extractPageText(pageIndex + 1); + } + ); + }; + extractPageText(0); + }, + getVisiblePages: function pdfViewGetVisiblePages() { var pages = this.pages; var kBottomMargin = 10; @@ -916,6 +1043,10 @@ var PageView = function pageView(container, pdfPage, id, scale, if (comment) div.appendChild(comment); break; + case 'Widget': + // TODO: support forms + PDFView.fallback(); + break; } } }); @@ -1397,6 +1528,19 @@ window.addEventListener('load', function webViewerLoad(evt) { PDFBug.init(); } + if (!PDFJS.isFirefoxExtension || + (PDFJS.isFirefoxExtension && FirefoxCom.request('searchEnabled'))) { + document.querySelector('#viewSearch').classList.remove('hidden'); + } + + // Listen for warnings to trigger the fallback UI. Errors should be caught + // and call PDFView.error() so we don't need to listen for those. + PDFJS.LogManager.addLogger({ + warn: function() { + PDFView.fallback(); + } + }); + var thumbsView = document.getElementById('thumbnailView'); thumbsView.addEventListener('scroll', updateThumbViewArea, true); diff --git a/browser/extensions/pdfjs/extension-files b/browser/extensions/pdfjs/extension-files index 08d7326d5f78..3d01131afcc2 100644 --- a/browser/extensions/pdfjs/extension-files +++ b/browser/extensions/pdfjs/extension-files @@ -1,8 +1,6 @@ -bootstrap.js -icon.png -icon64.png chrome.manifest components/PdfStreamConverter.js +content/PdfJs.jsm content/web/debugger.js content/web/images/annotation-check.svg content/web/images/annotation-comment.svg @@ -18,6 +16,7 @@ content/web/images/toolbarButton-pageDown.png content/web/images/toolbarButton-pageUp-rtl.png content/web/images/toolbarButton-pageUp.png content/web/images/toolbarButton-print.png +content/web/images/toolbarButton-search.png content/web/images/toolbarButton-sidebarToggle.png content/web/images/toolbarButton-viewOutline.png content/web/images/toolbarButton-viewThumbnail.png diff --git a/browser/extensions/pdfjs/test/Makefile.in b/browser/extensions/pdfjs/test/Makefile.in index 77b7a838d941..93ec187e28c4 100644 --- a/browser/extensions/pdfjs/test/Makefile.in +++ b/browser/extensions/pdfjs/test/Makefile.in @@ -13,6 +13,7 @@ include $(topsrcdir)/config/rules.mk _BROWSER_TEST_FILES = \ browser_pdfjs_main.js \ + browser_pdfjs_savedialog.js \ file_pdfjs_test.pdf \ $(NULL) From 51115602a823831a079ffde802c333bf7f6e276f Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Mon, 4 Jun 2012 09:17:16 -0700 Subject: [PATCH 14/53] Bug 759354 - Add other device sensors to nsEventListenerManager::IsDeviceType. r=olli --- content/events/src/nsEventListenerManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index ed9baeaa75aa..051cf1aa89fb 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -301,6 +301,9 @@ nsEventListenerManager::IsDeviceType(PRUint32 aType) switch (aType) { case NS_DEVICE_ORIENTATION: case NS_DEVICE_MOTION: + case NS_DEVICE_LIGHT: + case NS_DEVICE_PROXIMITY: + case NS_USER_PROXIMITY: return true; default: break; From 47c780390cba7c8e39bf7716598c6171622ec2ef Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Mon, 4 Jun 2012 09:19:15 -0700 Subject: [PATCH 15/53] Bug 742376 - DisableDevice is being called with types that are not known device sensors - follow up. Logic got reversed. r=smaug --- content/events/src/nsEventListenerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 051cf1aa89fb..bc93ec8e1299 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -404,7 +404,7 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener, mNoListenerForEvent = NS_EVENT_TYPE_NULL; mNoListenerForEventAtom = nsnull; - if (deviceType) { + if (!deviceType) { return; } --typeCount; From 82d4333178adf5d26ac00f35d198b016c41eaff8 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 4 Jun 2012 12:26:03 -0400 Subject: [PATCH 16/53] Bug 758361 - Move the before-first-paint event so it doesn't get improperly triggered on a plugin codepath. r=bz --- layout/base/nsDocumentViewer.cpp | 30 ------------------------------ layout/base/nsPresContext.cpp | 6 ++++-- layout/base/nsPresShell.cpp | 31 ++++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 7a885c577dfd..6991065233e9 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -471,18 +471,6 @@ public: nsCOMPtr mTop; }; -class nsBeforeFirstPaintDispatcher : public nsRunnable -{ -public: - nsBeforeFirstPaintDispatcher(nsIDocument* aDocument) - : mDocument(aDocument) {} - - NS_IMETHOD Run(); - -private: - nsCOMPtr mDocument; -}; - class nsDocumentShownDispatcher : public nsRunnable { public: @@ -2025,11 +2013,6 @@ DocumentViewerImpl::Show(void) } } - // Notify observers that a new page is about to be drawn. Execute this - // as soon as it is safe to run JS, which is guaranteed to be before we - // go back to the event loop and actually draw the page. - nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument)); - // Notify observers that a new page has been shown. This will get run // from the event loop after we actually draw the page. NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument)); @@ -4376,19 +4359,6 @@ DocumentViewerImpl::SetPrintPreviewPresentation(nsIViewManager* aViewManager, mPresShell = aPresShell; } -// Fires the "before-first-paint" event so that interested parties (right now, the -// mobile browser) are aware of it. -NS_IMETHODIMP -nsBeforeFirstPaintDispatcher::Run() -{ - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - if (observerService) { - observerService->NotifyObservers(mDocument, "before-first-paint", NULL); - } - return NS_OK; -} - // Fires the "document-shown" event so that interested parties are aware of it. NS_IMETHODIMP nsDocumentShownDispatcher::Run() diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 61594d4f56dc..7b7b1b4ebb5d 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1822,8 +1822,10 @@ nsPresContext::EnsureVisible() cv->GetPresContext(getter_AddRefs(currentPresContext)); if (currentPresContext == this) { // OK, this is us. We want to call Show() on the content viewer. - cv->Show(); - return true; + nsresult result = cv->Show(); + if (NS_SUCCEEDED(result)) { + return true; + } } } } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 79970ff6658c..d157c6d239b6 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -483,6 +483,28 @@ public: nsRefPtr mPresShell; }; +class nsBeforeFirstPaintDispatcher : public nsRunnable +{ +public: + nsBeforeFirstPaintDispatcher(nsIDocument* aDocument) + : mDocument(aDocument) {} + + // Fires the "before-first-paint" event so that interested parties (right now, the + // mobile browser) are aware of it. + NS_IMETHOD Run() + { + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (observerService) { + observerService->NotifyObservers(mDocument, "before-first-paint", NULL); + } + return NS_OK; + } + +private: + nsCOMPtr mDocument; +}; + bool PresShell::sDisableNonTestMouseEvents = false; #ifdef PR_LOGGING @@ -3509,7 +3531,14 @@ PresShell::UnsuppressAndInvalidate() // No point; we're about to be torn down anyway. return; } - + + if (!mDocument->IsResourceDoc()) { + // Notify observers that a new page is about to be drawn. Execute this + // as soon as it is safe to run JS, which is guaranteed to be before we + // go back to the event loop and actually draw the page. + nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument)); + } + mPaintingSuppressed = false; nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); if (rootFrame) { From 2c1901f5abc7f22b76bf2e18d1ca41eaf61262ae Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Mon, 4 Jun 2012 10:23:18 -0700 Subject: [PATCH 17/53] Bug 759989 - Add test to ensure device sensors are shutdown when listeners are removed. r=smaug --- content/events/test/Makefile.in | 1 + content/events/test/test_bug742376.html | 58 +++++++++++++++++++++++++ dom/base/nsGlobalWindow.cpp | 23 +++++++--- dom/system/nsDeviceSensors.cpp | 11 +++++ xpcom/system/nsIDeviceSensors.idl | 5 ++- 5 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 content/events/test/test_bug742376.html diff --git a/content/events/test/Makefile.in b/content/events/test/Makefile.in index 488085373624..5d7c62ec7f7a 100644 --- a/content/events/test/Makefile.in +++ b/content/events/test/Makefile.in @@ -85,6 +85,7 @@ _TEST_FILES = \ test_bug741666.html \ test_dom_keyboard_event.html \ test_dom_mouse_event.html \ + test_bug742376.html \ $(NULL) #bug 585630 diff --git a/content/events/test/test_bug742376.html b/content/events/test/test_bug742376.html new file mode 100644 index 000000000000..156a679d4b28 --- /dev/null +++ b/content/events/test/test_bug742376.html @@ -0,0 +1,58 @@ + + + + + Test for Bug 742376 + + + + + + +Mozilla Bug 742376 + + + + + diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 4b19d71d5217..2ce84bc30ee8 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -10040,35 +10040,44 @@ nsGlobalWindow::EnableDeviceSensor(PRUint32 aType) } } - if (alreadyEnabled) - return; - mEnabledSensors.AppendElement(aType); + if (alreadyEnabled) { + return; + } + nsCOMPtr ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); - if (ac) + if (ac) { ac->AddWindowListener(aType, this); + } } void nsGlobalWindow::DisableDeviceSensor(PRUint32 aType) { PRInt32 doomedElement = -1; + PRInt32 listenerCount = 0; for (PRUint32 i = 0; i < mEnabledSensors.Length(); i++) { if (mEnabledSensors[i] == aType) { doomedElement = i; - break; + listenerCount++; } } - if (doomedElement == -1) + if (doomedElement == -1) { return; + } mEnabledSensors.RemoveElementAt(doomedElement); + if (listenerCount > 1) { + return; + } + nsCOMPtr ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); - if (ac) + if (ac) { ac->RemoveWindowListener(aType, this); + } } NS_IMETHODIMP diff --git a/dom/system/nsDeviceSensors.cpp b/dom/system/nsDeviceSensors.cpp index 8722c0b29a72..c69cefb29bf4 100644 --- a/dom/system/nsDeviceSensors.cpp +++ b/dom/system/nsDeviceSensors.cpp @@ -118,6 +118,17 @@ nsDeviceSensors::~nsDeviceSensors() } } +NS_IMETHODIMP nsDeviceSensors::ListenerCount(PRUint32 aType, PRInt32 *aRetVal) +{ + if (!mEnabled) { + *aRetVal = 0; + return NS_OK; + } + + *aRetVal = mWindowListeners[aType]->Length(); + return NS_OK; +} + NS_IMETHODIMP nsDeviceSensors::AddWindowListener(PRUint32 aType, nsIDOMWindow *aWindow) { if (!mEnabled) diff --git a/xpcom/system/nsIDeviceSensors.idl b/xpcom/system/nsIDeviceSensors.idl index 482c168e2c04..b57f878afc30 100644 --- a/xpcom/system/nsIDeviceSensors.idl +++ b/xpcom/system/nsIDeviceSensors.idl @@ -24,11 +24,14 @@ interface nsIDeviceSensorData : nsISupports readonly attribute double z; }; -[scriptable, uuid(b672bfe0-4479-4094-a9ef-1b6847720d07)] +[scriptable, uuid(83306c9f-1c8f-43c4-900a-245d7f219511)] interface nsIDeviceSensors : nsISupports { + long listenerCount(in unsigned long aType); + // Holds pointers, not AddRef objects -- it is up to the caller // to call RemoveWindowListener before the window is deleted. + [noscript] void addWindowListener(in unsigned long aType, in nsIDOMWindow aWindow); [noscript] void removeWindowListener(in unsigned long aType, in nsIDOMWindow aWindow); [noscript] void removeWindowAsListener(in nsIDOMWindow aWindow); From 101bf90613a1202168aacec9f0e41025e755034a Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Fri, 1 Jun 2012 14:03:17 +0300 Subject: [PATCH 18/53] Bug 760143 - Get rid of useless nsresult in editor/; r=ehsan --- editor/libeditor/base/nsEditor.cpp | 16 +- editor/libeditor/base/nsEditor.h | 10 +- editor/libeditor/html/TypeInState.cpp | 27 +- editor/libeditor/html/TypeInState.h | 10 +- editor/libeditor/html/nsHTMLCSSUtils.cpp | 3 +- editor/libeditor/html/nsHTMLCSSUtils.h | 2 +- editor/libeditor/html/nsHTMLDataTransfer.cpp | 8 +- editor/libeditor/html/nsHTMLEditRules.cpp | 82 ++-- editor/libeditor/html/nsHTMLEditor.cpp | 35 +- editor/libeditor/html/nsHTMLEditor.h | 6 +- editor/libeditor/html/nsWSRunObject.cpp | 371 ++++++++----------- editor/libeditor/html/nsWSRunObject.h | 40 +- editor/libeditor/text/nsTextEditRules.cpp | 26 +- editor/libeditor/text/nsTextEditRules.h | 6 +- 14 files changed, 291 insertions(+), 351 deletions(-) diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 14b8aca7b721..e901f83bac64 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -1950,12 +1950,11 @@ nsEditor::ArePreservingSelection() return !(mSavedSel.IsEmpty()); } -nsresult +void nsEditor::PreserveSelectionAcrossActions(nsISelection *aSel) { mSavedSel.SaveSelection(aSel); mRangeUpdater.RegisterSelectionState(mSavedSel); - return NS_OK; } nsresult @@ -4245,11 +4244,11 @@ nsEditor::JoinNodeDeep(nsIDOMNode *aLeftNode, return res; } -nsresult nsEditor::BeginUpdateViewBatch() +void +nsEditor::BeginUpdateViewBatch() { NS_PRECONDITION(mUpdateCount >= 0, "bad state"); - if (0 == mUpdateCount) { // Turn off selection updates and notifications. @@ -4265,8 +4264,6 @@ nsresult nsEditor::BeginUpdateViewBatch() } mUpdateCount++; - - return NS_OK; } @@ -4397,11 +4394,10 @@ nsEditor::DeleteSelectionAndCreateNode(const nsAString& aTag, /* Non-interface, protected methods */ -nsresult -nsEditor::GetIMEBufferLength(PRInt32* length) +PRInt32 +nsEditor::GetIMEBufferLength() { - *length = mIMEBufferLength; - return NS_OK; + return mIMEBufferLength; } void diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index ff598a6f24cd..5f3869f29701 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -387,7 +387,7 @@ public: /** routines for managing the preservation of selection across * various editor actions */ bool ArePreservingSelection(); - nsresult PreserveSelectionAcrossActions(nsISelection *aSel); + void PreserveSelectionAcrossActions(nsISelection *aSel); nsresult RestorePreservedSelection(nsISelection *aSel); void StopPreservingSelection(); @@ -569,9 +569,9 @@ public: /** Find the deep first and last children. */ nsINode* GetFirstEditableNode(nsINode* aRoot); - nsresult GetIMEBufferLength(PRInt32* length); - bool IsIMEComposing(); /* test if IME is in composition state */ - void SetIsIMEComposing(); /* call this before |IsIMEComposing()| */ + PRInt32 GetIMEBufferLength(); + bool IsIMEComposing(); /* test if IME is in composition state */ + void SetIsIMEComposing(); /* call this before |IsIMEComposing()| */ /** from html rules code - migration in progress */ static nsresult GetTagString(nsIDOMNode *aNode, nsAString& outString); @@ -618,7 +618,7 @@ public: nsresult GetString(const nsAString& name, nsAString& value); - nsresult BeginUpdateViewBatch(void); + void BeginUpdateViewBatch(void); virtual nsresult EndUpdateViewBatch(void); bool GetShouldTxnSetSelection(); diff --git a/editor/libeditor/html/TypeInState.cpp b/editor/libeditor/html/TypeInState.cpp index 937ddfb51334..1436e9c74db2 100644 --- a/editor/libeditor/html/TypeInState.cpp +++ b/editor/libeditor/html/TypeInState.cpp @@ -211,16 +211,18 @@ TypeInState::TakeRelativeFontSize() return relSize; } -nsresult TypeInState::GetTypingState(bool &isSet, bool &theSetting, nsIAtom *aProp) +void +TypeInState::GetTypingState(bool &isSet, bool &theSetting, nsIAtom *aProp) { - return GetTypingState(isSet, theSetting, aProp, EmptyString(), nsnull); + GetTypingState(isSet, theSetting, aProp, EmptyString(), nsnull); } -nsresult TypeInState::GetTypingState(bool &isSet, - bool &theSetting, - nsIAtom *aProp, - const nsString &aAttr, - nsString *aValue) +void +TypeInState::GetTypingState(bool &isSet, + bool &theSetting, + nsIAtom *aProp, + const nsString &aAttr, + nsString *aValue) { if (IsPropSet(aProp, aAttr, aValue)) { @@ -236,7 +238,6 @@ nsresult TypeInState::GetTypingState(bool &isSet, { isSet = false; } - return NS_OK; } @@ -245,8 +246,8 @@ nsresult TypeInState::GetTypingState(bool &isSet, * protected methods *******************************************************************/ -nsresult TypeInState::RemovePropFromSetList(nsIAtom* aProp, - const nsAString& aAttr) +void +TypeInState::RemovePropFromSetList(nsIAtom* aProp, const nsAString& aAttr) { PRInt32 index; if (!aProp) @@ -263,12 +264,11 @@ nsresult TypeInState::RemovePropFromSetList(nsIAtom* aProp, delete mSetArray[index]; mSetArray.RemoveElementAt(index); } - return NS_OK; } -nsresult TypeInState::RemovePropFromClearedList(nsIAtom* aProp, - const nsAString& aAttr) +void +TypeInState::RemovePropFromClearedList(nsIAtom* aProp, const nsAString& aAttr) { PRInt32 index; if (FindPropInList(aProp, aAttr, nsnull, mClearedArray, index)) @@ -276,7 +276,6 @@ nsresult TypeInState::RemovePropFromClearedList(nsIAtom* aProp, delete mClearedArray[index]; mClearedArray.RemoveElementAt(index); } - return NS_OK; } diff --git a/editor/libeditor/html/TypeInState.h b/editor/libeditor/html/TypeInState.h index 03259fccc935..43c129a1a378 100644 --- a/editor/libeditor/html/TypeInState.h +++ b/editor/libeditor/html/TypeInState.h @@ -62,16 +62,16 @@ public: // cleared out. PRInt32 TakeRelativeFontSize(); - nsresult GetTypingState(bool &isSet, bool &theSetting, nsIAtom *aProp); - nsresult GetTypingState(bool &isSet, bool &theSetting, nsIAtom *aProp, - const nsString &aAttr, nsString* outValue); + void GetTypingState(bool &isSet, bool &theSetting, nsIAtom *aProp); + void GetTypingState(bool &isSet, bool &theSetting, nsIAtom *aProp, + const nsString &aAttr, nsString* outValue); static bool FindPropInList(nsIAtom *aProp, const nsAString &aAttr, nsAString *outValue, nsTArray &aList, PRInt32 &outIndex); protected: - nsresult RemovePropFromSetList(nsIAtom* aProp, const nsAString& aAttr); - nsresult RemovePropFromClearedList(nsIAtom* aProp, const nsAString& aAttr); + void RemovePropFromSetList(nsIAtom* aProp, const nsAString& aAttr); + void RemovePropFromClearedList(nsIAtom* aProp, const nsAString& aAttr); bool IsPropSet(nsIAtom* aProp, const nsAString& aAttr, nsAString* outValue); bool IsPropSet(nsIAtom* aProp, const nsAString& aAttr, nsAString* outValue, PRInt32& outIndex); bool IsPropCleared(nsIAtom* aProp, const nsAString& aAttr); diff --git a/editor/libeditor/html/nsHTMLCSSUtils.cpp b/editor/libeditor/html/nsHTMLCSSUtils.cpp index f832770178e3..a05199ee752d 100644 --- a/editor/libeditor/html/nsHTMLCSSUtils.cpp +++ b/editor/libeditor/html/nsHTMLCSSUtils.cpp @@ -1279,11 +1279,10 @@ nsHTMLCSSUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode *aNode, return NS_OK; } -nsresult +void nsHTMLCSSUtils::SetCSSEnabled(bool aIsCSSPrefChecked) { mIsCSSPrefChecked = aIsCSSPrefChecked; - return NS_OK; } bool diff --git a/editor/libeditor/html/nsHTMLCSSUtils.h b/editor/libeditor/html/nsHTMLCSSUtils.h index aeb4d475fc6f..4dfcd868f4b0 100644 --- a/editor/libeditor/html/nsHTMLCSSUtils.h +++ b/editor/libeditor/html/nsHTMLCSSUtils.h @@ -258,7 +258,7 @@ public: * * @param aIsCSSPrefChecked [IN] the new boolean state for the pref */ - nsresult SetCSSEnabled(bool aIsCSSPrefChecked); + void SetCSSEnabled(bool aIsCSSPrefChecked); /** retrieves the mIsCSSPrefChecked private member, true if the css pref is checked, * false if it is not diff --git a/editor/libeditor/html/nsHTMLDataTransfer.cpp b/editor/libeditor/html/nsHTMLDataTransfer.cpp index 8ae41b908e74..d064cd7eba40 100644 --- a/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -667,8 +667,8 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString, nsWSRunObject wsRunObj(this, selNode, selOffset); PRInt32 outVisOffset=0; PRInt16 visType=0; - rv = wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), &outVisOffset, &visType); - NS_ENSURE_SUCCESS(rv, rv); + wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), + &outVisOffset, &visType); if (visType == nsWSRunObject::eBreak) { // we are after a break. Is it visible? Despite the name, @@ -682,8 +682,8 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString, rv = GetNodeLocation(wsRunObj.mStartReasonNode, address_of(selNode), &selOffset); // we want to be inside any inline style prior to break nsWSRunObject wsRunObj(this, selNode, selOffset); - rv = wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), &outVisOffset, &visType); - NS_ENSURE_SUCCESS(rv, rv); + wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode), + &outVisOffset, &visType); if (visType == nsWSRunObject::eText || visType == nsWSRunObject::eNormalWS) { diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp index 6a5b0dc0699d..f817160546f8 100644 --- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -1591,15 +1591,13 @@ nsHTMLEditRules::StandardBreakImpl(nsIDOMNode* aNode, PRInt32 aOffset, nsCOMPtr visNode, linkNode; PRInt32 visOffset = 0, newOffset; PRInt16 wsType; - res = wsObj.PriorVisibleNode(node, aOffset, address_of(visNode), - &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.PriorVisibleNode(node, aOffset, address_of(visNode), + &visOffset, &wsType); if (wsType & nsWSRunObject::eBlock) { bAfterBlock = true; } - res = wsObj.NextVisibleNode(node, aOffset, address_of(visNode), - &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(node, aOffset, address_of(visNode), + &visOffset, &wsType); if (wsType & nsWSRunObject::eBlock) { bBeforeBlock = true; } @@ -1621,6 +1619,7 @@ nsHTMLEditRules::StandardBreakImpl(nsIDOMNode* aNode, PRInt32 aOffset, NS_ENSURE_SUCCESS(res, res); res = nsEditor::GetNodeLocation(brNode, address_of(node), &aOffset); NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); if (bAfterBlock && bBeforeBlock) { // we just placed a br between block boundaries. This is the one case // where we want the selection to be before the br we just placed, as the @@ -1632,9 +1631,8 @@ nsHTMLEditRules::StandardBreakImpl(nsIDOMNode* aNode, PRInt32 aOffset, nsCOMPtr secondBR; PRInt32 visOffset = 0; PRInt16 wsType; - res = wsObj.NextVisibleNode(node, aOffset+1, address_of(secondBR), - &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(node, aOffset+1, address_of(secondBR), + &visOffset, &wsType); if (wsType == nsWSRunObject::eBreak) { // the next thing after the break we inserted is another break. Move // the 2nd break to be the first breaks sibling. This will prevent them @@ -1703,8 +1701,8 @@ nsHTMLEditRules::SplitMailCites(nsISelection *aSelection, bool aPlaintext, bool nsCOMPtr visNode; PRInt32 visOffset=0; PRInt16 wsType; - res = wsObj.NextVisibleNode(selNode, selOffset, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(selNode, selOffset, address_of(visNode), + &visOffset, &wsType); if (wsType==nsWSRunObject::eBreak) { // ok, we are just before a break. is it inside the mailquote? @@ -1740,15 +1738,15 @@ nsHTMLEditRules::SplitMailCites(nsISelection *aSelection, bool aPlaintext, bool nsCOMPtr visNode; PRInt32 visOffset=0; PRInt16 wsType; - res = wsObj.PriorVisibleNode(selNode, newOffset, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.PriorVisibleNode(selNode, newOffset, address_of(visNode), + &visOffset, &wsType); if ((wsType==nsWSRunObject::eNormalWS) || (wsType==nsWSRunObject::eText) || (wsType==nsWSRunObject::eSpecial)) { nsWSRunObject wsObjAfterBR(mHTMLEditor, selNode, newOffset+1); - res = wsObjAfterBR.NextVisibleNode(selNode, newOffset+1, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObjAfterBR.NextVisibleNode(selNode, newOffset+1, address_of(visNode), + &visOffset, &wsType); if ((wsType==nsWSRunObject::eNormalWS) || (wsType==nsWSRunObject::eText) || (wsType==nsWSRunObject::eSpecial)) @@ -1872,10 +1870,11 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection* aSelection, // find next visible node if (aAction == nsIEditor::eNext) - res = wsObj.NextVisibleNode(startNode, startOffset, address_of(visNode), &visOffset, &wsType); + wsObj.NextVisibleNode(startNode, startOffset, address_of(visNode), + &visOffset, &wsType); else - res = wsObj.PriorVisibleNode(startNode, startOffset, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.PriorVisibleNode(startNode, startOffset, address_of(visNode), + &visOffset, &wsType); if (!visNode) // can't find anything to delete! { @@ -2009,8 +2008,8 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection* aSelection, nsCOMPtr otherNode; PRInt32 otherOffset; - res = wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), + &otherOffset, &otherWSType); if (otherWSType == nsWSRunObject::eBreak) { @@ -2077,10 +2076,11 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection* aSelection, // find node in other direction if (aAction == nsIEditor::eNext) - res = wsObj.PriorVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType); + wsObj.PriorVisibleNode(startNode, startOffset, address_of(otherNode), + &otherOffset, &otherWSType); else - res = wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), + &otherOffset, &otherWSType); // first find the adjacent node in the block nsCOMPtr leafNode, leftNode, rightNode, leftParent, rightParent; @@ -4964,8 +4964,8 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection) while (stillLooking) { nsWSRunObject wsObj(mHTMLEditor, selStartNode, selStartOffset); - res = wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(visNode), + &visOffset, &wsType); if (wsType == nsWSRunObject::eThisBlock) { // we want to keep looking up. But stop if we are crossing table element @@ -4995,8 +4995,8 @@ nsHTMLEditRules::ExpandSelectionForDeletion(nsISelection *aSelection) while (stillLooking) { nsWSRunObject wsObj(mHTMLEditor, selEndNode, selEndOffset); - res = wsObj.NextVisibleNode(selEndNode, selEndOffset, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(selEndNode, selEndOffset, address_of(visNode), + &visOffset, &wsType); if (wsType == nsWSRunObject::eBreak) { if (mHTMLEditor->IsVisBreak(wsObj.mEndReasonNode)) @@ -5137,8 +5137,8 @@ nsHTMLEditRules::NormalizeSelection(nsISelection *inSelection) nsWSRunObject wsEndObj(mHTMLEditor, endNode, endOffset); // is there any intervening visible whitespace? if so we can't push selection past that, // it would visibly change maening of users selection - res = wsEndObj.PriorVisibleNode(endNode, endOffset, address_of(someNode), &offset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsEndObj.PriorVisibleNode(endNode, endOffset, address_of(someNode), + &offset, &wsType); if ((wsType != nsWSRunObject::eText) && (wsType != nsWSRunObject::eNormalWS)) { // eThisBlock and eOtherBlock conveniently distinquish cases @@ -5181,8 +5181,8 @@ nsHTMLEditRules::NormalizeSelection(nsISelection *inSelection) nsWSRunObject wsStartObj(mHTMLEditor, startNode, startOffset); // is there any intervening visible whitespace? if so we can't push selection past that, // it would visibly change maening of users selection - res = wsStartObj.NextVisibleNode(startNode, startOffset, address_of(someNode), &offset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsStartObj.NextVisibleNode(startNode, startOffset, address_of(someNode), + &offset, &wsType); if ((wsType != nsWSRunObject::eText) && (wsType != nsWSRunObject::eNormalWS)) { // eThisBlock and eOtherBlock conveniently distinquish cases @@ -5252,7 +5252,6 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, nsCOMPtr *outNode, PRInt32 *outOffset) { - nsresult res = NS_OK; nsCOMPtr nearNode, node = aNode; nsCOMPtr parent = aNode; PRInt32 pOffset, offset = aOffset; @@ -5277,8 +5276,8 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, do { PRInt32 prevOffset; - res = mHTMLEditor->IsPrevCharWhitespace(node, offset, &isSpace, &isNBSP, address_of(temp), &prevOffset); - NS_ENSURE_SUCCESS(res, res); + mHTMLEditor->IsPrevCharWhitespace(node, offset, &isSpace, &isNBSP, + address_of(temp), &prevOffset); if (isSpace || isNBSP) { node = temp; offset = prevOffset; @@ -5295,8 +5294,8 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, do { PRInt32 nextOffset; - res = mHTMLEditor->IsNextCharWhitespace(node, offset, &isSpace, &isNBSP, address_of(temp), &nextOffset); - NS_ENSURE_SUCCESS(res, res); + mHTMLEditor->IsNextCharWhitespace(node, offset, &isSpace, &isNBSP, + address_of(temp), &nextOffset); if (isSpace || isNBSP) { node = temp; offset = nextOffset; @@ -5308,11 +5307,12 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode, *outNode = node; *outOffset = offset; } - return res; + return NS_OK; } // else not a text section. In this case we want to see if we should // grab any adjacent inline nodes and/or parents and other ancestors + nsresult res = NS_OK; if (aWhere == kStart) { // some special casing for text nodes @@ -6371,9 +6371,7 @@ nsHTMLEditRules::ReturnInParagraph(nsISelection* aSelection, nsresult res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset); NS_ENSURE_SUCCESS(res, res); - bool doesCRCreateNewP; - res = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph(&doesCRCreateNewP); - NS_ENSURE_SUCCESS(res, res); + bool doesCRCreateNewP = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph(); bool newBRneeded = false; nsCOMPtr sibling; @@ -6653,8 +6651,8 @@ nsHTMLEditRules::ReturnInListItem(nsISelection *aSelection, nsCOMPtr visNode; PRInt32 visOffset = 0; PRInt16 wsType; - res = wsObj.NextVisibleNode(aListItem, 0, address_of(visNode), &visOffset, &wsType); - NS_ENSURE_SUCCESS(res, res); + wsObj.NextVisibleNode(aListItem, 0, address_of(visNode), + &visOffset, &wsType); if ( (wsType==nsWSRunObject::eSpecial) || (wsType==nsWSRunObject::eBreak) || nsHTMLEditUtils::IsHR(visNode) ) diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index f8f3e3e54ac5..c7d8e5e2e4a8 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -976,7 +976,7 @@ static const PRUnichar nbsp = 160; /////////////////////////////////////////////////////////////////////////// // IsNextCharWhitespace: checks the adjacent content in the same block // to see if following selection is whitespace or nbsp -nsresult +void nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, PRInt32 aOffset, bool *outIsSpace, @@ -984,7 +984,7 @@ nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, nsCOMPtr *outNode, PRInt32 *outOffset) { - NS_ENSURE_TRUE(outIsSpace && outIsNBSP, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(outIsSpace && outIsNBSP); *outIsSpace = false; *outIsNBSP = false; if (outNode) *outNode = nsnull; @@ -1004,7 +1004,7 @@ nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, *outIsNBSP = (tempString.First() == nbsp); if (outNode) *outNode = do_QueryInterface(aParentNode); if (outOffset) *outOffset = aOffset+1; // yes, this is _past_ the character; - return NS_OK; + return; } } @@ -1028,7 +1028,7 @@ nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, *outIsNBSP = (tempString.First() == nbsp); if (outNode) *outNode = do_QueryInterface(node); if (outOffset) *outOffset = 1; // yes, this is _past_ the character; - return NS_OK; + return; } // else it's an empty text node, or not editable; skip it. } @@ -1040,15 +1040,13 @@ nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, tmp = node; node = NextNodeInBlock(tmp, kIterForward); } - - return NS_OK; } /////////////////////////////////////////////////////////////////////////// // IsPrevCharWhitespace: checks the adjacent content in the same block // to see if following selection is whitespace -nsresult +void nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, PRInt32 aOffset, bool *outIsSpace, @@ -1056,7 +1054,7 @@ nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, nsCOMPtr *outNode, PRInt32 *outOffset) { - NS_ENSURE_TRUE(outIsSpace && outIsNBSP, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(outIsSpace && outIsNBSP); *outIsSpace = false; *outIsNBSP = false; if (outNode) *outNode = nsnull; @@ -1075,7 +1073,7 @@ nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, *outIsNBSP = (tempString.First() == nbsp); if (outNode) *outNode = do_QueryInterface(aParentNode); if (outOffset) *outOffset = aOffset-1; - return NS_OK; + return; } } @@ -1100,7 +1098,7 @@ nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, *outIsNBSP = (tempString.First() == nbsp); if (outNode) *outNode = do_QueryInterface(aParentNode); if (outOffset) *outOffset = strLength-1; - return NS_OK; + return; } // else it's an empty text node, or not editable; skip it. } @@ -1113,9 +1111,6 @@ nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, tmp = node; node = NextNodeInBlock(tmp, kIterBackward); } - - return NS_OK; - } @@ -4625,9 +4620,8 @@ nsHTMLEditor::IsVisTextNode(nsIContent* aNode, nsCOMPtr visNode; PRInt32 outVisOffset=0; PRInt16 visType=0; - nsresult res = wsRunObj.NextVisibleNode(node, 0, address_of(visNode), - &outVisOffset, &visType); - NS_ENSURE_SUCCESS(res, res); + wsRunObj.NextVisibleNode(node, 0, address_of(visNode), + &outVisOffset, &visType); if ( (visType == nsWSRunObject::eNormalWS) || (visType == nsWSRunObject::eText) ) { @@ -4872,8 +4866,7 @@ nsHTMLEditor::SetIsCSSEnabled(bool aIsCSSPrefChecked) return NS_ERROR_NOT_INITIALIZED; } - nsresult rv = mHTMLCSSUtils->SetCSSEnabled(aIsCSSPrefChecked); - NS_ENSURE_SUCCESS(rv, rv); + mHTMLCSSUtils->SetCSSEnabled(aIsCSSPrefChecked); // Disable the eEditorNoCSSMask flag if we're enabling StyleWithCSS. PRUint32 flags = mFlags; @@ -5353,6 +5346,12 @@ nsHTMLEditor::SetReturnInParagraphCreatesNewParagraph(bool aCreatesNewParagraph) return NS_OK; } +bool +nsHTMLEditor::GetReturnInParagraphCreatesNewParagraph() +{ + return mCRInParagraphCreatesParagraph; +} + nsresult nsHTMLEditor::GetReturnInParagraphCreatesNewParagraph(bool *aCreatesNewParagraph) { diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index 9329f758df8b..c46331f99203 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -96,6 +96,8 @@ public: nsHTMLEditor(); virtual ~nsHTMLEditor(); + bool GetReturnInParagraphCreatesNewParagraph(); + /* ------------ nsPlaintextEditor overrides -------------- */ NS_IMETHOD GetIsDocumentEditable(bool *aIsDocumentEditable); NS_IMETHOD BeginningOfDocument(); @@ -228,13 +230,13 @@ public: static already_AddRefed GetBlockNodeParent(nsIDOMNode *aNode); static already_AddRefed NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir); - nsresult IsNextCharWhitespace(nsIDOMNode *aParentNode, + void IsNextCharWhitespace(nsIDOMNode *aParentNode, PRInt32 aOffset, bool *outIsSpace, bool *outIsNBSP, nsCOMPtr *outNode = 0, PRInt32 *outOffset = 0); - nsresult IsPrevCharWhitespace(nsIDOMNode *aParentNode, + void IsPrevCharWhitespace(nsIDOMNode *aParentNode, PRInt32 aOffset, bool *outIsSpace, bool *outIsNBSP, diff --git a/editor/libeditor/html/nsWSRunObject.cpp b/editor/libeditor/html/nsWSRunObject.cpp index 6d7d96229143..245cb9bafe6c 100644 --- a/editor/libeditor/html/nsWSRunObject.cpp +++ b/editor/libeditor/html/nsWSRunObject.cpp @@ -158,8 +158,8 @@ nsWSRunObject::InsertBreak(nsCOMPtr *aInOutParent, nsresult res = NS_OK; WSFragment *beforeRun, *afterRun; - res = FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false); - res = FindRun(*aInOutParent, *aInOutOffset, &afterRun, true); + FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false); + FindRun(*aInOutParent, *aInOutOffset, &afterRun, true); { // some scoping for nsAutoTrackDOMPoint. This will track our insertion point @@ -188,14 +188,10 @@ nsWSRunObject::InsertBreak(nsCOMPtr *aInOutParent, { // need to determine if break at front of non-nbsp run. if so // convert run to nbsp. - WSPoint thePoint; - res = GetCharAfter(*aInOutParent, *aInOutOffset, &thePoint); - if ( (NS_SUCCEEDED(res)) && thePoint.mTextNode && (nsCRT::IsAsciiSpace(thePoint.mChar)) ) - { - WSPoint prevPoint; - res = GetCharBefore(thePoint, &prevPoint); - if ( (NS_FAILED(res)) || (prevPoint.mTextNode && !nsCRT::IsAsciiSpace(prevPoint.mChar)) ) - { + WSPoint thePoint = GetCharAfter(*aInOutParent, *aInOutOffset); + if (thePoint.mTextNode && nsCRT::IsAsciiSpace(thePoint.mChar)) { + WSPoint prevPoint = GetCharBefore(thePoint); + if (prevPoint.mTextNode && !nsCRT::IsAsciiSpace(prevPoint.mChar)) { // we are at start of non-nbsps. convert to a single nbsp. res = ConvertToNBSP(thePoint); NS_ENSURE_SUCCESS(res, res); @@ -254,8 +250,8 @@ nsWSRunObject::InsertText(const nsAString& aStringToInsert, nsAutoString theString(aStringToInsert); WSFragment *beforeRun, *afterRun; - res = FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false); - res = FindRun(*aInOutParent, *aInOutOffset, &afterRun, true); + FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false); + FindRun(*aInOutParent, *aInOutOffset, &afterRun, true); { // some scoping for nsAutoTrackDOMPoint. This will track our insertion point @@ -327,10 +323,8 @@ nsWSRunObject::InsertText(const nsAString& aStringToInsert, } else if (beforeRun->mType & eNormalWS) { - WSPoint wspoint; - res = GetCharBefore(*aInOutParent, *aInOutOffset, &wspoint); - if (NS_SUCCEEDED(res) && wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar)) - { + WSPoint wspoint = GetCharBefore(*aInOutParent, *aInOutOffset); + if (wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar)) { theString.SetCharAt(nbsp, 0); } } @@ -358,10 +352,8 @@ nsWSRunObject::InsertText(const nsAString& aStringToInsert, } else if (afterRun->mType & eNormalWS) { - WSPoint wspoint; - res = GetCharAfter(*aInOutParent, *aInOutOffset, &wspoint); - if (NS_SUCCEEDED(res) && wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar)) - { + WSPoint wspoint = GetCharAfter(*aInOutParent, *aInOutOffset); + if (wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar)) { theString.SetCharAt(nbsp, lastCharIndex); } } @@ -409,9 +401,7 @@ nsresult nsWSRunObject::DeleteWSBackward() { nsresult res = NS_OK; - WSPoint point; - res = GetCharBefore(mNode, mOffset, &point); - NS_ENSURE_SUCCESS(res, res); + WSPoint point = GetCharBefore(mNode, mOffset); NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete if (mPRE) // easy case, preformatted ws @@ -431,9 +421,8 @@ nsWSRunObject::DeleteWSBackward() { nsCOMPtr startNode, endNode, node(do_QueryInterface(point.mTextNode)); PRInt32 startOffset, endOffset; - res = GetAsciiWSBounds(eBoth, node, point.mOffset+1, address_of(startNode), - &startOffset, address_of(endNode), &endOffset); - NS_ENSURE_SUCCESS(res, res); + GetAsciiWSBounds(eBoth, node, point.mOffset+1, address_of(startNode), + &startOffset, address_of(endNode), &endOffset); // adjust surrounding ws res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, address_of(startNode), &startOffset, @@ -464,9 +453,7 @@ nsresult nsWSRunObject::DeleteWSForward() { nsresult res = NS_OK; - WSPoint point; - res = GetCharAfter(mNode, mOffset, &point); - NS_ENSURE_SUCCESS(res, res); + WSPoint point = GetCharAfter(mNode, mOffset); NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete if (mPRE) // easy case, preformatted ws @@ -486,9 +473,8 @@ nsWSRunObject::DeleteWSForward() { nsCOMPtr startNode, endNode, node(do_QueryInterface(point.mTextNode)); PRInt32 startOffset, endOffset; - res = GetAsciiWSBounds(eBoth, node, point.mOffset+1, address_of(startNode), - &startOffset, address_of(endNode), &endOffset); - NS_ENSURE_SUCCESS(res, res); + GetAsciiWSBounds(eBoth, node, point.mOffset+1, address_of(startNode), + &startOffset, address_of(endNode), &endOffset); // adjust surrounding ws res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, address_of(startNode), &startOffset, @@ -515,7 +501,7 @@ nsWSRunObject::DeleteWSForward() return NS_OK; } -nsresult +void nsWSRunObject::PriorVisibleNode(nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr *outVisNode, @@ -524,7 +510,7 @@ nsWSRunObject::PriorVisibleNode(nsIDOMNode *aNode, { // Find first visible thing before the point. position outVisNode/outVisOffset // just _after_ that thing. If we don't find anything return start of ws. - NS_ENSURE_TRUE(aNode && outVisNode && outVisOffset && outType, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aNode && outVisNode && outVisOffset && outType); *outType = eNone; WSFragment *run; @@ -535,8 +521,7 @@ nsWSRunObject::PriorVisibleNode(nsIDOMNode *aNode, { if (run->mType == eNormalWS) { - WSPoint point; - GetCharBefore(aNode, aOffset, &point); + WSPoint point = GetCharBefore(aNode, aOffset); if (point.mTextNode) { *outVisNode = do_QueryInterface(point.mTextNode); @@ -554,7 +539,7 @@ nsWSRunObject::PriorVisibleNode(nsIDOMNode *aNode, { *outType = eText; } - return NS_OK; + return; } // else if no text node then keep looking. We should eventually fall out of loop } @@ -566,11 +551,10 @@ nsWSRunObject::PriorVisibleNode(nsIDOMNode *aNode, *outVisNode = mStartReasonNode; *outVisOffset = mStartOffset; // this really isn't meaningful if mStartReasonNode!=mStartNode *outType = mStartReason; - return NS_OK; } -nsresult +void nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr *outVisNode, @@ -579,7 +563,7 @@ nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode, { // Find first visible thing after the point. position outVisNode/outVisOffset // just _before_ that thing. If we don't find anything return end of ws. - NS_ENSURE_TRUE(aNode && outVisNode && outVisOffset && outType, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aNode && outVisNode && outVisOffset && outType); WSFragment *run; FindRun(aNode, aOffset, &run, true); @@ -589,8 +573,7 @@ nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode, { if (run->mType == eNormalWS) { - WSPoint point; - GetCharAfter(aNode, aOffset, &point); + WSPoint point = GetCharAfter(aNode, aOffset); if (point.mTextNode) { *outVisNode = do_QueryInterface(point.mTextNode); @@ -608,7 +591,7 @@ nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode, { *outType = eText; } - return NS_OK; + return; } // else if no text node then keep looking. We should eventually fall out of loop } @@ -620,7 +603,6 @@ nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode, *outVisNode = mEndReasonNode; *outVisOffset = mEndOffset; // this really isn't meaningful if mEndReasonNode!=mEndNode *outType = mEndReason; - return NS_OK; } nsresult @@ -951,7 +933,7 @@ nsWSRunObject::GetWSNodes() return NS_OK; } -nsresult +void nsWSRunObject::GetRuns() { ClearRuns(); @@ -963,7 +945,8 @@ nsWSRunObject::GetRuns() if ( mPRE || (((mStartReason == eText) || (mStartReason == eSpecial)) && ((mEndReason == eText) || (mEndReason == eSpecial) || (mEndReason == eBreak))) ) { - return MakeSingleWSRun(eNormalWS); + MakeSingleWSRun(eNormalWS); + return; } // if we are before or after a block (or after a break), and there are no nbsp's, @@ -976,12 +959,12 @@ nsWSRunObject::GetRuns() wstype = eLeadingWS; if (mEndReason & eBlock) wstype |= eTrailingWS; - return MakeSingleWSRun(wstype); + MakeSingleWSRun(wstype); + return; } // otherwise a little trickier. shucks. mStartRun = new WSFragment(); - NS_ENSURE_TRUE(mStartRun, NS_ERROR_NULL_POINTER); mStartRun->mStartNode = mStartNode; mStartRun->mStartOffset = mStartOffset; @@ -996,7 +979,6 @@ nsWSRunObject::GetRuns() // set up next run WSFragment *normalRun = new WSFragment(); - NS_ENSURE_TRUE(normalRun, NS_ERROR_NULL_POINTER); mStartRun->mRight = normalRun; normalRun->mType = eNormalWS; normalRun->mStartNode = mFirstNBSPNode; @@ -1033,7 +1015,6 @@ nsWSRunObject::GetRuns() // set up next run WSFragment *lastRun = new WSFragment(); - NS_ENSURE_TRUE(lastRun, NS_ERROR_NULL_POINTER); lastRun->mType = eTrailingWS; lastRun->mStartNode = mLastNBSPNode; lastRun->mStartOffset = mLastNBSPOffset+1; @@ -1070,7 +1051,6 @@ nsWSRunObject::GetRuns() { // set up next run WSFragment *lastRun = new WSFragment(); - NS_ENSURE_TRUE(lastRun, NS_ERROR_NULL_POINTER); lastRun->mType = eTrailingWS; lastRun->mStartNode = mLastNBSPNode; lastRun->mStartOffset = mLastNBSPOffset+1; @@ -1082,8 +1062,6 @@ nsWSRunObject::GetRuns() mStartRun->mRightType = eTrailingWS; } } - - return NS_OK; } void @@ -1101,11 +1079,10 @@ nsWSRunObject::ClearRuns() mEndRun = 0; } -nsresult +void nsWSRunObject::MakeSingleWSRun(PRInt16 aType) { mStartRun = new WSFragment(); - NS_ENSURE_TRUE(mStartRun, NS_ERROR_NULL_POINTER); mStartRun->mStartNode = mStartNode; mStartRun->mStartOffset = mStartOffset; @@ -1116,8 +1093,6 @@ nsWSRunObject::MakeSingleWSRun(PRInt16 aType) mStartRun->mRightType = mEndReason; mEndRun = mStartRun; - - return NS_OK; } nsresult @@ -1365,10 +1340,8 @@ nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject) // get the runs before and after selection WSFragment *beforeRun, *afterRun; - res = FindRun(mNode, mOffset, &beforeRun, false); - NS_ENSURE_SUCCESS(res, res); - res = aEndObject->FindRun(aEndObject->mNode, aEndObject->mOffset, &afterRun, true); - NS_ENSURE_SUCCESS(res, res); + FindRun(mNode, mOffset, &beforeRun, false); + aEndObject->FindRun(aEndObject->mNode, aEndObject->mOffset, &afterRun, true); // trim after run of any leading ws if (afterRun && (afterRun->mType & eLeadingWS)) @@ -1384,8 +1357,8 @@ nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject) (!beforeRun && ((mStartReason & eBlock) || (mStartReason == eBreak))) ) { // make sure leading char of following ws is an nbsp, so that it will show up - WSPoint point; - aEndObject->GetCharAfter(aEndObject->mNode, aEndObject->mOffset, &point); + WSPoint point = aEndObject->GetCharAfter(aEndObject->mNode, + aEndObject->mOffset); if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) { res = aEndObject->ConvertToNBSP(point, eOutsideUserSelectAll); @@ -1407,16 +1380,13 @@ nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject) (!afterRun && ((aEndObject->mEndReason & eBlock))) ) { // make sure trailing char of starting ws is an nbsp, so that it will show up - WSPoint point; - GetCharBefore(mNode, mOffset, &point); + WSPoint point = GetCharBefore(mNode, mOffset); if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) { nsCOMPtr wsStartNode, wsEndNode; PRInt32 wsStartOffset, wsEndOffset; - res = GetAsciiWSBounds(eBoth, mNode, mOffset, - address_of(wsStartNode), &wsStartOffset, - address_of(wsEndNode), &wsEndOffset); - NS_ENSURE_SUCCESS(res, res); + GetAsciiWSBounds(eBoth, mNode, mOffset, address_of(wsStartNode), + &wsStartOffset, address_of(wsEndNode), &wsEndOffset); point.mTextNode = do_QueryInterface(wsStartNode); if (!point.mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) { // Not sure if this is needed, but it'll maintain the same @@ -1442,16 +1412,14 @@ nsWSRunObject::PrepareToSplitAcrossBlocksPriv() // get the runs before and after selection WSFragment *beforeRun, *afterRun; - res = FindRun(mNode, mOffset, &beforeRun, false); - NS_ENSURE_SUCCESS(res, res); - res = FindRun(mNode, mOffset, &afterRun, true); + FindRun(mNode, mOffset, &beforeRun, false); + FindRun(mNode, mOffset, &afterRun, true); // adjust normal ws in afterRun if needed if (afterRun && (afterRun->mType == eNormalWS)) { // make sure leading char of following ws is an nbsp, so that it will show up - WSPoint point; - GetCharAfter(mNode, mOffset, &point); + WSPoint point = GetCharAfter(mNode, mOffset); if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) { res = ConvertToNBSP(point); @@ -1463,16 +1431,13 @@ nsWSRunObject::PrepareToSplitAcrossBlocksPriv() if (beforeRun && (beforeRun->mType == eNormalWS)) { // make sure trailing char of starting ws is an nbsp, so that it will show up - WSPoint point; - GetCharBefore(mNode, mOffset, &point); + WSPoint point = GetCharBefore(mNode, mOffset); if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) { nsCOMPtr wsStartNode, wsEndNode; PRInt32 wsStartOffset, wsEndOffset; - res = GetAsciiWSBounds(eBoth, mNode, mOffset, - address_of(wsStartNode), &wsStartOffset, - address_of(wsEndNode), &wsEndOffset); - NS_ENSURE_SUCCESS(res, res); + GetAsciiWSBounds(eBoth, mNode, mOffset, address_of(wsStartNode), + &wsStartOffset, address_of(wsEndNode), &wsEndOffset); point.mTextNode = do_QueryInterface(wsStartNode); if (!point.mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) { // Not sure if this is needed, but it'll maintain the same @@ -1590,117 +1555,121 @@ nsWSRunObject::DeleteChars(nsIDOMNode *aStartNode, PRInt32 aStartOffset, return res; } -nsresult -nsWSRunObject::GetCharAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint) +nsWSRunObject::WSPoint +nsWSRunObject::GetCharAfter(nsIDOMNode *aNode, PRInt32 aOffset) { - NS_ENSURE_TRUE(aNode && outPoint, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aNode); PRInt32 idx = mNodeArray.IndexOf(aNode); if (idx == -1) { // use range comparisons to get right ws node - return GetWSPointAfter(aNode, aOffset, outPoint); + return GetWSPointAfter(aNode, aOffset); } else { // use wspoint version of GetCharAfter() WSPoint point(aNode,aOffset,0); - return GetCharAfter(point, outPoint); + return GetCharAfter(point); } - - return NS_ERROR_FAILURE; } -nsresult -nsWSRunObject::GetCharBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint) +nsWSRunObject::WSPoint +nsWSRunObject::GetCharBefore(nsIDOMNode *aNode, PRInt32 aOffset) { - NS_ENSURE_TRUE(aNode && outPoint, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aNode); PRInt32 idx = mNodeArray.IndexOf(aNode); if (idx == -1) { // use range comparisons to get right ws node - return GetWSPointBefore(aNode, aOffset, outPoint); + return GetWSPointBefore(aNode, aOffset); } else { // use wspoint version of GetCharBefore() WSPoint point(aNode,aOffset,0); - return GetCharBefore(point, outPoint); + return GetCharBefore(point); } - - return NS_ERROR_FAILURE; } -nsresult -nsWSRunObject::GetCharAfter(WSPoint &aPoint, WSPoint *outPoint) +nsWSRunObject::WSPoint +nsWSRunObject::GetCharAfter(const WSPoint &aPoint) { - NS_ENSURE_TRUE(aPoint.mTextNode && outPoint, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aPoint.mTextNode); - outPoint->mTextNode = nsnull; - outPoint->mOffset = 0; - outPoint->mChar = 0; + WSPoint outPoint; + outPoint.mTextNode = nsnull; + outPoint.mOffset = 0; + outPoint.mChar = 0; nsCOMPtr pointTextNode(do_QueryInterface(aPoint.mTextNode)); PRInt32 idx = mNodeArray.IndexOf(pointTextNode); - if (idx == -1) return NS_OK; // can't find point, but it's not an error + if (idx == -1) { + // can't find point, but it's not an error + return outPoint; + } PRInt32 numNodes = mNodeArray.Count(); if (PRUint16(aPoint.mOffset) < aPoint.mTextNode->TextLength()) { - *outPoint = aPoint; - outPoint->mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset); - } - else if (idx < (PRInt32)(numNodes-1)) - { + outPoint = aPoint; + outPoint.mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset); + return outPoint; + } else if (idx + 1 < (PRInt32)numNodes) { nsIDOMNode* node = mNodeArray[idx+1]; - NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - outPoint->mTextNode = do_QueryInterface(node); - if (!outPoint->mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) { + MOZ_ASSERT(node); + outPoint.mTextNode = do_QueryInterface(node); + if (!outPoint.mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) { // Not sure if this is needed, but it'll maintain the same // functionality - outPoint->mTextNode = nsnull; + outPoint.mTextNode = nsnull; } - outPoint->mOffset = 0; - outPoint->mChar = GetCharAt(outPoint->mTextNode, 0); + outPoint.mOffset = 0; + outPoint.mChar = GetCharAt(outPoint.mTextNode, 0); } - return NS_OK; + return outPoint; } -nsresult -nsWSRunObject::GetCharBefore(WSPoint &aPoint, WSPoint *outPoint) +nsWSRunObject::WSPoint +nsWSRunObject::GetCharBefore(const WSPoint &aPoint) { - NS_ENSURE_TRUE(aPoint.mTextNode && outPoint, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aPoint.mTextNode); - outPoint->mTextNode = nsnull; - outPoint->mOffset = 0; - outPoint->mChar = 0; + WSPoint outPoint; + outPoint.mTextNode = nsnull; + outPoint.mOffset = 0; + outPoint.mChar = 0; nsCOMPtr pointTextNode(do_QueryInterface(aPoint.mTextNode)); PRInt32 idx = mNodeArray.IndexOf(pointTextNode); - if (idx == -1) return NS_OK; // can't find point, but it's not an error + if (idx == -1) { + // can't find point, but it's not an error + return outPoint; + } if (aPoint.mOffset != 0) { - *outPoint = aPoint; - outPoint->mOffset--; - outPoint->mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset-1); + outPoint = aPoint; + outPoint.mOffset--; + outPoint.mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset-1); + return outPoint; } else if (idx) { nsIDOMNode* node = mNodeArray[idx-1]; - NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - outPoint->mTextNode = do_QueryInterface(node); + MOZ_ASSERT(node); + outPoint.mTextNode = do_QueryInterface(node); - PRUint32 len = outPoint->mTextNode->TextLength(); + PRUint32 len = outPoint.mTextNode->TextLength(); if (len) { - outPoint->mOffset = len-1; - outPoint->mChar = GetCharAt(outPoint->mTextNode, len-1); + outPoint.mOffset = len-1; + outPoint.mChar = GetCharAt(outPoint.mTextNode, len-1); } } - return NS_OK; + return outPoint; } nsresult @@ -1735,9 +1704,8 @@ nsWSRunObject::ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR) nsCOMPtr startNode, endNode; PRInt32 startOffset=0, endOffset=0; - res = GetAsciiWSBounds(eAfter, node, aPoint.mOffset+1, address_of(startNode), - &startOffset, address_of(endNode), &endOffset); - NS_ENSURE_SUCCESS(res, res); + GetAsciiWSBounds(eAfter, node, aPoint.mOffset+1, address_of(startNode), + &startOffset, address_of(endNode), &endOffset); // finally, delete that replaced ws, if any if (startNode) @@ -1748,24 +1716,21 @@ nsWSRunObject::ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR) return res; } -nsresult +void nsWSRunObject::GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr *outStartNode, PRInt32 *outStartOffset, nsCOMPtr *outEndNode, PRInt32 *outEndOffset) { - NS_ENSURE_TRUE(aNode && outStartNode && outEndNode, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aNode && outStartNode && outEndNode); nsCOMPtr startNode, endNode; PRInt32 startOffset=0, endOffset=0; - nsresult res = NS_OK; - if (aDir & eAfter) { - WSPoint point, tmp; - res = GetCharAfter(aNode, aOffset, &point); - if (NS_SUCCEEDED(res) && point.mTextNode) - { // we found a text node, at least + WSPoint point = GetCharAfter(aNode, aOffset); + if (point.mTextNode) { + // we found a text node, at least endNode = do_QueryInterface(point.mTextNode); endOffset = point.mOffset; startNode = endNode; @@ -1777,19 +1742,19 @@ nsWSRunObject::GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset endNode = do_QueryInterface(point.mTextNode); point.mOffset++; // endOffset is _after_ ws endOffset = point.mOffset; - tmp = point; - res = GetCharAfter(tmp, &point); - if (NS_FAILED(res) || !point.mTextNode) break; + point = GetCharAfter(point); + if (!point.mTextNode) { + break; + } } } } if (aDir & eBefore) { - WSPoint point, tmp; - res = GetCharBefore(aNode, aOffset, &point); - if (NS_SUCCEEDED(res) && point.mTextNode) - { // we found a text node, at least + WSPoint point = GetCharBefore(aNode, aOffset); + if (point.mTextNode) { + // we found a text node, at least startNode = do_QueryInterface(point.mTextNode); startOffset = point.mOffset+1; if (!endNode) @@ -1803,9 +1768,10 @@ nsWSRunObject::GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset { startNode = do_QueryInterface(point.mTextNode); startOffset = point.mOffset; - tmp = point; - res = GetCharBefore(tmp, &point); - if (NS_FAILED(res) || !point.mTextNode) break; + point = GetCharBefore(point); + if (!point.mTextNode) { + break; + } } } } @@ -1814,18 +1780,15 @@ nsWSRunObject::GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset *outStartOffset = startOffset; *outEndNode = endNode; *outEndOffset = endOffset; - - return NS_OK; } -nsresult +void nsWSRunObject::FindRun(nsIDOMNode *aNode, PRInt32 aOffset, WSFragment **outRun, bool after) { *outRun = nsnull; // given a dompoint, find the ws run that is before or after it, as caller needs - NS_ENSURE_TRUE(aNode && outRun, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aNode && outRun); - nsresult res = NS_OK; WSFragment *run = mStartRun; while (run) { @@ -1836,50 +1799,46 @@ nsWSRunObject::FindRun(nsIDOMNode *aNode, PRInt32 aOffset, WSFragment **outRun, if (after) { *outRun = run; - return res; } else // before { *outRun = nsnull; - return res; } + return; } comp = nsContentUtils::ComparePoints(aNode, aOffset, run->mEndNode, run->mEndOffset); if (comp < 0) { *outRun = run; - return res; + return; } else if (comp == 0) { if (after) { *outRun = run->mRight; - return res; } else // before { *outRun = run; - return res; } + return; } if (!run->mRight) { if (after) { *outRun = nsnull; - return res; } else // before { *outRun = run; - return res; } + return; } run = run->mRight; } - return res; } PRUnichar @@ -1895,8 +1854,8 @@ nsWSRunObject::GetCharAt(nsIContent *aTextNode, PRInt32 aOffset) return aTextNode->GetText()->CharAt(aOffset); } -nsresult -nsWSRunObject::GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint) +nsWSRunObject::WSPoint +nsWSRunObject::GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset) { // Note: only to be called if aNode is not a ws node. @@ -1904,7 +1863,11 @@ nsWSRunObject::GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outP PRInt32 numNodes, firstNum, curNum, lastNum; numNodes = mNodeArray.Count(); - NS_ENSURE_TRUE(numNodes, NS_OK); // do nothing if there are no nodes to search + if (!numNodes) { + // do nothing if there are no nodes to search + WSPoint outPoint; + return outPoint; + } firstNum = 0; curNum = numNodes/2; @@ -1935,17 +1898,17 @@ nsWSRunObject::GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outP // will do the work for us when we pass it the last index of the last node. nsCOMPtr textNode(do_QueryInterface(mNodeArray[curNum-1])); WSPoint point(textNode, textNode->TextLength(), 0); - return GetCharAfter(point, outPoint); + return GetCharAfter(point); } else { // The char after the point of interest is the first character of our range. nsCOMPtr textNode(do_QueryInterface(mNodeArray[curNum])); WSPoint point(textNode, 0, 0); - return GetCharAfter(point, outPoint); + return GetCharAfter(point); } } -nsresult -nsWSRunObject::GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint) +nsWSRunObject::WSPoint +nsWSRunObject::GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset) { // Note: only to be called if aNode is not a ws node. @@ -1953,7 +1916,11 @@ nsWSRunObject::GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *out PRInt32 numNodes, firstNum, curNum, lastNum; numNodes = mNodeArray.Count(); - NS_ENSURE_TRUE(numNodes, NS_OK); // do nothing if there are no nodes to search + if (!numNodes) { + // do nothing if there are no nodes to search + WSPoint outPoint; + return outPoint; + } firstNum = 0; curNum = numNodes/2; @@ -1984,14 +1951,14 @@ nsWSRunObject::GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *out // of the node into GetCharBefore, and it will return the last character. nsCOMPtr textNode(do_QueryInterface(mNodeArray[curNum - 1])); WSPoint point(textNode, textNode->TextLength(), 0); - return GetCharBefore(point, outPoint); + return GetCharBefore(point); } else { // we can just ask the current node for the point immediately before it, // it will handle moving to the previous node (if any) and returning the // appropriate character nsCOMPtr textNode(do_QueryInterface(mNodeArray[curNum])); WSPoint point(textNode, 0, 0); - return GetCharBefore(point, outPoint); + return GetCharBefore(point); } } @@ -2001,7 +1968,7 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun) // try to change an nbsp to a space, if possible, just to prevent nbsp proliferation. // examine what is before and after the trailing nbsp, if any. NS_ENSURE_TRUE(aRun, NS_ERROR_NULL_POINTER); - WSPoint thePoint; + nsresult res; bool leftCheck = false; bool spaceNBSP = false; bool rightCheck = false; @@ -2010,14 +1977,11 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun) if (aRun->mType != eNormalWS) return NS_ERROR_FAILURE; // first check for trailing nbsp - nsresult res = GetCharBefore(aRun->mEndNode, aRun->mEndOffset, &thePoint); - if (NS_SUCCEEDED(res) && thePoint.mTextNode && thePoint.mChar == nbsp) - { + WSPoint thePoint = GetCharBefore(aRun->mEndNode, aRun->mEndOffset); + if (thePoint.mTextNode && thePoint.mChar == nbsp) { // now check that what is to the left of it is compatible with replacing nbsp with space - WSPoint prevPoint; - res = GetCharBefore(thePoint, &prevPoint); - if (NS_SUCCEEDED(res) && prevPoint.mTextNode) - { + WSPoint prevPoint = GetCharBefore(thePoint); + if (prevPoint.mTextNode) { if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) leftCheck = true; else spaceNBSP = true; } @@ -2055,10 +2019,8 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun) NS_ENSURE_SUCCESS(res, res); // refresh thePoint, prevPoint - res = GetCharBefore(aRun->mEndNode, aRun->mEndOffset, &thePoint); - NS_ENSURE_SUCCESS(res, res); - res = GetCharBefore(thePoint, &prevPoint); - NS_ENSURE_SUCCESS(res, res); + thePoint = GetCharBefore(aRun->mEndNode, aRun->mEndOffset); + prevPoint = GetCharBefore(thePoint); rightCheck = true; } } @@ -2088,9 +2050,8 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun) nsCOMPtr startNode, endNode, thenode(do_QueryInterface(prevPoint.mTextNode)); PRInt32 startOffset, endOffset; - res = GetAsciiWSBounds(eBoth, thenode, prevPoint.mOffset+1, address_of(startNode), - &startOffset, address_of(endNode), &endOffset); - NS_ENSURE_SUCCESS(res, res); + GetAsciiWSBounds(eBoth, thenode, prevPoint.mOffset+1, address_of(startNode), + &startOffset, address_of(endNode), &endOffset); // delete that nbsp nsCOMPtr delNode(do_QueryInterface(thePoint.mTextNode)); @@ -2116,15 +2077,11 @@ nsWSRunObject::CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aO // or text, so we don't have to worry about what is after it. What is after it now will // end up after the inserted object. NS_ENSURE_TRUE(aRun && aNode, NS_ERROR_NULL_POINTER); - WSPoint thePoint; bool canConvert = false; - nsresult res = GetCharBefore(aNode, aOffset, &thePoint); - if (NS_SUCCEEDED(res) && thePoint.mTextNode && thePoint.mChar == nbsp) - { - WSPoint prevPoint; - res = GetCharBefore(thePoint, &prevPoint); - if (NS_SUCCEEDED(res) && prevPoint.mTextNode) - { + WSPoint thePoint = GetCharBefore(aNode, aOffset); + if (thePoint.mTextNode && thePoint.mChar == nbsp) { + WSPoint prevPoint = GetCharBefore(thePoint); + if (prevPoint.mTextNode) { if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) canConvert = true; } else if (aRun->mLeftType == eText) canConvert = true; @@ -2137,7 +2094,9 @@ nsWSRunObject::CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aO NS_ENSURE_TRUE(textNode, NS_ERROR_NULL_POINTER); nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); nsAutoString spaceStr(PRUnichar(32)); - res = mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, textNode, thePoint.mOffset, true); + nsresult res = mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, textNode, + thePoint.mOffset, + true); NS_ENSURE_SUCCESS(res, res); // finally, delete that nbsp @@ -2155,16 +2114,13 @@ nsWSRunObject::CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOf // this routine is called when we about to make this point in the ws abut an inserted // text, so we don't have to worry about what is before it. What is before it now will // end up before the inserted text. - WSPoint thePoint; bool canConvert = false; - nsresult res = GetCharAfter(aNode, aOffset, &thePoint); - if (NS_SUCCEEDED(res) && thePoint.mChar == nbsp) - { - WSPoint nextPoint, tmp=thePoint; + WSPoint thePoint = GetCharAfter(aNode, aOffset); + if (thePoint.mChar == nbsp) { + WSPoint tmp = thePoint; tmp.mOffset++; // we want to be after thePoint - res = GetCharAfter(tmp, &nextPoint); - if (NS_SUCCEEDED(res) && nextPoint.mTextNode) - { + WSPoint nextPoint = GetCharAfter(tmp); + if (nextPoint.mTextNode) { if (!nsCRT::IsAsciiSpace(nextPoint.mChar)) canConvert = true; } else if (aRun->mRightType == eText) canConvert = true; @@ -2178,7 +2134,9 @@ nsWSRunObject::CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOf NS_ENSURE_TRUE(textNode, NS_ERROR_NULL_POINTER); nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); nsAutoString spaceStr(PRUnichar(32)); - res = mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, textNode, thePoint.mOffset, true); + nsresult res = mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, textNode, + thePoint.mOffset, + true); NS_ENSURE_SUCCESS(res, res); // finally, delete that nbsp @@ -2223,4 +2181,3 @@ nsWSRunObject::Scrub() } return NS_OK; } - diff --git a/editor/libeditor/html/nsWSRunObject.h b/editor/libeditor/html/nsWSRunObject.h index 3fc886fe8eaa..79fe8d3f28a1 100644 --- a/editor/libeditor/html/nsWSRunObject.h +++ b/editor/libeditor/html/nsWSRunObject.h @@ -132,22 +132,22 @@ class NS_STACK_CLASS nsWSRunObject // it returns what is before the ws run. Note that // {outVisNode,outVisOffset} is set to just AFTER the visible // object. - nsresult PriorVisibleNode(nsIDOMNode *aNode, - PRInt32 aOffset, - nsCOMPtr *outVisNode, - PRInt32 *outVisOffset, - PRInt16 *outType); + void PriorVisibleNode(nsIDOMNode *aNode, + PRInt32 aOffset, + nsCOMPtr *outVisNode, + PRInt32 *outVisOffset, + PRInt16 *outType); // NextVisibleNode returns the first piece of visible thing // after {aNode,aOffset}. If there is no visible ws qualifying // it returns what is after the ws run. Note that // {outVisNode,outVisOffset} is set to just BEFORE the visible // object. - nsresult NextVisibleNode (nsIDOMNode *aNode, - PRInt32 aOffset, - nsCOMPtr *outVisNode, - PRInt32 *outVisOffset, - PRInt16 *outType); + void NextVisibleNode(nsIDOMNode *aNode, + PRInt32 aOffset, + nsCOMPtr *outVisNode, + PRInt32 *outVisOffset, + PRInt16 *outType); // AdjustWhitespace examines the ws object for nbsp's that can // be safely converted to regular ascii space and converts them. @@ -230,9 +230,9 @@ class NS_STACK_CLASS nsWSRunObject already_AddRefed GetWSBoundingParent(); nsresult GetWSNodes(); - nsresult GetRuns(); + void GetRuns(); void ClearRuns(); - nsresult MakeSingleWSRun(PRInt16 aType); + void MakeSingleWSRun(PRInt16 aType); nsresult PrependNodeToList(nsIDOMNode *aNode); nsresult AppendNodeToList(nsIDOMNode *aNode); nsresult GetPreviousWSNode(nsIDOMNode *aStartNode, @@ -260,19 +260,19 @@ class NS_STACK_CLASS nsWSRunObject nsresult DeleteChars(nsIDOMNode *aStartNode, PRInt32 aStartOffset, nsIDOMNode *aEndNode, PRInt32 aEndOffset, AreaRestriction aAR = eAnywhere); - nsresult GetCharAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint); - nsresult GetCharBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint); - nsresult GetCharAfter(WSPoint &aPoint, WSPoint *outPoint); - nsresult GetCharBefore(WSPoint &aPoint, WSPoint *outPoint); + WSPoint GetCharAfter(nsIDOMNode *aNode, PRInt32 aOffset); + WSPoint GetCharBefore(nsIDOMNode *aNode, PRInt32 aOffset); + WSPoint GetCharAfter(const WSPoint &aPoint); + WSPoint GetCharBefore(const WSPoint &aPoint); nsresult ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR = eAnywhere); - nsresult GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset, + void GetAsciiWSBounds(PRInt16 aDir, nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr *outStartNode, PRInt32 *outStartOffset, nsCOMPtr *outEndNode, PRInt32 *outEndOffset); - nsresult FindRun(nsIDOMNode *aNode, PRInt32 aOffset, WSFragment **outRun, bool after); + void FindRun(nsIDOMNode *aNode, PRInt32 aOffset, WSFragment **outRun, bool after); PRUnichar GetCharAt(nsIContent *aTextNode, PRInt32 aOffset); - nsresult GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint); - nsresult GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset, WSPoint *outPoint); + WSPoint GetWSPointAfter(nsIDOMNode *aNode, PRInt32 aOffset); + WSPoint GetWSPointBefore(nsIDOMNode *aNode, PRInt32 aOffset); nsresult CheckTrailingNBSPOfRun(WSFragment *aRun); nsresult CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOffset); nsresult CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, PRInt32 aOffset); diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index df16d8853361..dbedaf32c641 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -611,8 +611,7 @@ nsTextEditRules::WillInsertText(nsEditor::OperationID aAction, if (IsPasswordEditor()) { if (aAction == nsEditor::kOpInsertIMEText) { - res = RemoveIMETextFromPWBuf(start, outString); - NS_ENSURE_SUCCESS(res, res); + RemoveIMETextFromPWBuf(start, outString); } } @@ -657,8 +656,7 @@ nsTextEditRules::WillInsertText(nsEditor::OperationID aAction, } else { - res = FillBufWithPWChars(outString, outString->Length()); - NS_ENSURE_SUCCESS(res, res); + FillBufWithPWChars(outString, outString->Length()); } } @@ -1178,9 +1176,7 @@ nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection, res = mEditor->GetTextSelectionOffsets(aSelection, start, end); if (NS_FAILED(res)) { return res; } - PRInt32 oldCompStrLength; - res = mEditor->GetIMEBufferLength(&oldCompStrLength); - if (NS_FAILED(res)) { return res; } + PRInt32 oldCompStrLength = mEditor->GetIMEBufferLength(); const PRInt32 selectionLength = end - start; const PRInt32 resultingDocLength = docLength - selectionLength - oldCompStrLength; @@ -1206,19 +1202,16 @@ nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection, return res; } -nsresult +void nsTextEditRules::ResetIMETextPWBuf() { mPasswordIMEText.Truncate(); - return NS_OK; } -nsresult +void nsTextEditRules::RemoveIMETextFromPWBuf(PRUint32 &aStart, nsAString *aIMEString) { - if (!aIMEString) { - return NS_ERROR_NULL_POINTER; - } + MOZ_ASSERT(aIMEString); // initialize PasswordIME if (mPasswordIMEText.IsEmpty()) { @@ -1231,7 +1224,6 @@ nsTextEditRules::RemoveIMETextFromPWBuf(PRUint32 &aStart, nsAString *aIMEString) } mPasswordIMEText.Assign(*aIMEString); - return NS_OK; } NS_IMETHODIMP nsTextEditRules::Notify(class nsITimer *) { @@ -1271,10 +1263,10 @@ nsresult nsTextEditRules::HideLastPWInput() { } // static -nsresult +void nsTextEditRules::FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength) { - if (!aOutString) {return NS_ERROR_NULL_POINTER;} + MOZ_ASSERT(aOutString); // change the output to the platform password character PRUnichar passwordChar = LookAndFeel::GetPasswordCharacter(); @@ -1283,8 +1275,6 @@ nsTextEditRules::FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength) aOutString->Truncate(); for (i=0; i < aLength; i++) aOutString->Append(passwordChar); - - return NS_OK; } diff --git a/editor/libeditor/text/nsTextEditRules.h b/editor/libeditor/text/nsTextEditRules.h index 8b06ded748f2..a94a007a9151 100644 --- a/editor/libeditor/text/nsTextEditRules.h +++ b/editor/libeditor/text/nsTextEditRules.h @@ -49,7 +49,7 @@ public: NS_IMETHOD DocumentModified(); public: - nsresult ResetIMETextPWBuf(); + void ResetIMETextPWBuf(); /** * Handles the newline characters either according to aNewLineHandling @@ -85,7 +85,7 @@ public: * @param aLength the number of password characters that aOutString should * contain. */ - static nsresult FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength); + static void FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength); protected: @@ -163,7 +163,7 @@ protected: bool *aTruncated); /** Remove IME composition text from password buffer */ - nsresult RemoveIMETextFromPWBuf(PRUint32 &aStart, nsAString *aIMEString); + void RemoveIMETextFromPWBuf(PRUint32 &aStart, nsAString *aIMEString); nsresult CreateMozBR(nsIDOMNode* inParent, PRInt32 inOffset, nsIDOMNode** outBRNode = nsnull); From d916e270e8f3d98555423651baf037368cc6b0c0 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 2 May 2012 09:56:02 -0700 Subject: [PATCH 19/53] Bug 659577 - Remove ScopeObject::maybeStackFrame use in the debugger, part 1 (r=jimb) --HG-- extra : rebase_source : ff45b986e1a260b0f935913533f9b1c1e1ffdad8 --- js/src/jsinterp.cpp | 5 +- js/src/vm/ScopeObject.cpp | 130 ++++++++++++++++++++++++++++++++------ js/src/vm/ScopeObject.h | 23 ++++++- js/src/vm/Stack.cpp | 3 + js/src/vm/Stack.h | 13 +++- 5 files changed, 153 insertions(+), 21 deletions(-) diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 5b71bfa07b2b..02912f1101ac 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -465,8 +465,11 @@ js::ExecuteKernel(JSContext *cx, JSScript *script_, JSObject &scopeChain, const bool ok = RunScript(cx, script, fp); - if (fp->isStrictEvalFrame()) + if (fp->isStrictEvalFrame()) { + if (cx->compartment->debugMode()) + cx->runtime->debugScopes->onPopStrictEvalScope(fp); js_PutCallObject(fp, fp->callObj()); + } Probes::stopExecution(cx, script); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 83bb102f3a6a..4a2737df7d77 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1468,7 +1468,8 @@ js_IsDebugScopeSlow(const JSObject *obj) DebugScopes::DebugScopes(JSRuntime *rt) : proxiedScopes(rt), - missingScopes(rt) + missingScopes(rt), + liveScopes(rt) {} DebugScopes::~DebugScopes() @@ -1479,7 +1480,8 @@ DebugScopes::~DebugScopes() bool DebugScopes::init() { - if (!proxiedScopes.init() || + if (!liveScopes.init() || + !proxiedScopes.init() || !missingScopes.init()) { return false; @@ -1505,6 +1507,18 @@ DebugScopes::sweep() if (!IsObjectMarked(&e.front().value)) e.removeFront(); } + + /* + * Since liveScopes includes entries for suspended generator frames which + * may be collected when the generator becomes unreachable we must sweep + * liveScopes for dead generator frames. + */ + for (LiveScopeMap::Enum e(liveScopes); !e.empty(); e.popFront()) { + if (JS_IsAboutToBeFinalized(e.front().key)) { + JS_ASSERT(e.front().value->isGeneratorFrame()); + e.removeFront(); + } + } } /* @@ -1574,7 +1588,15 @@ DebugScopes::onPopCall(StackFrame *fp) if (fp->isYielding()) return; - if (!fp->fun()->isHeavyweight()) { + if (fp->fun()->isHeavyweight()) { + /* + * When a frame finishes executing in mjit code, the epilogue is called + * once from the return and once when the frame is popped. + * TODO: bug 659577 will remove this (with HAS_CALL_OBJ). + */ + if (fp->hasCallObj()) + liveScopes.remove(&fp->scopeChain()->asCall()); + } else { JS_ASSERT(!fp->hasCallObj()); if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(fp))) { js_PutCallObject(fp, p->value->scope().asCall()); @@ -1587,7 +1609,9 @@ void DebugScopes::onPopBlock(JSContext *cx, StackFrame *fp) { StaticBlockObject &block = *fp->maybeBlockChain(); - if (!block.needsClone()) { + if (block.needsClone()) { + liveScopes.remove(&fp->scopeChain()->asClonedBlock()); + } else { JS_ASSERT(!fp->scopeChain()->isBlock() || fp->scopeChain()->asClonedBlock().staticBlock() != block); if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(fp))) { @@ -1597,11 +1621,36 @@ DebugScopes::onPopBlock(JSContext *cx, StackFrame *fp) } } +void +DebugScopes::onPopWith(StackFrame *fp) +{ + liveScopes.remove(&fp->scopeChain()->asWith()); +} + +void +DebugScopes::onPopStrictEvalScope(StackFrame *fp) +{ + liveScopes.remove(&fp->scopeChain()->asCall()); +} + void DebugScopes::onGeneratorFrameChange(StackFrame *from, StackFrame *to) { for (ScopeIter toIter(to); !toIter.done(); toIter = toIter.enclosing()) { - if (!toIter.hasScopeObject()) { + if (toIter.hasScopeObject()) { + /* + * Not only must we correctly replace mappings [scope -> from] with + * mappings [scope -> to], but we must add [scope -> to] if it + * doesn't already exist so that if we need to proxy a generator's + * scope while it is suspended, we can find its frame (which would + * otherwise not be found by AllFramesIter). + */ + LiveScopeMap::AddPtr livePtr = liveScopes.lookupForAdd(&toIter.scope()); + if (livePtr) + livePtr->value = to; + else + liveScopes.add(livePtr, &toIter.scope(), to); + } else { if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(toIter, from))) { DebugScopeObject &debugScope = *p->value; ScopeObject &scope = debugScope.scope(); @@ -1627,6 +1676,59 @@ DebugScopes::onCompartmentLeaveDebugMode(JSCompartment *c) if (e.front().key.fp()->compartment() == c) e.removeFront(); } + for (LiveScopeMap::Enum e(liveScopes); !e.empty(); e.popFront()) { + if (e.front().key->compartment() == c) + e.removeFront(); + } +} + +bool +DebugScopes::updateLiveScopes(JSContext *cx) +{ + JS_CHECK_RECURSION(cx, return false); + + /* + * Note that we must always update the top frame's scope objects' entries + * in liveScopes because we can't be sure code hasn't run in that frame to + * change the scope chain since we were last called. The fp->prevUpToDate() + * flag indicates whether the scopes of frames older than fp are already + * included in liveScopes. It might seem simpler to have fp instead carry a + * flag indicating whether fp itself is accurately described, but then we + * would need to clear that flag whenever fp ran code. By storing the 'up + * to date' bit for fp->prev() in fp, simply popping fp effectively clears + * the flag for us, at exactly the time when execution resumes fp->prev(). + */ + for (AllFramesIter i(cx->runtime->stackSpace); !i.done(); ++i) { + StackFrame *fp = i.fp(); + if (fp->isDummyFrame() || fp->scopeChain()->compartment() != cx->compartment) + continue; + + for (ScopeIter si(fp); !si.done(); si = si.enclosing()) { + if (si.hasScopeObject() && !liveScopes.put(&si.scope(), fp)) + return false; + } + + if (fp->prevUpToDate()) + return true; + JS_ASSERT(fp->compartment()->debugMode()); + fp->setPrevUpToDate(); + } + + return true; +} + +StackFrame * +DebugScopes::hasLiveFrame(ScopeObject &scope) +{ + if (LiveScopeMap::Ptr p = liveScopes.lookup(&scope)) { + JS_ASSERT_IF(scope.isClonedBlock(), + p->value == js_LiveFrameIfGenerator(scope.maybeStackFrame())); + JS_ASSERT_IF(scope.isCall(), + p->value == scope.maybeStackFrame()); + return p->value; + } + JS_ASSERT_IF(!scope.isWith(), !scope.maybeStackFrame()); + return NULL; } /*****************************************************************************/ @@ -1746,20 +1848,9 @@ GetDebugScope(JSContext *cx, JSObject &obj) return &obj; } - /* - * If 'scope' is a 'with' block, then the chain is fully reified from that - * point outwards, and there's no point in bothering with a ScopeIter. If - * |scope| has an associated stack frame, we can get more detailed scope - * chain information from that. - * Note: all this frame hackery will be removed by bug 659577. - */ ScopeObject &scope = obj.asScope(); - if (!scope.isWith() && scope.maybeStackFrame()) { - StackFrame *fp = scope.maybeStackFrame(); - if (scope.isClonedBlock()) - fp = js_LiveFrameIfGenerator(fp); + if (StackFrame *fp = cx->runtime->debugScopes->hasLiveFrame(scope)) return GetDebugScope(cx, ScopeIter(fp, scope)); - } return GetDebugScopeForScope(cx, scope, ScopeIter(scope.enclosingScope())); } @@ -1782,6 +1873,8 @@ js::GetDebugScopeForFunction(JSContext *cx, JSFunction *fun) { assertSameCompartment(cx, fun); JS_ASSERT(cx->compartment->debugMode()); + if (!cx->runtime->debugScopes->updateLiveScopes(cx)) + return NULL; return GetDebugScope(cx, *fun->environment()); } @@ -1789,6 +1882,7 @@ JSObject * js::GetDebugScopeForFrame(JSContext *cx, StackFrame *fp) { assertSameCompartment(cx, fp); - /* Unfortunately, we cannot JS_ASSERT(debugMode); see CanUseDebugScopeMaps. */ + if (CanUseDebugScopeMaps(cx) && !cx->runtime->debugScopes->updateLiveScopes(cx)) + return NULL; return GetDebugScope(cx, ScopeIter(fp)); } diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 0461f6edd209..d5e788a86a6b 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -422,9 +422,25 @@ class DebugScopes * The map from live frames which have optimized-away scopes to the * corresponding debug scopes. */ - typedef HashMap MissingScopeMap; + typedef HashMap MissingScopeMap; MissingScopeMap missingScopes; + /* + * The map from scope objects of live frames to the live frame. This map + * updated lazily whenever the debugger needs the information. In between + * two lazy updates, liveScopes becomes incomplete (but not invalid, onPop* + * removes scopes as they are popped). Thus, two consecutive debugger lazy + * updates of liveScopes need only fill in the new scopes. + */ + typedef HashMap, + RuntimeAllocPolicy> LiveScopeMap; + LiveScopeMap liveScopes; + public: DebugScopes(JSRuntime *rt); ~DebugScopes(); @@ -439,12 +455,17 @@ class DebugScopes DebugScopeObject *hasDebugScope(JSContext *cx, ScopeIter si) const; bool addDebugScope(JSContext *cx, ScopeIter si, DebugScopeObject &debugScope); + bool updateLiveScopes(JSContext *cx); + StackFrame *hasLiveFrame(ScopeObject &scope); + /* * In debug-mode, these must be called whenever exiting a call/block or * when activating/yielding a generator. */ void onPopCall(StackFrame *fp); void onPopBlock(JSContext *cx, StackFrame *fp); + void onPopWith(StackFrame *fp); + void onPopStrictEvalScope(StackFrame *fp); void onGeneratorFrameChange(StackFrame *from, StackFrame *to); void onCompartmentLeaveDebugMode(JSCompartment *c); }; diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 07f4df2b7842..0d97b820be3b 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -259,6 +259,9 @@ StackFrame::popBlock(JSContext *cx) void StackFrame::popWith(JSContext *cx) { + if (cx->compartment->debugMode()) + cx->runtime->debugScopes->onPopWith(this); + setScopeChain(scopeChain()->asWith().enclosingScope()); } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 9fc956d14730..a65c7baaa2e1 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -345,7 +345,10 @@ class StackFrame /* Method JIT state */ DOWN_FRAMES_EXPANDED = 0x100000, /* inlining in down frames has been expanded */ - LOWERED_CALL_APPLY = 0x200000 /* Pushed by a lowered call/apply */ + LOWERED_CALL_APPLY = 0x200000, /* Pushed by a lowered call/apply */ + + /* Debugger state */ + PREV_UP_TO_DATE = 0x400000 /* see DebugScopes::updateLiveScopes */ }; private: @@ -1089,6 +1092,14 @@ class StackFrame return !!(flags_ & DEBUGGER); } + bool prevUpToDate() const { + return !!(flags_ & PREV_UP_TO_DATE); + } + + void setPrevUpToDate() { + flags_ |= PREV_UP_TO_DATE; + } + bool hasOverflowArgs() const { return !!(flags_ & OVERFLOW_ARGS); } From b6cc0b9e2283198b65cb8b48c687ddf1b5681c05 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 9 May 2012 23:03:12 -0700 Subject: [PATCH 20/53] Bug 659577 - Remove ScopeObject::maybeStackFrame use in the debugger, part 2 (r=jimb) --HG-- extra : rebase_source : 997dd4ccb8e2dce45b1d1eeae2ab7ec6679efed9 --- js/src/jit-test/tests/debug/Frame-eval-14.js | 25 ++ js/src/jscntxt.cpp | 1 - js/src/jscntxt.h | 23 -- js/src/jsscope.h | 5 + js/src/jsscript.cpp | 2 - js/src/jsscript.h | 3 +- js/src/vm/ArgumentsObject-inl.h | 2 +- js/src/vm/ScopeObject-inl.h | 21 +- js/src/vm/ScopeObject.cpp | 257 +++++++++++++++---- js/src/vm/ScopeObject.h | 12 +- 10 files changed, 263 insertions(+), 88 deletions(-) create mode 100644 js/src/jit-test/tests/debug/Frame-eval-14.js diff --git a/js/src/jit-test/tests/debug/Frame-eval-14.js b/js/src/jit-test/tests/debug/Frame-eval-14.js new file mode 100644 index 000000000000..0e9829e04999 --- /dev/null +++ b/js/src/jit-test/tests/debug/Frame-eval-14.js @@ -0,0 +1,25 @@ +// Test the corner case of accessing an unaliased variable of a block +// while the block is not live. + +var g = newGlobal('new-compartment'); +g.eval("function h() { debugger }"); +g.eval("function f() { let (x = 1, y) { (function() { y = 0 })(); h() } }"); +g.eval("var surprise = null"); + +var dbg = new Debugger(g); +dbg.onDebuggerStatement = function(hFrame) { + var fFrame = hFrame.older; + assertEq(fFrame.environment.getVariable('x'), 1); + assertEq(fFrame.environment.getVariable('y'), 0); + fFrame.eval("surprise = function() { return ++x }"); + assertEq(g.surprise(), 2); +} +g.f(); +assertEq(g.surprise !== null, true); + +// Either succeed or throw an error about 'x' not being live +try { + assertEq(g.surprise(), 3); +} catch (e) { + assertEq(e+'', 'Error: x is not live'); +} diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index cc164252776b..433a61cf1139 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -996,7 +996,6 @@ JSContext::JSContext(JSRuntime *rt) enumerators(NULL), #ifdef DEBUG stackIterAssertionEnabled(true), - okToAccessUnaliasedBindings(0), #endif activeCompilations(0) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index db8712def084..5d050cead259 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1321,12 +1321,6 @@ struct JSContext : js::ContextFriendFields * stack iteration; defaults to true. */ bool stackIterAssertionEnabled; - - /* - * When greather than zero, it is ok to accessed non-aliased fields of - * ScopeObjects because the accesses are coming from the DebugScopeProxy. - */ - unsigned okToAccessUnaliasedBindings; #endif /* @@ -1363,23 +1357,6 @@ struct JSContext : js::ContextFriendFields namespace js { -class AutoAllowUnaliasedVarAccess -{ - JSContext *cx; - public: - AutoAllowUnaliasedVarAccess(JSContext *cx) : cx(cx) { -#ifdef DEBUG - cx->okToAccessUnaliasedBindings++; -#endif - } - ~AutoAllowUnaliasedVarAccess() { -#ifdef DEBUG - JS_ASSERT(cx->okToAccessUnaliasedBindings); - cx->okToAccessUnaliasedBindings--; -#endif - } -}; - struct AutoResolving { public: enum Kind { diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 08878ba4bda4..70d8117715f4 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -882,6 +882,11 @@ struct Shape : public js::gc::Cell inline void markChildren(JSTracer *trc); + inline Shape *search(JSContext *cx, jsid id) { + Shape **_; + return search(cx, this, id, &_); + } + /* For JIT usage */ static inline size_t offsetOfBase() { return offsetof(Shape, base_); } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 7dc546466eca..b13d0022d9a7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2213,7 +2213,6 @@ JSScript::applySpeculationFailed(JSContext *cx, JSScript *script_) return true; } -#ifdef DEBUG bool JSScript::varIsAliased(unsigned varSlot) { @@ -2257,4 +2256,3 @@ JSScript::formalLivesInCallObject(unsigned argSlot) return false; } -#endif diff --git a/js/src/jsscript.h b/js/src/jsscript.h index a91c26eb6f80..4a1bcc9fd9c0 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -861,12 +861,11 @@ struct JSScript : public js::gc::Cell } -#ifdef DEBUG bool varIsAliased(unsigned varSlot); bool formalIsAliased(unsigned argSlot); bool formalLivesInArgumentsObject(unsigned argSlot); bool formalLivesInCallObject(unsigned argSlot); -#endif + private: /* * Recompile with or without single-stepping support, as directed diff --git a/js/src/vm/ArgumentsObject-inl.h b/js/src/vm/ArgumentsObject-inl.h index 20ccb96e9113..f89148b796ca 100644 --- a/js/src/vm/ArgumentsObject-inl.h +++ b/js/src/vm/ArgumentsObject-inl.h @@ -74,7 +74,7 @@ ArgumentsObject::markElementDeleted(uint32_t i) SetBitArrayElement(data()->deletedBits, initialLength(), i); } -inline const js::Value & +inline const Value & ArgumentsObject::element(uint32_t i) const { JS_ASSERT(!isElementDeleted(i)); diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index cd2b8d53e62c..d4a24cb08368 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -186,13 +186,20 @@ BlockObject::slotCount() const return propertyCount(); } -inline HeapSlot & +inline const Value & BlockObject::slotValue(unsigned i) { JS_ASSERT(i < slotCount()); return getSlotRef(RESERVED_SLOTS + i); } +inline void +BlockObject::setSlotValue(unsigned i, const Value &v) +{ + JS_ASSERT(i < slotCount()); + setSlot(RESERVED_SLOTS + i, v); +} + inline StaticBlockObject * StaticBlockObject::enclosingBlock() const { @@ -217,7 +224,7 @@ inline void StaticBlockObject::setDefinitionParseNode(unsigned i, Definition *def) { JS_ASSERT(slotValue(i).isUndefined()); - slotValue(i).init(this, i, PrivateValue(def)); + setSlotValue(i, PrivateValue(def)); } inline Definition * @@ -230,7 +237,7 @@ StaticBlockObject::maybeDefinitionParseNode(unsigned i) inline void StaticBlockObject::setAliased(unsigned i, bool aliased) { - slotValue(i).init(this, i, BooleanValue(aliased)); + setSlotValue(i, BooleanValue(aliased)); if (aliased) JSObject::setPrivate(reinterpret_cast(1)); } @@ -260,12 +267,18 @@ ClonedBlockObject::staticBlock() const } inline const Value & -ClonedBlockObject::closedSlot(unsigned i) +ClonedBlockObject::var(unsigned i) { JS_ASSERT(!maybeStackFrame()); return slotValue(i); } +inline void +ClonedBlockObject::setVar(unsigned i, const Value &v) +{ + setSlotValue(i, v); +} + } /* namespace js */ inline js::ScopeObject & diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 4a2737df7d77..09077788f205 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -204,6 +204,29 @@ CallObject::createForFunction(JSContext *cx, StackFrame *fp) return callobj; } +void +CallObject::copyUnaliasedValues(StackFrame *fp) +{ + JS_ASSERT(fp->script() == getCalleeFunction()->script()); + JSScript *script = fp->script(); + + /* If bindings are accessed dynamically, everything is aliased. */ + if (script->bindingsAccessedDynamically) + return; + + /* Copy the unaliased formals. */ + for (unsigned i = 0; i < script->bindings.numArgs(); ++i) { + if (!script->formalLivesInCallObject(i)) + setArg(i, fp->formalArg(i)); + } + + /* Copy the unaliased var/let bindings. */ + for (unsigned i = 0; i < script->bindings.numVars(); ++i) { + if (!script->varIsAliased(i)) + setVar(i, fp->localSlot(i)); + } +} + CallObject * CallObject::createForStrictEval(JSContext *cx, StackFrame *fp) { @@ -225,7 +248,7 @@ CallObject::getArgOp(JSContext *cx, HandleObject obj, HandleId id, Value *vp) unsigned i = (uint16_t) JSID_TO_INT(id); DebugOnly script = callobj.getCalleeFunction()->script(); - JS_ASSERT_IF(!cx->okToAccessUnaliasedBindings, script->formalLivesInCallObject(i)); + JS_ASSERT(script->formalLivesInCallObject(i)); if (StackFrame *fp = callobj.maybeStackFrame()) *vp = fp->formalArg(i); @@ -243,7 +266,7 @@ CallObject::setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict unsigned i = (uint16_t) JSID_TO_INT(id); JSScript *script = callobj.getCalleeFunction()->script(); - JS_ASSERT_IF(!cx->okToAccessUnaliasedBindings, script->formalLivesInCallObject(i)); + JS_ASSERT(script->formalLivesInCallObject(i)); if (StackFrame *fp = callobj.maybeStackFrame()) fp->formalArg(i) = *vp; @@ -267,7 +290,7 @@ CallObject::getVarOp(JSContext *cx, HandleObject obj, HandleId id, Value *vp) unsigned i = (uint16_t) JSID_TO_INT(id); DebugOnly script = callobj.getCalleeFunction()->script(); - JS_ASSERT_IF(!cx->okToAccessUnaliasedBindings, script->varIsAliased(i)); + JS_ASSERT(script->varIsAliased(i)); if (StackFrame *fp = callobj.maybeStackFrame()) *vp = fp->varSlot(i); @@ -287,7 +310,7 @@ CallObject::setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict unsigned i = (uint16_t) JSID_TO_INT(id); JSScript *script = callobj.getCalleeFunction()->script(); - JS_ASSERT_IF(!cx->okToAccessUnaliasedBindings, script->varIsAliased(i)); + JS_ASSERT(script->varIsAliased(i)); if (StackFrame *fp = callobj.maybeStackFrame()) fp->varSlot(i) = *vp; @@ -708,6 +731,17 @@ ClonedBlockObject::put(StackFrame *fp) setPrivate(NULL); } +void +ClonedBlockObject::copyUnaliasedValues(StackFrame *fp) +{ + StaticBlockObject &block = staticBlock(); + unsigned base = fp->script()->nfixed + stackDepth(); + for (unsigned i = 0; i < slotCount(); ++i) { + if (!block.isAliased(i)) + setVar(i, fp->localSlot(base + i)); + } +} + static JSBool block_getProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp) { @@ -730,7 +764,7 @@ block_getProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp) } /* Values are in slots immediately following the class-reserved ones. */ - JS_ASSERT(block.closedSlot(index) == *vp); + JS_ASSERT(block.var(index) == *vp); return true; } @@ -1235,6 +1269,8 @@ namespace js { * - We want to pass the ScopeObject as the receiver to forwarded scope * property ops so that Call/Block/With ops do not all require a * 'normalization' step. + * - The debug scope proxy can directly manipulate the stack frame to allow + * the debugger to read/write args/locals that were otherwise unaliased. * - The engine has made certain assumptions about the possible reads/writes * in a scope. DebugScopeProxy allows us to prevent the debugger from * breaking those assumptions. Examples include adding shadowing variables @@ -1245,6 +1281,109 @@ namespace js { */ class DebugScopeProxy : public BaseProxyHandler { + enum Action { SET, GET }; + + /* + * This function handles access to unaliased locals/formals. If such + * accesses were passed on directly to the DebugScopeObject::scope, they + * would not be reading/writing the canonical location for the variable, + * which is on the stack. Thus, handleUn must translate would-be + * accesses to scope objects into analogous accesses of the stack frame. + * + * handleUnaliasedAccess returns 'true' if the access was unaliased and + * completed by handleUnaliasedAccess. + */ + bool handleUnaliasedAccess(JSContext *cx, ScopeObject &scope, jsid id, Action action, Value *vp) + { + Shape *shape = scope.lastProperty()->search(cx, id); + if (!shape) + return false; + + StackFrame *maybefp = cx->runtime->debugScopes->hasLiveFrame(scope); + + if (scope.isCall() && !scope.asCall().isForEval()) { + CallObject &callobj = scope.asCall(); + JSScript *script = callobj.getCalleeFunction()->script(); + if (!script->ensureHasTypes(cx)) + return false; + + if (shape->setterOp() == CallObject::setVarOp) { + unsigned i = shape->shortid(); + if (script->varIsAliased(i)) + return false; + + if (maybefp) { + if (action == GET) + *vp = maybefp->varSlot(i); + else + maybefp->varSlot(i) = *vp; + } else { + if (action == GET) + *vp = callobj.var(i); + else + callobj.setVar(i, *vp); + } + + if (action == SET) + TypeScript::SetLocal(cx, script, i, *vp); + + return true; + } + + if (shape->setterOp() == CallObject::setArgOp) { + unsigned i = shape->shortid(); + if (script->formalLivesInCallObject(i)) + return false; + + if (maybefp) { + if (action == GET) + *vp = maybefp->formalArg(i); + else + maybefp->formalArg(i) = *vp; + } else { + if (action == GET) + *vp = callobj.arg(i); + else + callobj.setArg(i, *vp); + } + + if (action == SET) + TypeScript::SetArgument(cx, script, i, *vp); + + return true; + } + + return false; + } + + if (scope.isClonedBlock()) { + ClonedBlockObject &block = scope.asClonedBlock(); + unsigned i = shape->shortid(); + if (block.staticBlock().isAliased(i)) + return false; + + if (maybefp) { + JSScript *script = maybefp->script(); + unsigned local = i + script->nfixed + block.stackDepth(); + if (action == GET) + *vp = maybefp->localSlot(local); + else + maybefp->localSlot(local) = *vp; + JS_ASSERT(analyze::LocalSlot(script, local) >= analyze::TotalSlots(script)); + } else { + if (action == GET) + *vp = block.var(i); + else + block.setVar(i, *vp); + } + + return true; + } + + JS_ASSERT(scope.isDeclEnv() || scope.isWith() || scope.asCall().isForEval()); + return false; + } + static bool isArguments(JSContext *cx, jsid id) { return id == NameToId(cx->runtime->atomState.argumentsAtom); @@ -1285,14 +1424,14 @@ class DebugScopeProxy : public BaseProxyHandler if (script->needsArgsObj()) return true; - StackFrame *fp = scope.maybeStackFrame(); - if (!fp) { + StackFrame *maybefp = cx->runtime->debugScopes->hasLiveFrame(scope); + if (!maybefp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_LIVE, "Debugger scope"); return false; } - *maybeArgsObj = ArgumentsObject::createUnexpected(cx, fp); + *maybeArgsObj = ArgumentsObject::createUnexpected(cx, maybefp); return true; } @@ -1325,7 +1464,15 @@ class DebugScopeProxy : public BaseProxyHandler return true; } - AutoAllowUnaliasedVarAccess a(cx); + Value v; + if (handleUnaliasedAccess(cx, scope, id, GET, &v)) { + PodZero(desc); + desc->obj = proxy; + desc->attrs = JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT; + desc->value = v; + return true; + } + return JS_GetPropertyDescriptorById(cx, &scope, id, JSRESOLVE_QUALIFIED, desc); } @@ -1342,15 +1489,20 @@ class DebugScopeProxy : public BaseProxyHandler return true; } - AutoAllowUnaliasedVarAccess a(cx); + if (handleUnaliasedAccess(cx, scope, id, GET, vp)) + return true; + return scope.getGeneric(cx, RootedObject(cx, &scope), RootedId(cx, id), vp); } bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp) MOZ_OVERRIDE { - AutoAllowUnaliasedVarAccess a(cx); ScopeObject &scope = proxy->asDebugScope().scope(); + + if (handleUnaliasedAccess(cx, scope, id, SET, vp)) + return true; + return scope.setGeneric(cx, RootedId(cx, id), vp, strict); } @@ -1509,13 +1661,14 @@ DebugScopes::sweep() } /* - * Since liveScopes includes entries for suspended generator frames which - * may be collected when the generator becomes unreachable we must sweep - * liveScopes for dead generator frames. + * Scopes can be finalized when a suspended generator becomes garbage or + * when a debugger-synthesized ScopeObject is no longer rooted by its + * DebugScopeObject. */ for (LiveScopeMap::Enum e(liveScopes); !e.empty(); e.popFront()) { - if (JS_IsAboutToBeFinalized(e.front().key)) { - JS_ASSERT(e.front().value->isGeneratorFrame()); + ScopeObject &scope = *e.front().key; + if (JS_IsAboutToBeFinalized(&scope)) { + JS_ASSERT(!scope.maybeStackFrame() || scope.maybeStackFrame()->isGeneratorFrame()); e.removeFront(); } } @@ -1549,6 +1702,7 @@ DebugScopes::addDebugScope(JSContext *cx, ScopeObject &scope, DebugScopeObject & { if (!CanUseDebugScopeMaps(cx)) return true; + JS_ASSERT(!proxiedScopes.has(&scope)); if (!proxiedScopes.put(&scope, &debugScope)) { js_ReportOutOfMemory(cx); @@ -1574,11 +1728,18 @@ DebugScopes::addDebugScope(JSContext *cx, ScopeIter si, DebugScopeObject &debugS JS_ASSERT(!si.hasScopeObject()); if (!CanUseDebugScopeMaps(cx)) return true; + JS_ASSERT(!missingScopes.has(si)); if (!missingScopes.put(si, &debugScope)) { js_ReportOutOfMemory(cx); return false; } + + JS_ASSERT(!liveScopes.has(&debugScope.scope())); + if (!liveScopes.put(&debugScope.scope(), si.fp())) { + js_ReportOutOfMemory(cx); + return false; + } return true; } @@ -1594,12 +1755,17 @@ DebugScopes::onPopCall(StackFrame *fp) * once from the return and once when the frame is popped. * TODO: bug 659577 will remove this (with HAS_CALL_OBJ). */ - if (fp->hasCallObj()) - liveScopes.remove(&fp->scopeChain()->asCall()); + if (fp->hasCallObj()) { + CallObject &callobj = fp->scopeChain()->asCall(); + callobj.copyUnaliasedValues(fp); + liveScopes.remove(&callobj); + } } else { JS_ASSERT(!fp->hasCallObj()); if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(fp))) { - js_PutCallObject(fp, p->value->scope().asCall()); + CallObject &callobj = p->value->scope().asCall(); + callobj.copyUnaliasedValues(fp); + liveScopes.remove(&callobj); missingScopes.remove(p); } } @@ -1608,14 +1774,18 @@ DebugScopes::onPopCall(StackFrame *fp) void DebugScopes::onPopBlock(JSContext *cx, StackFrame *fp) { - StaticBlockObject &block = *fp->maybeBlockChain(); - if (block.needsClone()) { - liveScopes.remove(&fp->scopeChain()->asClonedBlock()); + StaticBlockObject &staticBlock = *fp->maybeBlockChain(); + if (staticBlock.needsClone()) { + ClonedBlockObject &clone = fp->scopeChain()->asClonedBlock(); + clone.copyUnaliasedValues(fp); + liveScopes.remove(&clone); } else { JS_ASSERT(!fp->scopeChain()->isBlock() || - fp->scopeChain()->asClonedBlock().staticBlock() != block); + fp->scopeChain()->asClonedBlock().staticBlock() != staticBlock); if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(fp))) { - p->value->scope().asClonedBlock().put(fp); + ClonedBlockObject &clone = p->value->scope().asClonedBlock(); + clone.copyUnaliasedValues(fp); + liveScopes.remove(&clone); missingScopes.remove(p); } } @@ -1653,15 +1823,7 @@ DebugScopes::onGeneratorFrameChange(StackFrame *from, StackFrame *to) } else { if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(toIter, from))) { DebugScopeObject &debugScope = *p->value; - ScopeObject &scope = debugScope.scope(); - if (scope.isCall()) { - JS_ASSERT(scope.maybeStackFrame() == from); - scope.setStackFrame(to); - if (scope.enclosingScope().isDeclEnv()) { - JS_ASSERT(scope.enclosingScope().asDeclEnv().maybeStackFrame() == from); - scope.enclosingScope().asDeclEnv().setStackFrame(to); - } - } + liveScopes.lookup(&debugScope.scope())->value = to; missingScopes.remove(p); missingScopes.put(toIter, &debugScope); } @@ -1720,14 +1882,8 @@ DebugScopes::updateLiveScopes(JSContext *cx) StackFrame * DebugScopes::hasLiveFrame(ScopeObject &scope) { - if (LiveScopeMap::Ptr p = liveScopes.lookup(&scope)) { - JS_ASSERT_IF(scope.isClonedBlock(), - p->value == js_LiveFrameIfGenerator(scope.maybeStackFrame())); - JS_ASSERT_IF(scope.isCall(), - p->value == scope.maybeStackFrame()); + if (LiveScopeMap::Ptr p = liveScopes.lookup(&scope)) return p->value; - } - JS_ASSERT_IF(!scope.isWith(), !scope.maybeStackFrame()); return NULL; } @@ -1789,20 +1945,17 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si) if (!callobj) return NULL; - JSObject &maybeDecl = callobj->enclosingScope(); - if (maybeDecl.isDeclEnv()) { + if (callobj->enclosingScope().isDeclEnv()) { JS_ASSERT(CallObjectLambdaName(callobj->getCalleeFunction())); - enclosingDebug = DebugScopeObject::create(cx, maybeDecl.asDeclEnv(), *enclosingDebug); + DeclEnvObject &declenv = callobj->enclosingScope().asDeclEnv(); + declenv.setStackFrame(NULL); + enclosingDebug = DebugScopeObject::create(cx, declenv, *enclosingDebug); if (!enclosingDebug) return NULL; } + callobj->setStackFrame(NULL); debugScope = DebugScopeObject::create(cx, *callobj, *enclosingDebug); - if (!debugScope) - return NULL; - - if (!CanUseDebugScopeMaps(cx)) - js_PutCallObject(si.fp(), *callobj); break; } case ScopeIter::Block: { @@ -1811,18 +1964,16 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si) if (!block) return NULL; + block->setStackFrame(NULL); debugScope = DebugScopeObject::create(cx, *block, *enclosingDebug); - if (!debugScope) - return NULL; - - if (!CanUseDebugScopeMaps(cx)) - block->put(si.fp()); break; } case ScopeIter::With: case ScopeIter::StrictEvalScope: JS_NOT_REACHED("should already have a scope"); } + if (!debugScope) + return NULL; if (!debugScopes.addDebugScope(cx, si, *debugScope)) return NULL; diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index d5e788a86a6b..413e1805e4fa 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -160,6 +160,9 @@ class CallObject : public ScopeObject /* Return whether this environment contains 'name' and, if so, its value. */ bool containsVarOrArg(PropertyName *name, Value *vp, JSContext *cx); + + /* Copy in all the unaliased formals and locals. */ + void copyUnaliasedValues(StackFrame *fp); }; class DeclEnvObject : public ScopeObject @@ -218,7 +221,8 @@ class BlockObject : public NestedScopeObject protected: /* Blocks contain an object slot for each slot i: 0 <= i < slotCount. */ - inline HeapSlot &slotValue(unsigned i); + inline const Value &slotValue(unsigned i); + inline void setSlotValue(unsigned i, const Value &v); }; class StaticBlockObject : public BlockObject @@ -275,10 +279,14 @@ class ClonedBlockObject : public BlockObject void put(StackFrame *fp); /* Assuming 'put' has been called, return the value of the ith let var. */ - const Value &closedSlot(unsigned i); + const Value &var(unsigned i); + void setVar(unsigned i, const Value &v); /* Return whether this environment contains 'name' and, if so, its value. */ bool containsVar(PropertyName *name, Value *vp, JSContext *cx); + + /* Copy in all the unaliased formals and locals. */ + void copyUnaliasedValues(StackFrame *fp); }; template From 4a77c8108ce8577dd9d0e31efdaf07ea4fef06dc Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 11 Apr 2012 18:09:20 -0700 Subject: [PATCH 21/53] Bug 659577 - emit ScopeCoordinate::hops (r=waldo) --HG-- extra : rebase_source : e8496f21b3e025b5cee07f627e39535add9904f0 --- js/src/frontend/BytecodeEmitter.cpp | 77 +++++++++++++++---- js/src/jit-test/tests/basic/testBug659577.js | 1 + .../jaeger/bug563000/trap-from-add-ool.js | 2 +- js/src/jsanalyze.cpp | 10 ++- js/src/jsanalyze.h | 6 +- js/src/jsinterp.cpp | 28 +------ js/src/jsopcode.tbl | 18 +++-- js/src/methodjit/Compiler.cpp | 12 +-- js/src/vm/ScopeObject-inl.h | 55 ++++++++++++- js/src/vm/ScopeObject.h | 23 ++++-- js/src/vm/Stack-inl.h | 22 ++++++ js/src/vm/Stack.h | 3 + 12 files changed, 188 insertions(+), 69 deletions(-) create mode 100644 js/src/jit-test/tests/basic/testBug659577.js diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index cbcbba59951b..7c38bbf7a11e 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -834,43 +834,84 @@ EmitUnaliasedVarOp(JSContext *cx, JSOp op, uint16_t slot, BytecodeEmitter *bce) } static bool -EmitAliasedVarOp(JSContext *cx, JSOp op, uint16_t binding, JSAtom *atom, BytecodeEmitter *bce) +EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, JSAtom *atom, BytecodeEmitter *bce) { JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD); - /* - * XXX This is temporary: bug 659577 will need to compute the number of - * cloned block objects to hop over. - */ - uint16_t hops = 0; - jsatomid atomIndex; if (!bce->makeAtomIndex(atom, &atomIndex)) return false; bool decomposed = js_CodeSpec[op].format & JOF_DECOMPOSE; - unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + (decomposed ? 1 : 0); + unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (decomposed ? 1 : 0); + JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length); ptrdiff_t off = EmitN(cx, bce, op, n); if (off < 0) return false; jsbytecode *pc = bce->code(off); - SET_UINT16(pc, hops); + SET_UINT16(pc, sc.hops); pc += sizeof(uint16_t); - SET_UINT16(pc, binding); + SET_UINT16(pc, sc.binding); pc += sizeof(uint16_t); SET_UINT32_INDEX(pc, atomIndex); + pc += sizeof(uint32_t); + SET_UINT16(pc, sc.frameBinding); return true; } +static unsigned +ClonedBlockDepth(BytecodeEmitter *bce) +{ + unsigned clonedBlockDepth = 0; + for (StaticBlockObject *b = bce->sc->blockChain; b; b = b->enclosingBlock()) { + if (b->needsClone()) + ++clonedBlockDepth; + } + + return clonedBlockDepth; +} + static bool EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce) { - uint16_t binding = JOF_OPTYPE(pn->getOp()) == JOF_QARG - ? bce->sc->bindings.argToBinding(pn->pn_cookie.slot()) - : bce->sc->bindings.localToBinding(pn->pn_cookie.slot()); - return EmitAliasedVarOp(cx, op, binding, pn->atom(), bce); + /* + * The contents of the dynamic scope chain (fp->scopeChain) exactly reflect + * the needsClone-subset of the block chain. Use this to determine the + * number of ClonedBlockObjects on fp->scopeChain to skip to find the scope + * object containing the var to which pn is bound. ALIASEDVAR ops cannot + * reach across with scopes so ClonedBlockObjects is the only NestedScope + * on the scope chain. + */ + ScopeCoordinate sc; + if (JOF_OPTYPE(pn->getOp()) == JOF_QARG) { + JS_ASSERT(bce->sc->funIsHeavyweight()); + sc.hops = ClonedBlockDepth(bce); + sc.binding = bce->sc->bindings.argToBinding(pn->pn_cookie.slot()); + sc.frameBinding = sc.binding; + } else { + JS_ASSERT(JOF_OPTYPE(pn->getOp()) == JOF_LOCAL || pn->isKind(PNK_FUNCTION)); + unsigned local = pn->pn_cookie.slot(); + sc.frameBinding = bce->sc->bindings.localToBinding(local); + if (local < bce->sc->bindings.numVars()) { + sc.hops = ClonedBlockDepth(bce); + sc.binding = sc.frameBinding; + } else { + unsigned depth = local - bce->sc->bindings.numVars(); + unsigned hops = 0; + StaticBlockObject *b = bce->sc->blockChain; + while (!b->containsVarAtDepth(depth)) { + if (b->needsClone()) + hops++; + b = b->enclosingBlock(); + } + sc.hops = hops; + sc.binding = depth - b->stackDepth(); + } + } + + return EmitAliasedVarOp(cx, op, sc, pn->atom(), bce); } static bool @@ -1033,7 +1074,6 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op) /* Beware the empty destructuring dummy. */ if (!dn) { - JS_ASSERT(i + 1 <= blockObj->slotCount()); blockObj->setAliased(i, bce->sc->bindingsAccessedDynamically()); continue; } @@ -2595,9 +2635,12 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0) return false; if (bce->sc->bindingsAccessedDynamically()) { + ScopeCoordinate sc; + sc.hops = 0; + sc.binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot()); + sc.frameBinding = sc.binding; JSAtom *atom = cx->runtime->atomState.argumentsAtom; - uint16_t binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot()); - if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, binding, atom, bce)) + if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, atom, bce)) return false; } else { if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocalSlot(), bce)) diff --git a/js/src/jit-test/tests/basic/testBug659577.js b/js/src/jit-test/tests/basic/testBug659577.js new file mode 100644 index 000000000000..3ae1a605a303 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug659577.js @@ -0,0 +1 @@ +Function("for(;(function(){([x],0)});x){}var x") diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js index 0b4cd6699b59..d6afbb7adea6 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js @@ -3,7 +3,7 @@ setDebug(true); x = "notset"; function main() { /* The JSOP_STOP in main. */ - a = { valueOf: function () { trap(main, 95, "success()"); } }; + a = { valueOf: function () { trap(main, 97, "success()"); } }; b = ""; eval(); a + b; diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index 95eb78d2f486..93bd13a49394 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -320,13 +320,19 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) case JSOP_GETALIASEDVAR: case JSOP_CALLALIASEDVAR: - case JSOP_SETALIASEDVAR: + case JSOP_SETALIASEDVAR: { JS_ASSERT(!isInlineable); usesScopeChain_ = true; + /* XXX: this can be removed after bug 659577. */ - if (ScopeCoordinate(pc).binding >= script->nfixed) + ScopeCoordinate sc(pc); + if (script->bindings.bindingIsLocal(sc.frameBinding) && + script->bindings.bindingToLocal(sc.frameBinding) >= script->nfixed) + { localsAliasStack_ = true; + } break; + } case JSOP_DEFFUN: case JSOP_DEFVAR: diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h index 5da8819d120d..839e045c738f 100644 --- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -364,9 +364,9 @@ static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc) case JSOP_SETALIASEDVAR: { ScopeCoordinate sc = ScopeCoordinate(pc); - return script->bindings.bindingIsArg(sc.binding) - ? ArgSlot(script->bindings.bindingToArg(sc.binding)) - : LocalSlot(script, script->bindings.bindingToLocal(sc.binding)); + return script->bindings.bindingIsArg(sc.frameBinding) + ? ArgSlot(script->bindings.bindingToArg(sc.frameBinding)) + : LocalSlot(script, script->bindings.bindingToLocal(sc.frameBinding)); } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 02912f1101ac..798a418fcffb 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -880,26 +880,6 @@ CheckArgAccess(StackFrame *fp, unsigned index) fp->script()->argsObjAliasesFormals()); } -/* - * This function is temporary. Bug 659577 will change all ALIASEDVAR - * access to use the scope chain instead. - */ -static inline Value & -AliasedVar(StackFrame *fp, ScopeCoordinate sc) -{ - JSScript *script = fp->script(); -#ifdef DEBUG - JS_ASSERT(sc.hops == 0); /* Temporary */ - if (script->bindings.bindingIsArg(sc.binding)) - JS_ASSERT(script->formalLivesInCallObject(script->bindings.bindingToArg(sc.binding))); - else - CheckLocalAccess(fp, script->bindings.bindingToLocal(sc.binding), true); -#endif - return script->bindings.bindingIsArg(sc.binding) - ? fp->formalArg(script->bindings.bindingToArg(sc.binding)) - : fp->localSlot(script->bindings.bindingToLocal(sc.binding)); -} - #define PUSH_COPY(v) do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0) #define PUSH_COPY_SKIP_CHECK(v) *regs.sp++ = v #define PUSH_NULL() regs.sp++->setNull() @@ -1178,6 +1158,8 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) # define END_CASE_LEN8 len = 8; goto advance_pc; # define END_CASE_LEN9 len = 9; goto advance_pc; # define END_CASE_LEN10 len = 10; goto advance_pc; +# define END_CASE_LEN11 len = 11; goto advance_pc; +# define END_CASE_LEN12 len = 12; goto advance_pc; # define END_VARLEN_CASE goto advance_pc; # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) # define END_EMPTY_CASES goto advance_pc_by_one; @@ -2846,16 +2828,14 @@ BEGIN_CASE(JSOP_CALLALIASEDVAR) BEGIN_CASE(JSOP_GETALIASEDVAR) { ScopeCoordinate sc = ScopeCoordinate(regs.pc); - Value &var = AliasedVar(regs.fp(), sc); - PUSH_COPY(var); + PUSH_COPY(regs.fp()->aliasedVarScope(sc).aliasedVar(sc)); } END_CASE(JSOP_GETALIASEDVAR) BEGIN_CASE(JSOP_SETALIASEDVAR) { ScopeCoordinate sc = ScopeCoordinate(regs.pc); - Value &var = AliasedVar(regs.fp(), sc); - var = regs.sp[-1]; + regs.fp()->aliasedVarScope(sc).setAliasedVar(sc, regs.sp[-1]); } END_CASE(JSOP_SETALIASEDVAR) diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl index ae0077bf5762..27044a346686 100644 --- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -333,14 +333,18 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE) * function, function statements that are conditionally executed, 'eval', * 'with', 'arguments' and E4X filters. All of these cases require creating a * CallObject to own the aliased variable. + * + * XXX: there is also a temporary 2-byte index (indicating the frame slot + * aliased by the scope chain) which will be removed with the last patch of bug + * 659577. */ -OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) -OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) -OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 9, 1, 1, 3, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) -OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 11, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) +OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 11, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) +OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 11, 1, 1, 3, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) /* Unused. */ OPDEF(JSOP_UNUSED8, 143,"unused8", NULL, 1, 0, 0, 0, JOF_BYTE) diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 375cbaddefca..1696109c5131 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -2835,10 +2835,10 @@ mjit::Compiler::generateMethod() frame.push(ObjectValue(*singleton)); } else { ScopeCoordinate sc = ScopeCoordinate(PC); - if (script->bindings.bindingIsArg(sc.binding)) - frame.pushArg(script->bindings.bindingToArg(sc.binding)); + if (script->bindings.bindingIsArg(sc.frameBinding)) + frame.pushArg(script->bindings.bindingToArg(sc.frameBinding)); else - frame.pushLocal(script->bindings.bindingToLocal(sc.binding)); + frame.pushLocal(script->bindings.bindingToLocal(sc.frameBinding)); } } END_CASE(JSOP_GETALIASEDVAR) @@ -2869,10 +2869,10 @@ mjit::Compiler::generateMethod() jsbytecode *next = &PC[JSOP_SETALIASEDVAR_LENGTH]; bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); ScopeCoordinate sc = ScopeCoordinate(PC); - if (script->bindings.bindingIsArg(sc.binding)) - frame.storeArg(script->bindings.bindingToArg(sc.binding), pop); + if (script->bindings.bindingIsArg(sc.frameBinding)) + frame.storeArg(script->bindings.bindingToArg(sc.frameBinding), pop); else - frame.storeLocal(script->bindings.bindingToLocal(sc.binding), pop); + frame.storeLocal(script->bindings.bindingToLocal(sc.frameBinding), pop); updateVarType(); if (pop) { diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index d4a24cb08368..216563606e24 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -14,7 +14,8 @@ namespace js { inline ScopeCoordinate::ScopeCoordinate(jsbytecode *pc) - : hops(GET_UINT16(pc)), binding(GET_UINT16(pc + 2)) + : hops(GET_UINT16(pc)), binding(GET_UINT16(pc + 2)), + frameBinding(GET_UINT16(pc + 8)) { JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); } @@ -55,6 +56,58 @@ ScopeObject::setStackFrame(StackFrame *frame) return setPrivate(frame); } +inline const Value & +ScopeObject::aliasedVar(ScopeCoordinate sc) +{ + /* XXX: all this is temporary until the last patch of 659577 */ + StackFrame *fp = maybeStackFrame(); + Bindings &bindings = fp->script()->bindings; + if (isCall()) { + JS_ASSERT(sc.binding == sc.frameBinding); + if (bindings.bindingIsArg(sc.binding)) { + unsigned arg = bindings.bindingToArg(sc.binding); + JS_ASSERT(fp->script()->formalLivesInCallObject(arg)); + return fp->formalArg(arg); + } + + unsigned var = bindings.bindingToLocal(sc.binding); + JS_ASSERT(fp->script()->varIsAliased(var)); + return fp->localSlot(var); + } + + unsigned var = bindings.bindingToLocal(sc.frameBinding); + fp = js_LiveFrameIfGenerator(fp); + JS_ASSERT(var == sc.binding + asClonedBlock().staticBlock().stackDepth() + fp->numFixed()); + JS_ASSERT(asClonedBlock().staticBlock().isAliased(sc.binding)); + return fp->localSlot(var); +} + +inline void +ScopeObject::setAliasedVar(ScopeCoordinate sc, const Value &v) +{ + /* XXX: all this is temporary until the last patch of 659577 */ + StackFrame *fp = maybeStackFrame(); + Bindings &bindings = fp->script()->bindings; + if (isCall()) { + JS_ASSERT(sc.binding == sc.frameBinding); + if (bindings.bindingIsArg(sc.binding)) { + unsigned arg = bindings.bindingToArg(sc.binding); + JS_ASSERT(fp->script()->formalLivesInCallObject(arg)); + fp->formalArg(arg) = v; + } else { + unsigned var = bindings.bindingToLocal(sc.binding); + JS_ASSERT(fp->script()->varIsAliased(var)); + fp->localSlot(var) = v; + } + } else { + unsigned var = bindings.bindingToLocal(sc.frameBinding); + fp = js_LiveFrameIfGenerator(fp); + JS_ASSERT(var == sc.binding + asClonedBlock().staticBlock().stackDepth() + fp->numFixed()); + JS_ASSERT(asClonedBlock().staticBlock().isAliased(sc.binding)); + fp->localSlot(var) = v; + } +} + /*static*/ inline size_t ScopeObject::offsetOfEnclosingScope() { diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 413e1805e4fa..8ab2e6dd564a 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -9,6 +9,7 @@ #define ScopeObject_h___ #include "jscntxt.h" +#include "jsiter.h" #include "jsobj.h" #include "jsweakmap.h" @@ -21,20 +22,17 @@ namespace js { * given lexically-enclosing variable. A scope coordinate has two dimensions: * - hops: the number of scope objects on the scope chain to skip * - binding: which binding on the scope object - * - * XXX: Until bug 659577 lands, this is all for show and all ScopeCoordinates - * have hops fixed at 0 and 'binding' is just the js::Bindings binding for args - * and vars and the stack depth for let bindings. Thus, aliased-var access - * touches the StackFrame like it always did and 'binding' must be first - * converted to either an arg or local slot (using Bindings::bindingToLocal or - * bindingToArg). With bug 659577, ScopeObject will have a 'var' function that - * takes a ScopeCoordinate. */ struct ScopeCoordinate { uint16_t hops; uint16_t binding; + + /* XXX this will be removed with the last patch of bug 659577. */ + uint16_t frameBinding; + inline ScopeCoordinate(jsbytecode *pc); + inline ScopeCoordinate() {} }; inline JSAtom * @@ -97,6 +95,15 @@ class ScopeObject : public JSObject inline JSObject &enclosingScope() const; inline bool setEnclosingScope(JSContext *cx, HandleObject obj); + /* + * Get or set an aliased variable contained in this scope. Unaliased + * variables should instead access the StackFrame. Aliased variable access + * is primarily made through JOF_SCOPECOORD ops which is why these members + * take a ScopeCoordinate instead of just the slot index. + */ + inline const Value &aliasedVar(ScopeCoordinate sc); + inline void setAliasedVar(ScopeCoordinate sc, const Value &v); + /* * The stack frame for this scope object, if the frame is still active. * Note: these members may not be called for a StaticBlockObject or diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 663fb2dc8c84..e36113f96b6c 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -286,6 +286,28 @@ StackFrame::actualArgsEnd() const return formalArgs() + numActualArgs(); } +inline ScopeObject & +StackFrame::aliasedVarScope(ScopeCoordinate sc) const +{ + JSObject *scope = &scopeChain()->asScope(); + for (unsigned i = sc.hops; i; i--) + scope = &scope->asScope().enclosingScope(); + +#ifdef DEBUG + if (scope->isCall()) { + JS_ASSERT(scope->asCall() == callObj()); + JS_ASSERT(scope->asCall().maybeStackFrame() == this); + } else { + StaticBlockObject &target = scope->asClonedBlock().staticBlock(); + StaticBlockObject *b = &blockChain(); + while (b != &target) + b = b->enclosingBlock(); + } +#endif + + return scope->asScope(); +} + inline void StackFrame::setScopeChain(JSObject &obj) { diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index a65c7baaa2e1..61c1a7165e28 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -43,6 +43,8 @@ class ScriptFrameIter; class AllFramesIter; class ArgumentsObject; +class ScopeCoordinate; +class ScopeObject; class StaticBlockObject; #ifdef JS_METHODJIT @@ -847,6 +849,7 @@ class StackFrame */ inline HandleObject scopeChain() const; + inline ScopeObject &aliasedVarScope(ScopeCoordinate sc) const; inline GlobalObject &global() const; bool hasCallObj() const { From 73c4e60e88821e52bf1953e4cb61896ccf54a00c Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 10 May 2012 11:24:20 -0700 Subject: [PATCH 22/53] Bug 659577 - Embed blockChain information in ALIASEDVAR ops (r=waldo) --HG-- extra : rebase_source : ea0deae107902520b392ed1eeddcd8c6420945ee --- js/src/frontend/BytecodeEmitter.cpp | 35 +++++++++++++--------- js/src/frontend/BytecodeEmitter.h | 3 +- js/src/frontend/TreeContext.h | 4 +-- js/src/jsopcode.cpp | 17 ++++++----- js/src/jsopcode.h | 2 +- js/src/jsopcode.tbl | 8 +++++ js/src/vm/ScopeObject-inl.h | 7 ----- js/src/vm/ScopeObject.cpp | 45 +++++++++++++++++++++++++++++ js/src/vm/ScopeObject.h | 12 ++++++-- 9 files changed, 98 insertions(+), 35 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 7c38bbf7a11e..15b55ddba6d5 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -806,7 +806,7 @@ static bool EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce) { JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT); - return EmitIndex32(cx, op, bce->objectList.index(objbox), bce); + return EmitIndex32(cx, op, bce->objectList.add(objbox), bce); } static bool @@ -834,13 +834,13 @@ EmitUnaliasedVarOp(JSContext *cx, JSOp op, uint16_t slot, BytecodeEmitter *bce) } static bool -EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, JSAtom *atom, BytecodeEmitter *bce) +EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce) { JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD); - jsatomid atomIndex; - if (!bce->makeAtomIndex(atom, &atomIndex)) - return false; + uint32_t maybeBlockIndex = UINT32_MAX; + if (bce->sc->blockChain) + maybeBlockIndex = bce->objectList.indexOf(bce->sc->blockChain); bool decomposed = js_CodeSpec[op].format & JOF_DECOMPOSE; unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (decomposed ? 1 : 0); @@ -855,7 +855,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, JSAtom *atom, Bytec pc += sizeof(uint16_t); SET_UINT16(pc, sc.binding); pc += sizeof(uint16_t); - SET_UINT32_INDEX(pc, atomIndex); + SET_UINT32_INDEX(pc, maybeBlockIndex); pc += sizeof(uint32_t); SET_UINT16(pc, sc.frameBinding); return true; @@ -911,7 +911,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce) } } - return EmitAliasedVarOp(cx, op, sc, pn->atom(), bce); + return EmitAliasedVarOp(cx, op, sc, bce); } static bool @@ -2639,8 +2639,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod sc.hops = 0; sc.binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot()); sc.frameBinding = sc.binding; - JSAtom *atom = cx->runtime->atomState.argumentsAtom; - if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, atom, bce)) + if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce)) return false; } else { if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocalSlot(), bce)) @@ -4877,7 +4876,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } /* Make the function object a literal in the outer script's pool. */ - unsigned index = bce->objectList.index(pn->pn_funbox); + unsigned index = bce->objectList.add(pn->pn_funbox); /* Emit a bytecode pointing to the closure object in its immediate. */ if (pn->getOp() != JSOP_NOP) { @@ -5766,7 +5765,7 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) ObjectBox *objbox = bce->parser->newObjectBox(obj); if (!objbox) return false; - unsigned index = bce->objectList.index(objbox); + unsigned index = bce->objectList.add(objbox); MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, "newinit and newobject must have equal length to edit in-place"); EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index)); @@ -6454,7 +6453,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) case PNK_REGEXP: JS_ASSERT(pn->isOp(JSOP_REGEXP)); - ok = EmitRegExp(cx, bce->regexpList.index(pn->pn_objbox), bce); + ok = EmitRegExp(cx, bce->regexpList.add(pn->pn_objbox), bce); break; #if JS_HAS_XML_SUPPORT @@ -6954,7 +6953,7 @@ frontend::FinishTakingTryNotes(BytecodeEmitter *bce, TryNoteArray *array) * the pre-compilation prototype, a pigeon-hole problem for instanceof tests. */ unsigned -CGObjectList::index(ObjectBox *objbox) +CGObjectList::add(ObjectBox *objbox) { JS_ASSERT(!objbox->emitLink); objbox->emitLink = lastbox; @@ -6962,6 +6961,16 @@ CGObjectList::index(ObjectBox *objbox) return length++; } +unsigned +CGObjectList::indexOf(JSObject *obj) +{ + JS_ASSERT(length > 0); + unsigned index = length - 1; + for (ObjectBox *box = lastbox; box->object != obj; box = box->emitLink) + index--; + return index; +} + void CGObjectList::finish(ObjectArray *array) { diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 4b54d85409a1..226d2e9e9698 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -49,7 +49,8 @@ struct CGObjectList { CGObjectList() : length(0), lastbox(NULL) {} - unsigned index(ObjectBox *objbox); + unsigned add(ObjectBox *objbox); + unsigned indexOf(JSObject *obj); void finish(ObjectArray *array); }; diff --git a/js/src/frontend/TreeContext.h b/js/src/frontend/TreeContext.h index e38970e9dbad..3b8a6cad2160 100644 --- a/js/src/frontend/TreeContext.h +++ b/js/src/frontend/TreeContext.h @@ -136,9 +136,7 @@ struct SharedContext { StmtInfo *topStmt; /* top of statement info stack */ StmtInfo *topScopeStmt; /* top lexical scope statement */ Rooted blockChain; - /* compile time block scope chain (NB: one - deeper than the topScopeStmt/downScope - chain when in head of let block/expr) */ + /* compile time block scope chain */ private: const RootedFunction fun_; /* function to store argument and variable diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 2eeb14bb9c80..611d42c86c80 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -514,14 +514,15 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, } case JOF_SCOPECOORD: { - unsigned i = GET_UINT16(pc); - Sprint(sp, " %u", i); - pc += sizeof(uint16_t); - i = GET_UINT16(pc); - Sprint(sp, " %u", i); - pc += sizeof(uint16_t); - /* FALL THROUGH */ + Value v = StringValue(ScopeCoordinateName(script, pc)); + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, v, &bytes)) + return 0; + ScopeCoordinate sc(pc); + Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), sc.hops, sc.binding); + break; } + case JOF_ATOM: { Value v = StringValue(script->getAtom(GET_UINT32_INDEX(pc))); JSAutoByteString bytes; @@ -1843,7 +1844,7 @@ static bool IsVarSlot(JSPrinter *jp, jsbytecode *pc, JSAtom **varAtom, int *localSlot) { if (JOF_OPTYPE(*pc) == JOF_SCOPECOORD) { - *varAtom = ScopeCoordinateAtom(jp->script, pc); + *varAtom = ScopeCoordinateName(jp->script, pc); LOCAL_ASSERT_RV(*varAtom, NULL); return true; } diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index 9e31cea09ed4..e87833c196b4 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -60,7 +60,7 @@ typedef enum JSOp { #define JOF_INT8 18 /* int8_t immediate operand */ #define JOF_ATOMOBJECT 19 /* uint16_t constant index + object index */ #define JOF_UINT16PAIR 20 /* pair of uint16_t immediates */ -#define JOF_SCOPECOORD 21 /* pair of uint16_t immediates followed by atom index */ +#define JOF_SCOPECOORD 21 /* pair of uint16_t immediates followed by block index */ #define JOF_TYPEMASK 0x001f /* mask for above immediate types */ #define JOF_NAME (1U<<5) /* name operation */ diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl index 27044a346686..5688c6346a4d 100644 --- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -334,6 +334,14 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE) * 'with', 'arguments' and E4X filters. All of these cases require creating a * CallObject to own the aliased variable. * + * An ALIASEDVAR opcode contains the following immediates: + * uint16 hops: the number of scope objects to skip to find the ScopeObject + * containing the variable being accessed + * uint16 slot: the slot containing the variable in the ScopeObject (this + * 'slot' does not include RESERVED_SLOTS). + * uint32 block: the index (into the script object table) of the block chain + * at the point of the variable access. + * * XXX: there is also a temporary 2-byte index (indicating the frame slot * aliased by the scope chain) which will be removed with the last patch of bug * 659577. diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index 216563606e24..8a6a71a50f02 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -20,13 +20,6 @@ ScopeCoordinate::ScopeCoordinate(jsbytecode *pc) JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); } -inline JSAtom * -ScopeCoordinateAtom(JSScript *script, jsbytecode *pc) -{ - JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); - return script->getAtom(GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t))); -} - inline JSObject & ScopeObject::enclosingScope() const { diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 09077788f205..5152970ea2e8 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -23,6 +23,51 @@ using namespace js::types; /*****************************************************************************/ +StaticBlockObject * +js::ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc) +{ + ScopeCoordinate sc(pc); + + uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t)); + if (blockIndex == UINT32_MAX) + return NULL; + + StaticBlockObject *block = &script->getObject(blockIndex)->asStaticBlock(); + unsigned i = 0; + while (true) { + while (block && !block->needsClone()) + block = block->enclosingBlock(); + if (i++ == sc.hops) + break; + block = block->enclosingBlock(); + } + return block; +} + +PropertyName * +js::ScopeCoordinateName(JSScript *script, jsbytecode *pc) +{ + StaticBlockObject *maybeBlock = ScopeCoordinateBlockChain(script, pc); + ScopeCoordinate sc(pc); + + uint32_t targetSlot; + Shape *shape; + if (maybeBlock) { + targetSlot = BlockObject::RESERVED_SLOTS + sc.binding; + shape = maybeBlock->lastProperty(); + } else { + targetSlot = CallObject::RESERVED_SLOTS + sc.binding; + shape = script->bindings.lastShape(); + } + + Shape::Range r = shape->all(); + while (r.front().slot() != targetSlot) + r.popFront(); + return JSID_TO_ATOM(r.front().propid())->asPropertyName(); +} + +/*****************************************************************************/ + void js_PutCallObject(StackFrame *fp, CallObject &callobj) { diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 8ab2e6dd564a..e167f9bedef3 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -22,6 +22,9 @@ namespace js { * given lexically-enclosing variable. A scope coordinate has two dimensions: * - hops: the number of scope objects on the scope chain to skip * - binding: which binding on the scope object + * Additionally (as described in jsopcode.tbl) there is a 'block' index, but + * this is only needed for decompilation/inference so it is not included in the + * main ScopeCoordinate struct: use ScopeCoordinate{BlockChain,Atom} instead. */ struct ScopeCoordinate { @@ -35,8 +38,13 @@ struct ScopeCoordinate inline ScopeCoordinate() {} }; -inline JSAtom * -ScopeCoordinateAtom(JSScript *script, jsbytecode *pc); +/* Return the static block chain (or null) accessed by *pc. */ +extern StaticBlockObject * +ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc); + +/* Return the name being accessed by the given ALIASEDVAR op. */ +extern PropertyName * +ScopeCoordinateName(JSScript *script, jsbytecode *pc); /*****************************************************************************/ From e89e33891bbb57758681421d22124560fb3975ea Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 23 Feb 2012 13:59:10 -0800 Subject: [PATCH 23/53] Bug 659577 - Don't alias stack variables (r=bhackett) --HG-- rename : js/src/jit-test/tests/basic/testBug659577.js => js/src/jit-test/tests/basic/testBug659577-1.js --- js/src/frontend/BytecodeEmitter.cpp | 19 +- js/src/frontend/TreeContext-inl.h | 3 +- js/src/frontend/TreeContext.h | 2 +- js/src/gc/Barrier.h | 9 + js/src/gc/Marking.h | 6 + js/src/jit-test/tests/basic/testAliasedLet.js | 11 + .../{testBug659577.js => testBug659577-1.js} | 0 .../jit-test/tests/basic/testBug659577-2.js | 15 + .../basic/testDestructuringFormalError.js | 6 + .../tests/basic/testFunApplyOverflow.js | 10 + .../tests/basic/testGCNewbornGenerator.js | 6 + .../basic/testGeneratorDieButScopeAlive.js | 16 + .../jaeger/bug563000/trap-from-add-ool.js | 2 +- js/src/js.msg | 2 +- js/src/jsanalyze.cpp | 17 +- js/src/jsanalyze.h | 11 +- js/src/jsapi-tests/testArgumentsObject.cpp | 2 +- js/src/jsarray.cpp | 4 +- js/src/jscntxt.cpp | 33 +- js/src/jscntxt.h | 30 +- js/src/jscntxtinlines.h | 17 - js/src/jsdbgapi.cpp | 9 +- js/src/jsfun.cpp | 4 +- js/src/jsfun.h | 6 - js/src/jsgc.cpp | 2 +- js/src/jsinfer.cpp | 4 +- js/src/jsinfer.h | 5 +- js/src/jsinterp.cpp | 246 +++---- js/src/jsinterp.h | 28 - js/src/jsinterpinlines.h | 111 +-- js/src/jsiter.cpp | 88 +-- js/src/jsiter.h | 53 +- js/src/jsobj.cpp | 19 +- js/src/jsopcode.cpp | 14 +- js/src/jsopcode.tbl | 18 +- js/src/jsscope.cpp | 8 +- js/src/jsscript.cpp | 60 +- js/src/jsscript.h | 24 +- js/src/jsscriptinlines.h | 4 +- js/src/jsstr.cpp | 14 +- js/src/jsval.h | 3 +- js/src/methodjit/Compiler.cpp | 326 +++++---- js/src/methodjit/Compiler.h | 4 +- js/src/methodjit/InvokeHelpers.cpp | 123 ++-- js/src/methodjit/MethodJIT.cpp | 4 - js/src/methodjit/MethodJIT.h | 14 +- js/src/methodjit/MonoIC.cpp | 2 +- js/src/methodjit/PolyIC.cpp | 78 +- js/src/methodjit/StubCalls.cpp | 61 +- js/src/methodjit/StubCalls.h | 6 +- js/src/shell/js.cpp | 29 +- js/src/vm/ArgumentsObject-inl.h | 150 ++-- js/src/vm/ArgumentsObject.cpp | 205 ++---- js/src/vm/ArgumentsObject.h | 131 ++-- js/src/vm/Debugger.cpp | 13 +- js/src/vm/ScopeObject-inl.h | 133 +--- js/src/vm/ScopeObject.cpp | 478 ++++-------- js/src/vm/ScopeObject.h | 85 +-- js/src/vm/Stack-inl.h | 312 ++++---- js/src/vm/Stack.cpp | 241 ++++-- js/src/vm/Stack.h | 690 ++++++++---------- 61 files changed, 1674 insertions(+), 2352 deletions(-) create mode 100644 js/src/jit-test/tests/basic/testAliasedLet.js rename js/src/jit-test/tests/basic/{testBug659577.js => testBug659577-1.js} (100%) create mode 100644 js/src/jit-test/tests/basic/testBug659577-2.js create mode 100644 js/src/jit-test/tests/basic/testDestructuringFormalError.js create mode 100644 js/src/jit-test/tests/basic/testFunApplyOverflow.js create mode 100644 js/src/jit-test/tests/basic/testGCNewbornGenerator.js create mode 100644 js/src/jit-test/tests/basic/testGeneratorDieButScopeAlive.js diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 15b55ddba6d5..eda548aea3b8 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -843,7 +843,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bc maybeBlockIndex = bce->objectList.indexOf(bce->sc->blockChain); bool decomposed = js_CodeSpec[op].format & JOF_DECOMPOSE; - unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (decomposed ? 1 : 0); + unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + (decomposed ? 1 : 0); JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length); ptrdiff_t off = EmitN(cx, bce, op, n); @@ -853,11 +853,9 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bc jsbytecode *pc = bce->code(off); SET_UINT16(pc, sc.hops); pc += sizeof(uint16_t); - SET_UINT16(pc, sc.binding); + SET_UINT16(pc, sc.slot); pc += sizeof(uint16_t); SET_UINT32_INDEX(pc, maybeBlockIndex); - pc += sizeof(uint32_t); - SET_UINT16(pc, sc.frameBinding); return true; } @@ -888,15 +886,13 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce) if (JOF_OPTYPE(pn->getOp()) == JOF_QARG) { JS_ASSERT(bce->sc->funIsHeavyweight()); sc.hops = ClonedBlockDepth(bce); - sc.binding = bce->sc->bindings.argToBinding(pn->pn_cookie.slot()); - sc.frameBinding = sc.binding; + sc.slot = bce->sc->bindings.argToSlot(pn->pn_cookie.slot()); } else { JS_ASSERT(JOF_OPTYPE(pn->getOp()) == JOF_LOCAL || pn->isKind(PNK_FUNCTION)); unsigned local = pn->pn_cookie.slot(); - sc.frameBinding = bce->sc->bindings.localToBinding(local); if (local < bce->sc->bindings.numVars()) { sc.hops = ClonedBlockDepth(bce); - sc.binding = sc.frameBinding; + sc.slot = bce->sc->bindings.localToSlot(local); } else { unsigned depth = local - bce->sc->bindings.numVars(); unsigned hops = 0; @@ -907,7 +903,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce) b = b->enclosingBlock(); } sc.hops = hops; - sc.binding = depth - b->stackDepth(); + sc.slot = depth - b->stackDepth(); } } @@ -2637,12 +2633,11 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod if (bce->sc->bindingsAccessedDynamically()) { ScopeCoordinate sc; sc.hops = 0; - sc.binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot()); - sc.frameBinding = sc.binding; + sc.slot = bce->sc->bindings.localToSlot(bce->sc->argumentsLocal()); if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce)) return false; } else { - if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocalSlot(), bce)) + if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocal(), bce)) return false; } if (Emit1(cx, bce, JSOP_POP) < 0) diff --git a/js/src/frontend/TreeContext-inl.h b/js/src/frontend/TreeContext-inl.h index c3f7f392bd69..fc99e69c434c 100644 --- a/js/src/frontend/TreeContext-inl.h +++ b/js/src/frontend/TreeContext-inl.h @@ -53,7 +53,8 @@ SharedContext::needStrictChecks() { } inline unsigned -SharedContext::argumentsLocalSlot() const { +SharedContext::argumentsLocal() const +{ PropertyName *arguments = context->runtime->atomState.argumentsAtom; unsigned slot; DebugOnly kind = bindings.lookup(context, arguments, &slot); diff --git a/js/src/frontend/TreeContext.h b/js/src/frontend/TreeContext.h index 3b8a6cad2160..82f15ef4f196 100644 --- a/js/src/frontend/TreeContext.h +++ b/js/src/frontend/TreeContext.h @@ -187,7 +187,7 @@ struct SharedContext { #undef INFUNC - unsigned argumentsLocalSlot() const; + unsigned argumentsLocal() const; bool inFunction() const { return !!fun_; } diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 9a735f1f568f..314d3c1fea76 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -338,6 +338,7 @@ class EncapsulatedValue bool isDouble() const { return value.isDouble(); } bool isString() const { return value.isString(); } bool isObject() const { return value.isObject(); } + bool isMagic() const { return value.isMagic(); } bool isMagic(JSWhyMagic why) const { return value.isMagic(why); } bool isGCThing() const { return value.isGCThing(); } bool isMarkable() const { return value.isMarkable(); } @@ -463,6 +464,14 @@ Valueify(const EncapsulatedValue *array) return (const Value *)array; } +static inline HeapValue * +HeapValueify(Value *v) +{ + JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value)); + JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value)); + return (HeapValue *)v; +} + class HeapSlotArray { HeapSlot *array; diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index 5c4344f7f57e..905a7290da22 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -129,6 +129,12 @@ MarkValue(JSTracer *trc, EncapsulatedValue *v, const char *name); void MarkValueRange(JSTracer *trc, size_t len, EncapsulatedValue *vec, const char *name); +inline void +MarkValueRange(JSTracer *trc, HeapValue *begin, HeapValue *end, const char *name) +{ + return MarkValueRange(trc, end - begin, begin, name); +} + void MarkValueRoot(JSTracer *trc, Value *v, const char *name); diff --git a/js/src/jit-test/tests/basic/testAliasedLet.js b/js/src/jit-test/tests/basic/testAliasedLet.js new file mode 100644 index 000000000000..c07cbea2e5c4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAliasedLet.js @@ -0,0 +1,11 @@ +function f() { + let (x, y, z) { + eval('x = 1; y = 2; z = 3'); + for (var i = 0; i < 10000; ++i) { + assertEq(x, 1); + assertEq(y, 2); + assertEq(z, 3); + } + } +} +f(); diff --git a/js/src/jit-test/tests/basic/testBug659577.js b/js/src/jit-test/tests/basic/testBug659577-1.js similarity index 100% rename from js/src/jit-test/tests/basic/testBug659577.js rename to js/src/jit-test/tests/basic/testBug659577-1.js diff --git a/js/src/jit-test/tests/basic/testBug659577-2.js b/js/src/jit-test/tests/basic/testBug659577-2.js new file mode 100644 index 000000000000..dbd4ec240792 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug659577-2.js @@ -0,0 +1,15 @@ +gczeal(4); +evaluate("\ +Date.formatFunctions = {count:0};\ +Date.prototype.dateFormat = function(format) {\ + var funcName = 'format' + Date.formatFunctions.count++;\ + var code = 'Date.prototype.' + funcName + ' = function(){return ';\ + var ch = '';\ + for (var i = 0; i < format.length; ++i) {\ + ch = format.charAt(i);\ + eval(code.substring(0, code.length - 3) + ';}');\ + }\ +};\ +var date = new Date('1/1/2007 1:11:11');\ + var shortFormat = date.dateFormat('Y-m-d');\ +"); diff --git a/js/src/jit-test/tests/basic/testDestructuringFormalError.js b/js/src/jit-test/tests/basic/testDestructuringFormalError.js new file mode 100644 index 000000000000..1d1a8c2c0340 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDestructuringFormalError.js @@ -0,0 +1,6 @@ +// |jit-test| error:TypeError +(function({ + l +}) { + eval(); +})() diff --git a/js/src/jit-test/tests/basic/testFunApplyOverflow.js b/js/src/jit-test/tests/basic/testFunApplyOverflow.js new file mode 100644 index 000000000000..45be944e99e4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testFunApplyOverflow.js @@ -0,0 +1,10 @@ +function g(x,y) { + return x + y; +} + +function f(x) { + return g.apply(null, arguments); +} + +for (var i = 0; i < 100; ++i) + assertEq(f(i, 1), i+1); diff --git a/js/src/jit-test/tests/basic/testGCNewbornGenerator.js b/js/src/jit-test/tests/basic/testGCNewbornGenerator.js new file mode 100644 index 000000000000..3f883147ee94 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGCNewbornGenerator.js @@ -0,0 +1,6 @@ +// |jit-test| debug +try { + function f() {} + (1 for (x in [])) +} catch (e) {} +gc() diff --git a/js/src/jit-test/tests/basic/testGeneratorDieButScopeAlive.js b/js/src/jit-test/tests/basic/testGeneratorDieButScopeAlive.js new file mode 100644 index 000000000000..3c3e70f48ab3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGeneratorDieButScopeAlive.js @@ -0,0 +1,16 @@ +var g = newGlobal('new-compartment'); +var dbg = new Debugger(g); + + +var hits = 0; +dbg.onDebuggerStatement = function(frame) { + ++hits; + frame.older.eval("escaped = function() { return y }"); +} + +g.escaped = undefined; +g.eval("function h() { debugger }"); +g.eval("(function () { var y = 42; h(); yield })().next();"); +assertEq(g.eval("escaped()"), 42); +gc(); +assertEq(g.eval("escaped()"), 42); diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js index d6afbb7adea6..0b4cd6699b59 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js @@ -3,7 +3,7 @@ setDebug(true); x = "notset"; function main() { /* The JSOP_STOP in main. */ - a = { valueOf: function () { trap(main, 97, "success()"); } }; + a = { valueOf: function () { trap(main, 95, "success()"); } }; b = ""; eval(); a + b; diff --git a/js/src/js.msg b/js/src/js.msg index 2d7fee285a4f..38a3e7fcfd2d 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -225,7 +225,7 @@ MSG_DEF(JSMSG_BAD_XML_CHARACTER, 171, 0, JSEXN_SYNTAXERR, "illegal XML char MSG_DEF(JSMSG_BAD_DEFAULT_XML_NAMESPACE,172,0,JSEXN_SYNTAXERR, "invalid default XML namespace") MSG_DEF(JSMSG_BAD_XML_NAME_SYNTAX, 173, 0, JSEXN_SYNTAXERR, "invalid XML name") MSG_DEF(JSMSG_BRACKET_AFTER_ATTR_EXPR,174, 0, JSEXN_SYNTAXERR, "missing ] after attribute expression") -MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 1, JSEXN_TYPEERR, "already executing generator {0}") +MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 0, JSEXN_TYPEERR, "already executing generator") MSG_DEF(JSMSG_CURLY_IN_XML_EXPR, 176, 0, JSEXN_SYNTAXERR, "missing } in XML expression") MSG_DEF(JSMSG_BAD_XML_NAMESPACE, 177, 1, JSEXN_TYPEERR, "invalid XML namespace {0}") MSG_DEF(JSMSG_BAD_XML_ATTR_NAME, 178, 1, JSEXN_TYPEERR, "invalid XML attribute name {0}") diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index 93bd13a49394..6e06302b2658 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -323,14 +323,6 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) case JSOP_SETALIASEDVAR: { JS_ASSERT(!isInlineable); usesScopeChain_ = true; - - /* XXX: this can be removed after bug 659577. */ - ScopeCoordinate sc(pc); - if (script->bindings.bindingIsLocal(sc.frameBinding) && - script->bindings.bindingToLocal(sc.frameBinding) >= script->nfixed) - { - localsAliasStack_ = true; - } break; } @@ -1925,15 +1917,15 @@ ScriptAnalysis::needsArgsObj(NeedsArgsObjState &state, SSAUseChain *use) if (op == JSOP_POP || op == JSOP_POPN) return false; -#ifdef JS_METHODJIT /* SplatApplyArgs can read fp->canonicalActualArg(i) directly. */ if (state.canOptimizeApply && op == JSOP_FUNAPPLY && GET_ARGC(pc) == 2 && use->u.which == 0) { +#ifdef JS_METHODJIT JS_ASSERT(mjit::IsLowerableFunCallOrApply(pc)); +#endif state.haveOptimizedApply = true; state.canOptimizeApply = false; return false; } -#endif /* arguments[i] can read fp->canonicalActualArg(i) directly. */ if (!state.haveOptimizedApply && op == JSOP_GETELEM && use->u.which == 1) { @@ -1973,8 +1965,11 @@ ScriptAnalysis::needsArgsObj(JSContext *cx) * soundly perform this analysis in their presence. Also, debuggers may * want to see 'arguments', so assume every arguments object escapes. */ - if (script->bindingsAccessedDynamically || localsAliasStack() || cx->compartment->debugMode()) + if (script->bindingsAccessedDynamically || script->numClosedArgs() > 0 || + localsAliasStack() || cx->compartment->debugMode()) + { return true; + } unsigned pcOff = script->argumentsBytecode() - script->code; diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h index 839e045c738f..5346626de194 100644 --- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -363,13 +363,14 @@ static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc) case JSOP_CALLALIASEDVAR: case JSOP_SETALIASEDVAR: { - ScopeCoordinate sc = ScopeCoordinate(pc); - return script->bindings.bindingIsArg(sc.frameBinding) - ? ArgSlot(script->bindings.bindingToArg(sc.frameBinding)) - : LocalSlot(script, script->bindings.bindingToLocal(sc.frameBinding)); + ScopeCoordinate sc(pc); + if (StaticBlockObject *block = ScopeCoordinateBlockChain(script, pc)) + return LocalSlot(script, block->slotToFrameLocal(script, sc.slot)); + if (script->bindings.slotIsArg(sc.slot)) + return ArgSlot(script->bindings.slotToArg(sc.slot)); + return LocalSlot(script, script->bindings.slotToLocal(sc.slot)); } - case JSOP_THIS: return ThisSlot(); diff --git a/js/src/jsapi-tests/testArgumentsObject.cpp b/js/src/jsapi-tests/testArgumentsObject.cpp index 5f14d4bccfe8..1d853494a6aa 100644 --- a/js/src/jsapi-tests/testArgumentsObject.cpp +++ b/js/src/jsapi-tests/testArgumentsObject.cpp @@ -97,7 +97,7 @@ ExhaustiveTest(const char funcode[]) for (size_t i = 0; i <= ArgCount; i++) { for (size_t j = 0; j <= ArgCount - i; j++) { ClearElements(elems); - CHECK(argsobj.getElements(i, j, elems)); + CHECK(argsobj.maybeGetElements(i, j, elems)); for (size_t k = 0; k < j; k++) CHECK_SAME(elems[k], INT_TO_JSVAL(i + k)); for (size_t k = j; k < MAX_ELEMS - 1; k++) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index f7ff09eb1752..c2767a2ea88d 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -399,7 +399,7 @@ GetElement(JSContext *cx, JSObject *obj, IndexType index, JSBool *hole, Value *v return JS_TRUE; } if (obj->isArguments()) { - if (obj->asArguments().getElement(uint32_t(index), vp)) { + if (obj->asArguments().maybeGetElement(uint32_t(index), vp)) { *hole = JS_FALSE; return true; } @@ -438,7 +438,7 @@ GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp) if (aobj->isArguments()) { ArgumentsObject &argsobj = aobj->asArguments(); if (!argsobj.hasOverriddenLength()) { - if (argsobj.getElements(0, length, vp)) + if (argsobj.maybeGetElements(0, length, vp)) return true; } } diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 433a61cf1139..281be37cacdb 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -994,6 +994,7 @@ JSContext::JSContext(JSRuntime *rt) functionCallback(NULL), #endif enumerators(NULL), + innermostGenerator_(NULL), #ifdef DEBUG stackIterAssertionEnabled(true), #endif @@ -1079,26 +1080,24 @@ JSContext::wrapPendingException() setPendingException(v); } -JSGenerator * -JSContext::generatorFor(StackFrame *fp) const + +void +JSContext::enterGenerator(JSGenerator *gen) { - JS_ASSERT(stack.containsSlow(fp)); - JS_ASSERT(fp->isGeneratorFrame()); - JS_ASSERT(!fp->isFloatingGenerator()); - JS_ASSERT(!genStack.empty()); - - if (JS_LIKELY(fp == genStack.back()->liveFrame())) - return genStack.back(); - - /* General case; should only be needed for debug APIs. */ - for (size_t i = 0; i < genStack.length(); ++i) { - if (genStack[i]->liveFrame() == fp) - return genStack[i]; - } - JS_NOT_REACHED("no matching generator"); - return NULL; + JS_ASSERT(!gen->prevGenerator); + gen->prevGenerator = innermostGenerator_; + innermostGenerator_ = gen; } +void +JSContext::leaveGenerator(JSGenerator *gen) +{ + JS_ASSERT(innermostGenerator_ == gen); + innermostGenerator_ = innermostGenerator_->prevGenerator; + gen->prevGenerator = NULL; +} + + bool JSContext::runningWithTrustedPrincipals() const { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 5d050cead259..cacbd987c564 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1242,29 +1242,12 @@ struct JSContext : js::ContextFriendFields JSObject *enumerators; private: - /* - * To go from a live generator frame (on the stack) to its generator object - * (see comment js_FloatingFrameIfGenerator), we maintain a stack of active - * generators, pushing and popping when entering and leaving generator - * frames, respectively. - */ - js::Vector genStack; - + /* Innermost-executing generator or null if no generator are executing. */ + JSGenerator *innermostGenerator_; public: - /* Return the generator object for the given generator frame. */ - JSGenerator *generatorFor(js::StackFrame *fp) const; - - /* Early OOM-check. */ - inline bool ensureGeneratorStackSpace(); - - bool enterGenerator(JSGenerator *gen) { - return genStack.append(gen); - } - - void leaveGenerator(JSGenerator *gen) { - JS_ASSERT(genStack.back() == gen); - genStack.popBack(); - } + JSGenerator *innermostGenerator() const { return innermostGenerator_; } + void enterGenerator(JSGenerator *gen); + void leaveGenerator(JSGenerator *gen); inline void* malloc_(size_t bytes) { return runtime->malloc_(bytes, this); @@ -1296,9 +1279,6 @@ struct JSContext : js::ContextFriendFields void purge(); - /* For DEBUG. */ - inline void assertValidStackDepth(unsigned depth); - bool isExceptionPending() { return throwing; } diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index f3886fdc312a..d72e7f888050 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -541,14 +541,6 @@ JSContext::setCompileOptions(unsigned newcopts) maybeOverrideVersion(newVersion); } -inline void -JSContext::assertValidStackDepth(unsigned depth) -{ -#ifdef DEBUG - JS_ASSERT(0 <= regs().sp - fp()->base()); - JS_ASSERT(depth <= uintptr_t(regs().sp - fp()->base())); -#endif -} inline js::LifoAlloc & JSContext::typeLifoAlloc() @@ -556,15 +548,6 @@ JSContext::typeLifoAlloc() return compartment->typeLifoAlloc; } -inline bool -JSContext::ensureGeneratorStackSpace() -{ - bool ok = genStack.reserve(genStack.length() + 1); - if (!ok) - js_ReportOutOfMemory(this); - return ok; -} - inline void JSContext::setPendingException(js::Value v) { JS_ASSERT(!IsPoisonedValue(v)); diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 9fa78eff225a..db19626d7840 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -565,11 +565,8 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fpArg) */ while (o) { ScopeObject &scope = o->asDebugScope().scope(); - if (scope.isCall()) { - JS_ASSERT_IF(cx->compartment->debugMode() && fp->isNonEvalFunctionFrame(), - fp == scope.asCall().maybeStackFrame()); + if (scope.isCall()) return o; - } o = o->enclosingScope(); } return NULL; @@ -805,10 +802,10 @@ GetPropertyDesc(JSContext *cx, JSObject *obj_, Shape *shape, JSPropertyDesc *pd) | (!shape->writable() ? JSPD_READONLY : 0) | (!shape->configurable() ? JSPD_PERMANENT : 0); pd->spare = 0; - if (shape->getter() == CallObject::getArgOp) { + if (shape->setter() == CallObject::setArgOp) { pd->slot = shape->shortid(); pd->flags |= JSPD_ARGUMENT; - } else if (shape->getter() == CallObject::getVarOp) { + } else if (shape->setter() == CallObject::setVarOp) { pd->slot = shape->shortid(); pd->flags |= JSPD_VARIABLE; } else { diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 6acaa837196b..b9e09bb44ae6 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -127,7 +127,7 @@ fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, Value *vp) * innermost function as uninlineable to expand its frame and allow us * to recover its callee object. */ - JSInlinedSite *inlined; + InlinedSite *inlined; jsbytecode *prevpc = fp->prev()->pcQuadratic(cx->stack, fp, &inlined); if (inlined) { mjit::JITChunk *chunk = fp->prev()->jit()->chunk(prevpc); @@ -696,7 +696,7 @@ js_fun_apply(JSContext *cx, unsigned argc, Value *vp) args.thisv() = vp[2]; /* Steps 7-8. */ - cx->fp()->forEachCanonicalActualArg(CopyTo(args.array())); + cx->fp()->forEachUnaliasedActual(CopyTo(args.array())); } else { /* Step 3. */ if (!vp[3].isObject()) { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 2526d611ed7b..648252af982f 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -244,9 +244,6 @@ js_ValueToCallableObject(JSContext *cx, js::Value *vp, unsigned flags); extern void js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, unsigned flags); -extern void -js_PutCallObject(js::StackFrame *fp, js::CallObject &callobj); - namespace js { /* @@ -278,9 +275,6 @@ JSFunction::toExtended() const return static_cast(this); } -extern void -js_PutArgsObject(js::StackFrame *fp); - inline bool js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 35d28233a1c5..016354870475 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3241,7 +3241,7 @@ SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep) /* Finalize unreachable (key,value) pairs in all weak maps. */ WeakMapBase::sweepAll(&rt->gcMarker); - rt->debugScopes->sweep(); + rt->debugScopes->sweep(rt); SweepAtomState(rt); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 93bbad4f9d57..adef366cf3e0 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -5192,8 +5192,8 @@ NestingPrologue(JSContext *cx, StackFrame *fp) } nesting->activeCall = &fp->callObj(); - nesting->argArray = fp->formalArgs(); - nesting->varArray = fp->slots(); + nesting->argArray = Valueify(nesting->activeCall->argArray()); + nesting->varArray = Valueify(nesting->activeCall->varArray()); } /* Maintain stack frame count for the function. */ diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 3347851406c8..463dd5d8b966 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -23,6 +23,9 @@ struct TypeInferenceSizes; } namespace js { + +class CallObject; + namespace types { /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */ @@ -961,7 +964,7 @@ struct TypeScriptNesting JSScript *next; /* If this is an outer function, the most recent activation. */ - JSObject *activeCall; + CallObject *activeCall; /* * If this is an outer function, pointers to the most recent activation's diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 798a418fcffb..4e8e1e6227c8 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -223,6 +223,7 @@ js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp) JS_ASSERT(fp == cx->fp()); JS_ASSERT(fp->script() == script); JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code); + JS_ASSERT_IF(fp->isEvalFrame(), script->isActiveEval); #ifdef JS_METHODJIT_SPEW JMCheckLogging(); #endif @@ -317,16 +318,11 @@ js::InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct) if (!cx->stack.pushInvokeFrame(cx, args, initial, &ifg)) return false; - /* Now that the new frame is rooted, maybe create a call object. */ - StackFrame *fp = ifg.fp(); - if (!fp->functionPrologue(cx)) - return false; - /* Run function until JSOP_STOP, JSOP_RETURN or error. */ - JSBool ok = RunScript(cx, fun->script(), fp); + JSBool ok = RunScript(cx, fun->script(), ifg.fp()); /* Propagate the return value out. */ - args.rval() = fp->returnValue(); + args.rval() = ifg.fp()->returnValue(); JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive()); return ok; } @@ -453,29 +449,15 @@ js::ExecuteKernel(JSContext *cx, JSScript *script_, JSObject &scopeChain, const if (!script->ensureRanAnalysis(cx, &scopeChain)) return false; - - /* Give strict mode eval its own fresh lexical environment. */ - StackFrame *fp = efg.fp(); - if (fp->isStrictEvalFrame() && !CallObject::createForStrictEval(cx, fp)) - return false; + TypeScript::SetThis(cx, script, efg.fp()->thisValue()); Probes::startExecution(cx, script); - - TypeScript::SetThis(cx, script, fp->thisValue()); - - bool ok = RunScript(cx, script, fp); - - if (fp->isStrictEvalFrame()) { - if (cx->compartment->debugMode()) - cx->runtime->debugScopes->onPopStrictEvalScope(fp); - js_PutCallObject(fp, fp->callObj()); - } - + bool ok = RunScript(cx, script, efg.fp()); Probes::stopExecution(cx, script); /* Propgate the return value out. */ if (result) - *result = fp->returnValue(); + *result = efg.fp()->returnValue(); return ok; } @@ -698,7 +680,7 @@ EnterWith(JSContext *cx, int stackIndex) StackFrame *fp = cx->fp(); Value *sp = cx->regs().sp; JS_ASSERT(stackIndex < 0); - JS_ASSERT(fp->base() <= sp + stackIndex); + JS_ASSERT(int(cx->regs().stackDepth()) + stackIndex >= 0); RootedObject obj(cx); if (sp[-1].isObject()) { @@ -706,17 +688,17 @@ EnterWith(JSContext *cx, int stackIndex) } else { obj = js_ValueToNonNullObject(cx, sp[-1]); if (!obj) - return JS_FALSE; + return false; sp[-1].setObject(*obj); } - JSObject *withobj = WithObject::create(cx, obj, fp->scopeChain(), - sp + stackIndex - fp->base()); + WithObject *withobj = WithObject::create(cx, obj, fp->scopeChain(), + cx->regs().stackDepth() + stackIndex); if (!withobj) - return JS_FALSE; + return false; - fp->setScopeChain(*withobj); - return JS_TRUE; + fp->pushOnScopeChain(*withobj); + return true; } /* Unwind block and scope chains to match the given depth. */ @@ -724,7 +706,7 @@ void js::UnwindScope(JSContext *cx, uint32_t stackDepth) { StackFrame *fp = cx->fp(); - JS_ASSERT(fp->base() + stackDepth <= cx->regs().sp); + JS_ASSERT(stackDepth <= cx->regs().stackDepth()); for (ScopeIter si(fp); !si.done(); si = si.enclosing()) { switch (si.type()) { @@ -753,7 +735,7 @@ js::UnwindForUncatchableException(JSContext *cx, const FrameRegs ®s) for (TryNoteIter tni(regs); !tni.done(); ++tni) { JSTryNote *tn = *tni; if (tn->kind == JSTRY_ITER) { - Value *sp = regs.fp()->base() + tn->stackDepth; + Value *sp = regs.spForStackDepth(tn->stackDepth); UnwindIteratorForUncatchableException(cx, &sp[-1].toObject()); } } @@ -813,7 +795,7 @@ TryNoteIter::settle() * depth exceeding the current one and this condition is what we use to * filter them out. */ - if (tn->stackDepth <= regs.sp - regs.fp()->base()) + if (tn->stackDepth <= regs.stackDepth()) break; } } @@ -850,36 +832,6 @@ DoIncDec(JSContext *cx, JSScript *script, jsbytecode *pc, const Value &v, Value return true; } -static inline void -CheckLocalAccess(StackFrame *fp, unsigned index, bool aliased = false) -{ -#ifdef DEBUG - if (index < fp->numFixed()) { - JS_ASSERT(fp->script()->varIsAliased(index) == aliased); - } else { - unsigned depth = index - fp->numFixed(); - for (StaticBlockObject *b = fp->maybeBlockChain(); b; b = b->enclosingBlock()) { - if (b->containsVarAtDepth(depth)) { - JS_ASSERT(b->isAliased(depth - b->stackDepth()) == aliased); - return; - } - } - /* - * Unfortunately, strange uses of JSOP_GETLOCAL (e.g., comprehensions - * and group assignment) access slots above script->nfixed and not in - * any block so we cannot use JS_NOT_REACHED here. - */ - } -#endif -} - -static inline void -CheckArgAccess(StackFrame *fp, unsigned index) -{ - JS_ASSERT(fp->script()->formalLivesInArgumentsObject(index) == - fp->script()->argsObjAliasesFormals()); -} - #define PUSH_COPY(v) do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0) #define PUSH_COPY_SKIP_CHECK(v) *regs.sp++ = v #define PUSH_NULL() regs.sp++->setNull() @@ -1222,7 +1174,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) #define RESTORE_INTERP_VARS() \ JS_BEGIN_MACRO \ SET_SCRIPT(regs.fp()->script()); \ - argv = regs.fp()->maybeFormalArgs(); \ atoms = FrameAtomBase(cx, regs.fp()); \ JS_ASSERT(&cx->regs() == ®s); \ JS_END_MACRO @@ -1285,7 +1236,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) JSRuntime *const rt = cx->runtime; Rooted script(cx); SET_SCRIPT(regs.fp()->script()); - Value *argv = regs.fp()->maybeFormalArgs(); CHECK_INTERRUPT_HANDLER(); /* @@ -1320,8 +1270,8 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) #if JS_HAS_GENERATORS if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) { - JS_ASSERT((size_t) (regs.pc - script->code) <= script->length); - JS_ASSERT((size_t) (regs.sp - regs.fp()->base()) <= StackDepth(script)); + JS_ASSERT(size_t(regs.pc - script->code) <= script->length); + JS_ASSERT(regs.stackDepth() <= script->nslots); /* * To support generator_throw and to catch ignored exceptions, @@ -1338,8 +1288,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) /* Don't call the script prologue if executing between Method and Trace JIT. */ if (interpMode == JSINTERP_NORMAL) { StackFrame *fp = regs.fp(); - JS_ASSERT_IF(!fp->isGeneratorFrame(), regs.pc == script->code); - if (!ScriptPrologueOrGeneratorResume(cx, fp, UseNewTypeAtEntry(cx, fp))) + if (!fp->isGeneratorFrame() && !fp->prologue(cx, UseNewTypeAtEntry(cx, fp))) goto error; if (cx->compartment->debugMode()) { JSTrapStatus status = ScriptDebugPrologue(cx, fp); @@ -1574,25 +1523,12 @@ BEGIN_CASE(JSOP_POP) END_CASE(JSOP_POP) BEGIN_CASE(JSOP_POPN) -{ + JS_ASSERT(GET_UINT16(regs.pc) <= regs.stackDepth()); regs.sp -= GET_UINT16(regs.pc); #ifdef DEBUG - JS_ASSERT(regs.fp()->base() <= regs.sp); - StaticBlockObject *block = regs.fp()->maybeBlockChain(); - JS_ASSERT_IF(block, - block->stackDepth() + block->slotCount() - <= (size_t) (regs.sp - regs.fp()->base())); - for (JSObject *obj = regs.fp()->scopeChain(); obj; obj = obj->enclosingScope()) { - if (!obj->isBlock() || !obj->isWith()) - continue; - if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp())) - break; - JS_ASSERT(regs.fp()->base() + obj->asBlock().stackDepth() - + (obj->isBlock() ? obj->asBlock().slotCount() : 1) - <= regs.sp); - } + if (StaticBlockObject *block = regs.fp()->maybeBlockChain()) + JS_ASSERT(regs.stackDepth() >= block->stackDepth() + block->slotCount()); #endif -} END_CASE(JSOP_POPN) BEGIN_CASE(JSOP_SETRVAL) @@ -1639,14 +1575,13 @@ BEGIN_CASE(JSOP_STOP) if (entryFrame != regs.fp()) inline_return: { - AssertValidFunctionScopeChainAtExit(regs.fp()); - if (cx->compartment->debugMode()) interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK); - interpReturnOK = ScriptEpilogue(cx, regs.fp(), interpReturnOK); + if (!regs.fp()->isYielding()) + regs.fp()->epilogue(cx); - /* The JIT inlines ScriptEpilogue. */ + /* The JIT inlines the epilogue. */ #ifdef JS_METHODJIT jit_return: #endif @@ -1679,7 +1614,7 @@ BEGIN_CASE(JSOP_STOP) regs.pc += JSOP_CALL_LENGTH; goto error; } else { - JS_ASSERT(regs.sp == regs.fp()->base()); + JS_ASSERT(regs.stackDepth() == 0); } interpReturnOK = true; goto exit; @@ -1796,7 +1731,7 @@ END_CASE(JSOP_IN) BEGIN_CASE(JSOP_ITER) { - JS_ASSERT(regs.sp > regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= 1); uint8_t flags = GET_UINT8(regs.pc); if (!ValueToIterator(cx, flags, ®s.sp[-1])) goto error; @@ -1807,7 +1742,7 @@ END_CASE(JSOP_ITER) BEGIN_CASE(JSOP_MOREITER) { - JS_ASSERT(regs.sp - 1 >= regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= 1); JS_ASSERT(regs.sp[-1].isObject()); PUSH_NULL(); bool cond; @@ -1820,8 +1755,8 @@ END_CASE(JSOP_MOREITER) BEGIN_CASE(JSOP_ITERNEXT) { + JS_ASSERT(regs.stackDepth() >= unsigned(GET_INT8(regs.pc))); Value *itervp = regs.sp - GET_INT8(regs.pc); - JS_ASSERT(itervp >= regs.fp()->base()); JS_ASSERT(itervp->isObject()); PUSH_NULL(); if (!IteratorNext(cx, &itervp->toObject(), ®s.sp[-1])) @@ -1831,7 +1766,7 @@ END_CASE(JSOP_ITERNEXT) BEGIN_CASE(JSOP_ENDITER) { - JS_ASSERT(regs.sp - 1 >= regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= 1); bool ok = CloseIterator(cx, ®s.sp[-1].toObject()); regs.sp--; if (!ok) @@ -1841,7 +1776,7 @@ END_CASE(JSOP_ENDITER) BEGIN_CASE(JSOP_DUP) { - JS_ASSERT(regs.sp > regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= 1); const Value &rref = regs.sp[-1]; PUSH_COPY(rref); } @@ -1849,7 +1784,7 @@ END_CASE(JSOP_DUP) BEGIN_CASE(JSOP_DUP2) { - JS_ASSERT(regs.sp - 2 >= regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= 2); const Value &lref = regs.sp[-2]; const Value &rref = regs.sp[-1]; PUSH_COPY(lref); @@ -1859,7 +1794,7 @@ END_CASE(JSOP_DUP2) BEGIN_CASE(JSOP_SWAP) { - JS_ASSERT(regs.sp - 2 >= regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= 2); Value &lref = regs.sp[-2]; Value &rref = regs.sp[-1]; lref.swap(rref); @@ -1869,7 +1804,7 @@ END_CASE(JSOP_SWAP) BEGIN_CASE(JSOP_PICK) { unsigned i = GET_UINT8(regs.pc); - JS_ASSERT(regs.sp - (i + 1) >= regs.fp()->base()); + JS_ASSERT(regs.stackDepth() >= i + 1); Value lval = regs.sp[-int(i + 1)]; memmove(regs.sp - (i + 1), regs.sp - i, sizeof(Value) * i); regs.sp[-1] = lval; @@ -2355,10 +2290,17 @@ BEGIN_CASE(JSOP_INCARG) BEGIN_CASE(JSOP_ARGINC) { unsigned i = GET_ARGNO(regs.pc); - CheckArgAccess(regs.fp(), i); - Value &arg = regs.fp()->formalArg(i); - if (!DoIncDec(cx, script, regs.pc, arg, &arg, ®s.sp[0])) - goto error; + if (script->argsObjAliasesFormals()) { + const Value &arg = regs.fp()->argsObj().arg(i); + Value v; + if (!DoIncDec(cx, script, regs.pc, arg, &v, ®s.sp[0])) + goto error; + regs.fp()->argsObj().setArg(i, v); + } else { + Value &arg = regs.fp()->unaliasedFormal(i); + if (!DoIncDec(cx, script, regs.pc, arg, &arg, ®s.sp[0])) + goto error; + } regs.sp++; } END_CASE(JSOP_ARGINC); @@ -2369,8 +2311,7 @@ BEGIN_CASE(JSOP_INCLOCAL) BEGIN_CASE(JSOP_LOCALINC) { unsigned i = GET_SLOTNO(regs.pc); - CheckLocalAccess(regs.fp(), i); - Value &local = regs.fp()->localSlot(i); + Value &local = regs.fp()->unaliasedLocal(i); if (!DoIncDec(cx, script, regs.pc, local, &local, ®s.sp[0])) goto error; regs.sp++; @@ -2481,13 +2422,12 @@ BEGIN_CASE(JSOP_NEW) BEGIN_CASE(JSOP_CALL) BEGIN_CASE(JSOP_FUNCALL) { + JS_ASSERT(regs.stackDepth() >= 2 + GET_ARGC(regs.pc)); CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp); - JS_ASSERT(args.base() >= regs.fp()->base()); bool construct = (*regs.pc == JSOP_NEW); RootedFunction &fun = rootFunction0; - /* Don't bother trying to fast-path calls to scripted non-constructors. */ if (!IsFunctionObject(args.calleev(), fun.address()) || !fun->isInterpretedConstructor()) { if (construct) { @@ -2521,10 +2461,6 @@ BEGIN_CASE(JSOP_FUNCALL) goto error; RESTORE_INTERP_VARS(); - - if (!regs.fp()->functionPrologue(cx)) - goto error; - RESET_USE_METHODJIT(); bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc); @@ -2547,7 +2483,7 @@ BEGIN_CASE(JSOP_FUNCALL) } #endif - if (!ScriptPrologue(cx, regs.fp(), newType)) + if (!regs.fp()->prologue(cx, newType)) goto error; if (cx->compartment->debugMode()) { @@ -2804,7 +2740,7 @@ END_CASE(JSOP_ACTUALSFILLED) BEGIN_CASE(JSOP_ARGUMENTS) JS_ASSERT(!regs.fp()->fun()->hasRest()); if (script->needsArgsObj()) { - ArgumentsObject *obj = ArgumentsObject::create(cx, regs.fp()); + ArgumentsObject *obj = ArgumentsObject::createExpected(cx, regs.fp()); if (!obj) goto error; PUSH_COPY(ObjectValue(*obj)); @@ -2843,16 +2779,20 @@ BEGIN_CASE(JSOP_GETARG) BEGIN_CASE(JSOP_CALLARG) { unsigned i = GET_ARGNO(regs.pc); - CheckArgAccess(regs.fp(), i); - PUSH_COPY(regs.fp()->formalArg(i)); + if (script->argsObjAliasesFormals()) + PUSH_COPY(regs.fp()->argsObj().arg(i)); + else + PUSH_COPY(regs.fp()->unaliasedFormal(i)); } END_CASE(JSOP_GETARG) BEGIN_CASE(JSOP_SETARG) { unsigned i = GET_ARGNO(regs.pc); - CheckArgAccess(regs.fp(), i); - regs.fp()->formalArg(i) = regs.sp[-1]; + if (script->argsObjAliasesFormals()) + regs.fp()->argsObj().setArg(i, regs.sp[-1]); + else + regs.fp()->unaliasedFormal(i) = regs.sp[-1]; } END_CASE(JSOP_SETARG) @@ -2860,8 +2800,7 @@ BEGIN_CASE(JSOP_GETLOCAL) BEGIN_CASE(JSOP_CALLLOCAL) { unsigned i = GET_SLOTNO(regs.pc); - CheckLocalAccess(regs.fp(), i); - PUSH_COPY_SKIP_CHECK(regs.fp()->localSlot(i)); + PUSH_COPY_SKIP_CHECK(regs.fp()->unaliasedLocal(i)); /* * Skip the same-compartment assertion if the local will be immediately @@ -2877,8 +2816,7 @@ END_CASE(JSOP_GETLOCAL) BEGIN_CASE(JSOP_SETLOCAL) { unsigned i = GET_SLOTNO(regs.pc); - CheckLocalAccess(regs.fp(), i); - regs.fp()->localSlot(i) = regs.sp[-1]; + regs.fp()->unaliasedLocal(i) = regs.sp[-1]; } END_CASE(JSOP_SETLOCAL) @@ -3025,7 +2963,7 @@ END_CASE(JSOP_LAMBDA) BEGIN_CASE(JSOP_CALLEE) JS_ASSERT(regs.fp()->isNonEvalFunctionFrame()); - PUSH_COPY(argv[-2]); + PUSH_COPY(regs.fp()->calleev()); END_CASE(JSOP_CALLEE) BEGIN_CASE(JSOP_GETTER) @@ -3057,7 +2995,7 @@ BEGIN_CASE(JSOP_SETTER) case JSOP_INITPROP: { - JS_ASSERT(regs.sp - regs.fp()->base() >= 2); + JS_ASSERT(regs.stackDepth() >= 2); rval = regs.sp[-1]; i = -1; PropertyName *name; @@ -3067,8 +3005,7 @@ BEGIN_CASE(JSOP_SETTER) } default: JS_ASSERT(op2 == JSOP_INITELEM); - - JS_ASSERT(regs.sp - regs.fp()->base() >= 3); + JS_ASSERT(regs.stackDepth() >= 3); rval = regs.sp[-1]; id = JSID_VOID; i = -2; @@ -3186,7 +3123,7 @@ END_CASE(JSOP_NEWOBJECT) BEGIN_CASE(JSOP_ENDINIT) { /* FIXME remove JSOP_ENDINIT bug 588522 */ - JS_ASSERT(regs.sp - regs.fp()->base() >= 1); + JS_ASSERT(regs.stackDepth() >= 1); JS_ASSERT(regs.sp[-1].isObject()); } END_CASE(JSOP_ENDINIT) @@ -3194,7 +3131,7 @@ END_CASE(JSOP_ENDINIT) BEGIN_CASE(JSOP_INITPROP) { /* Load the property's initial value into rval. */ - JS_ASSERT(regs.sp - regs.fp()->base() >= 2); + JS_ASSERT(regs.stackDepth() >= 2); Value rval = regs.sp[-1]; /* Load the object being initialized into lval/obj. */ @@ -3222,7 +3159,7 @@ END_CASE(JSOP_INITPROP); BEGIN_CASE(JSOP_INITELEM) { /* Pop the element's value into rval. */ - JS_ASSERT(regs.sp - regs.fp()->base() >= 3); + JS_ASSERT(regs.stackDepth() >= 3); const Value &rref = regs.sp[-1]; RootedObject &obj = rootObject0; @@ -3708,24 +3645,17 @@ BEGIN_CASE(JSOP_ENTERLET1) { StaticBlockObject &blockObj = script->getObject(GET_UINT32_INDEX(regs.pc))->asStaticBlock(); + if (op == JSOP_ENTERBLOCK) { + JS_ASSERT(regs.stackDepth() == blockObj.stackDepth()); + JS_ASSERT(regs.stackDepth() + blockObj.slotCount() <= script->nslots); + Value *vp = regs.sp + blockObj.slotCount(); + SetValueRangeToUndefined(regs.sp, vp); + regs.sp = vp; + } + /* Clone block iff there are any closed-over variables. */ if (!regs.fp()->pushBlock(cx, blockObj)) goto error; - - if (op == JSOP_ENTERBLOCK) { - JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp); - Value *vp = regs.sp + blockObj.slotCount(); - JS_ASSERT(regs.sp < vp); - JS_ASSERT(vp <= regs.fp()->slots() + script->nslots); - SetValueRangeToUndefined(regs.sp, vp); - regs.sp = vp; - } else if (op == JSOP_ENTERLET0) { - JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount() - == regs.sp); - } else if (op == JSOP_ENTERLET1) { - JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount() - == regs.sp - 1); - } } END_CASE(JSOP_ENTERBLOCK) @@ -3740,12 +3670,12 @@ BEGIN_CASE(JSOP_LEAVEBLOCKEXPR) if (op == JSOP_LEAVEBLOCK) { /* Pop the block's slots. */ regs.sp -= GET_UINT16(regs.pc); - JS_ASSERT(regs.fp()->base() + blockDepth == regs.sp); + JS_ASSERT(regs.stackDepth() == blockDepth); } else if (op == JSOP_LEAVEBLOCKEXPR) { /* Pop the block's slots maintaining the topmost expr. */ Value *vp = ®s.sp[-1]; regs.sp -= GET_UINT16(regs.pc); - JS_ASSERT(regs.fp()->base() + blockDepth == regs.sp - 1); + JS_ASSERT(regs.stackDepth() == blockDepth + 1); regs.sp[-1] = *vp; } else { /* Another op will pop; nothing to do here. */ @@ -3759,11 +3689,13 @@ END_CASE(JSOP_LEAVEBLOCK) BEGIN_CASE(JSOP_GENERATOR) { JS_ASSERT(!cx->isExceptionPending()); + regs.fp()->initGeneratorFrame(); regs.pc += JSOP_GENERATOR_LENGTH; JSObject *obj = js_NewGenerator(cx); if (!obj) goto error; regs.fp()->setReturnValue(ObjectValue(*obj)); + regs.fp()->setYielding(); interpReturnOK = true; if (entryFrame != regs.fp()) goto inline_return; @@ -3773,9 +3705,9 @@ BEGIN_CASE(JSOP_GENERATOR) BEGIN_CASE(JSOP_YIELD) JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(regs.fp()->isNonEvalFunctionFrame()); - if (cx->generatorFor(regs.fp())->state == JSGEN_CLOSING) { - js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, - JSDVG_SEARCH_STACK, argv[-2], NULL); + if (cx->innermostGenerator()->state == JSGEN_CLOSING) { + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, + ObjectValue(regs.fp()->callee()), NULL); goto error; } regs.fp()->setReturnValue(regs.sp[-1]); @@ -3789,9 +3721,8 @@ BEGIN_CASE(JSOP_ARRAYPUSH) uint32_t slot = GET_UINT16(regs.pc); JS_ASSERT(script->nfixed <= slot); JS_ASSERT(slot < script->nslots); - CheckLocalAccess(regs.fp(), slot); RootedObject &obj = rootObject0; - obj = ®s.fp()->slots()[slot].toObject(); + obj = ®s.fp()->unaliasedLocal(slot).toObject(); if (!js_NewbornArrayPush(cx, obj, regs.sp[-1])) goto error; regs.sp--; @@ -3907,7 +3838,7 @@ END_CASE(JSOP_ARRAYPUSH) * the for-in loop. */ regs.pc = (script)->main() + tn->start + tn->length; - regs.sp = regs.fp()->base() + tn->stackDepth; + regs.sp = regs.spForStackDepth(tn->stackDepth); switch (tn->kind) { case JSTRY_CATCH: @@ -3977,19 +3908,10 @@ END_CASE(JSOP_ARRAYPUSH) exit: if (cx->compartment->debugMode()) interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK); - interpReturnOK = ScriptEpilogueOrGeneratorYield(cx, regs.fp(), interpReturnOK); + if (!regs.fp()->isYielding()) + regs.fp()->epilogue(cx); regs.fp()->setFinishedInInterpreter(); -#ifdef DEBUG - JS_ASSERT(entryFrame == regs.fp()); - if (regs.fp()->isFunctionFrame()) - AssertValidFunctionScopeChainAtExit(regs.fp()); - else if (regs.fp()->isEvalFrame()) - AssertValidEvalFrameScopeChainAtExit(regs.fp()); - else if (!regs.fp()->isGeneratorFrame()) - JS_ASSERT(!regs.fp()->scopeChain()->isScope()); -#endif - #ifdef JS_METHODJIT /* * This path is used when it's guaranteed the method can be finished diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index baf2907f0b85..53b42080162f 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -18,31 +18,6 @@ namespace js { -/* - * ScriptPrologue/ScriptEpilogue must be called in pairs. ScriptPrologue - * must be called before the script executes. ScriptEpilogue must be called - * after the script returns or exits via exception. - */ - -inline bool -ScriptPrologue(JSContext *cx, StackFrame *fp, JSScript *script); - -inline bool -ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok); - -/* - * It is not valid to call ScriptPrologue when a generator is resumed or to - * call ScriptEpilogue when a generator yields. However, the debugger still - * needs LIFO notification of generator start/stop. This pair of functions does - * the right thing based on the state of 'fp'. - */ - -inline bool -ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp); - -inline bool -ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok); - /* Implemented in jsdbgapi: */ /* @@ -274,9 +249,6 @@ UnwindForUncatchableException(JSContext *cx, const FrameRegs ®s); extern bool OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, Value *vp); -inline void -AssertValidFunctionScopeChainAtExit(StackFrame *fp); - class TryNoteIter { const FrameRegs ®s; diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 5e43e2f734ad..49028c90285b 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -421,70 +421,6 @@ DefVarOrConstOperation(JSContext *cx, HandleObject varobj, PropertyName *dn, uns return true; } -inline bool -FunctionNeedsPrologue(JSContext *cx, JSFunction *fun) -{ - /* Heavyweight functions need call objects created. */ - if (fun->isHeavyweight()) - return true; - - /* Outer and inner functions need to preserve nesting invariants. */ - if (cx->typeInferenceEnabled() && fun->script()->nesting()) - return true; - - return false; -} - -inline bool -ScriptPrologue(JSContext *cx, StackFrame *fp, bool newType) -{ - JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(), fp->hasCallObj()); - - if (fp->isConstructing()) { - JSObject *obj = js_CreateThisForFunction(cx, RootedObject(cx, &fp->callee()), newType); - if (!obj) - return false; - fp->functionThis().setObject(*obj); - } - - Probes::enterJSFun(cx, fp->maybeFun(), fp->script()); - - return true; -} - -inline bool -ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok) -{ - Probes::exitJSFun(cx, fp->maybeFun(), fp->script()); - - /* - * If inline-constructing, replace primitive rval with the new object - * passed in via |this|, and instrument this constructor invocation. - */ - if (fp->isConstructing() && ok) { - if (fp->returnValue().isPrimitive()) - fp->setReturnValue(ObjectValue(fp->constructorThis())); - } - - return ok; -} - -inline bool -ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp, bool newType) -{ - if (!fp->isGeneratorFrame()) - return ScriptPrologue(cx, fp, newType); - return true; -} - -inline bool -ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok) -{ - if (!fp->isYielding()) - return ScriptEpilogue(cx, fp, ok); - return ok; -} - inline void InterpreterFrames::enableInterruptsIfRunning(JSScript *script) { @@ -492,49 +428,6 @@ InterpreterFrames::enableInterruptsIfRunning(JSScript *script) enabler.enableInterrupts(); } -inline void -AssertValidEvalFrameScopeChainAtExit(StackFrame *fp) -{ -#ifdef DEBUG - JS_ASSERT(fp->isEvalFrame()); - - JS_ASSERT(!fp->hasBlockChain()); - JSObject &scope = *fp->scopeChain(); - - if (fp->isStrictEvalFrame()) - JS_ASSERT(scope.asCall().maybeStackFrame() == fp); - else if (fp->isDebuggerFrame()) - JS_ASSERT(!scope.isScope()); - else if (fp->isDirectEvalFrame()) - JS_ASSERT(scope == *fp->prev()->scopeChain()); - else - JS_ASSERT(scope.isGlobal()); -#endif -} - -inline void -AssertValidFunctionScopeChainAtExit(StackFrame *fp) -{ -#ifdef DEBUG - JS_ASSERT(fp->isFunctionFrame()); - if (fp->isGeneratorFrame() || fp->isYielding()) - return; - - if (fp->isEvalFrame()) { - AssertValidEvalFrameScopeChainAtExit(fp); - return; - } - - JS_ASSERT(!fp->hasBlockChain()); - JSObject &scope = *fp->scopeChain(); - - if (fp->fun()->isHeavyweight() && fp->hasCallObj()) - JS_ASSERT(scope.asCall().maybeStackFrame() == fp); - else if (scope.isCall() || scope.isBlock()) - JS_ASSERT(scope.asScope().maybeStackFrame() != fp); -#endif -} - static JS_ALWAYS_INLINE bool AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res) { @@ -722,7 +615,7 @@ GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value break; } } else if (obj->isArguments()) { - if (obj->asArguments().getElement(index, res)) + if (obj->asArguments().maybeGetElement(index, res)) break; } if (!obj->getElement(cx, index, res)) @@ -888,7 +781,7 @@ GuardFunApplySpeculation(JSContext *cx, FrameRegs ®s) if (!IsNativeFunction(args.calleev(), js_fun_apply)) { if (!JSScript::applySpeculationFailed(cx, regs.fp()->script())) return false; - args[1] = ObjectValue(regs.fp()->argsObj()); + regs.sp[-1] = ObjectValue(regs.fp()->argsObj()); } } return true; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 179bc9689ae3..bce911da94f0 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1324,32 +1324,23 @@ generator_finalize(FreeOp *fop, JSObject *obj) JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_CLOSED || gen->state == JSGEN_OPEN); + JS_POISON(gen->fp, JS_FREE_PATTERN, sizeof(StackFrame)); + JS_POISON(gen, JS_FREE_PATTERN, sizeof(JSGenerator)); fop->free_(gen); } static void MarkGenerator(JSTracer *trc, JSGenerator *gen) { - StackFrame *fp = gen->floatingFrame(); - - /* - * MarkGenerator should only be called when regs is based on the floating frame. - * See calls to RebaseRegsFromTo. - */ - JS_ASSERT(size_t(gen->regs.sp - fp->slots()) <= fp->numSlots()); - - /* - * Currently, generators are not mjitted. Still, (overflow) args can be - * pushed by the mjit and need to be conservatively marked. Technically, the - * formal args and generator slots are safe for exact marking, but since the - * plan is to eventually mjit generators, it makes sense to future-proof - * this code and save someone an hour later. - */ - MarkValueRange(trc, (HeapValue *)fp->formalArgsEnd() - gen->floatingStack, - gen->floatingStack, "Generator Floating Args"); - fp->mark(trc); - MarkValueRange(trc, gen->regs.sp - fp->slots(), - (HeapValue *)fp->slots(), "Generator Floating Stack"); + MarkValueRange(trc, + HeapValueify(gen->fp->generatorArgsSnapshotBegin()), + HeapValueify(gen->fp->generatorArgsSnapshotEnd()), + "Generator Floating Args"); + gen->fp->mark(trc); + MarkValueRange(trc, + HeapValueify(gen->fp->generatorSlotsSnapshotBegin()), + HeapValueify(gen->regs.sp), + "Generator Floating Stack"); } static void @@ -1367,15 +1358,8 @@ generator_trace(JSTracer *trc, JSObject *obj) if (!gen) return; - /* - * Do not mark if the generator is running; the contents may be trash and - * will be replaced when the generator stops. - */ - if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) - return; - - JS_ASSERT(gen->liveFrame() == gen->floatingFrame()); - MarkGenerator(trc, gen); + if (gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN) + MarkGenerator(trc, gen); } Class js::GeneratorClass = { @@ -1415,9 +1399,8 @@ JSObject * js_NewGenerator(JSContext *cx) { FrameRegs &stackRegs = cx->regs(); + JS_ASSERT(stackRegs.stackDepth() == 0); StackFrame *stackfp = stackRegs.fp(); - JS_ASSERT(stackfp->base() == cx->regs().sp); - JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs()); Rooted global(cx, &stackfp->global()); JSObject *proto = global->getOrCreateGeneratorPrototype(cx); @@ -1428,15 +1411,15 @@ js_NewGenerator(JSContext *cx) return NULL; /* Load and compute stack slot counts. */ - Value *stackvp = stackfp->actualArgs() - 2; - unsigned vplen = stackfp->formalArgsEnd() - stackvp; + Value *stackvp = stackfp->generatorArgsSnapshotBegin(); + unsigned vplen = stackfp->generatorArgsSnapshotEnd() - stackvp; /* Compute JSGenerator size. */ unsigned nbytes = sizeof(JSGenerator) + (-1 + /* one Value included in JSGenerator */ vplen + VALUES_PER_STACK_FRAME + - stackfp->numSlots()) * sizeof(HeapValue); + stackfp->script()->nslots) * sizeof(HeapValue); JS_ASSERT(nbytes % sizeof(Value) == 0); JS_STATIC_ASSERT(sizeof(StackFrame) % sizeof(HeapValue) == 0); @@ -1447,35 +1430,25 @@ js_NewGenerator(JSContext *cx) SetValueRangeToUndefined((Value *)gen, nbytes / sizeof(Value)); /* Cut up floatingStack space. */ - HeapValue *genvp = gen->floatingStack; + HeapValue *genvp = gen->stackSnapshot; StackFrame *genfp = reinterpret_cast(genvp + vplen); /* Initialize JSGenerator. */ gen->obj.init(obj); gen->state = JSGEN_NEWBORN; gen->enumerators = NULL; - gen->floating = genfp; + gen->fp = genfp; + gen->prevGenerator = NULL; /* Copy from the stack to the generator's floating frame. */ gen->regs.rebaseFromTo(stackRegs, *genfp); - genfp->stealFrameAndSlots( + genfp->copyFrameAndValues( cx, genfp, genvp, stackfp, stackvp, stackRegs.sp); - genfp->initFloatingGenerator(); - stackfp->setYielding(); /* XXX: to be removed */ obj->setPrivate(gen); return obj; } -JSGenerator * -js_FloatingFrameToGenerator(StackFrame *fp) -{ - JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator()); - char *floatingStackp = (char *)(fp->actualArgs() - 2); - char *p = floatingStackp - offsetof(JSGenerator, floatingStack); - return reinterpret_cast(p); -} - typedef enum JSGeneratorOp { JSGENOP_NEXT, JSGENOP_SEND, @@ -1492,16 +1465,10 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, JSGenerator *gen, const Value &arg) { if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) { - js_ReportValueError(cx, JSMSG_NESTING_GENERATOR, - JSDVG_SEARCH_STACK, ObjectOrNullValue(obj), - JS_GetFunctionId(gen->floatingFrame()->fun())); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NESTING_GENERATOR); return JS_FALSE; } - /* Check for OOM errors here, where we can fail easily. */ - if (!cx->ensureGeneratorStackSpace()) - return JS_FALSE; - /* * Write barrier is needed since the generator stack can be updated, * and it's not barriered in any other way. We need to do it before @@ -1541,8 +1508,6 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, break; } - StackFrame *genfp = gen->floatingFrame(); - JSBool ok; { GeneratorFrameGuard gfg; @@ -1553,7 +1518,6 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, StackFrame *fp = gfg.fp(); gen->regs = cx->regs(); - JS_ASSERT(gen->liveFrame() == fp); cx->enterGenerator(gen); /* OOM check above. */ JSObject *enumerators = cx->enumerators; @@ -1566,18 +1530,18 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, cx->leaveGenerator(gen); } - if (gen->floatingFrame()->isYielding()) { + if (gen->fp->isYielding()) { /* Yield cannot fail, throw or be called on closing. */ JS_ASSERT(ok); JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(gen->state == JSGEN_RUNNING); JS_ASSERT(op != JSGENOP_CLOSE); - genfp->clearYielding(); + gen->fp->clearYielding(); gen->state = JSGEN_OPEN; return JS_TRUE; } - genfp->clearReturnValue(); + gen->fp->clearReturnValue(); gen->state = JSGEN_CLOSED; if (ok) { /* Returned, explicitly or by falling off the end. */ @@ -1669,7 +1633,7 @@ generator_op(JSContext *cx, Native native, JSGeneratorOp op, Value *vp, unsigned if (!SendToGenerator(cx, op, obj, gen, undef ? args[0] : UndefinedValue())) return false; - args.rval() = gen->floatingFrame()->returnValue(); + args.rval() = gen->fp->returnValue(); return true; } diff --git a/js/src/jsiter.h b/js/src/jsiter.h index c88301fc2519..67ce7a973a42 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -262,65 +262,28 @@ ForOf(JSContext *cx, const Value &iterable, Op op) /* * Generator state codes. */ -typedef enum JSGeneratorState { +enum JSGeneratorState +{ JSGEN_NEWBORN, /* not yet started */ JSGEN_OPEN, /* started by a .next() or .send(undefined) call */ JSGEN_RUNNING, /* currently executing via .next(), etc., call */ JSGEN_CLOSING, /* close method is doing asynchronous return */ JSGEN_CLOSED /* closed, cannot be started or closed again */ -} JSGeneratorState; +}; -struct JSGenerator { +struct JSGenerator +{ js::HeapPtrObject obj; JSGeneratorState state; js::FrameRegs regs; JSObject *enumerators; - js::StackFrame *floating; - js::HeapValue floatingStack[1]; - - js::StackFrame *floatingFrame() { - return floating; - } - - js::StackFrame *liveFrame() { - JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) == - (regs.fp() != floatingFrame())); - return regs.fp(); - } + JSGenerator *prevGenerator; + js::StackFrame *fp; + js::HeapValue stackSnapshot[1]; }; extern JSObject * js_NewGenerator(JSContext *cx); - -/* - * Generator stack frames do not have stable pointers since they get copied to - * and from the generator object and the stack (see SendToGenerator). This is a - * problem for Block and With objects, which need to store a pointer to the - * enclosing stack frame. The solution is for Block and With objects to store - * a pointer to the "floating" stack frame stored in the generator object, - * since it is stable, and maintain, in the generator object, a pointer to the - * "live" stack frame (either a copy on the stack or the floating frame). Thus, - * Block and With objects must "normalize" to and from the floating/live frames - * in the case of generators using the following functions. - */ -inline js::StackFrame * -js_FloatingFrameIfGenerator(JSContext *cx, js::StackFrame *fp) -{ - if (JS_UNLIKELY(fp->isGeneratorFrame())) - return cx->generatorFor(fp)->floatingFrame(); - return fp; -} - -/* Given a floating frame, given the JSGenerator containing it. */ -extern JSGenerator * -js_FloatingFrameToGenerator(js::StackFrame *fp); - -inline js::StackFrame * -js_LiveFrameIfGenerator(js::StackFrame *fp) -{ - return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp; -} - #endif extern JSObject * diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 36babb814b3f..f3adca88a830 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2849,6 +2849,7 @@ js::NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc JS_ASSERT(type->proto->hasNewType(type)); JS_ASSERT(parent); + JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST); if (CanBeFinalizedInBackground(kind, &ObjectClass)) kind = GetBackgroundAllocKind(kind); @@ -3871,14 +3872,6 @@ JSObject::growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount) JS_ASSERT(newCount >= SLOT_CAPACITY_MIN); JS_ASSERT(!isDenseArray()); - /* - * Slots are only allocated for call objects when new properties are - * added to them, which can only happen while the call is still on the - * stack (and an eval, DEFFUN, etc. happens). We thus do not need to - * worry about updating any active outer function args/vars. - */ - JS_ASSERT_IF(isCall(), asCall().maybeStackFrame() != NULL); - /* * Slot capacities are determined by the span of allocated objects. Due to * the limited number of bits to store shape slots, object growth is @@ -6245,15 +6238,9 @@ js_DumpStackFrame(JSContext *cx, StackFrame *start) } } if (fp->hasArgs()) { - fprintf(stderr, " actuals: %p (%u) ", (void *) fp->actualArgs(), (unsigned) fp->numActualArgs()); - fprintf(stderr, " formals: %p (%u)\n", (void *) fp->formalArgs(), (unsigned) fp->numFormalArgs()); + fprintf(stderr, " actuals: %p (%u) ", (void *) fp->actuals(), (unsigned) fp->numActualArgs()); + fprintf(stderr, " formals: %p (%u)\n", (void *) fp->formals(), (unsigned) fp->numFormalArgs()); } - if (fp->hasCallObj()) { - fprintf(stderr, " has call obj: "); - dumpValue(ObjectValue(fp->callObj())); - fprintf(stderr, "\n"); - } - MaybeDumpObject("argsobj", fp->maybeArgsObj()); MaybeDumpObject("blockChain", fp->maybeBlockChain()); if (!fp->isDummyFrame()) { MaybeDumpValue("this", fp->thisValue()); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 611d42c86c80..119ec96f1549 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -514,12 +514,12 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, } case JOF_SCOPECOORD: { - Value v = StringValue(ScopeCoordinateName(script, pc)); + Value v = StringValue(ScopeCoordinateName(cx->runtime, script, pc)); JSAutoByteString bytes; if (!ToDisassemblySource(cx, v, &bytes)) return 0; ScopeCoordinate sc(pc); - Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), sc.hops, sc.binding); + Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), sc.hops, sc.slot); break; } @@ -1409,6 +1409,12 @@ AddParenSlop(SprintStack *ss) ss->sprinter.reserveAndClear(PAREN_SLOP); } +static unsigned +StackDepth(JSScript *script) +{ + return script->nslots - script->nfixed; +} + static JSBool PushOff(SprintStack *ss, ptrdiff_t off, JSOp op, jsbytecode *pc = NULL) { @@ -1844,7 +1850,7 @@ static bool IsVarSlot(JSPrinter *jp, jsbytecode *pc, JSAtom **varAtom, int *localSlot) { if (JOF_OPTYPE(*pc) == JOF_SCOPECOORD) { - *varAtom = ScopeCoordinateName(jp->script, pc); + *varAtom = ScopeCoordinateName(jp->sprinter.context->runtime, jp->script, pc); LOCAL_ASSERT_RV(*varAtom, NULL); return true; } @@ -5725,7 +5731,7 @@ js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v, * calculated value matching v under assumption that it is * it that caused exception, see bug 328664. */ - Value *stackBase = fp->base(); + Value *stackBase = cx->regs().spForStackDepth(0); Value *sp = cx->regs().sp; do { if (sp == stackBase) { diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl index 5688c6346a4d..520134b4fa30 100644 --- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -341,18 +341,14 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE) * 'slot' does not include RESERVED_SLOTS). * uint32 block: the index (into the script object table) of the block chain * at the point of the variable access. - * - * XXX: there is also a temporary 2-byte index (indicating the frame slot - * aliased by the scope chain) which will be removed with the last patch of bug - * 659577. */ -OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 11, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) -OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 11, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) -OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 11, 1, 1, 3, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) -OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 12, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) +OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME) +OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 9, 1, 1, 3, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) /* Unused. */ OPDEF(JSOP_UNUSED8, 143,"unused8", NULL, 1, 0, 0, 0, JOF_BYTE) diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 78235303b931..b4722bdf7cfd 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -289,7 +289,7 @@ Shape::getChildBinding(JSContext *cx, const StackShape &child) * the fixed slot count here, which will feed into call objects created * off of the bindings. */ - uint32_t slots = child.slotSpan() + 1; /* Add one for private data. */ + uint32_t slots = child.slotSpan(); gc::AllocKind kind = gc::GetGCObjectKind(slots); /* @@ -300,11 +300,11 @@ Shape::getChildBinding(JSContext *cx, const StackShape &child) */ uint32_t nfixed = gc::GetGCKindSlots(kind); if (nfixed < slots) { - nfixed = CallObject::RESERVED_SLOTS + 1; - JS_ASSERT(gc::GetGCKindSlots(gc::GetGCObjectKind(nfixed)) == CallObject::RESERVED_SLOTS + 1); + nfixed = CallObject::RESERVED_SLOTS; + JS_ASSERT(gc::GetGCKindSlots(gc::GetGCObjectKind(nfixed)) == CallObject::RESERVED_SLOTS); } - shape->setNumFixedSlots(nfixed - 1); + shape->setNumFixedSlots(nfixed); } return shape; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index b13d0022d9a7..bc8a598c4adc 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -67,7 +67,7 @@ Bindings::lookup(JSContext *cx, JSAtom *name, unsigned *indexp) const if (indexp) *indexp = shape->shortid(); - if (shape->getter() == CallObject::getArgOp) + if (shape->setter() == CallObject::setArgOp) return ARGUMENT; return shape->writable() ? VARIABLE : CONSTANT; @@ -102,14 +102,14 @@ Bindings::add(JSContext *cx, HandleAtom name, BindingKind kind) if (kind == ARGUMENT) { JS_ASSERT(nvars == 0); indexp = &nargs; - getter = CallObject::getArgOp; + getter = NULL; setter = CallObject::setArgOp; slot += nargs; } else { JS_ASSERT(kind == VARIABLE || kind == CONSTANT); indexp = &nvars; - getter = CallObject::getVarOp; + getter = NULL; setter = CallObject::setVarOp; if (kind == CONSTANT) attrs |= JSPROP_READONLY; @@ -208,7 +208,7 @@ Bindings::getLocalNameArray(JSContext *cx, BindingNames *namesp) const Shape &shape = r.front(); unsigned index = uint16_t(shape.shortid()); - if (shape.getter() == CallObject::getArgOp) { + if (shape.setter() == CallObject::setArgOp) { JS_ASSERT(index < nargs); names[index].kind = ARGUMENT; } else { @@ -221,7 +221,7 @@ Bindings::getLocalNameArray(JSContext *cx, BindingNames *namesp) names[index].maybeAtom = JSID_TO_ATOM(shape.propid()); } else { JS_ASSERT(JSID_IS_INT(shape.propid())); - JS_ASSERT(shape.getter() == CallObject::getArgOp); + JS_ASSERT(shape.setter() == CallObject::setArgOp); names[index].maybeAtom = NULL; } } @@ -241,7 +241,7 @@ Bindings::lastArgument() const const js::Shape *shape = lastVariable(); if (nvars > 0) { - while (shape->previous() && shape->getter() != CallObject::getArgOp) + while (shape->previous() && shape->setter() != CallObject::setArgOp) shape = shape->previous(); } return shape; @@ -604,10 +604,10 @@ js::XDRScript(XDRState *xdr, JSScript **scriptp, JSScript *parentScript) script->bindingsAccessedDynamically = true; if (scriptBits & (1 << ArgumentsHasLocalBinding)) { PropertyName *arguments = cx->runtime->atomState.argumentsAtom; - unsigned slot; - DebugOnly kind = script->bindings.lookup(cx, arguments, &slot); + unsigned local; + DebugOnly kind = script->bindings.lookup(cx, arguments, &local); JS_ASSERT(kind == VARIABLE || kind == CONSTANT); - script->setArgumentsHasLocalBinding(slot); + script->setArgumentsHasLocalBinding(local); } if (scriptBits & (1 << NeedsArgsObj)) script->setNeedsArgsObj(true); @@ -1311,9 +1311,9 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) if (bce->sc->inFunction()) { if (bce->sc->funArgumentsHasLocalBinding()) { - // This must precede the script->bindings.transfer() call below. - script->setArgumentsHasLocalBinding(bce->sc->argumentsLocalSlot()); - if (bce->sc->funDefinitelyNeedsArgsObj()) + // This must precede the script->bindings.transfer() call below + script->setArgumentsHasLocalBinding(bce->sc->argumentsLocal()); + if (bce->sc->funDefinitelyNeedsArgsObj()) script->setNeedsArgsObj(true); } else { JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj()); @@ -1799,7 +1799,7 @@ js::CloneScript(JSContext *cx, JSScript *src) dst->nslots = src->nslots; dst->staticLevel = src->staticLevel; if (src->argumentsHasLocalBinding()) { - dst->setArgumentsHasLocalBinding(src->argumentsLocalSlot()); + dst->setArgumentsHasLocalBinding(src->argumentsLocal()); if (src->analyzedArgsUsage()) dst->setNeedsArgsObj(src->needsArgsObj()); } @@ -2127,10 +2127,10 @@ JSScript::markChildren(JSTracer *trc) } void -JSScript::setArgumentsHasLocalBinding(uint16_t slot) +JSScript::setArgumentsHasLocalBinding(uint16_t local) { argsHasLocalBinding_ = true; - argsSlot_ = slot; + argsLocal_ = local; needsArgsAnalysis_ = true; } @@ -2162,7 +2162,7 @@ JSScript::applySpeculationFailed(JSContext *cx, JSScript *script_) script->needsArgsObj_ = true; - const unsigned slot = script->argumentsLocalSlot(); + const unsigned local = script->argumentsLocal(); /* * By design, the apply-arguments optimization is only made when there @@ -2179,22 +2179,20 @@ JSScript::applySpeculationFailed(JSContext *cx, JSScript *script_) for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) { StackFrame *fp = i.fp(); if (fp->isFunctionFrame() && fp->script() == script) { - if (!fp->hasArgsObj()) { - ArgumentsObject *obj = ArgumentsObject::create(cx, fp); - if (!obj) { - /* - * We can't leave stack frames where script->needsArgsObj - * and !fp->hasArgsObj. It is, however, safe to leave frames - * where fp->hasArgsObj and !fp->script->needsArgsObj. - */ - script->needsArgsObj_ = false; - return false; - } - - /* Note: 'arguments' may have already been overwritten. */ - if (fp->localSlot(slot).isMagic(JS_OPTIMIZED_ARGUMENTS)) - fp->localSlot(slot) = ObjectValue(*obj); + ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, fp); + if (!argsobj) { + /* + * We can't leave stack frames with script->needsArgsObj but no + * arguments object. It is, however, safe to leave frames with + * an arguments object but !script->needsArgsObj. + */ + script->needsArgsObj_ = false; + return false; } + + /* Note: 'arguments' may have already been overwritten. */ + if (fp->unaliasedLocal(local).isMagic(JS_OPTIMIZED_ARGUMENTS)) + fp->unaliasedLocal(local) = ObjectValue(*argsobj); } } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 4a1bcc9fd9c0..6f1b7569b46b 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -114,12 +114,12 @@ class Bindings * These functions map between argument/var indices [0, nargs/nvars) and * and Bindings indices [0, nargs + nvars). */ - bool bindingIsArg(uint16_t i) const { return i < nargs; } - bool bindingIsLocal(uint16_t i) const { return i >= nargs; } - uint16_t argToBinding(uint16_t i) { JS_ASSERT(i < nargs); return i; } - uint16_t localToBinding(uint16_t i) { return i + nargs; } - uint16_t bindingToArg(uint16_t i) { JS_ASSERT(bindingIsArg(i)); return i; } - uint16_t bindingToLocal(uint16_t i) { JS_ASSERT(bindingIsLocal(i)); return i - nargs; } + bool slotIsArg(uint16_t i) const { return i < nargs; } + bool slotIsLocal(uint16_t i) const { return i >= nargs; } + uint16_t argToSlot(uint16_t i) { JS_ASSERT(i < nargs); return i; } + uint16_t localToSlot(uint16_t i) { return i + nargs; } + uint16_t slotToArg(uint16_t i) { JS_ASSERT(slotIsArg(i)); return i; } + uint16_t slotToLocal(uint16_t i) { JS_ASSERT(slotIsLocal(i)); return i - nargs; } /* Ensure these bindings have a shape lineage. */ inline bool ensureShape(JSContext *cx); @@ -493,7 +493,7 @@ struct JSScript : public js::gc::Cell uint16_t staticLevel;/* static level for display maintenance */ private: - uint16_t argsSlot_; /* slot holding 'arguments' (if argumentsHasLocalBindings) */ + uint16_t argsLocal_; /* local holding 'arguments' (if argumentsHasLocalBindings) */ // 8-bit fields. @@ -588,8 +588,8 @@ struct JSScript : public js::gc::Cell /* See ContextFlags::funArgumentsHasLocalBinding comment. */ bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; } jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; } - unsigned argumentsLocalSlot() const { JS_ASSERT(argsHasLocalBinding_); return argsSlot_; } - void setArgumentsHasLocalBinding(uint16_t slot); + unsigned argumentsLocal() const { JS_ASSERT(argsHasLocalBinding_); return argsLocal_; } + void setArgumentsHasLocalBinding(uint16_t local); /* * As an optimization, even when argsHasLocalBinding, the function prologue @@ -943,12 +943,6 @@ JS_STATIC_ASSERT(sizeof(JSScript::ArrayBitsT) * 8 >= JSScript::LIMIT); /* If this fails, add/remove padding within JSScript. */ JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::Cell::CellSize == 0); -static JS_INLINE unsigned -StackDepth(JSScript *script) -{ - return script->nslots - script->nfixed; -} - /* * New-script-hook calling is factored from NewScriptFromEmitter so that it * and callers of XDRScript can share this code. In the case of callers diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index d85ee167b5b6..5a5590254ec3 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -61,8 +61,8 @@ Shape * Bindings::initialShape(JSContext *cx) const { /* Get an allocation kind to match an empty call object. */ - gc::AllocKind kind = gc::FINALIZE_OBJECT4; - JS_ASSERT(gc::GetGCKindSlots(kind) == CallObject::RESERVED_SLOTS + 1); + gc::AllocKind kind = gc::FINALIZE_OBJECT2_BACKGROUND; + JS_ASSERT(gc::GetGCKindSlots(kind) == CallObject::RESERVED_SLOTS); return EmptyShape::getInitialShape(cx, &CallClass, NULL, NULL, kind, BaseShape::VAROBJ); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index e5f26c997d2e..5c27f087826e 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2215,17 +2215,13 @@ LambdaIsGetElem(JSObject &lambda, JSContext *cx) * real name lookup since this can trigger observable effects. */ Value b; - JSObject *scope = cx->stack.currentScriptedScopeChain(); + RootedObject scope(cx); + scope = cx->stack.currentScriptedScopeChain(); while (true) { - if (scope->isCall()) { - if (scope->asCall().containsVarOrArg(bname, &b, cx)) - break; - } else if (scope->isBlock()) { - if (scope->asClonedBlock().containsVar(bname, &b, cx)) - break; - } else { + if (!scope->isCall() && !scope->isBlock()) return NULL; - } + if (HasDataProperty(cx, scope, bname, &b)) + break; scope = &scope->asScope().enclosingScope(); } diff --git a/js/src/jsval.h b/js/src/jsval.h index cdcca50a0a5f..9fcf07980737 100644 --- a/js/src/jsval.h +++ b/js/src/jsval.h @@ -215,10 +215,11 @@ typedef enum JSWhyMagic JS_ARG_POISON, /* used in debug builds to catch tracing errors */ JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */ - JS_UNASSIGNED_ARGUMENTS, /* the initial value of callobj.arguments */ JS_OPTIMIZED_ARGUMENTS, /* optimized-away 'arguments' value */ JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */ JS_OVERWRITTEN_CALLEE, /* arguments.callee has been overwritten */ + JS_FORWARD_TO_CALL_OBJECT, /* args object element stored in call object */ + JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */ JS_GENERIC_MAGIC /* for local use */ } JSWhyMagic; diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 1696109c5131..7d7e2a045f34 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -1077,60 +1077,22 @@ mjit::Compiler::generatePrologue() markUndefinedLocals(); - types::TypeScriptNesting *nesting = script->nesting(); - /* - * Run the function prologue if necessary. This is always done in a - * stub for heavyweight functions (including nesting outer functions). + * Load the scope chain into the frame if it will be needed by NAME + * opcodes or by the nesting prologue below. The scope chain is always + * set for global and eval frames, and will have been set by + * HeavyweightFunctionPrologue for heavyweight function frames. */ - JS_ASSERT_IF(nesting && nesting->children, script->function()->isHeavyweight()); - if (script->function()->isHeavyweight()) { - prepareStubCall(Uses(0)); - INLINE_STUBCALL(stubs::FunctionFramePrologue, REJOIN_FUNCTION_PROLOGUE); - } else { - /* - * Load the scope chain into the frame if it will be needed by NAME - * opcodes or by the nesting prologue below. The scope chain is - * always set for global and eval frames, and will have been set by - * CreateFunCallObject for heavyweight function frames. - */ - if (analysis->usesScopeChain() || nesting) { - RegisterID t0 = Registers::ReturnReg; - Jump hasScope = masm.branchTest32(Assembler::NonZero, - FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN)); - masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->function())), t0); - masm.loadPtr(Address(t0, JSFunction::offsetOfEnvironment()), t0); - masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain())); - hasScope.linkTo(masm.label(), &masm); - } - - if (nesting) { - /* - * Inline the common case for the nesting prologue: the - * function is a non-heavyweight inner function with no - * children of its own. We ensure during inference that the - * outer function does not add scope objects for 'let' or - * 'with', so that the frame's scope chain will be - * the parent's call object, and if it differs from the - * parent's current activation then the parent is reentrant. - */ - JSScript *parent = nesting->parent; - JS_ASSERT(parent); - JS_ASSERT_IF(parent->hasAnalysis() && parent->analysis()->ranBytecode(), - !parent->analysis()->addsScopeObjects()); - - RegisterID t0 = Registers::ReturnReg; - masm.move(ImmPtr(&parent->nesting()->activeCall), t0); - masm.loadPtr(Address(t0), t0); - - Address scopeChain(JSFrameReg, StackFrame::offsetOfScopeChain()); - Jump mismatch = masm.branchPtr(Assembler::NotEqual, t0, scopeChain); - masm.add32(Imm32(1), AbsoluteAddress(&nesting->activeFrames)); - - stubcc.linkExitDirect(mismatch, stubcc.masm.label()); - OOL_STUBCALL(stubs::FunctionFramePrologue, REJOIN_FUNCTION_PROLOGUE); - stubcc.crossJump(stubcc.masm.jump(), masm.label()); - } + if (!script->function()->isHeavyweight() && + (analysis->usesScopeChain() || script->nesting())) + { + RegisterID t0 = Registers::ReturnReg; + Jump hasScope = masm.branchTest32(Assembler::NonZero, + FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN)); + masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->function())), t0); + masm.loadPtr(Address(t0, JSFunction::offsetOfEnvironment()), t0); + masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain())); + hasScope.linkTo(masm.label(), &masm); } /* @@ -1161,9 +1123,50 @@ mjit::Compiler::generatePrologue() ensureDoubleArguments(); } - if (isConstructing) { - if (!constructThis()) - return Compile_Error; + /* Inline StackFrame::prologue. */ + if (script->isActiveEval && script->strictModeCode) { + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::StrictEvalPrologue, REJOIN_EVAL_PROLOGUE); + } else if (script->function()) { + if (script->function()->isHeavyweight()) { + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::HeavyweightFunctionPrologue, REJOIN_FUNCTION_PROLOGUE); + } else if (types::TypeScriptNesting *nesting = script->nesting()) { + /* + * Inline the common case for the nesting prologue: the + * function is a non-heavyweight inner function with no + * children of its own. We ensure during inference that the + * outer function does not add scope objects for 'let' or + * 'with', so that the frame's scope chain will be + * the parent's call object, and if it differs from the + * parent's current activation then the parent is reentrant. + */ + JSScript *parent = nesting->parent; + JS_ASSERT(parent); + JS_ASSERT_IF(parent->hasAnalysis() && parent->analysis()->ranBytecode(), + !parent->analysis()->addsScopeObjects()); + + RegisterID t0 = Registers::ReturnReg; + masm.move(ImmPtr(&parent->nesting()->activeCall), t0); + masm.loadPtr(Address(t0), t0); + + Address scopeChain(JSFrameReg, StackFrame::offsetOfScopeChain()); + Jump mismatch = masm.branchPtr(Assembler::NotEqual, t0, scopeChain); + masm.add32(Imm32(1), AbsoluteAddress(&nesting->activeFrames)); + + masm.load32(FrameFlagsAddress(), t0); + masm.or32(Imm32(StackFrame::HAS_NESTING), t0); + masm.store32(t0, FrameFlagsAddress()); + + stubcc.linkExitDirect(mismatch, stubcc.masm.label()); + OOL_STUBCALL(stubs::TypeNestingPrologue, REJOIN_FUNCTION_PROLOGUE); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + } + + if (isConstructing) { + if (!constructThis()) + return Compile_Error; + } } if (debugMode()) { @@ -1209,8 +1212,8 @@ void mjit::Compiler::markUndefinedLocals() { /* - * Set locals to undefined, as in initCallFrameLatePrologue. - * Skip locals which aren't closed and are known to be defined before used, + * Set locals to undefined. Skip locals which aren't closed and are known + * to be defined before used, */ for (uint32_t i = 0; i < script->nfixed; i++) markUndefinedLocal(0, i); @@ -2803,6 +2806,8 @@ mjit::Compiler::generateMethod() uint32_t arg = GET_SLOTNO(PC); if (JSObject *singleton = pushedSingleton(0)) frame.push(ObjectValue(*singleton)); + else if (script->argsObjAliasesFormals()) + jsop_aliasedArg(arg, /* get = */ true); else frame.pushArg(arg); } @@ -2816,7 +2821,13 @@ mjit::Compiler::generateMethod() { jsbytecode *next = &PC[JSOP_SETARG_LENGTH]; bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); - frame.storeArg(GET_SLOTNO(PC), pop); + + uint32_t arg = GET_SLOTNO(PC); + if (script->argsObjAliasesFormals()) + jsop_aliasedArg(arg, /* get = */ false, pop); + else + frame.storeArg(arg, pop); + updateVarType(); if (pop) { @@ -2827,26 +2838,11 @@ mjit::Compiler::generateMethod() } END_CASE(JSOP_SETARG) + BEGIN_CASE(JSOP_GETLOCAL) + BEGIN_CASE(JSOP_CALLLOCAL) BEGIN_CASE(JSOP_GETALIASEDVAR) BEGIN_CASE(JSOP_CALLALIASEDVAR) { - /* This is all temporary until bug 659577. */ - if (JSObject *singleton = pushedSingleton(0)) { - frame.push(ObjectValue(*singleton)); - } else { - ScopeCoordinate sc = ScopeCoordinate(PC); - if (script->bindings.bindingIsArg(sc.frameBinding)) - frame.pushArg(script->bindings.bindingToArg(sc.frameBinding)); - else - frame.pushLocal(script->bindings.bindingToLocal(sc.frameBinding)); - } - } - END_CASE(JSOP_GETALIASEDVAR) - - BEGIN_CASE(JSOP_GETLOCAL) - BEGIN_CASE(JSOP_CALLLOCAL) - { - /* * Update the var type unless we are about to pop the variable. * Sync is not guaranteed for types of dead locals, and GETLOCAL @@ -2855,46 +2851,37 @@ mjit::Compiler::generateMethod() jsbytecode *next = &PC[JSOP_GETLOCAL_LENGTH]; if (JSOp(*next) != JSOP_POP || analysis->jumpTarget(next)) restoreVarType(); - uint32_t slot = GET_SLOTNO(PC); if (JSObject *singleton = pushedSingleton(0)) frame.push(ObjectValue(*singleton)); + else if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD) + jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ true); else - frame.pushLocal(slot); + frame.pushLocal(GET_SLOTNO(PC)); + + PC += GetBytecodeLength(PC); + break; } END_CASE(JSOP_GETLOCAL) + BEGIN_CASE(JSOP_SETLOCAL) BEGIN_CASE(JSOP_SETALIASEDVAR) { - /* This is all temporary until bug 659577. */ - jsbytecode *next = &PC[JSOP_SETALIASEDVAR_LENGTH]; + jsbytecode *next = &PC[GetBytecodeLength(PC)]; bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); - ScopeCoordinate sc = ScopeCoordinate(PC); - if (script->bindings.bindingIsArg(sc.frameBinding)) - frame.storeArg(script->bindings.bindingToArg(sc.frameBinding), pop); + if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD) + jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ false, pop); else - frame.storeLocal(script->bindings.bindingToLocal(sc.frameBinding), pop); + frame.storeLocal(GET_SLOTNO(PC), pop); updateVarType(); if (pop) { frame.pop(); - PC += JSOP_SETALIASEDVAR_LENGTH + JSOP_POP_LENGTH; + PC = next + JSOP_POP_LENGTH; break; } - } - END_CASE(JSOP_SETALIASEDVAR) - BEGIN_CASE(JSOP_SETLOCAL) - { - jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH]; - bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); - frame.storeLocal(GET_SLOTNO(PC), pop); - updateVarType(); - - if (pop) { - frame.pop(); - PC += JSOP_SETLOCAL_LENGTH + JSOP_POP_LENGTH; - break; - } + PC = next; + break; } END_CASE(JSOP_SETLOCAL) @@ -3792,47 +3779,12 @@ mjit::Compiler::emitReturn(FrameEntry *fe) return; } - /* - * Outside the mjit, activation objects (call objects and arguments objects) are put - * by ContextStack::pop* members. For JSOP_RETURN, the interpreter only calls - * popInlineFrame if fp != entryFrame since the VM protocol is that Invoke/Execute are - * responsible for pushing/popping the initial frame. However, an mjit function - * epilogue doesn't treat the initial StackFrame of its VMFrame specially: it always - * puts activation objects. And furthermore, if the last mjit frame throws, the mjit - * does *not* put the activation objects. So we can't assume any particular state of - * puttedness upon exit from the mjit. - * - * To avoid double-putting, EnterMethodJIT calls updateEpilogueFlags to clear the - * entry frame's hasArgsObj() and hasCallObj() flags if the given objects have already - * been put. - */ - if (script->function()) { - types::TypeScriptNesting *nesting = script->nesting(); - if (script->function()->isHeavyweight() || script->needsArgsObj() || - (nesting && nesting->children) || debugMode()) - { - prepareStubCall(Uses(fe ? 1 : 0)); - INLINE_STUBCALL(stubs::FunctionFrameEpilogue, REJOIN_NONE); - } else { - /* if hasCallObj() */ - Jump putObjs = masm.branchTest32(Assembler::NonZero, - Address(JSFrameReg, StackFrame::offsetOfFlags()), - Imm32(StackFrame::HAS_CALL_OBJ)); - stubcc.linkExit(putObjs, Uses(frame.frameSlots())); - - stubcc.leave(); - OOL_STUBCALL(stubs::FunctionFrameEpilogue, REJOIN_NONE); - - emitReturnValue(&stubcc.masm, fe); - emitFinalReturn(stubcc.masm); - - /* - * Do frame count balancing inline for inner functions in a nesting - * with no children of their own. - */ - if (nesting) - masm.sub32(Imm32(1), AbsoluteAddress(&nesting->activeFrames)); - } + /* Inline StackFrame::epilogue. */ + if (debugMode()) { + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::Epilogue, REJOIN_NONE); + } else if (script->function() && script->nesting()) { + masm.sub32(Imm32(1), AbsoluteAddress(&script->nesting()->activeFrames)); } emitReturnValue(&masm, fe); @@ -5718,7 +5670,7 @@ mjit::Compiler::jsop_bindname(PropertyName *name) analysis->resolveNameAccess(cx, NameToId(name), true); if (access.nesting) { RegisterID reg = frame.allocReg(); - JSObject **pobj = &access.nesting->activeCall; + CallObject **pobj = &access.nesting->activeCall; masm.move(ImmPtr(pobj), reg); masm.loadPtr(Address(reg), reg); frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg); @@ -5829,6 +5781,100 @@ mjit::Compiler::jsop_bindname(PropertyName *name) } #endif +void +mjit::Compiler::jsop_aliasedArg(unsigned arg, bool get, bool poppedAfter) +{ + RegisterID reg = frame.allocReg(); + masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfArgsObj()), reg); + size_t dataOff = ArgumentsObject::getDataSlotOffset(); + masm.loadPrivate(Address(reg, dataOff), reg); + int32_t argsOff = ArgumentsData::offsetOfArgs() + arg * sizeof(Value); + masm.addPtr(Imm32(argsOff), reg, reg); + if (get) { + FrameEntry *fe = frame.getArg(arg); + JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN; + frame.push(Address(reg), type, true /* = reuseBase */); + } else { +#ifdef JSGC_INCREMENTAL_MJ + if (cx->compartment->needsBarrier()) { + /* Write barrier. */ + stubcc.linkExit(masm.testGCThing(Address(reg)), Uses(0)); + stubcc.leave(); + stubcc.masm.move(reg, Registers::ArgReg1); + OOL_STUBCALL(stubs::GCThingWriteBarrier, REJOIN_NONE); + stubcc.rejoin(Changes(0)); + } +#endif + frame.storeTo(frame.peek(-1), Address(reg), poppedAfter); + frame.freeReg(reg); + } +} + +void +mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter) +{ + RegisterID reg = frame.allocReg(); + masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), reg); + for (unsigned i = 0; i < sc.hops; i++) + masm.loadPayload(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg); + + unsigned slot = ScopeObject::CALL_BLOCK_RESERVED_SLOTS + sc.slot; + + /* + * TODO bug 753158: Call and Block objects should use the same layout + * strategy: up to the maximum numFixedSlots and overflow (if any) in + * dynamic slots. For now, we special case for different layouts: + */ + Address addr; + if (ScopeCoordinateBlockChain(script, PC)) { + /* + * Block objects use a fixed AllocKind which means an invariant number + * of fixed slots. Any slot below the fixed slot count is inline, any + * slot over is in the dynamic slots. + */ + uint32_t nfixed = gc::GetGCKindSlots(BlockObject::FINALIZE_KIND); + if (nfixed <= slot) { + masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg); + addr = Address(reg, (slot - nfixed) * sizeof(Value)); + } else { + addr = Address(reg, JSObject::getFixedSlotOffset(slot)); + } + } else { + /* + * Using special-case hackery in Shape::getChildBinding, CallObject + * slots are either altogether in fixed slots or altogether in dynamic + * slots (by having numFixed == RESERVED_SLOTS). + */ + if (script->bindings.lastShape()->numFixedSlots() <= slot) { + masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg); + addr = Address(reg, sc.slot * sizeof(Value)); + } else { + addr = Address(reg, JSObject::getFixedSlotOffset(slot)); + } + } + + if (get) { + FrameEntry *fe = script->bindings.slotIsLocal(sc.slot) + ? frame.getLocal(script->bindings.slotToLocal(sc.slot)) + : frame.getArg(script->bindings.slotToArg(sc.slot)); + JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN; + frame.push(addr, type, true /* = reuseBase */); + } else { +#ifdef JSGC_INCREMENTAL_MJ + if (cx->compartment->needsBarrier()) { + /* Write barrier. */ + stubcc.linkExit(masm.testGCThing(addr), Uses(0)); + stubcc.leave(); + stubcc.masm.addPtr(Imm32(addr.offset), addr.base, Registers::ArgReg1); + OOL_STUBCALL(stubs::GCThingWriteBarrier, REJOIN_NONE); + stubcc.rejoin(Changes(0)); + } +#endif + frame.storeTo(frame.peek(-1), addr, poppedAfter); + frame.freeReg(reg); + } +} + void mjit::Compiler::jsop_this() { diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index 7193bdeedd4c..08b526956c06 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -626,8 +626,8 @@ private: void jsop_bindname(PropertyName *name); void jsop_setglobal(uint32_t index); void jsop_getprop_slow(PropertyName *name, bool forPrototype = false); - void jsop_getarg(uint32_t slot); - void jsop_setarg(uint32_t slot, bool popped); + void jsop_aliasedArg(unsigned i, bool get, bool poppedAfter = false); + void jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter = false); void jsop_this(); void emitReturn(FrameEntry *fe); void emitFinalReturn(Assembler &masm); diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index 343eb74294a1..fcc3e5b2c189 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -62,7 +62,7 @@ FindExceptionHandler(JSContext *cx) */ jsbytecode *pc = script->main() + tn->start + tn->length; cx->regs().pc = pc; - cx->regs().sp = fp->base() + tn->stackDepth; + cx->regs().sp = cx->regs().spForStackDepth(tn->stackDepth); switch (tn->kind) { case JSTRY_CATCH: @@ -119,22 +119,6 @@ FindExceptionHandler(JSContext *cx) /* * Clean up a frame and return. */ -static void -InlineReturn(VMFrame &f) -{ - JS_ASSERT(f.fp() != f.entryfp); - AssertValidFunctionScopeChainAtExit(f.fp()); - - f.cx->stack.popInlineFrame(f.regs); - - DebugOnly op = JSOp(*f.regs.pc); - JS_ASSERT(op == JSOP_CALL || - op == JSOP_NEW || - op == JSOP_EVAL || - op == JSOP_FUNCALL || - op == JSOP_FUNAPPLY); - f.regs.pc += JSOP_CALL_LENGTH; -} void JS_FASTCALL stubs::SlowCall(VMFrame &f, uint32_t argc) @@ -162,7 +146,7 @@ stubs::SlowNew(VMFrame &f, uint32_t argc) static inline bool CheckStackQuota(VMFrame &f) { - JS_ASSERT(f.regs.sp == f.fp()->base()); + JS_ASSERT(f.regs.stackDepth() == 0); f.stackLimit = f.cx->stack.space().getStackLimit(f.cx, DONT_REPORT_ERROR); if (f.stackLimit) @@ -306,10 +290,6 @@ UncachedInlineCall(VMFrame &f, InitialFrameFlags initial, /* Finish the handoff to the new frame regs. */ PreserveRegsGuard regsGuard(cx, regs); - /* Scope with a call object parented by callee's parent. */ - if (!regs.fp()->functionPrologue(cx)) - return false; - /* * If newscript was successfully compiled, run it. Skip for calls which * will be constructing a new type object for 'this'. @@ -543,7 +523,7 @@ js_InternalThrow(VMFrame &f) } - ScriptEpilogue(f.cx, f.fp(), false); + f.fp()->epilogue(f.cx); // Don't remove the last frame, this is the responsibility of // JaegerShot()'s caller. We only guarantee that ScriptEpilogue() @@ -551,8 +531,14 @@ js_InternalThrow(VMFrame &f) if (f.entryfp == f.fp()) break; - JS_ASSERT(&cx->regs() == &f.regs); - InlineReturn(f); + f.cx->stack.popInlineFrame(f.regs); + DebugOnly op = JSOp(*f.regs.pc); + JS_ASSERT(op == JSOP_CALL || + op == JSOP_NEW || + op == JSOP_EVAL || + op == JSOP_FUNCALL || + op == JSOP_FUNAPPLY); + f.regs.pc += JSOP_CALL_LENGTH; } JS_ASSERT(&cx->regs() == &f.regs); @@ -587,11 +573,11 @@ js_InternalThrow(VMFrame &f) if (cx->isExceptionPending()) { JS_ASSERT(JSOp(*pc) == JSOP_ENTERBLOCK); StaticBlockObject &blockObj = script->getObject(GET_UINT32_INDEX(pc))->asStaticBlock(); - if (!cx->regs().fp()->pushBlock(cx, blockObj)) - return NULL; Value *vp = cx->regs().sp + blockObj.slotCount(); SetValueRangeToUndefined(cx->regs().sp, vp); cx->regs().sp = vp; + if (!cx->regs().fp()->pushBlock(cx, blockObj)) + return NULL; JS_ASSERT(JSOp(pc[JSOP_ENTERBLOCK_LENGTH]) == JSOP_EXCEPTION); cx->regs().sp[0] = cx->getPendingException(); @@ -615,7 +601,7 @@ stubs::CreateThis(VMFrame &f, JSObject *proto) JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto); if (!obj) THROW(); - fp->formalArgs()[-1].setObject(*obj); + fp->thisValue() = ObjectValue(*obj); } void JS_FASTCALL @@ -706,7 +692,9 @@ FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp) const JSCodeSpec *cs = &js_CodeSpec[op]; unsigned i = GET_SLOTNO(f.pc()); - Value *var = (JOF_TYPE(cs->format) == JOF_LOCAL) ? f.fp()->slots() + i : &f.fp()->formalArg(i); + Value *var = (JOF_TYPE(cs->format) == JOF_LOCAL) + ? &f.fp()->unaliasedLocal(i) + : &f.fp()->unaliasedFormal(i); if (rejoin == REJOIN_POS) { double d = ov.toNumber(); @@ -722,7 +710,7 @@ FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp) extern "C" void * js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VMFrame &f) { - JSRejoinState jsrejoin = f.fp()->rejoin(); + FrameRejoinState jsrejoin = f.fp()->rejoin(); RejoinState rejoin; if (jsrejoin & 0x1) { /* Rejoin after a scripted call finished. Restore f.regs.pc and f.regs.inlined (NULL) */ @@ -757,12 +745,12 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM * here. Update it to its value at the start of the opcode. */ Value *oldsp = f.regs.sp; - f.regs.sp = fp->base() + analysis->getCode(pc).stackDepth; + f.regs.sp = f.regs.spForStackDepth(analysis->getCode(pc).stackDepth); jsbytecode *nextpc = pc + GetBytecodeLength(pc); Value *nextsp = NULL; if (nextpc != script->code + script->length && analysis->maybeCode(nextpc)) - nextsp = fp->base() + analysis->getCode(nextpc).stackDepth; + nextsp = f.regs.spForStackDepth(analysis->getCode(nextpc).stackDepth); JS_ASSERT(&cx->regs() == &f.regs); @@ -867,18 +855,13 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM f.regs.pc = nextpc; break; - case REJOIN_DEFLOCALFUN: - fp->slots()[GET_SLOTNO(pc)].setObject(* (JSObject *) returnReg); - f.regs.pc = nextpc; - break; - case REJOIN_THIS_PROTOTYPE: { RootedObject callee(cx, &fp->callee()); JSObject *proto = f.regs.sp[0].isObject() ? &f.regs.sp[0].toObject() : NULL; JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto); if (!obj) return js_InternalThrow(f); - fp->formalArgs()[-1].setObject(*obj); + fp->thisValue() = ObjectValue(*obj); if (Probes::callTrackingActive(cx)) Probes::enterJSFun(f.cx, f.fp()->maybeFun(), f.fp()->script()); @@ -902,42 +885,56 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM break; } + /* + * Each of these cases indicates a point of progress through + * generatePrologue. Execute the rest of the prologue here. + */ case REJOIN_CHECK_ARGUMENTS: - /* - * Do all the work needed in arity check JIT prologues after the - * arguments check occurs (FixupArity has been called if needed, but - * the stack check and late prologue have not been performed. - */ if (!CheckStackQuota(f)) return js_InternalThrow(f); - - SetValueRangeToUndefined(fp->slots(), script->nfixed); - - if (!fp->functionPrologue(cx)) - return js_InternalThrow(f); - /* FALLTHROUGH */ - - case REJOIN_FUNCTION_PROLOGUE: + fp->initVarsToUndefined(); fp->scopeChain(); - - /* Construct the 'this' object for the frame if necessary. */ - if (!ScriptPrologueOrGeneratorResume(cx, fp, types::UseNewTypeAtEntry(cx, fp))) + if (!fp->prologue(cx, types::UseNewTypeAtEntry(cx, fp))) return js_InternalThrow(f); /* - * Having called ScriptPrologueOrGeneratorResume, we would normally call - * ScriptDebugPrologue here. But in debug mode, we only use JITted - * functions' invokeEntry entry point, whereas CheckArgumentTypes - * (REJOIN_CHECK_ARGUMENTS) and FunctionFramePrologue - * (REJOIN_FUNCTION_PROLOGUE) are only reachable via the other entry - * points. So we should never need either of these rejoin tails in debug - * mode. + * We would normally call ScriptDebugPrologue here. But in debug mode, + * we only use JITted functions' invokeEntry entry point, whereas + * CheckArgumentTypes (REJOIN_CHECK_ARGUMENTS) is only reachable via + * the other entry points. * * If we fix bug 699196 ("Debug mode code could use inline caches - * now"), then these cases will become reachable again. + * now"), then this case will become reachable again. */ JS_ASSERT(!cx->compartment->debugMode()); + break; + /* Finish executing the tail of generatePrologue. */ + case REJOIN_FUNCTION_PROLOGUE: + if (fp->isConstructing()) { + RootedObject callee(cx, &fp->callee()); + JSObject *obj = js_CreateThisForFunction(cx, callee, types::UseNewTypeAtEntry(cx, fp)); + if (!obj) + return js_InternalThrow(f); + fp->functionThis() = ObjectValue(*obj); + } + /* FALLTHROUGH */ + case REJOIN_EVAL_PROLOGUE: + if (cx->compartment->debugMode()) { + Probes::enterJSFun(cx, fp->maybeFun(), fp->script()); + JSTrapStatus status = ScriptDebugPrologue(cx, fp); + switch (status) { + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + return f.cx->jaegerRuntime().forceReturnFromFastCall(); + case JSTRAP_ERROR: + case JSTRAP_THROW: + return js_InternalThrow(f); + default: + JS_NOT_REACHED("bad ScriptDebugPrologue status"); + } + } break; case REJOIN_CALL_PROLOGUE: @@ -1060,7 +1057,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM if (nextDepth == UINT32_MAX) nextDepth = analysis->getCode(f.regs.pc).stackDepth; - f.regs.sp = fp->base() + nextDepth; + f.regs.sp = f.regs.spForStackDepth(nextDepth); /* * Monitor the result of the previous op when finishing a JOF_TYPESET op. diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index a4eb072d6966..e373922fa28b 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1056,10 +1056,6 @@ mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimi fp->markReturnValue(); } - /* See comment in mjit::Compiler::emitReturn. */ - if (fp->isFunctionFrame()) - fp->updateEpilogueFlags(); - return ok ? Jaeger_Returned : Jaeger_Throwing; } diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index 457b348f31b0..f2362126b16c 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -109,7 +109,7 @@ struct VMFrame Value *stackLimit; StackFrame *entryfp; FrameRegs *oldregs; - JSRejoinState stubRejoin; /* How to rejoin if inside a call from an IC stub. */ + FrameRejoinState stubRejoin; /* How to rejoin if inside a call from an IC stub. */ #if defined(JS_CPU_X86) void *unused0, *unused1; /* For 16 byte alignment */ @@ -294,9 +294,6 @@ enum RejoinState { REJOIN_PUSH_BOOLEAN, REJOIN_PUSH_OBJECT, - /* Call returns an object, which should be assigned to a local per the current bytecode. */ - REJOIN_DEFLOCALFUN, - /* * During the prologue of constructing scripts, after the function's * .prototype property has been fetched. @@ -310,9 +307,10 @@ enum RejoinState { REJOIN_CHECK_ARGUMENTS, /* - * The script's jitcode was discarded after marking an outer function as - * reentrant or due to a GC while creating a call object. + * The script's jitcode was discarded during one of the following steps of + * a frame's prologue. */ + REJOIN_EVAL_PROLOGUE, REJOIN_FUNCTION_PROLOGUE, /* @@ -339,14 +337,14 @@ enum RejoinState { }; /* Get the rejoin state for a StackFrame after returning from a scripted call. */ -static inline JSRejoinState +static inline FrameRejoinState ScriptedRejoin(uint32_t pcOffset) { return REJOIN_SCRIPTED | (pcOffset << 1); } /* Get the rejoin state for a StackFrame after returning from a stub call. */ -static inline JSRejoinState +static inline FrameRejoinState StubRejoin(RejoinState rejoin) { return rejoin << 1; diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 8c6b0bac1044..d3dffd553465 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -1054,7 +1054,7 @@ ic::SplatApplyArgs(VMFrame &f) THROWV(false); /* Steps 7-8. */ - f.regs.fp()->forEachCanonicalActualArg(CopyTo(f.regs.sp)); + f.regs.fp()->forEachUnaliasedActual(CopyTo(f.regs.sp)); f.regs.sp += length; f.u.call.dynamicArgc = length; diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index 8cdc0898765a..4fa9abdbcae5 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -294,8 +294,6 @@ class SetPropCompiler : public PICStubCompiler JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->isCall()); - MaybeJump skipOver; - if (adding) { JS_ASSERT(shape->hasSlot()); pic.shapeRegHasBaseShape = false; @@ -353,29 +351,11 @@ class SetPropCompiler : public PICStubCompiler // then we can rely on fun->nargs remaining invariant. JSFunction *fun = obj->asCall().getCalleeFunction(); uint16_t slot = uint16_t(shape->shortid()); - - /* Guard that the call object has a frame. */ - masm.loadObjPrivate(pic.objReg, pic.shapeReg, obj->numFixedSlots()); - Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg); - - { - Address addr(pic.shapeReg, shape->setterOp() == CallObject::setArgOp - ? StackFrame::offsetOfFormalArg(fun, slot) - : StackFrame::offsetOfFixed(slot)); - masm.storeValue(pic.u.vr, addr); - skipOver = masm.jump(); - } - - escapedFrame.linkTo(masm.label(), &masm); - { - if (shape->setterOp() == CallObject::setVarOp) - slot += fun->nargs; - - slot += CallObject::RESERVED_SLOTS; - Address address = masm.objPropAddress(obj, pic.objReg, slot); - - masm.storeValue(pic.u.vr, address); - } + if (shape->setterOp() == CallObject::setVarOp) + slot += fun->nargs; + slot += CallObject::RESERVED_SLOTS; + Address address = masm.objPropAddress(obj, pic.objReg, slot); + masm.storeValue(pic.u.vr, address); pic.shapeRegHasBaseShape = false; } @@ -410,8 +390,6 @@ class SetPropCompiler : public PICStubCompiler for (Jump *pj = slowExits.begin(); pj != slowExits.end(); ++pj) buffer.link(*pj, pic.slowPathStart); buffer.link(done, pic.fastPathRejoin); - if (skipOver.isSet()) - buffer.link(skipOver.get(), pic.fastPathRejoin); CodeLocationLabel cs = buffer.finalize(f); JaegerSpew(JSpew_PICs, "generate setprop stub %p %p %d at %p\n", (void*)&pic, @@ -762,6 +740,9 @@ struct GetPropHelper { } }; +namespace js { +namespace mjit { + class GetPropCompiler : public PICStubCompiler { JSObject *obj; @@ -1392,6 +1373,9 @@ class GetPropCompiler : public PICStubCompiler } }; +} // namespace mjit +} // namespace js + class ScopeNameCompiler : public PICStubCompiler { private: @@ -1570,9 +1554,9 @@ class ScopeNameCompiler : public PICStubCompiler CallObjPropKind kind; const Shape *shape = getprop.shape; - if (shape->getterOp() == CallObject::getArgOp) { + if (shape->setterOp() == CallObject::setArgOp) { kind = ARG; - } else if (shape->getterOp() == CallObject::getVarOp) { + } else if (shape->setterOp() == CallObject::setVarOp) { kind = VAR; } else { return disable("unhandled callobj sprop getter"); @@ -1590,38 +1574,16 @@ class ScopeNameCompiler : public PICStubCompiler Jump finalShape = masm.branchPtr(Assembler::NotEqual, pic.shapeReg, ImmPtr(getprop.holder->lastProperty())); - /* Get callobj's stack frame. */ - masm.loadObjPrivate(pic.objReg, pic.shapeReg, getprop.holder->numFixedSlots()); - JSFunction *fun = getprop.holder->asCall().getCalleeFunction(); - uint16_t slot = uint16_t(shape->shortid()); + unsigned slot = shape->shortid(); + if (kind == VAR) + slot += fun->nargs; + slot += CallObject::RESERVED_SLOTS; + Address address = masm.objPropAddress(obj, pic.objReg, slot); - Jump skipOver; - Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg); + /* Safe because type is loaded first. */ + masm.loadValueAsComponents(address, pic.shapeReg, pic.objReg); - /* Not-escaped case. */ - { - Address addr(pic.shapeReg, kind == ARG ? StackFrame::offsetOfFormalArg(fun, slot) - : StackFrame::offsetOfFixed(slot)); - masm.loadPayload(addr, pic.objReg); - masm.loadTypeTag(addr, pic.shapeReg); - skipOver = masm.jump(); - } - - escapedFrame.linkTo(masm.label(), &masm); - - { - if (kind == VAR) - slot += fun->nargs; - - slot += CallObject::RESERVED_SLOTS; - Address address = masm.objPropAddress(obj, pic.objReg, slot); - - /* Safe because type is loaded first. */ - masm.loadValueAsComponents(address, pic.shapeReg, pic.objReg); - } - - skipOver.linkTo(masm.label(), &masm); Jump done = masm.jump(); // All failures flow to here, so there is a common point to patch. diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 6b50b30d3931..57c054f5b208 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -912,7 +912,7 @@ stubs::InitElem(VMFrame &f, uint32_t last) FrameRegs ®s = f.regs; /* Pop the element's value into rval. */ - JS_ASSERT(regs.sp - f.fp()->base() >= 3); + JS_ASSERT(regs.stackDepth() >= 3); const Value &rref = regs.sp[-1]; /* Find the object being initialized at top of stack. */ @@ -1020,7 +1020,7 @@ InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op) FrameRegs ®s = f.regs; /* Load the property's initial value into rval. */ - JS_ASSERT(regs.sp - f.fp()->base() >= 2); + JS_ASSERT(regs.stackDepth() >= 2); Value rval; rval = regs.sp[-1]; @@ -1048,7 +1048,7 @@ stubs::InitProp(VMFrame &f, PropertyName *name) void JS_FASTCALL stubs::IterNext(VMFrame &f, int32_t offset) { - JS_ASSERT(f.regs.sp - offset >= f.fp()->base()); + JS_ASSERT(f.regs.stackDepth() >= unsigned(offset)); JS_ASSERT(f.regs.sp[-offset].isObject()); JSObject *iterobj = &f.regs.sp[-offset].toObject(); @@ -1061,7 +1061,7 @@ stubs::IterNext(VMFrame &f, int32_t offset) JSBool JS_FASTCALL stubs::IterMore(VMFrame &f) { - JS_ASSERT(f.regs.sp - 1 >= f.fp()->base()); + JS_ASSERT(f.regs.stackDepth() >= 1); JS_ASSERT(f.regs.sp[-1].isObject()); Value v; @@ -1075,7 +1075,7 @@ stubs::IterMore(VMFrame &f) void JS_FASTCALL stubs::EndIter(VMFrame &f) { - JS_ASSERT(f.regs.sp - 1 >= f.fp()->base()); + JS_ASSERT(f.regs.stackDepth() >= 1); if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject())) THROW(); } @@ -1125,7 +1125,7 @@ stubs::Throw(VMFrame &f) void JS_FASTCALL stubs::Arguments(VMFrame &f) { - ArgumentsObject *obj = ArgumentsObject::create(f.cx, f.fp()); + ArgumentsObject *obj = ArgumentsObject::createExpected(f.cx, f.fp()); if (!obj) THROW(); f.regs.sp[0] = ObjectValue(*obj); @@ -1173,27 +1173,21 @@ void JS_FASTCALL stubs::EnterBlock(VMFrame &f, JSObject *obj) { FrameRegs ®s = f.regs; - StackFrame *fp = f.fp(); JS_ASSERT(!f.regs.inlined()); StaticBlockObject &blockObj = obj->asStaticBlock(); - if (!fp->pushBlock(f.cx, blockObj)) - THROW(); if (*regs.pc == JSOP_ENTERBLOCK) { - JS_ASSERT(fp->base() + blockObj.stackDepth() == regs.sp); + JS_ASSERT(regs.stackDepth() == blockObj.stackDepth()); + JS_ASSERT(regs.stackDepth() + blockObj.slotCount() <= f.fp()->script()->nslots); Value *vp = regs.sp + blockObj.slotCount(); - JS_ASSERT(regs.sp < vp); - JS_ASSERT(vp <= fp->slots() + fp->script()->nslots); SetValueRangeToUndefined(regs.sp, vp); regs.sp = vp; - } else if (*regs.pc == JSOP_ENTERLET0) { - JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount() - == regs.sp); - } else if (*regs.pc == JSOP_ENTERLET1) { - JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount() - == regs.sp - 1); } + + /* Clone block iff there are any closed-over variables. */ + if (!regs.fp()->pushBlock(f.cx, blockObj)) + THROW(); } void JS_FASTCALL @@ -1522,7 +1516,7 @@ stubs::CheckArgumentTypes(VMFrame &f) if (!f.fp()->isConstructing()) TypeScript::SetThis(f.cx, script, fp->thisValue()); for (unsigned i = 0; i < fun->nargs; i++) - TypeScript::SetArgument(f.cx, script, i, fp->formalArg(i)); + TypeScript::SetArgument(f.cx, script, i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING)); } if (monitor.recompiled()) @@ -1552,7 +1546,7 @@ stubs::AssertArgumentTypes(VMFrame &f) } for (unsigned i = 0; i < fun->nargs; i++) { - Type type = GetValueType(f.cx, fp->formalArg(i)); + Type type = GetValueType(f.cx, fp->unaliasedFormal(i, DONT_CHECK_ALIASING)); if (!TypeScript::ArgTypes(script, i)->hasType(type)) TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type)); } @@ -1609,16 +1603,29 @@ stubs::Exception(VMFrame &f) } void JS_FASTCALL -stubs::FunctionFramePrologue(VMFrame &f) +stubs::StrictEvalPrologue(VMFrame &f) { - if (!f.fp()->functionPrologue(f.cx)) + if (!f.fp()->jitStrictEvalPrologue(f.cx)) THROW(); } void JS_FASTCALL -stubs::FunctionFrameEpilogue(VMFrame &f) +stubs::HeavyweightFunctionPrologue(VMFrame &f) { - f.fp()->functionEpilogue(f.cx); + if (!f.fp()->jitHeavyweightFunctionPrologue(f.cx)) + THROW(); +} + +void JS_FASTCALL +stubs::TypeNestingPrologue(VMFrame &f) +{ + f.fp()->jitTypeNestingPrologue(f.cx); +} + +void JS_FASTCALL +stubs::Epilogue(VMFrame &f) +{ + f.fp()->epilogue(f.cx); } void JS_FASTCALL @@ -1626,17 +1633,15 @@ stubs::AnyFrameEpilogue(VMFrame &f) { /* * On the normal execution path, emitReturn calls ScriptDebugEpilogue - * and inlines ScriptEpilogue. This function implements forced early + * and inlines epilogue. This function implements forced early * returns, so it must have the same effect. */ bool ok = true; if (f.cx->compartment->debugMode()) ok = js::ScriptDebugEpilogue(f.cx, f.fp(), ok); - ok = ScriptEpilogue(f.cx, f.fp(), ok); + f.fp()->epilogue(f.cx); if (!ok) THROW(); - if (f.fp()->isNonEvalFunctionFrame()) - f.fp()->functionEpilogue(f.cx); } template diff --git a/js/src/methodjit/StubCalls.h b/js/src/methodjit/StubCalls.h index 70d6df6f71f8..811e6ae5f8f5 100644 --- a/js/src/methodjit/StubCalls.h +++ b/js/src/methodjit/StubCalls.h @@ -168,10 +168,12 @@ void JS_FASTCALL ConvertToTypedFloat(JSContext *cx, Value *vp); void JS_FASTCALL Exception(VMFrame &f); -void JS_FASTCALL FunctionFramePrologue(VMFrame &f); -void JS_FASTCALL FunctionFrameEpilogue(VMFrame &f); +void JS_FASTCALL StrictEvalPrologue(VMFrame &f); +void JS_FASTCALL HeavyweightFunctionPrologue(VMFrame &f); +void JS_FASTCALL TypeNestingPrologue(VMFrame &f); void JS_FASTCALL AnyFrameEpilogue(VMFrame &f); +void JS_FASTCALL Epilogue(VMFrame &f); JSObject * JS_FASTCALL NewDenseUnallocatedArray(VMFrame &f, uint32_t length); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index d66c8d7b2194..03e467484e1e 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1281,31 +1281,14 @@ AssertJit(JSContext *cx, unsigned argc, jsval *vp) static JSScript * ValueToScript(JSContext *cx, jsval v, JSFunction **funp = NULL) { - JSScript *script = NULL; - JSFunction *fun = NULL; + JSFunction *fun = JS_ValueToFunction(cx, v); + if (!fun) + return NULL; - if (!JSVAL_IS_PRIMITIVE(v)) { - JSObject *obj = JSVAL_TO_OBJECT(v); - JSClass *clasp = JS_GetClass(obj); + JSScript *script = fun->maybeScript(); + if (!script) + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_SCRIPTS_ONLY); - if (clasp == Jsvalify(&GeneratorClass)) { - if (JSGenerator *gen = (JSGenerator *) JS_GetPrivate(obj)) { - fun = gen->floatingFrame()->fun(); - script = fun->script(); - } - } - } - - if (!script) { - fun = JS_ValueToFunction(cx, v); - if (!fun) - return NULL; - script = fun->maybeScript(); - if (!script) { - JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, - JSSMSG_SCRIPTS_ONLY); - } - } if (fun && funp) *funp = fun; diff --git a/js/src/vm/ArgumentsObject-inl.h b/js/src/vm/ArgumentsObject-inl.h index f89148b796ca..3aa5f309e5ce 100644 --- a/js/src/vm/ArgumentsObject-inl.h +++ b/js/src/vm/ArgumentsObject-inl.h @@ -10,16 +10,9 @@ #include "ArgumentsObject.h" -namespace js { +#include "ScopeObject-inl.h" -inline void -ArgumentsObject::initInitialLength(uint32_t length) -{ - JS_ASSERT(getFixedSlot(INITIAL_LENGTH_SLOT).isUndefined()); - initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(length << PACKED_BITS_COUNT)); - JS_ASSERT((getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() >> PACKED_BITS_COUNT) == int32_t(length)); - JS_ASSERT(!hasOverriddenLength()); -} +namespace js { inline uint32_t ArgumentsObject::initialLength() const @@ -39,26 +32,67 @@ ArgumentsObject::markLengthOverridden() inline bool ArgumentsObject::hasOverriddenLength() const { - const js::Value &v = getFixedSlot(INITIAL_LENGTH_SLOT); + const Value &v = getFixedSlot(INITIAL_LENGTH_SLOT); return v.toInt32() & LENGTH_OVERRIDDEN_BIT; } -inline void -ArgumentsObject::initData(ArgumentsData *data) -{ - JS_ASSERT(getFixedSlot(DATA_SLOT).isUndefined()); - initFixedSlot(DATA_SLOT, PrivateValue(data)); -} - inline ArgumentsData * ArgumentsObject::data() const { - return reinterpret_cast(getFixedSlot(DATA_SLOT).toPrivate()); + return reinterpret_cast(getFixedSlot(DATA_SLOT).toPrivate()); +} + +inline JSScript * +ArgumentsObject::containingScript() const +{ + return data()->script; +} + +inline const Value & +ArgumentsObject::arg(unsigned i) const +{ + JS_ASSERT(i < data()->numArgs); + const Value &v = data()->args[i]; + JS_ASSERT(!v.isMagic(JS_FORWARD_TO_CALL_OBJECT)); + return v; +} + +inline void +ArgumentsObject::setArg(unsigned i, const Value &v) +{ + JS_ASSERT(i < data()->numArgs); + HeapValue &lhs = data()->args[i]; + JS_ASSERT(!lhs.isMagic(JS_FORWARD_TO_CALL_OBJECT)); + lhs = v; +} + +inline const Value & +ArgumentsObject::element(uint32_t i) const +{ + JS_ASSERT(!isElementDeleted(i)); + const Value &v = data()->args[i]; + if (v.isMagic(JS_FORWARD_TO_CALL_OBJECT)) + return getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().arg(i); + return v; +} + +inline void +ArgumentsObject::setElement(uint32_t i, const Value &v) +{ + JS_ASSERT(!isElementDeleted(i)); + HeapValue &lhs = data()->args[i]; + if (lhs.isMagic(JS_FORWARD_TO_CALL_OBJECT)) + getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().setArg(i, v); + else + lhs = v; } inline bool ArgumentsObject::isElementDeleted(uint32_t i) const { + JS_ASSERT(i < data()->numArgs); + if (i >= initialLength()) + return false; return IsBitArrayElementSet(data()->deletedBits, initialLength(), i); } @@ -74,57 +108,17 @@ ArgumentsObject::markElementDeleted(uint32_t i) SetBitArrayElement(data()->deletedBits, initialLength(), i); } -inline const Value & -ArgumentsObject::element(uint32_t i) const -{ - JS_ASSERT(!isElementDeleted(i)); - return data()->slots[i]; -} - -inline void -ArgumentsObject::setElement(uint32_t i, const js::Value &v) -{ - JS_ASSERT(!isElementDeleted(i)); - data()->slots[i] = v; -} - inline bool -ArgumentsObject::getElement(uint32_t i, Value *vp) +ArgumentsObject::maybeGetElement(uint32_t i, Value *vp) { if (i >= initialLength() || isElementDeleted(i)) return false; - - /* - * If this arguments object has an associated stack frame, that contains - * the canonical argument value. Note that strict arguments objects do not - * alias named arguments and never have a stack frame. - */ - StackFrame *fp = maybeStackFrame(); - JS_ASSERT_IF(isStrictArguments(), !fp); - if (fp) - *vp = fp->canonicalActualArg(i); - else - *vp = element(i); + *vp = element(i); return true; } -namespace detail { - -struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo -{ - CopyNonHoleArgsTo(ArgumentsObject *argsobj, Value *dst) : argsobj(*argsobj), dst(dst) {} - ArgumentsObject &argsobj; - Value *dst; - bool operator()(uint32_t argi, Value *src) { - *dst++ = *src; - return true; - } -}; - -} /* namespace detail */ - inline bool -ArgumentsObject::getElements(uint32_t start, uint32_t count, Value *vp) +ArgumentsObject::maybeGetElements(uint32_t start, uint32_t count, Value *vp) { JS_ASSERT(start + count >= start); @@ -132,33 +126,9 @@ ArgumentsObject::getElements(uint32_t start, uint32_t count, Value *vp) if (start > length || start + count > length || isAnyElementDeleted()) return false; - StackFrame *fp = maybeStackFrame(); - - /* If there's no stack frame for this, argument values are in elements(). */ - if (!fp) { - const Value *srcbeg = Valueify(data()->slots) + start; - const Value *srcend = srcbeg + count; - const Value *src = srcbeg; - for (Value *dst = vp; src < srcend; ++dst, ++src) - *dst = *src; - return true; - } - - /* Otherwise, element values are on the stack. */ - JS_ASSERT(fp->numActualArgs() <= StackSpace::ARGS_LENGTH_MAX); - return fp->forEachCanonicalActualArg(detail::CopyNonHoleArgsTo(this, vp), start, count); -} - -inline js::StackFrame * -ArgumentsObject::maybeStackFrame() const -{ - return reinterpret_cast(getFixedSlot(STACK_FRAME_SLOT).toPrivate()); -} - -inline void -ArgumentsObject::setStackFrame(StackFrame *frame) -{ - setFixedSlot(STACK_FRAME_SLOT, PrivateValue(frame)); + for (uint32_t i = start, end = start + count; i < end; ++i, ++vp) + *vp = element(i); + return true; } inline size_t @@ -167,7 +137,7 @@ ArgumentsObject::sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const return mallocSizeOf(data()); } -inline const js::Value & +inline const Value & NormalArgumentsObject::callee() const { return data()->callee; @@ -179,6 +149,6 @@ NormalArgumentsObject::clearCallee() data()->callee.set(compartment(), MagicValue(JS_OVERWRITTEN_CALLEE)); } -} // namespace js +} /* namespace js */ #endif /* ArgumentsObject_inl_h___ */ diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index c42255bbfba7..0eaead5c48a9 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -22,53 +22,20 @@ using namespace js; using namespace js::gc; -struct PutArg -{ - PutArg(JSCompartment *comp, ArgumentsObject &argsobj) - : compartment(comp), argsobj(argsobj), dst(argsobj.data()->slots) {} - JSCompartment *compartment; - ArgumentsObject &argsobj; - HeapValue *dst; - bool operator()(unsigned i, Value *src) { - JS_ASSERT(dst->isUndefined()); - if (!argsobj.isElementDeleted(i)) - dst->set(compartment, *src); - ++dst; - return true; - } -}; - -void -js_PutArgsObject(StackFrame *fp) -{ - ArgumentsObject &argsobj = fp->argsObj(); - if (argsobj.isNormalArguments()) { - JS_ASSERT(argsobj.maybeStackFrame() == fp); - JSCompartment *comp = fp->compartment(); - fp->forEachCanonicalActualArg(PutArg(comp, argsobj)); - argsobj.setStackFrame(NULL); - } else { - JS_ASSERT(!argsobj.maybeStackFrame()); - } -} - ArgumentsObject * -ArgumentsObject::create(JSContext *cx, uint32_t argc, HandleObject callee) +ArgumentsObject::create(JSContext *cx, StackFrame *fp) { - JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX); - JS_ASSERT(!callee->toFunction()->hasRest()); - - RootedObject proto(cx, callee->global().getOrCreateObjectPrototype(cx)); + JSFunction &callee = fp->callee(); + RootedObject proto(cx, callee.global().getOrCreateObjectPrototype(cx)); if (!proto) return NULL; RootedTypeObject type(cx); - type = proto->getNewType(cx); if (!type) return NULL; - bool strict = callee->toFunction()->inStrictMode(); + bool strict = callee.inStrictMode(); Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass; RootedShape emptyArgumentsShape(cx); @@ -79,59 +46,76 @@ ArgumentsObject::create(JSContext *cx, uint32_t argc, HandleObject callee) if (!emptyArgumentsShape) return NULL; - unsigned numDeletedWords = NumWordsForBitArrayOfLength(argc); - unsigned numBytes = offsetof(ArgumentsData, slots) + + unsigned numActuals = fp->numActualArgs(); + unsigned numFormals = fp->numFormalArgs(); + unsigned numDeletedWords = NumWordsForBitArrayOfLength(numActuals); + unsigned numArgs = Max(numActuals, numFormals); + unsigned numBytes = offsetof(ArgumentsData, args) + numDeletedWords * sizeof(size_t) + - argc * sizeof(Value); + numArgs * sizeof(Value); ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes); if (!data) return NULL; - data->callee.init(ObjectValue(*callee)); - for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++) - vp->init(UndefinedValue()); - data->deletedBits = (size_t *)(data->slots + argc); + data->numArgs = numArgs; + data->callee.init(ObjectValue(callee)); + data->script = fp->script(); + + /* Copy [0, numArgs) into data->slots. */ + HeapValue *dst = data->args, *dstEnd = data->args + numArgs; + for (Value *src = fp->formals(), *end = src + numFormals; src != end; ++src, ++dst) + dst->init(*src); + if (numActuals > numFormals) { + for (Value *src = fp->actuals() + numFormals; dst != dstEnd; ++src, ++dst) + dst->init(*src); + } else if (numActuals < numFormals) { + for (; dst != dstEnd; ++dst) + dst->init(UndefinedValue()); + } + + data->deletedBits = reinterpret_cast(dstEnd); ClearAllBitArrayElements(data->deletedBits, numDeletedWords); - /* We have everything needed to fill in the object, so make the object. */ JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL); if (!obj) return NULL; + obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT)); + obj->initFixedSlot(DATA_SLOT, PrivateValue(data)); + + /* + * If it exists and the arguments object aliases formals, the call object + * is the canonical location for formals. + */ + JSScript *script = fp->script(); + if (fp->fun()->isHeavyweight() && script->argsObjAliasesFormals()) { + obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(fp->callObj())); + + /* Flag each slot that canonically lives in the callObj. */ + if (script->bindingsAccessedDynamically) { + for (unsigned i = 0; i < numFormals; ++i) + data->args[i] = MagicValue(JS_FORWARD_TO_CALL_OBJECT); + } else { + for (unsigned i = 0; i < script->numClosedArgs(); ++i) + data->args[script->getClosedArg(i)] = MagicValue(JS_FORWARD_TO_CALL_OBJECT); + } + } + ArgumentsObject &argsobj = obj->asArguments(); - - JS_ASSERT(UINT32_MAX > (uint64_t(argc) << PACKED_BITS_COUNT)); - argsobj.initInitialLength(argc); - argsobj.initData(data); - argsobj.setStackFrame(NULL); - - JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS); - JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS); - + JS_ASSERT(argsobj.initialLength() == numActuals); + JS_ASSERT(!argsobj.hasOverriddenLength()); return &argsobj; } ArgumentsObject * -ArgumentsObject::create(JSContext *cx, StackFrame *fp) +ArgumentsObject::createExpected(JSContext *cx, StackFrame *fp) { JS_ASSERT(fp->script()->needsArgsObj()); - - ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), - RootedObject(cx, &fp->callee())); + ArgumentsObject *argsobj = create(cx, fp); if (!argsobj) return NULL; - /* - * Strict mode functions have arguments objects that copy the initial - * actual parameter values. Non-strict mode arguments use the frame pointer - * to retrieve up-to-date parameter values. - */ - if (argsobj->isStrictArguments()) - fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj)); - else - argsobj->setStackFrame(fp); - fp->initArgsObj(*argsobj); return argsobj; } @@ -139,12 +123,7 @@ ArgumentsObject::create(JSContext *cx, StackFrame *fp) ArgumentsObject * ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp) { - ArgumentsObject *argsobj = create(cx, fp->numActualArgs(), RootedObject(cx, &fp->callee())); - if (!argsobj) - return NULL; - - fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj)); - return argsobj; + return create(cx, fp); } static JSBool @@ -153,10 +132,8 @@ args_delProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp) ArgumentsObject &argsobj = obj->asArguments(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); - if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) { - argsobj.setElement(arg, UndefinedValue()); + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) argsobj.markElementDeleted(arg); - } } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { argsobj.markLengthOverridden(); } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) { @@ -178,22 +155,15 @@ ArgGetter(JSContext *cx, HandleObject obj, HandleId id, Value *vp) * prototype to point to another Arguments object with a bigger argc. */ unsigned arg = unsigned(JSID_TO_INT(id)); - if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) { - if (StackFrame *fp = argsobj.maybeStackFrame()) { - JS_ASSERT_IF(arg < fp->numFormalArgs(), fp->script()->formalIsAliased(arg)); - *vp = fp->canonicalActualArg(arg); - } else { - *vp = argsobj.element(arg); - } - } + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) + *vp = argsobj.element(arg); } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { if (!argsobj.hasOverriddenLength()) - vp->setInt32(argsobj.initialLength()); + *vp = Int32Value(argsobj.initialLength()); } else { JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)); - const Value &v = argsobj.callee(); - if (!v.isMagic(JS_OVERWRITTEN_CALLEE)) - *vp = v; + if (!argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE)) + *vp = argsobj.callee(); } return true; } @@ -205,20 +175,15 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp return true; NormalArgumentsObject &argsobj = obj->asNormalArguments(); + JSScript *script = argsobj.containingScript(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); - if (arg < argsobj.initialLength()) { - if (StackFrame *fp = argsobj.maybeStackFrame()) { - JSScript *script = fp->functionScript(); - JS_ASSERT(script->needsArgsObj()); - if (arg < fp->numFormalArgs()) { - JS_ASSERT(fp->script()->formalIsAliased(arg)); - types::TypeScript::SetArgument(cx, script, arg, *vp); - } - fp->canonicalActualArg(arg) = *vp; - return true; - } + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) { + argsobj.setElement(arg, *vp); + if (arg < script->function()->nargs) + types::TypeScript::SetArgument(cx, script, arg, *vp); + return true; } } else { JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) || @@ -275,13 +240,13 @@ args_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, bool NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Value &elem, Value *vp) { - JS_ASSERT(!fp->hasArgsObj()); + JS_ASSERT(!fp->script()->needsArgsObj()); /* Fast path: no need to convert to id when elem is already an int in range. */ if (elem.isInt32()) { int32_t i = elem.toInt32(); if (i >= 0 && uint32_t(i) < fp->numActualArgs()) { - *vp = fp->canonicalActualArg(i); + *vp = fp->unaliasedActual(i); return true; } } @@ -295,7 +260,7 @@ NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Val if (JSID_IS_INT(id)) { int32_t i = JSID_TO_INT(id); if (i >= 0 && uint32_t(i) < fp->numActualArgs()) { - *vp = fp->canonicalActualArg(i); + *vp = fp->unaliasedActual(i); return true; } } @@ -472,34 +437,20 @@ strictargs_enumerate(JSContext *cx, HandleObject obj) return true; } -static void -args_finalize(FreeOp *fop, JSObject *obj) +void +ArgumentsObject::finalize(FreeOp *fop, JSObject *obj) { fop->free_(reinterpret_cast(obj->asArguments().data())); } -static void -args_trace(JSTracer *trc, JSObject *obj) +void +ArgumentsObject::trace(JSTracer *trc, JSObject *obj) { ArgumentsObject &argsobj = obj->asArguments(); ArgumentsData *data = argsobj.data(); MarkValue(trc, &data->callee, js_callee_str); - MarkValueRange(trc, argsobj.initialLength(), data->slots, js_arguments_str); - - /* - * If a generator's arguments or call object escapes, and the generator - * frame is not executing, the generator object needs to be marked because - * it is not otherwise reachable. An executing generator is rooted by its - * invocation. To distinguish the two cases (which imply different access - * paths to the generator object), we use the JSFRAME_FLOATING_GENERATOR - * flag, which is only set on the StackFrame kept in the generator object's - * JSGenerator. - */ -#if JS_HAS_GENERATORS - StackFrame *fp = argsobj.maybeStackFrame(); - if (fp && fp->isFloatingGenerator()) - MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object"); -#endif + MarkValueRange(trc, data->numArgs, data->args, js_arguments_str); + MarkScriptUnbarriered(trc, &data->script, "script"); } /* @@ -521,12 +472,12 @@ Class js::NormalArgumentsObjectClass = { args_enumerate, reinterpret_cast(args_resolve), JS_ConvertStub, - args_finalize, /* finalize */ + ArgumentsObject::finalize, NULL, /* checkAccess */ NULL, /* call */ NULL, /* construct */ NULL, /* hasInstance */ - args_trace, + ArgumentsObject::trace, { NULL, /* equality */ NULL, /* outerObject */ @@ -555,12 +506,12 @@ Class js::StrictArgumentsObjectClass = { strictargs_enumerate, reinterpret_cast(strictargs_resolve), JS_ConvertStub, - args_finalize, /* finalize */ + ArgumentsObject::finalize, NULL, /* checkAccess */ NULL, /* call */ NULL, /* construct */ NULL, /* hasInstance */ - args_trace, + ArgumentsObject::trace, { NULL, /* equality */ NULL, /* outerObject */ diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 645da465e984..b2f783bde292 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -16,17 +16,25 @@ namespace js { * ArgumentsData stores the initial indexed arguments provided to the * corresponding and that function itself. It is used to store arguments[i] * and arguments.callee -- up until the corresponding property is modified, - * when the relevant value is overwritten with MagicValue(JS_ARGS_HOLE) to - * memorialize the modification. + * when the relevant value is flagged to memorialize the modification. */ struct ArgumentsData { /* - * arguments.callee, or MagicValue(JS_ARGS_HOLE) if arguments.callee has - * been modified. + * numArgs = Max(numFormalArgs, numActualArgs) + * The array 'args' has numArgs elements. + */ + unsigned numArgs; + + /* + * arguments.callee, or MagicValue(JS_OVERWRITTEN_CALLEE) if + * arguments.callee has been modified. */ HeapValue callee; + /* The script for the function containing this arguments object. */ + JSScript *script; + /* * Pointer to an array of bits indicating, for every argument in 'slots', * whether the element has been deleted. See isElementDeleted comment. @@ -34,17 +42,25 @@ struct ArgumentsData size_t *deletedBits; /* - * Values of the arguments for this object, or MagicValue(JS_ARGS_HOLE) if - * the indexed argument has been modified. + * This array holds either the current argument value or the magic value + * JS_FORWARD_TO_CALL_OBJECT. The latter means that the function has both a + * CallObject and an ArgumentsObject AND the particular formal variable is + * aliased by the CallObject. In such cases, the CallObject holds the + * canonical value so any element access to the arguments object should + * load the value out of the CallObject (which is pointed to by + * MAYBE_CALL_SLOT). */ - HeapValue slots[1]; + HeapValue args[1]; + + /* For jit use: */ + static ptrdiff_t offsetOfArgs() { return offsetof(ArgumentsData, args); } }; /* * ArgumentsObject instances represent |arguments| objects created to store * function arguments when a function is called. It's expensive to create such - * objects if they're never used, so they're only created lazily. (See - * js::StackFrame::setArgsObj and friends.) + * objects if they're never used, so they're only created when they are + * potentially used. * * Arguments objects are complicated because, for non-strict mode code, they * must alias any named arguments which were provided to the function. Gnarly @@ -75,43 +91,27 @@ struct ArgumentsData * been modified, then the current value of arguments.length is stored in * another slot associated with a new property. * DATA_SLOT - * Stores an ArgumentsData* storing argument values and the callee, or - * sentinels for any of these if the corresponding property is modified. - * Use callee() to access the callee/sentinel, and use - * element/addressOfElement/setElement to access the values stored in - * the ArgumentsData. If you're simply looking to get arguments[i], - * however, use getElement or getElements to avoid spreading arguments - * object implementation details around too much. - * STACK_FRAME_SLOT - * Stores the function's stack frame for non-strict arguments objects until - * the function returns, when it is replaced with null. When an arguments - * object is created on-trace its private is JS_ARGUMENTS_OBJECT_ON_TRACE, - * and when the trace exits its private is replaced with the stack frame or - * null, as appropriate. This slot is used by strict arguments objects as - * well, but the slot is always null. Conceptually it would be better to - * remove this oddity, but preserving it allows us to work with arguments - * objects of either kind more abstractly, so we keep it for now. + * Stores an ArgumentsData*, described above. */ class ArgumentsObject : public JSObject { + protected: static const uint32_t INITIAL_LENGTH_SLOT = 0; static const uint32_t DATA_SLOT = 1; - static const uint32_t STACK_FRAME_SLOT = 2; + static const uint32_t MAYBE_CALL_SLOT = 2; - /* Lower-order bit stolen from the length slot. */ static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1; static const uint32_t PACKED_BITS_COUNT = 1; - void initInitialLength(uint32_t length); - void initData(ArgumentsData *data); - static ArgumentsObject *create(JSContext *cx, uint32_t argc, HandleObject callee); + static ArgumentsObject *create(JSContext *cx, StackFrame *fp); + inline ArgumentsData *data() const; public: static const uint32_t RESERVED_SLOTS = 3; static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4; /* Create an arguments object for a frame that is expecting them. */ - static ArgumentsObject *create(JSContext *cx, StackFrame *fp); + static ArgumentsObject *createExpected(JSContext *cx, StackFrame *fp); /* * Purposefully disconnect the returned arguments object from the frame @@ -127,33 +127,13 @@ class ArgumentsObject : public JSObject */ inline uint32_t initialLength() const; + /* The script for the function containing this arguments object. */ + JSScript *containingScript() const; + /* True iff arguments.length has been assigned or its attributes changed. */ inline bool hasOverriddenLength() const; inline void markLengthOverridden(); - /* - * Attempt to speedily and efficiently access the i-th element of this - * arguments object. Return true if the element was speedily returned. - * Return false if the element must be looked up more slowly using - * getProperty or some similar method. - * - * NB: Returning false does not indicate error! - */ - inline bool getElement(uint32_t i, js::Value *vp); - - /* - * Attempt to speedily and efficiently get elements [start, start + count) - * of this arguments object into the locations starting at |vp|. Return - * true if all elements were copied. Return false if the elements must be - * gotten more slowly, perhaps using a getProperty or some similar method - * in a loop. - * - * NB: Returning false does not indicate error! - */ - inline bool getElements(uint32_t start, uint32_t count, js::Value *vp); - - inline js::ArgumentsData *data() const; - /* * Because the arguments object is a real object, its elements may be * deleted. This is implemented by setting a 'deleted' flag for the arg @@ -172,18 +152,51 @@ class ArgumentsObject : public JSObject inline bool isAnyElementDeleted() const; inline void markElementDeleted(uint32_t i); - inline const js::Value &element(uint32_t i) const; - inline void setElement(uint32_t i, const js::Value &v); + /* + * An ArgumentsObject serves two roles: + * - a real object, accessed through regular object operations, e.g.., + * JSObject::getElement corresponding to 'arguments[i]'; + * - a VM-internal data structure, storing the value of arguments (formal + * and actual) that are accessed directly by the VM when a reading the + * value of a formal parameter. + * There are two ways to access the ArgumentsData::args corresponding to + * these two use cases: + * - object access should use elements(i) which will take care of + * forwarding when the value is JS_FORWARD_TO_CALL_OBJECT; + * - VM argument access should use arg(i) which will assert that the + * value is not JS_FORWARD_TO_CALL_OBJECT (since, if such forwarding was + * needed, the frontend should have emitted JSOP_GETALIASEDVAR. + */ + inline const Value &element(uint32_t i) const; + inline void setElement(uint32_t i, const Value &v); + inline const Value &arg(unsigned i) const; + inline void setArg(unsigned i, const Value &v); - /* The stack frame for this ArgumentsObject, if the frame is still active. */ - inline js::StackFrame *maybeStackFrame() const; - inline void setStackFrame(js::StackFrame *frame); + /* + * Attempt to speedily and efficiently access the i-th element of this + * arguments object. Return true if the element was speedily returned. + * Return false if the element must be looked up more slowly using + * getProperty or some similar method. The second overload copies the + * elements [start, start + count) into the locations starting at 'vp'. + * + * NB: Returning false does not indicate error! + */ + inline bool maybeGetElement(uint32_t i, Value *vp); + inline bool maybeGetElements(uint32_t start, uint32_t count, js::Value *vp); /* * Measures things hanging off this ArgumentsObject that are counted by the * |miscSize| argument in JSObject::sizeOfExcludingThis(). */ inline size_t sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const; + + static void finalize(FreeOp *fop, JSObject *obj); + static void trace(JSTracer *trc, JSObject *obj); + + /* For jit use: */ + static size_t getDataSlotOffset() { + return getFixedSlotOffset(DATA_SLOT); + } }; class NormalArgumentsObject : public ArgumentsObject diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 96b8d8ba6595..c766b4646770 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -3137,10 +3137,16 @@ DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp) */ JS_ASSERT(i >= 0); Value arg; - if (unsigned(i) < fp->numActualArgs()) - arg = fp->canonicalActualArg(i); - else + if (unsigned(i) < fp->numActualArgs()) { + if (unsigned(i) < fp->numFormalArgs() && fp->script()->formalLivesInCallObject(i)) + arg = fp->callObj().arg(i); + else if (fp->script()->argsObjAliasesFormals()) + arg = fp->argsObj().arg(i); + else + arg = fp->unaliasedActual(i); + } else { arg.setUndefined(); + } if (!Debugger::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, &arg)) return false; @@ -3370,6 +3376,7 @@ js::EvaluateInEnv(JSContext *cx, Handle env, StackFrame *fp, const jschar if (!script) return false; + script->isActiveEval = true; return ExecuteKernel(cx, script, *env, fp->thisValue(), EXECUTE_DEBUG, fp, rval); } diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index 8a6a71a50f02..48d923b93b24 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -14,8 +14,7 @@ namespace js { inline ScopeCoordinate::ScopeCoordinate(jsbytecode *pc) - : hops(GET_UINT16(pc)), binding(GET_UINT16(pc + 2)), - frameBinding(GET_UINT16(pc + 8)) + : hops(GET_UINT16(pc)), slot(GET_UINT16(pc + 2)) { JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); } @@ -36,69 +35,22 @@ ScopeObject::setEnclosingScope(JSContext *cx, HandleObject obj) return true; } -inline StackFrame * -ScopeObject::maybeStackFrame() const -{ - JS_ASSERT(!isStaticBlock() && !isWith()); - return reinterpret_cast(JSObject::getPrivate()); -} - -inline void -ScopeObject::setStackFrame(StackFrame *frame) -{ - return setPrivate(frame); -} - inline const Value & ScopeObject::aliasedVar(ScopeCoordinate sc) { - /* XXX: all this is temporary until the last patch of 659577 */ - StackFrame *fp = maybeStackFrame(); - Bindings &bindings = fp->script()->bindings; - if (isCall()) { - JS_ASSERT(sc.binding == sc.frameBinding); - if (bindings.bindingIsArg(sc.binding)) { - unsigned arg = bindings.bindingToArg(sc.binding); - JS_ASSERT(fp->script()->formalLivesInCallObject(arg)); - return fp->formalArg(arg); - } - - unsigned var = bindings.bindingToLocal(sc.binding); - JS_ASSERT(fp->script()->varIsAliased(var)); - return fp->localSlot(var); - } - - unsigned var = bindings.bindingToLocal(sc.frameBinding); - fp = js_LiveFrameIfGenerator(fp); - JS_ASSERT(var == sc.binding + asClonedBlock().staticBlock().stackDepth() + fp->numFixed()); - JS_ASSERT(asClonedBlock().staticBlock().isAliased(sc.binding)); - return fp->localSlot(var); + JS_ASSERT(isCall() || isClonedBlock()); + JS_STATIC_ASSERT(CALL_BLOCK_RESERVED_SLOTS == CallObject::RESERVED_SLOTS); + JS_STATIC_ASSERT(CALL_BLOCK_RESERVED_SLOTS == BlockObject::RESERVED_SLOTS); + return getSlot(CALL_BLOCK_RESERVED_SLOTS + sc.slot); } inline void ScopeObject::setAliasedVar(ScopeCoordinate sc, const Value &v) { - /* XXX: all this is temporary until the last patch of 659577 */ - StackFrame *fp = maybeStackFrame(); - Bindings &bindings = fp->script()->bindings; - if (isCall()) { - JS_ASSERT(sc.binding == sc.frameBinding); - if (bindings.bindingIsArg(sc.binding)) { - unsigned arg = bindings.bindingToArg(sc.binding); - JS_ASSERT(fp->script()->formalLivesInCallObject(arg)); - fp->formalArg(arg) = v; - } else { - unsigned var = bindings.bindingToLocal(sc.binding); - JS_ASSERT(fp->script()->varIsAliased(var)); - fp->localSlot(var) = v; - } - } else { - unsigned var = bindings.bindingToLocal(sc.frameBinding); - fp = js_LiveFrameIfGenerator(fp); - JS_ASSERT(var == sc.binding + asClonedBlock().staticBlock().stackDepth() + fp->numFixed()); - JS_ASSERT(asClonedBlock().staticBlock().isAliased(sc.binding)); - fp->localSlot(var) = v; - } + JS_ASSERT(isCall() || isClonedBlock()); + JS_STATIC_ASSERT(CALL_BLOCK_RESERVED_SLOTS == CallObject::RESERVED_SLOTS); + JS_STATIC_ASSERT(CALL_BLOCK_RESERVED_SLOTS == BlockObject::RESERVED_SLOTS); + setSlot(CALL_BLOCK_RESERVED_SLOTS + sc.slot, v); } /*static*/ inline size_t @@ -136,61 +88,35 @@ CallObject::getCalleeFunction() const } inline const Value & -CallObject::arg(unsigned i) const +CallObject::arg(unsigned i, MaybeCheckAliasing checkAliasing) const { - JS_ASSERT(i < getCalleeFunction()->nargs); + JS_ASSERT_IF(checkAliasing, getCalleeFunction()->script()->formalLivesInCallObject(i)); return getSlot(RESERVED_SLOTS + i); } inline void -CallObject::setArg(unsigned i, const Value &v) +CallObject::setArg(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing) { - JS_ASSERT(i < getCalleeFunction()->nargs); + JS_ASSERT_IF(checkAliasing, getCalleeFunction()->script()->formalLivesInCallObject(i)); setSlot(RESERVED_SLOTS + i, v); } -inline void -CallObject::initArgUnchecked(unsigned i, const Value &v) -{ - JS_ASSERT(i < getCalleeFunction()->nargs); - initSlotUnchecked(RESERVED_SLOTS + i, v); -} - inline const Value & -CallObject::var(unsigned i) const +CallObject::var(unsigned i, MaybeCheckAliasing checkAliasing) const { JSFunction *fun = getCalleeFunction(); - JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs()); - JS_ASSERT(i < fun->script()->bindings.numVars()); + JS_ASSERT_IF(checkAliasing, fun->script()->varIsAliased(i)); return getSlot(RESERVED_SLOTS + fun->nargs + i); } inline void -CallObject::setVar(unsigned i, const Value &v) +CallObject::setVar(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing) { JSFunction *fun = getCalleeFunction(); - JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs()); - JS_ASSERT(i < fun->script()->bindings.numVars()); + JS_ASSERT_IF(checkAliasing, fun->script()->varIsAliased(i)); setSlot(RESERVED_SLOTS + fun->nargs + i, v); } -inline void -CallObject::initVarUnchecked(unsigned i, const Value &v) -{ - JSFunction *fun = getCalleeFunction(); - JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs()); - JS_ASSERT(i < fun->script()->bindings.numVars()); - initSlotUnchecked(RESERVED_SLOTS + fun->nargs + i, v); -} - -inline void -CallObject::copyValues(unsigned nargs, Value *argv, unsigned nvars, Value *slots) -{ - JS_ASSERT(slotInRange(RESERVED_SLOTS + nargs + nvars, SENTINEL_ALLOWED)); - copySlotRange(RESERVED_SLOTS, argv, nargs); - copySlotRange(RESERVED_SLOTS + nargs, slots, nvars); -} - inline HeapSlotArray CallObject::argArray() { @@ -232,6 +158,13 @@ BlockObject::slotCount() const return propertyCount(); } +inline unsigned +BlockObject::slotToFrameLocal(JSScript *script, unsigned i) +{ + JS_ASSERT(i < slotCount()); + return script->nfixed + stackDepth() + i; +} + inline const Value & BlockObject::slotValue(unsigned i) { @@ -283,9 +216,12 @@ StaticBlockObject::maybeDefinitionParseNode(unsigned i) inline void StaticBlockObject::setAliased(unsigned i, bool aliased) { + JS_ASSERT_IF(i > 0, slotValue(i-1).isBoolean()); setSlotValue(i, BooleanValue(aliased)); - if (aliased) - JSObject::setPrivate(reinterpret_cast(1)); + if (aliased && !needsClone()) { + setSlotValue(0, MagicValue(JS_BLOCK_NEEDS_CLONE)); + JS_ASSERT(needsClone()); + } } inline bool @@ -295,9 +231,9 @@ StaticBlockObject::isAliased(unsigned i) } inline bool -StaticBlockObject::needsClone() const +StaticBlockObject::needsClone() { - return JSObject::getPrivate() != NULL; + return !slotValue(0).isFalse(); } inline bool @@ -313,15 +249,16 @@ ClonedBlockObject::staticBlock() const } inline const Value & -ClonedBlockObject::var(unsigned i) +ClonedBlockObject::var(unsigned i, MaybeCheckAliasing checkAliasing) { - JS_ASSERT(!maybeStackFrame()); + JS_ASSERT_IF(checkAliasing, staticBlock().isAliased(i)); return slotValue(i); } inline void -ClonedBlockObject::setVar(unsigned i, const Value &v) +ClonedBlockObject::setVar(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing) { + JS_ASSERT_IF(checkAliasing, staticBlock().isAliased(i)); setSlotValue(i, v); } diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 5152970ea2e8..6e55030ebdf3 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -45,115 +45,24 @@ js::ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc) } PropertyName * -js::ScopeCoordinateName(JSScript *script, jsbytecode *pc) +js::ScopeCoordinateName(JSRuntime *rt, JSScript *script, jsbytecode *pc) { StaticBlockObject *maybeBlock = ScopeCoordinateBlockChain(script, pc); ScopeCoordinate sc(pc); - - uint32_t targetSlot; - Shape *shape; - if (maybeBlock) { - targetSlot = BlockObject::RESERVED_SLOTS + sc.binding; - shape = maybeBlock->lastProperty(); - } else { - targetSlot = CallObject::RESERVED_SLOTS + sc.binding; - shape = script->bindings.lastShape(); - } - + uint32_t targetSlot = ScopeObject::CALL_BLOCK_RESERVED_SLOTS + sc.slot; + Shape *shape = maybeBlock ? maybeBlock->lastProperty() : script->bindings.lastShape(); Shape::Range r = shape->all(); while (r.front().slot() != targetSlot) r.popFront(); - return JSID_TO_ATOM(r.front().propid())->asPropertyName(); + jsid id = r.front().propid(); + /* Beware nameless destructuring formal. */ + if (!JSID_IS_ATOM(id)) + return rt->atomState.emptyAtom; + return JSID_TO_ATOM(id)->asPropertyName(); } /*****************************************************************************/ -void -js_PutCallObject(StackFrame *fp, CallObject &callobj) -{ - JS_ASSERT(callobj.maybeStackFrame() == fp); - JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame()); - JS_ASSERT(fp->isEvalFrame() == callobj.isForEval()); - - JSScript *script = fp->script(); - Bindings &bindings = script->bindings; - - if (callobj.isForEval()) { - JS_ASSERT(script->strictModeCode); - JS_ASSERT(bindings.numArgs() == 0); - - /* This could be optimized as below, but keep it simple for now. */ - callobj.copyValues(0, NULL, bindings.numVars(), fp->slots()); - } else { - JSFunction *fun = fp->fun(); - JS_ASSERT(script == callobj.getCalleeFunction()->script()); - JS_ASSERT(script == fun->script()); - - unsigned n = bindings.count(); - if (n > 0) { - uint32_t nvars = bindings.numVars(); - uint32_t nargs = bindings.numArgs(); - JS_ASSERT(fun->nargs == nargs); - JS_ASSERT(nvars + nargs == n); - - JSScript *script = fun->script(); - if (script->bindingsAccessedDynamically -#ifdef JS_METHODJIT - || script->debugMode -#endif - ) { - callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots()); - } else { - /* - * For each arg & var that is closed over, copy it from the stack - * into the call object. We use initArg/VarUnchecked because, - * when you call a getter on a call object, js_NativeGetInline - * caches the return value in the slot, so we can't assert that - * it's undefined. - */ - uint32_t nclosed = script->numClosedArgs(); - for (uint32_t i = 0; i < nclosed; i++) { - uint32_t e = script->getClosedArg(i); -#ifdef JS_GC_ZEAL - callobj.setArg(e, fp->formalArg(e)); -#else - callobj.initArgUnchecked(e, fp->formalArg(e)); -#endif - } - - nclosed = script->numClosedVars(); - for (uint32_t i = 0; i < nclosed; i++) { - uint32_t e = script->getClosedVar(i); -#ifdef JS_GC_ZEAL - callobj.setVar(e, fp->slots()[e]); -#else - callobj.initVarUnchecked(e, fp->slots()[e]); -#endif - } - } - - /* - * Update the args and vars for the active call if this is an outer - * function in a script nesting. - */ - types::TypeScriptNesting *nesting = script->nesting(); - if (nesting && script->isOuterFunction) { - nesting->argArray = callobj.argArray(); - nesting->varArray = callobj.varArray(); - } - } - - /* Clear private pointers to fp, which is about to go away. */ - if (js_IsNamedLambda(fun)) { - JSObject &env = callobj.enclosingScope(); - JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp); - env.setPrivate(NULL); - } - } - - callobj.setStackFrame(NULL); -} - /* * Construct a call object for the given bindings. If this is a call object * for a function invocation, callee should be the function being called. @@ -161,14 +70,18 @@ js_PutCallObject(StackFrame *fp, CallObject &callobj) * must be null. */ CallObject * -CallObject::create(JSContext *cx, JSScript *script, HandleObject enclosing, HandleObject callee) +CallObject::create(JSContext *cx, JSScript *script, HandleObject enclosing, HandleFunction callee) { RootedShape shape(cx); shape = script->bindings.callObjectShape(cx); if (shape == NULL) return NULL; - gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots() + 1); + gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots()); +#ifdef JS_THREADSAFE + JS_ASSERT(CanBeFinalizedInBackground(kind, &CallClass)); + kind = gc::GetBackgroundAllocKind(kind); +#endif RootedTypeObject type(cx); type = cx->compartment->getEmptyType(cx); @@ -194,21 +107,9 @@ CallObject::create(JSContext *cx, JSScript *script, HandleObject enclosing, Hand return NULL; } -#ifdef DEBUG - JS_ASSERT(!obj->inDictionaryMode()); - for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) { - const Shape &s = r.front(); - if (s.hasSlot()) { - JS_ASSERT(s.slot() + 1 == obj->slotSpan()); - break; - } - } -#endif - if (!obj->asScope().setEnclosingScope(cx, enclosing)) return NULL; - JS_ASSERT_IF(callee, callee->isFunction()); obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee)); /* @@ -227,7 +128,6 @@ CallObject * CallObject::createForFunction(JSContext *cx, StackFrame *fp) { JS_ASSERT(fp->isNonEvalFunctionFrame()); - JS_ASSERT(!fp->hasCallObj()); RootedObject scopeChain(cx, fp->scopeChain()); @@ -241,11 +141,24 @@ CallObject::createForFunction(JSContext *cx, StackFrame *fp) return NULL; } - CallObject *callobj = create(cx, fp->script(), scopeChain, RootedObject(cx, &fp->callee())); + JSScript *script = fp->script(); + CallObject *callobj = create(cx, script, scopeChain, RootedFunction(cx, &fp->callee())); if (!callobj) return NULL; - callobj->setStackFrame(fp); + /* Copy in the closed-over formal arguments. */ + if (script->bindingsAccessedDynamically) { + Value *formals = fp->formals(); + for (unsigned slot = 0, n = fp->fun()->nargs; slot < n; ++slot) + callobj->setArg(slot, formals[slot]); + } else if (unsigned n = script->numClosedArgs()) { + Value *formals = fp->formals(); + for (unsigned i = 0; i < n; ++i) { + uint32_t slot = script->getClosedArg(i); + callobj->setArg(slot, formals[slot]); + } + } + return callobj; } @@ -261,45 +174,29 @@ CallObject::copyUnaliasedValues(StackFrame *fp) /* Copy the unaliased formals. */ for (unsigned i = 0; i < script->bindings.numArgs(); ++i) { - if (!script->formalLivesInCallObject(i)) - setArg(i, fp->formalArg(i)); + if (!script->formalLivesInCallObject(i)) { + if (script->argsObjAliasesFormals()) + setArg(i, fp->argsObj().arg(i), DONT_CHECK_ALIASING); + else + setArg(i, fp->unaliasedFormal(i), DONT_CHECK_ALIASING); + } } /* Copy the unaliased var/let bindings. */ for (unsigned i = 0; i < script->bindings.numVars(); ++i) { if (!script->varIsAliased(i)) - setVar(i, fp->localSlot(i)); + setVar(i, fp->unaliasedLocal(i), DONT_CHECK_ALIASING); } } CallObject * CallObject::createForStrictEval(JSContext *cx, StackFrame *fp) { - CallObject *callobj = create(cx, fp->script(), fp->scopeChain(), RootedObject(cx)); - if (!callobj) - return NULL; + JS_ASSERT(fp->isStrictEvalFrame()); + JS_ASSERT(cx->fp() == fp); + JS_ASSERT(cx->regs().pc == fp->script()->code); - callobj->setStackFrame(fp); - fp->initScopeChain(*callobj); - return callobj; -} - -JSBool -CallObject::getArgOp(JSContext *cx, HandleObject obj, HandleId id, Value *vp) -{ - CallObject &callobj = obj->asCall(); - - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - unsigned i = (uint16_t) JSID_TO_INT(id); - - DebugOnly script = callobj.getCalleeFunction()->script(); - JS_ASSERT(script->formalLivesInCallObject(i)); - - if (StackFrame *fp = callobj.maybeStackFrame()) - *vp = fp->formalArg(i); - else - *vp = callobj.arg(i); - return true; + return create(cx, fp->script(), fp->scopeChain(), RootedFunction(cx)); } JSBool @@ -313,36 +210,12 @@ CallObject::setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict JSScript *script = callobj.getCalleeFunction()->script(); JS_ASSERT(script->formalLivesInCallObject(i)); - if (StackFrame *fp = callobj.maybeStackFrame()) - fp->formalArg(i) = *vp; - else - callobj.setArg(i, *vp); + callobj.setArg(i, *vp); if (!script->ensureHasTypes(cx)) return false; TypeScript::SetArgument(cx, script, i, *vp); - - return true; -} - -JSBool -CallObject::getVarOp(JSContext *cx, HandleObject obj, HandleId id, Value *vp) -{ - CallObject &callobj = obj->asCall(); - - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - unsigned i = (uint16_t) JSID_TO_INT(id); - - DebugOnly script = callobj.getCalleeFunction()->script(); - JS_ASSERT(script->varIsAliased(i)); - - if (StackFrame *fp = callobj.maybeStackFrame()) - *vp = fp->varSlot(i); - else - *vp = callobj.var(i); - - JS_ASSERT(!vp->isMagic(JS_OPTIMIZED_ARGUMENTS)); return true; } @@ -357,10 +230,7 @@ CallObject::setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict JSScript *script = callobj.getCalleeFunction()->script(); JS_ASSERT(script->varIsAliased(i)); - if (StackFrame *fp = callobj.maybeStackFrame()) - fp->varSlot(i) = *vp; - else - callobj.setVar(i, *vp); + callobj.setVar(i, *vp); if (!script->ensureHasTypes(cx)) return false; @@ -369,52 +239,16 @@ CallObject::setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict return true; } -bool -CallObject::containsVarOrArg(PropertyName *name, Value *vp, JSContext *cx) -{ - jsid id = NameToId(name); - const Shape *shape = nativeLookup(cx, id); - if (!shape) - return false; - - PropertyOp op = shape->getterOp(); - if (op != getVarOp && op != getArgOp) - return false; - - JS_ALWAYS_TRUE(op(cx, RootedObject(cx, this), RootedId(cx, INT_TO_JSID(shape->shortid())), vp)); - return true; -} - -static void -call_trace(JSTracer *trc, JSObject *obj) -{ - JS_ASSERT(obj->isCall()); - - /* Mark any generator frame, as for arguments objects. */ -#if JS_HAS_GENERATORS - StackFrame *fp = (StackFrame *) obj->getPrivate(); - if (fp && fp->isFloatingGenerator()) - MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object"); -#endif -} - JS_PUBLIC_DATA(Class) js::CallClass = { "Call", - JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS | - JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS), + JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS), JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, JS_ResolveStub, - NULL, /* convert: Leave it NULL so we notice if calls ever escape */ - NULL, /* finalize */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* construct */ - NULL, /* hasInstance */ - call_trace + NULL /* convert: Leave it NULL so we notice if calls ever escape */ }; Class js::DeclEnvClass = { @@ -449,7 +283,6 @@ DeclEnvObject::create(JSContext *cx, StackFrame *fp) if (!obj) return NULL; - obj->setPrivate(fp); if (!obj->asScope().setEnclosingScope(cx, fp->scopeChain())) return NULL; @@ -753,103 +586,35 @@ ClonedBlockObject::create(JSContext *cx, Handle block, Stac obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*fp->scopeChain())); obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(block->stackDepth())); - obj->setPrivate(js_FloatingFrameIfGenerator(cx, fp)); if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx)) return NULL; + /* + * Copy in the closed-over locals. Closed-over locals don't need + * any fixup since the initial value is 'undefined'. + */ + Value *src = fp->base() + block->stackDepth(); + unsigned nslots = block->slotCount(); + for (unsigned i = 0; i < nslots; ++i, ++src) { + if (block->isAliased(i)) + obj->asClonedBlock().setVar(i, *src); + } + return &obj->asClonedBlock(); } -void -ClonedBlockObject::put(StackFrame *fp) -{ - uint32_t count = slotCount(); - uint32_t depth = stackDepth(); - - /* See comments in CheckDestructuring in frontend/Parser.cpp. */ - JS_ASSERT(count >= 1); - - copySlotRange(RESERVED_SLOTS, fp->base() + depth, count); - - /* We must clear the private slot even with errors. */ - setPrivate(NULL); -} - void ClonedBlockObject::copyUnaliasedValues(StackFrame *fp) { StaticBlockObject &block = staticBlock(); - unsigned base = fp->script()->nfixed + stackDepth(); + unsigned base = block.slotToFrameLocal(fp->script(), 0); for (unsigned i = 0; i < slotCount(); ++i) { if (!block.isAliased(i)) - setVar(i, fp->localSlot(base + i)); + setVar(i, fp->unaliasedLocal(base + i), DONT_CHECK_ALIASING); } } -static JSBool -block_getProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp) -{ - /* - * Block objects are never exposed to script, and the engine handles them - * with care. So unlike other getters, this one can assert (rather than - * check) certain invariants about obj. - */ - ClonedBlockObject &block = obj->asClonedBlock(); - unsigned index = (unsigned) JSID_TO_INT(id); - - JS_ASSERT_IF(!block.compartment()->debugMode(), block.staticBlock().isAliased(index)); - - if (StackFrame *fp = block.maybeStackFrame()) { - fp = js_LiveFrameIfGenerator(fp); - index += fp->numFixed() + block.stackDepth(); - JS_ASSERT(index < fp->numSlots()); - *vp = fp->slots()[index]; - return true; - } - - /* Values are in slots immediately following the class-reserved ones. */ - JS_ASSERT(block.var(index) == *vp); - return true; -} - -static JSBool -block_setProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp) -{ - ClonedBlockObject &block = obj->asClonedBlock(); - unsigned index = (unsigned) JSID_TO_INT(id); - - JS_ASSERT_IF(!block.compartment()->debugMode(), block.staticBlock().isAliased(index)); - - if (StackFrame *fp = block.maybeStackFrame()) { - fp = js_LiveFrameIfGenerator(fp); - index += fp->numFixed() + block.stackDepth(); - JS_ASSERT(index < fp->numSlots()); - fp->slots()[index] = *vp; - return true; - } - - /* - * The value in *vp will be written back to the slot in obj that was - * allocated when this let binding was defined. - */ - return true; -} - -bool -ClonedBlockObject::containsVar(PropertyName *name, Value *vp, JSContext *cx) -{ - RootedObject self(cx, this); - - const Shape *shape = nativeLookup(cx, NameToId(name)); - if (!shape) - return false; - - JS_ASSERT(shape->getterOp() == block_getProperty); - JS_ALWAYS_TRUE(block_getProperty(cx, self, RootedId(cx, INT_TO_JSID(shape->shortid())), vp)); - return true; -} - StaticBlockObject * StaticBlockObject::create(JSContext *cx) { @@ -867,7 +632,6 @@ StaticBlockObject::create(JSContext *cx) if (!obj) return NULL; - obj->setPrivate(NULL); return &obj->asStaticBlock(); } @@ -890,29 +654,15 @@ StaticBlockObject::addVar(JSContext *cx, jsid id, int index, bool *redeclared) * block's shape later. */ uint32_t slot = JSSLOT_FREE(&BlockClass) + index; - return addPropertyInternal(cx, id, block_getProperty, block_setProperty, + return addPropertyInternal(cx, id, /* getter = */ NULL, /* setter = */ NULL, slot, JSPROP_ENUMERATE | JSPROP_PERMANENT, Shape::HAS_SHORTID, index, spp, /* allowDictionary = */ false); } -static void -block_trace(JSTracer *trc, JSObject *obj) -{ - if (obj->isStaticBlock()) - return; - - /* XXX: this will be removed again with bug 659577. */ -#if JS_HAS_GENERATORS - StackFrame *fp = obj->asClonedBlock().maybeStackFrame(); - if (fp && fp->isFloatingGenerator()) - MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object"); -#endif -} - Class js::BlockClass = { "Block", - JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | + JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, JS_PropertyStub, /* addProperty */ @@ -921,13 +671,7 @@ Class js::BlockClass = { JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, - NULL, /* finalize */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* construct */ - NULL, /* hasInstance */ - block_trace + JS_ConvertStub }; #define NO_PARENT_INDEX UINT32_MAX @@ -1044,7 +788,7 @@ js::XDRStaticBlockObject(XDRState *xdr, JSScript *script, StaticBlockObjec */ for (unsigned i = 0; i < count; i++) { const Shape *shape = shapes[i]; - JS_ASSERT(shape->getter() == block_getProperty); + JS_ASSERT(shape->hasDefaultGetter()); JS_ASSERT(unsigned(shape->shortid()) == i); jsid propid = shape->propid(); @@ -1263,6 +1007,9 @@ ScopeIter::settle() } else if (fp_->isNonEvalFunctionFrame() && !fp_->hasCallObj()) { JS_ASSERT(cur_ == fp_->fun()->environment()); fp_ = NULL; + } else if (fp_->isStrictEvalFrame() && !fp_->hasCallObj()) { + JS_ASSERT(cur_ == fp_->prev()->scopeChain()); + fp_ = NULL; } else if (cur_->isWith()) { JS_ASSERT_IF(fp_->isFunctionFrame(), fp_->fun()->isHeavyweight()); JS_ASSERT_IF(block_, block_->needsClone()); @@ -1359,14 +1106,14 @@ class DebugScopeProxy : public BaseProxyHandler if (maybefp) { if (action == GET) - *vp = maybefp->varSlot(i); + *vp = maybefp->unaliasedVar(i); else - maybefp->varSlot(i) = *vp; + maybefp->unaliasedVar(i) = *vp; } else { if (action == GET) - *vp = callobj.var(i); + *vp = callobj.var(i, DONT_CHECK_ALIASING); else - callobj.setVar(i, *vp); + callobj.setVar(i, *vp, DONT_CHECK_ALIASING); } if (action == SET) @@ -1381,15 +1128,22 @@ class DebugScopeProxy : public BaseProxyHandler return false; if (maybefp) { - if (action == GET) - *vp = maybefp->formalArg(i); - else - maybefp->formalArg(i) = *vp; + if (script->argsObjAliasesFormals()) { + if (action == GET) + *vp = maybefp->argsObj().arg(i); + else + maybefp->argsObj().setArg(i, *vp); + } else { + if (action == GET) + *vp = maybefp->unaliasedFormal(i); + else + maybefp->unaliasedFormal(i) = *vp; + } } else { if (action == GET) - *vp = callobj.arg(i); + *vp = callobj.arg(i, DONT_CHECK_ALIASING); else - callobj.setArg(i, *vp); + callobj.setArg(i, *vp, DONT_CHECK_ALIASING); } if (action == SET) @@ -1409,17 +1163,17 @@ class DebugScopeProxy : public BaseProxyHandler if (maybefp) { JSScript *script = maybefp->script(); - unsigned local = i + script->nfixed + block.stackDepth(); + unsigned local = block.slotToFrameLocal(maybefp->script(), i); if (action == GET) - *vp = maybefp->localSlot(local); + *vp = maybefp->unaliasedLocal(local); else - maybefp->localSlot(local) = *vp; + maybefp->unaliasedLocal(local) = *vp; JS_ASSERT(analyze::LocalSlot(script, local) >= analyze::TotalSlots(script)); } else { if (action == GET) - *vp = block.var(i); + *vp = block.var(i, DONT_CHECK_ALIASING); else - block.setVar(i, *vp); + block.setVar(i, *vp, DONT_CHECK_ALIASING); } return true; @@ -1693,7 +1447,7 @@ DebugScopes::mark(JSTracer *trc) } void -DebugScopes::sweep() +DebugScopes::sweep(JSRuntime *rt) { /* * Note: missingScopes points to debug scopes weakly not just so that debug @@ -1705,16 +1459,36 @@ DebugScopes::sweep() e.removeFront(); } - /* - * Scopes can be finalized when a suspended generator becomes garbage or - * when a debugger-synthesized ScopeObject is no longer rooted by its - * DebugScopeObject. - */ for (LiveScopeMap::Enum e(liveScopes); !e.empty(); e.popFront()) { - ScopeObject &scope = *e.front().key; - if (JS_IsAboutToBeFinalized(&scope)) { - JS_ASSERT(!scope.maybeStackFrame() || scope.maybeStackFrame()->isGeneratorFrame()); + ScopeObject *scope = e.front().key; + StackFrame *fp = e.front().value; + + /* + * Scopes can be finalized when a debugger-synthesized ScopeObject is + * no longer reachable via its DebugScopeObject. + */ + if (JS_IsAboutToBeFinalized(scope)) { e.removeFront(); + continue; + } + + /* + * As explained in onGeneratorFrameChange, liveScopes includes + * suspended generator frames. Since a generator can be finalized while + * its scope is live, we must explicitly detect finalized generators. + * Since the scope is still live, we simulate the onPop* call by + * copying unaliased variables into the scope object. + */ + if (JSGenerator *gen = fp->maybeSuspendedGenerator(rt)) { + JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN); + if (!IsMarked(&gen->obj)) { + if (scope->isCall()) + scope->asCall().copyUnaliasedValues(fp); + else if (scope->isBlock()) + scope->asClonedBlock().copyUnaliasedValues(fp); + e.removeFront(); + continue; + } } } } @@ -1791,14 +1565,11 @@ DebugScopes::addDebugScope(JSContext *cx, ScopeIter si, DebugScopeObject &debugS void DebugScopes::onPopCall(StackFrame *fp) { - if (fp->isYielding()) - return; - + JS_ASSERT(!fp->isYielding()); if (fp->fun()->isHeavyweight()) { /* - * When a frame finishes executing in mjit code, the epilogue is called - * once from the return and once when the frame is popped. - * TODO: bug 659577 will remove this (with HAS_CALL_OBJ). + * The StackFrame may be observed before the prologue has created the + * CallObject. See ScopeIter::settle. */ if (fp->hasCallObj()) { CallObject &callobj = fp->scopeChain()->asCall(); @@ -1806,7 +1577,6 @@ DebugScopes::onPopCall(StackFrame *fp) liveScopes.remove(&callobj); } } else { - JS_ASSERT(!fp->hasCallObj()); if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(fp))) { CallObject &callobj = p->value->scope().asCall(); callobj.copyUnaliasedValues(fp); @@ -1825,8 +1595,6 @@ DebugScopes::onPopBlock(JSContext *cx, StackFrame *fp) clone.copyUnaliasedValues(fp); liveScopes.remove(&clone); } else { - JS_ASSERT(!fp->scopeChain()->isBlock() || - fp->scopeChain()->asClonedBlock().staticBlock() != staticBlock); if (MissingScopeMap::Ptr p = missingScopes.lookup(ScopeIter(fp))) { ClonedBlockObject &clone = p->value->scope().asClonedBlock(); clone.copyUnaliasedValues(fp); @@ -1845,7 +1613,12 @@ DebugScopes::onPopWith(StackFrame *fp) void DebugScopes::onPopStrictEvalScope(StackFrame *fp) { - liveScopes.remove(&fp->scopeChain()->asCall()); + /* + * The StackFrame may be observed before the prologue has created the + * CallObject. See ScopeIter::settle. + */ + if (fp->hasCallObj()) + liveScopes.remove(&fp->scopeChain()->asCall()); } void @@ -1993,13 +1766,11 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si) if (callobj->enclosingScope().isDeclEnv()) { JS_ASSERT(CallObjectLambdaName(callobj->getCalleeFunction())); DeclEnvObject &declenv = callobj->enclosingScope().asDeclEnv(); - declenv.setStackFrame(NULL); enclosingDebug = DebugScopeObject::create(cx, declenv, *enclosingDebug); if (!enclosingDebug) return NULL; } - callobj->setStackFrame(NULL); debugScope = DebugScopeObject::create(cx, *callobj, *enclosingDebug); break; } @@ -2009,7 +1780,6 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si) if (!block) return NULL; - block->setStackFrame(NULL); debugScope = DebugScopeObject::create(cx, *block, *enclosingDebug); break; } diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index e167f9bedef3..9e4aeeeff307 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -9,7 +9,6 @@ #define ScopeObject_h___ #include "jscntxt.h" -#include "jsiter.h" #include "jsobj.h" #include "jsweakmap.h" @@ -29,10 +28,7 @@ namespace js { struct ScopeCoordinate { uint16_t hops; - uint16_t binding; - - /* XXX this will be removed with the last patch of bug 659577. */ - uint16_t frameBinding; + uint16_t slot; inline ScopeCoordinate(jsbytecode *pc); inline ScopeCoordinate() {} @@ -44,7 +40,7 @@ ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc); /* Return the name being accessed by the given ALIASEDVAR op. */ extern PropertyName * -ScopeCoordinateName(JSScript *script, jsbytecode *pc); +ScopeCoordinateName(JSRuntime *rt, JSScript *script, jsbytecode *pc); /*****************************************************************************/ @@ -88,13 +84,13 @@ ScopeCoordinateName(JSScript *script, jsbytecode *pc); class ScopeObject : public JSObject { - /* Use maybeStackFrame() instead. */ - void *getPrivate() const; - protected: static const uint32_t SCOPE_CHAIN_SLOT = 0; public: + /* Number of reserved slots for both CallObject and BlockObject. */ + static const uint32_t CALL_BLOCK_RESERVED_SLOTS = 2; + /* * Since every scope chain terminates with a global object and GlobalObject * does not derive ScopeObject (it has a completely different layout), the @@ -112,14 +108,6 @@ class ScopeObject : public JSObject inline const Value &aliasedVar(ScopeCoordinate sc); inline void setAliasedVar(ScopeCoordinate sc, const Value &v); - /* - * The stack frame for this scope object, if the frame is still active. - * Note: these members may not be called for a StaticBlockObject or - * WithObject. - */ - inline StackFrame *maybeStackFrame() const; - inline void setStackFrame(StackFrame *frame); - /* For jit access. */ static inline size_t offsetOfEnclosingScope(); }; @@ -129,10 +117,10 @@ class CallObject : public ScopeObject static const uint32_t CALLEE_SLOT = 1; static CallObject * - create(JSContext *cx, JSScript *script, HandleObject enclosing, HandleObject callee); + create(JSContext *cx, JSScript *script, HandleObject enclosing, HandleFunction callee); public: - static const uint32_t RESERVED_SLOTS = 3; + static const uint32_t RESERVED_SLOTS = CALL_BLOCK_RESERVED_SLOTS; static CallObject *createForFunction(JSContext *cx, StackFrame *fp); static CallObject *createForStrictEval(JSContext *cx, StackFrame *fp); @@ -149,14 +137,12 @@ class CallObject : public ScopeObject inline void setCallee(JSObject *callee); /* Returns the formal argument at the given index. */ - inline const Value &arg(unsigned i) const; - inline void setArg(unsigned i, const Value &v); - inline void initArgUnchecked(unsigned i, const Value &v); + inline const Value &arg(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const; + inline void setArg(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING); /* Returns the variable at the given index. */ - inline const Value &var(unsigned i) const; - inline void setVar(unsigned i, const Value &v); - inline void initVarUnchecked(unsigned i, const Value &v); + inline const Value &var(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const; + inline void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING); /* * Get the actual arrays of arguments and variables. Only call if type @@ -166,16 +152,9 @@ class CallObject : public ScopeObject inline HeapSlotArray argArray(); inline HeapSlotArray varArray(); - inline void copyValues(unsigned nargs, Value *argv, unsigned nvars, Value *slots); - - static JSBool getArgOp(JSContext *cx, HandleObject obj, HandleId id, Value *vp); - static JSBool getVarOp(JSContext *cx, HandleObject obj, HandleId id, Value *vp); static JSBool setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp); static JSBool setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp); - /* Return whether this environment contains 'name' and, if so, its value. */ - bool containsVarOrArg(PropertyName *name, Value *vp, JSContext *cx); - /* Copy in all the unaliased formals and locals. */ void copyUnaliasedValues(StackFrame *fp); }; @@ -202,10 +181,6 @@ class NestedScopeObject : public ScopeObject class WithObject : public NestedScopeObject { - /* These ScopeObject operations are not valid on a with object. */ - js::StackFrame *maybeStackFrame() const; - void setStackFrame(StackFrame *frame); - static const unsigned THIS_SLOT = 2; /* Use WithObject::object() instead. */ @@ -213,7 +188,11 @@ class WithObject : public NestedScopeObject public: static const unsigned RESERVED_SLOTS = 3; +#ifdef JS_THREADSAFE + static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4_BACKGROUND; +#else static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4; +#endif static WithObject * create(JSContext *cx, HandleObject proto, HandleObject enclosing, uint32_t depth); @@ -228,12 +207,23 @@ class WithObject : public NestedScopeObject class BlockObject : public NestedScopeObject { public: - static const unsigned RESERVED_SLOTS = 2; + static const unsigned RESERVED_SLOTS = CALL_BLOCK_RESERVED_SLOTS; +#ifdef JS_THREADSAFE + static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4_BACKGROUND; +#else static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4; +#endif /* Return the number of variables associated with this block. */ inline uint32_t slotCount() const; + /* + * Return the local corresponding to the ith binding where i is in the + * range [0, slotCount()) and the return local index is in the range + * [script->nfixed, script->nfixed + script->nslots). + */ + unsigned slotToFrameLocal(JSScript *script, unsigned i); + protected: /* Blocks contain an object slot for each slot i: 0 <= i < slotCount. */ inline const Value &slotValue(unsigned i); @@ -242,10 +232,6 @@ class BlockObject : public NestedScopeObject class StaticBlockObject : public BlockObject { - /* These ScopeObject operations are not valid on a static block object. */ - StackFrame *maybeStackFrame() const; - void setStackFrame(StackFrame *frame); - public: static StaticBlockObject *create(JSContext *cx); @@ -273,7 +259,7 @@ class StaticBlockObject : public BlockObject * A static block object is cloned (when entering the block) iff some * variable of the block isAliased. */ - bool needsClone() const; + bool needsClone(); const Shape *addVar(JSContext *cx, jsid id, int index, bool *redeclared); }; @@ -287,18 +273,9 @@ class ClonedBlockObject : public BlockObject /* The static block from which this block was cloned. */ StaticBlockObject &staticBlock() const; - /* - * When this block's stack slots are about to be popped, 'put' must be - * called to copy the slot values into this block's object slots. - */ - void put(StackFrame *fp); - /* Assuming 'put' has been called, return the value of the ith let var. */ - const Value &var(unsigned i); - void setVar(unsigned i, const Value &v); - - /* Return whether this environment contains 'name' and, if so, its value. */ - bool containsVar(PropertyName *name, Value *vp, JSContext *cx); + const Value &var(unsigned i, MaybeCheckAliasing = CHECK_ALIASING); + void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING); /* Copy in all the unaliased formals and locals. */ void copyUnaliasedValues(StackFrame *fp); @@ -470,7 +447,7 @@ class DebugScopes bool init(); void mark(JSTracer *trc); - void sweep(); + void sweep(JSRuntime *rt); DebugScopeObject *hasDebugScope(JSContext *cx, ScopeObject &scope) const; bool addDebugScope(JSContext *cx, ScopeObject &scope, DebugScopeObject &debugScope); diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index e36113f96b6c..76485a5b82a4 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -92,7 +92,7 @@ StackFrame::initPrev(JSContext *cx) prev_ = NULL; #ifdef DEBUG prevpc_ = (jsbytecode *)0xbadc; - prevInline_ = (JSInlinedSite *)0xbadc; + prevInline_ = (InlinedSite *)0xbadc; #endif } } @@ -147,9 +147,8 @@ StackFrame::initCallFrame(JSContext *cx, JSFunction &callee, JS_ASSERT(!hasBlockChain()); JS_ASSERT(!hasHookData()); JS_ASSERT(annotation() == NULL); - JS_ASSERT(!hasCallObj()); - SetValueRangeToUndefined(slots(), script->nfixed); + initVarsToUndefined(); } /* @@ -171,85 +170,137 @@ StackFrame::initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncod u.nactual = nactual; } +inline bool +StackFrame::jitHeavyweightFunctionPrologue(JSContext *cx) +{ + JS_ASSERT(isNonEvalFunctionFrame()); + JS_ASSERT(fun()->isHeavyweight()); + + CallObject *callobj = CallObject::createForFunction(cx, this); + if (!callobj) + return false; + + pushOnScopeChain(*callobj); + flags_ |= HAS_CALL_OBJ; + + if (script()->nesting()) { + types::NestingPrologue(cx, this); + flags_ |= HAS_NESTING; + } + + return true; +} + +inline void +StackFrame::jitTypeNestingPrologue(JSContext *cx) +{ + types::NestingPrologue(cx, this); + flags_ |= HAS_NESTING; +} + +inline void +StackFrame::initVarsToUndefined() +{ + SetValueRangeToUndefined(slots(), script()->nfixed); +} + inline JSObject * StackFrame::createRestParameter(JSContext *cx) { JS_ASSERT(fun()->hasRest()); unsigned nformal = fun()->nargs - 1, nactual = numActualArgs(); unsigned nrest = (nactual > nformal) ? nactual - nformal : 0; - return NewDenseCopiedArray(cx, nrest, actualArgs() + nformal); + return NewDenseCopiedArray(cx, nrest, actuals() + nformal); } inline Value & -StackFrame::canonicalActualArg(unsigned i) const +StackFrame::unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing) +{ + JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i)); + JS_ASSERT(i < script()->nfixed); + return slots()[i]; +} + +inline Value & +StackFrame::unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing) +{ +#ifdef DEBUG + if (checkAliasing) { + JS_ASSERT(i < script()->nslots); + if (i < script()->nfixed) { + JS_ASSERT(!script()->varIsAliased(i)); + } else { + unsigned depth = i - script()->nfixed; + for (StaticBlockObject *b = maybeBlockChain(); b; b = b->enclosingBlock()) { + if (b->containsVarAtDepth(depth)) { + JS_ASSERT(!b->isAliased(depth - b->stackDepth())); + break; + } + } + } + } +#endif + return slots()[i]; +} + +inline Value & +StackFrame::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing) +{ + JS_ASSERT(i < numFormalArgs()); + JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i)); + return formals()[i]; +} + +inline Value & +StackFrame::unaliasedActual(unsigned i) { - if (i < numFormalArgs()) - return formalArg(i); JS_ASSERT(i < numActualArgs()); - return actualArgs()[i]; + JS_ASSERT(!script()->formalIsAliased(i)); + return i < numFormalArgs() ? formals()[i] : actuals()[i]; } template -inline bool -StackFrame::forEachCanonicalActualArg(Op op, unsigned start /* = 0 */, unsigned count /* = unsigned(-1) */) +inline void +StackFrame::forEachUnaliasedActual(Op op) { - unsigned nformal = fun()->nargs; - JS_ASSERT(start <= nformal); + JS_ASSERT(script()->numClosedArgs() == 0); + JS_ASSERT(!script()->needsArgsObj()); - Value *formals = formalArgsEnd() - nformal; + unsigned nformal = numFormalArgs(); unsigned nactual = numActualArgs(); - if (count == unsigned(-1)) - count = nactual - start; - unsigned end = start + count; - JS_ASSERT(end >= start); - JS_ASSERT(end <= nactual); + const Value *formalsEnd = (const Value *)this; + const Value *formals = formalsEnd - nformal; - if (end <= nformal) { - Value *p = formals + start; - for (; start < end; ++p, ++start) { - if (!op(start, p)) - return false; - } + if (nactual <= nformal) { + const Value *actualsEnd = formals + nactual; + for (const Value *p = formals; p < actualsEnd; ++p) + op(*p); } else { - for (Value *p = formals + start; start < nformal; ++p, ++start) { - if (!op(start, p)) - return false; - } - JS_ASSERT(start >= nformal); - Value *actuals = formals - (nactual + 2) + start; - for (Value *p = actuals; start < end; ++p, ++start) { - if (!op(start, p)) - return false; - } - } - return true; -} + for (const Value *p = formals; p < formalsEnd; ++p) + op(*p); -template -inline bool -StackFrame::forEachFormalArg(Op op) -{ - Value *formals = formalArgsEnd() - fun()->nargs; - Value *formalsEnd = formalArgsEnd(); - unsigned i = 0; - for (Value *p = formals; p != formalsEnd; ++p, ++i) { - if (!op(i, p)) - return false; + const Value *actualsEnd = formals - 2; + const Value *actuals = actualsEnd - nactual; + for (const Value *p = actuals + nformal; p < actualsEnd; ++p) + op(*p); } - return true; } struct CopyTo { Value *dst; CopyTo(Value *dst) : dst(dst) {} - bool operator()(unsigned, Value *src) { - *dst++ = *src; - return true; - } + void operator()(const Value &src) { *dst++ = src; } }; +inline unsigned +StackFrame::numFormalArgs() const +{ + JS_ASSERT(hasArgs()); + return fun()->nargs; +} + inline unsigned StackFrame::numActualArgs() const { @@ -267,23 +318,20 @@ StackFrame::numActualArgs() const return numFormalArgs(); } -inline Value * -StackFrame::actualArgs() const +inline ArgumentsObject & +StackFrame::argsObj() const { - JS_ASSERT(hasArgs()); - Value *argv = formalArgs(); - if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS)) - return argv - (2 + u.nactual); - return argv; + JS_ASSERT(script()->needsArgsObj()); + JS_ASSERT(flags_ & HAS_ARGS_OBJ); + return *argsObj_; } -inline Value * -StackFrame::actualArgsEnd() const +inline void +StackFrame::initArgsObj(ArgumentsObject &argsobj) { - JS_ASSERT(hasArgs()); - if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS)) - return formalArgs() - 2; - return formalArgs() + numActualArgs(); + JS_ASSERT(script()->needsArgsObj()); + flags_ |= HAS_ARGS_OBJ; + argsObj_ = &argsobj; } inline ScopeObject & @@ -292,54 +340,29 @@ StackFrame::aliasedVarScope(ScopeCoordinate sc) const JSObject *scope = &scopeChain()->asScope(); for (unsigned i = sc.hops; i; i--) scope = &scope->asScope().enclosingScope(); - -#ifdef DEBUG - if (scope->isCall()) { - JS_ASSERT(scope->asCall() == callObj()); - JS_ASSERT(scope->asCall().maybeStackFrame() == this); - } else { - StaticBlockObject &target = scope->asClonedBlock().staticBlock(); - StaticBlockObject *b = &blockChain(); - while (b != &target) - b = b->enclosingBlock(); - } -#endif - return scope->asScope(); } inline void -StackFrame::setScopeChain(JSObject &obj) +StackFrame::pushOnScopeChain(ScopeObject &scope) { -#ifdef DEBUG - JS_ASSERT(&obj != NULL); - if (hasCallObj()) { - JSObject *pobj = &obj; - while (pobj && !pobj->isWith() && pobj->asScope().maybeStackFrame() != this) - pobj = pobj->enclosingScope(); - JS_ASSERT(pobj); - } else { - for (JSObject *pobj = &obj; pobj->isScope() && !pobj->isWith(); pobj = pobj->enclosingScope()) - JS_ASSERT_IF(pobj->isCall(), pobj->asScope().maybeStackFrame() != this); - } -#endif - scopeChain_ = &obj; + JS_ASSERT(*scopeChain() == scope.enclosingScope() || + *scopeChain() == scope.asCall().enclosingScope().asDeclEnv().enclosingScope()); + scopeChain_ = &scope; flags_ |= HAS_SCOPECHAIN; } inline void -StackFrame::initScopeChain(CallObject &obj) +StackFrame::popOffScopeChain() { - JS_ASSERT(&obj != NULL); - JS_ASSERT(!hasCallObj() && obj.maybeStackFrame() == this); - scopeChain_ = &obj; - flags_ |= HAS_SCOPECHAIN | HAS_CALL_OBJ; + JS_ASSERT(flags_ & HAS_SCOPECHAIN); + scopeChain_ = &scopeChain_->asScope().enclosingScope(); } inline CallObject & StackFrame::callObj() const { - JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj()); + JS_ASSERT(fun()->isHeavyweight()); JSObject *pobj = scopeChain(); while (JS_UNLIKELY(!pobj->isCall())) @@ -347,89 +370,6 @@ StackFrame::callObj() const return pobj->asCall(); } -inline bool -StackFrame::maintainNestingState() const -{ - /* - * Whether to invoke the nesting epilogue/prologue to maintain active - * frame counts and check for reentrant outer functions. - */ - return isNonEvalFunctionFrame() && !isGeneratorFrame() && script()->nesting(); -} - -inline bool -StackFrame::functionPrologue(JSContext *cx) -{ - JS_ASSERT(isNonEvalFunctionFrame()); - JS_ASSERT(!isGeneratorFrame()); - - if (fun()->isHeavyweight()) { - CallObject *callobj = CallObject::createForFunction(cx, this); - if (!callobj) - return false; - initScopeChain(*callobj); - } else { - /* Force instantiation of the scope chain, for JIT frames. */ - scopeChain(); - } - - if (script()->nesting()) { - JS_ASSERT(maintainNestingState()); - types::NestingPrologue(cx, this); - } - - return true; -} - -inline void -StackFrame::functionEpilogue(JSContext *cx) -{ - JS_ASSERT(isNonEvalFunctionFrame()); - - if (cx->compartment->debugMode()) - cx->runtime->debugScopes->onPopCall(this); - - if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) { - if (hasCallObj()) - js_PutCallObject(this, scopeChain_->asCall()); - if (hasArgsObj()) - js_PutArgsObject(this); - } - - if (maintainNestingState()) - types::NestingEpilogue(this); -} - -inline void -StackFrame::updateEpilogueFlags() -{ - if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) { - if (hasArgsObj() && !argsObj().maybeStackFrame()) - flags_ &= ~HAS_ARGS_OBJ; - if (hasCallObj() && !callObj().maybeStackFrame()) { - /* - * For function frames, the call object may or may not have have an - * enclosing DeclEnv object, so we use the callee's parent, since - * it was the initial scope chain. For global (strict) eval frames, - * there is no callee, but the call object's parent is the initial - * scope chain. - */ - scopeChain_ = isFunctionFrame() - ? callee().environment() - : &scopeChain_->asScope().enclosingScope(); - flags_ &= ~HAS_CALL_OBJ; - } - } - - /* - * For outer/inner function frames, undo the active frame balancing so that - * when we redo it in the epilogue we get the right final value. The other - * nesting epilogue changes (update active args/vars) are idempotent. - */ - if (maintainNestingState()) - script()->nesting()->activeFrames++; -} - /*****************************************************************************/ STATIC_POSTCONDITION(!return || ubound(from) >= nvals) @@ -451,7 +391,7 @@ inline Value * StackSpace::getStackLimit(JSContext *cx, MaybeReportError report) { FrameRegs ®s = cx->regs(); - unsigned nvals = regs.fp()->numSlots() + STACK_JIT_EXTRA; + unsigned nvals = regs.fp()->script()->nslots + STACK_JIT_EXTRA; return ensureSpace(cx, report, regs.sp, nvals) ? conservativeEnd_ : NULL; @@ -472,7 +412,7 @@ ContextStack::getCallFrame(JSContext *cx, MaybeReportError report, const CallArg /* Include extra space to satisfy the method-jit stackLimit invariant. */ unsigned nvals = VALUES_PER_STACK_FRAME + script->nslots + StackSpace::STACK_JIT_EXTRA; - /* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */ + /* Maintain layout invariant: &formals[0] == ((Value *)fp) - nformal. */ if (args.length() == nformal) { if (!space().ensureSpace(cx, report, firstUnused, nvals)) @@ -564,9 +504,7 @@ ContextStack::popInlineFrame(FrameRegs ®s) JS_ASSERT(®s == &seg_->regs()); StackFrame *fp = regs.fp(); - fp->functionEpilogue(cx_); - - Value *newsp = fp->actualArgs() - 1; + Value *newsp = fp->actuals() - 1; JS_ASSERT(newsp >= fp->prev()->base()); newsp[-1] = fp->returnValue(); @@ -579,7 +517,7 @@ ContextStack::popFrameAfterOverflow() /* Restore the regs to what they were on entry to JSOP_CALL. */ FrameRegs ®s = seg_->regs(); StackFrame *fp = regs.fp(); - regs.popFrame(fp->actualArgsEnd()); + regs.popFrame(fp->actuals() + fp->numActualArgs()); } inline JSScript * diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 0d97b820be3b..ba73c7eae517 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -90,22 +90,22 @@ StackFrame::initDummyFrame(JSContext *cx, JSObject &chain) flags_ = DUMMY | HAS_PREVPC | HAS_SCOPECHAIN; initPrev(cx); JS_ASSERT(chain.isGlobal()); - setScopeChain(chain); + scopeChain_ = &chain; } template void -StackFrame::stealFrameAndSlots(JSContext *cx, StackFrame *fp, T *vp, +StackFrame::copyFrameAndValues(JSContext *cx, StackFrame *fp, T *vp, StackFrame *otherfp, U *othervp, Value *othersp) { JS_ASSERT((U *)vp == (U *)this - ((U *)otherfp - othervp)); - JS_ASSERT((Value *)othervp == otherfp->actualArgs() - 2); + JS_ASSERT((Value *)othervp == otherfp->generatorArgsSnapshotBegin()); JS_ASSERT(othersp >= otherfp->slots()); - JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots()); + JS_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots); JS_ASSERT((T *)fp - vp == (U *)otherfp - othervp); /* Copy args, StackFrame, and slots. */ - U *srcend = (U *)otherfp->formalArgsEnd(); + U *srcend = (U *)otherfp->generatorArgsSnapshotEnd(); T *dst = vp; for (U *src = othervp; src < srcend; src++, dst++) *dst = *src; @@ -119,39 +119,15 @@ StackFrame::stealFrameAndSlots(JSContext *cx, StackFrame *fp, T *vp, for (U *src = (U *)otherfp->slots(); src < srcend; src++, dst++) *dst = *src; - /* - * Repoint Call, Arguments, Block and With objects to the new live frame. - * Call and Arguments are done directly because we have pointers to them. - * Block and With objects are done indirectly through 'liveFrame'. See - * js_LiveFrameToFloating comment in jsiter.h. - */ - if (hasCallObj()) { - CallObject &obj = callObj(); - obj.setStackFrame(this); - otherfp->flags_ &= ~HAS_CALL_OBJ; - if (js_IsNamedLambda(fun())) { - DeclEnvObject &env = obj.enclosingScope().asDeclEnv(); - env.setStackFrame(this); - } - } - if (hasArgsObj()) { - ArgumentsObject &argsobj = argsObj(); - if (argsobj.isNormalArguments()) - argsobj.setStackFrame(this); - else - JS_ASSERT(!argsobj.maybeStackFrame()); - otherfp->flags_ &= ~HAS_ARGS_OBJ; - } - if (cx->compartment->debugMode()) cx->runtime->debugScopes->onGeneratorFrameChange(otherfp, this); } /* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */ -template void StackFrame::stealFrameAndSlots( +template void StackFrame::copyFrameAndValues( JSContext *, StackFrame *, Value *, StackFrame *, HeapValue *, Value *); -template void StackFrame::stealFrameAndSlots( +template void StackFrame::copyFrameAndValues( JSContext *, StackFrame *, HeapValue *, StackFrame *, Value *, Value *); @@ -163,7 +139,7 @@ StackFrame::writeBarrierPost() JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_); if (isDummyFrame()) return; - if (hasArgsObj()) + if (flags_ & HAS_ARGS_OBJ) JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_); if (isScriptFrame()) { if (isFunctionFrame()) { @@ -178,8 +154,29 @@ StackFrame::writeBarrierPost() HeapValue::writeBarrierPost(rval_, &rval_); } +JSGenerator * +StackFrame::maybeSuspendedGenerator(JSRuntime *rt) +{ + /* + * A suspended generator's frame is embedded inside the JSGenerator object + * instead of on the contiguous stack like all active frames. + */ + if (!isGeneratorFrame() || rt->stackSpace.containsFast(this)) + return NULL; + + /* + * Once we know we have a suspended generator frame, there is a static + * offset from the frame's snapshot to beginning of the JSGenerator. + */ + char *vp = reinterpret_cast(generatorArgsSnapshotBegin()); + char *p = vp - offsetof(JSGenerator, stackSnapshot); + JSGenerator *gen = reinterpret_cast(p); + JS_ASSERT(gen->fp == this); + return gen; +} + jsbytecode * -StackFrame::prevpcSlow(JSInlinedSite **pinlined) +StackFrame::prevpcSlow(InlinedSite **pinlined) { JS_ASSERT(!(flags_ & HAS_PREVPC)); #if defined(JS_METHODJIT) && defined(JS_MONOIC) @@ -197,7 +194,7 @@ StackFrame::prevpcSlow(JSInlinedSite **pinlined) } jsbytecode * -StackFrame::pcQuadratic(const ContextStack &stack, StackFrame *next, JSInlinedSite **pinlined) +StackFrame::pcQuadratic(const ContextStack &stack, StackFrame *next, InlinedSite **pinlined) { JS_ASSERT_IF(next, next->prev() == this); @@ -219,6 +216,116 @@ StackFrame::pcQuadratic(const ContextStack &stack, StackFrame *next, JSInlinedSi return next->prevpc(pinlined); } +bool +StackFrame::prologue(JSContext *cx, bool newType) +{ + JS_ASSERT(!isDummyFrame()); + JS_ASSERT(!isGeneratorFrame()); + JS_ASSERT(cx->regs().pc == script()->code); + + if (isEvalFrame()) { + if (script()->strictModeCode) { + CallObject *callobj = CallObject::createForStrictEval(cx, this); + if (!callobj) + return false; + pushOnScopeChain(*callobj); + flags_ |= HAS_CALL_OBJ; + } + return true; + } + + if (isGlobalFrame()) + return true; + + JS_ASSERT(isNonEvalFunctionFrame()); + + if (fun()->isHeavyweight()) { + CallObject *callobj = CallObject::createForFunction(cx, this); + if (!callobj) + return false; + pushOnScopeChain(*callobj); + flags_ |= HAS_CALL_OBJ; + } + + if (script()->nesting()) { + types::NestingPrologue(cx, this); + flags_ |= HAS_NESTING; + } + + if (isConstructing()) { + RootedObject callee(cx, &this->callee()); + JSObject *obj = js_CreateThisForFunction(cx, callee, newType); + if (!obj) + return false; + functionThis() = ObjectValue(*obj); + } + + Probes::enterJSFun(cx, fun(), script()); + return true; +} + +void +StackFrame::epilogue(JSContext *cx) +{ + JS_ASSERT(!isDummyFrame()); + JS_ASSERT(!isYielding()); + JS_ASSERT(!hasBlockChain()); + + if (isEvalFrame()) { + if (isStrictEvalFrame()) { + JS_ASSERT_IF(hasCallObj(), scopeChain()->asCall().isForEval()); + if (cx->compartment->debugMode()) + cx->runtime->debugScopes->onPopStrictEvalScope(this); + } else if (isDirectEvalFrame()) { + if (isDebuggerFrame()) + JS_ASSERT(!scopeChain()->isScope()); + else + JS_ASSERT(scopeChain() == prev()->scopeChain()); + } else { + JS_ASSERT(scopeChain()->isGlobal()); + } + return; + } + + if (isGlobalFrame()) { + JS_ASSERT(!scopeChain()->isScope()); + return; + } + + JS_ASSERT(isNonEvalFunctionFrame()); + if (fun()->isHeavyweight()) { + JS_ASSERT_IF(hasCallObj(), + scopeChain()->asCall().getCalleeFunction()->script() == script()); + } else { + JS_ASSERT(!scopeChain()->isCall() || scopeChain()->asCall().isForEval() || + scopeChain()->asCall().getCalleeFunction()->script() != script()); + } + + if (cx->compartment->debugMode()) + cx->runtime->debugScopes->onPopCall(this); + + Probes::exitJSFun(cx, fun(), script()); + + if (script()->nesting() && (flags_ & HAS_NESTING)) + types::NestingEpilogue(this); + + if (isConstructing() && returnValue().isPrimitive()) + setReturnValue(ObjectValue(constructorThis())); +} + +bool +StackFrame::jitStrictEvalPrologue(JSContext *cx) +{ + JS_ASSERT(isStrictEvalFrame()); + CallObject *callobj = CallObject::createForStrictEval(cx, this); + if (!callobj) + return false; + + pushOnScopeChain(*callobj); + flags_ |= HAS_CALL_OBJ; + return true; +} + bool StackFrame::pushBlock(JSContext *cx, StaticBlockObject &block) { @@ -230,7 +337,7 @@ StackFrame::pushBlock(JSContext *cx, StaticBlockObject &block) if (!clone) return false; - scopeChain_ = clone; + pushOnScopeChain(*clone); } flags_ |= HAS_BLOCKCHAIN; @@ -247,10 +354,8 @@ StackFrame::popBlock(JSContext *cx) cx->runtime->debugScopes->onPopBlock(cx, this); if (blockChain_->needsClone()) { - ClonedBlockObject &clone = scopeChain()->asClonedBlock(); - JS_ASSERT(clone.staticBlock() == *blockChain_); - clone.put(cx->fp()); - scopeChain_ = &clone.enclosingScope(); + JS_ASSERT(scopeChain_->asClonedBlock().staticBlock() == *blockChain_); + popOffScopeChain(); } blockChain_ = blockChain_->enclosingBlock(); @@ -262,7 +367,8 @@ StackFrame::popWith(JSContext *cx) if (cx->compartment->debugMode()) cx->runtime->debugScopes->onPopWith(this); - setScopeChain(scopeChain()->asWith().enclosingScope()); + JS_ASSERT(scopeChain()->isWith()); + popOffScopeChain(); } void @@ -277,7 +383,7 @@ StackFrame::mark(JSTracer *trc) gc::MarkObjectUnbarriered(trc, &scopeChain_, "scope chain"); if (isDummyFrame()) return; - if (hasArgsObj()) + if (flags_ & HAS_ARGS_OBJ) gc::MarkObjectUnbarriered(trc, &argsObj_, "arguments"); if (isFunctionFrame()) { gc::MarkObjectUnbarriered(trc, &exec.fun, "fun"); @@ -462,7 +568,7 @@ StackSpace::containingSegment(const StackFrame *target) const } void -StackSpace::markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc) +StackSpace::markFrameValues(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc) { Value *slotsBegin = fp->slots(); @@ -536,12 +642,12 @@ StackSpace::mark(JSTracer *trc) jsbytecode *pc = seg->maybepc(); for (StackFrame *fp = seg->maybefp(); (Value *)fp > (Value *)seg; fp = fp->prev()) { /* Mark from fp->slots() to slotsEnd. */ - markFrameSlots(trc, fp, slotsEnd, pc); + markFrameValues(trc, fp, slotsEnd, pc); fp->mark(trc); slotsEnd = (Value *)fp; - JSInlinedSite *site; + InlinedSite *site; pc = fp->prevpc(&site); JS_ASSERT_IF(fp->prev(), !site); } @@ -701,7 +807,7 @@ ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars */ if (FrameRegs *regs = cx->maybeRegs()) { JSFunction *fun = NULL; - if (JSInlinedSite *site = regs->inlined()) { + if (InlinedSite *site = regs->inlined()) { mjit::JITChunk *chunk = regs->fp()->jit()->chunk(regs->pc); fun = chunk->inlineFrames()[site->inlineIndex].fun; } else { @@ -852,7 +958,7 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi StackFrame *prev = evalInFrame ? evalInFrame : maybefp(); StackFrame *fp = reinterpret_cast(firstUnused + 2); fp->initExecuteFrame(script, prev, seg_->maybeRegs(), thisv, scopeChain, type); - SetValueRangeToUndefined(fp->slots(), script->nfixed); + fp->initVarsToUndefined(); efg->regs_.prepareToRun(*fp, script); /* pushRegs() below links the prev-frame; manually link the prev-call. */ @@ -894,9 +1000,6 @@ ContextStack::popFrame(const FrameGuard &fg) JS_ASSERT(space().firstUnused() == fg.regs_.sp); JS_ASSERT(&fg.regs_ == &seg_->regs()); - if (fg.regs_.fp()->isNonEvalFunctionFrame()) - fg.regs_.fp()->functionEpilogue(cx_); - seg_->popRegs(fg.prevRegs_); if (fg.pushedSeg_) popSegment(); @@ -912,11 +1015,11 @@ ContextStack::popFrame(const FrameGuard &fg) bool ContextStack::pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg) { - StackFrame *genfp = gen->floatingFrame(); - HeapValue *genvp = gen->floatingStack; - unsigned vplen = (HeapValue *)genfp - genvp; + HeapValue *genvp = gen->stackSnapshot; + JS_ASSERT(genvp == HeapValueify(gen->fp->generatorArgsSnapshotBegin())); + unsigned vplen = HeapValueify(gen->fp->generatorArgsSnapshotEnd()) - genvp; - unsigned nvars = vplen + VALUES_PER_STACK_FRAME + genfp->numSlots(); + unsigned nvars = vplen + VALUES_PER_STACK_FRAME + gen->fp->script()->nslots; Value *firstUnused = ensureOnTop(cx, REPORT_ERROR, nvars, CAN_EXTEND, &gfg->pushedSeg_); if (!firstUnused) return false; @@ -935,15 +1038,13 @@ ContextStack::pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrame * We don't need to worry about generational barriers as the generator * object has a trace hook and cannot be nursery allocated. */ - JSObject *genobj = js_FloatingFrameToGenerator(genfp)->obj; - JS_ASSERT(genobj->getClass()->trace); - JSObject::writeBarrierPre(genobj); + JS_ASSERT(gen->obj->getClass()->trace); + JSObject::writeBarrierPre(gen->obj); /* Copy from the generator's floating frame to the stack. */ - stackfp->stealFrameAndSlots( - cx, stackfp, stackvp, genfp, genvp, gen->regs.sp); + stackfp->copyFrameAndValues( + cx, stackfp, stackvp, gen->fp, genvp, gen->regs.sp); stackfp->resetGeneratorPrev(cx); - stackfp->unsetFloatingGenerator(); gfg->regs_.rebaseFromTo(gen->regs, *stackfp); gfg->prevRegs_ = seg_->pushRegs(gfg->regs_); @@ -956,18 +1057,19 @@ void ContextStack::popGeneratorFrame(const GeneratorFrameGuard &gfg) { JSGenerator *gen = gfg.gen_; - StackFrame *genfp = gen->floatingFrame(); - HeapValue *genvp = gen->floatingStack; + HeapValue *genvp = gen->stackSnapshot; + JS_ASSERT(genvp == HeapValueify(gen->fp->generatorArgsSnapshotBegin())); const FrameRegs &stackRegs = gfg.regs_; StackFrame *stackfp = stackRegs.fp(); Value *stackvp = gfg.stackvp_; /* Copy from the stack to the generator's floating frame. */ - gen->regs.rebaseFromTo(stackRegs, *genfp); - genfp->stealFrameAndSlots( - cx_, genfp, genvp, stackfp, stackvp, stackRegs.sp); - genfp->setFloatingGenerator(); + if (stackfp->isYielding()) { + gen->regs.rebaseFromTo(stackRegs, *gen->fp); + gen->fp->copyFrameAndValues( + cx_, gen->fp, genvp, stackfp, stackvp, stackRegs.sp); + } /* ~FrameGuard/popFrame will finish the popping. */ JS_ASSERT(ImplicitCast(gfg).pushed()); @@ -1016,7 +1118,7 @@ StackIter::popFrame() JS_ASSERT(seg_->contains(oldfp)); fp_ = fp_->prev(); if (seg_->contains(fp_)) { - JSInlinedSite *inline_; + InlinedSite *inline_; pc_ = oldfp->prevpc(&inline_); JS_ASSERT(!inline_); @@ -1029,7 +1131,7 @@ StackIter::popFrame() */ if (oldfp->isGeneratorFrame()) { /* Generator's args do not overlap with the caller's expr stack. */ - sp_ = (Value *)oldfp->actualArgs() - 2; + sp_ = oldfp->generatorArgsSnapshotBegin(); } else if (oldfp->isNonEvalFunctionFrame()) { /* * When Invoke is called from a native, there will be an enclosing @@ -1039,7 +1141,7 @@ StackIter::popFrame() * cases, the actual arguments of the callee should be included in * the caller's expr stack. */ - sp_ = oldfp->actualArgsEnd(); + sp_ = oldfp->actuals() + oldfp->numActualArgs(); } else if (oldfp->isFramePushedByExecute()) { /* pushExecuteFrame pushes exactly (callee, this) before frame. */ sp_ = (Value *)oldfp - 2; @@ -1094,7 +1196,8 @@ StackIter::startOnSegment(StackSegment *seg) static void JS_NEVER_INLINE CrashIfInvalidSlot(StackFrame *fp, Value *vp) { - if (vp < fp->slots() || vp >= fp->slots() + fp->script()->nslots) { + Value *slots = (Value *)(fp + 1); + if (vp < slots || vp >= slots + fp->script()->nslots) { JS_ASSERT(false && "About to dereference invalid slot"); *(int *)0xbad = 0; // show up nicely in crash-stats MOZ_Assert("About to dereference invalid slot", __FILE__, __LINE__); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 61c1a7165e28..812f62bc74d4 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -14,14 +14,7 @@ struct JSContext; struct JSCompartment; -#ifdef JS_METHODJIT -namespace js { namespace mjit { struct CallSite; }} -typedef js::mjit::CallSite JSInlinedSite; -#else -struct JSInlinedSite {}; -#endif - -typedef /* js::mjit::RejoinState */ size_t JSRejoinState; +extern void js_DumpStackFrame(JSContext *, js::StackFrame *); namespace js { @@ -49,10 +42,18 @@ class StaticBlockObject; #ifdef JS_METHODJIT namespace mjit { + class CallCompiler; + class GetPropCompiler; + struct CallSite; struct JITScript; jsbytecode *NativeToPC(JITScript *jit, void *ncode, CallSite **pinline); + namespace ic { struct GetElementIC; } } +typedef mjit::CallSite InlinedSite; +#else +struct InlinedSite {}; #endif +typedef size_t FrameRejoinState; namespace detail { struct OOMCheck; @@ -63,10 +64,9 @@ namespace detail { /* * VM stack layout * - * SpiderMonkey uses a per-thread stack to store the activation records, + * SpiderMonkey uses a per-runtime stack to store the activation records, * parameters, locals, and expression temporaries for the stack of actively - * executing scripts, functions and generators. The stack is owned by the - * StackSpace object stored in the runtime. + * executing scripts, functions and generators. * * The stack is subdivided into contiguous segments of memory which * have a memory layout invariant that allows fixed offsets to be used for stack @@ -78,13 +78,13 @@ namespace detail { * A sample memory layout of a segment looks like: * * regs - * .---------------------------------------------. - * | V - * | fp .--FrameRegs--. sp - * | V V - * |StackSegment| slots |StackFrame| slots |StackFrame| slots | - * | ^ | - * ? <----------' `-----------' + * .------------------------------------------------. + * | V + * | fp .--FrameRegs--. sp + * | V V + * |StackSegment| values |StackFrame| values |StackFrame| values | + * | ^ | + * ? <-----------' `------------' * prev prev * * A segment starts with a fixed-size header (js::StackSegment) which logically @@ -92,14 +92,14 @@ namespace detail { * end of the stack. * * Each script activation (global or function code) is given a fixed-size header - * (js::StackFrame) which is associated with the values (called "slots") before - * and after it. The frame contains bookkeeping information about the activation - * and links to the previous frame. + * (js::StackFrame) which is associated with the values before and after it. + * The frame contains bookkeeping information about the activation and links to + * the previous frame. * - * The slots preceding a (function) StackFrame in memory are the arguments of - * the call. The slots after a StackFrame in memory are its locals followed by + * The value preceding a (function) StackFrame in memory are the arguments of + * the call. The values after a StackFrame in memory are its locals followed by * its expression stack. There is no clean line between the arguments of a - * frame and the expression stack of the previous frame since the top slots of + * frame and the expression stack of the previous frame since the top values of * the expression become the arguments of a call. There are also layout * invariants concerning the arguments and StackFrame; see "Arguments" comment * in StackFrame for more details. @@ -115,20 +115,20 @@ namespace detail { * A call to a native (C++) function does not push a frame. Instead, an array * of values is passed to the native. The layout of this array is abstracted by * js::CallArgs. With respect to the StackSegment layout above, the args to a - * native call are inserted anywhere there can be slots. A sample memory layout + * native call are inserted anywhere there can be values. A sample memory layout * looks like: * * regs - * .----------------------------------------. - * | V - * | fp .--FrameRegs--. sp - * | V V - * |StackSegment| native call | slots |StackFrame| slots | native call | - * | vp <--argc--> end vp <--argc--> end - * | CallArgs <------------------------------ CallArgs - * | prev ^ - * `-----------------------------------------------------' - * calls + * .------------------------------------------. + * | V + * | fp .--FrameRegs--. sp + * | V V + * |StackSegment| native call | values |StackFrame| values | native call | + * | vp <--argc--> end vp <--argc--> end + * | CallArgs <------------------------------ CallArgs + * | prev ^ + * `-------------------------------------------------------' + * calls * * Here there are two native calls on the stack. The start of each native arg * range is recorded by a CallArgs element which is prev-linked like stack @@ -295,10 +295,14 @@ CallArgsListFromVp(unsigned argc, Value *vp, CallArgsList *prev) /*****************************************************************************/ +enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false }; + +/*****************************************************************************/ + /* Flags specified for a frame as it is constructed. */ enum InitialFrameFlags { INITIAL_NONE = 0, - INITIAL_CONSTRUCT = 0x80, /* == StackFrame::CONSTRUCTING, asserted below */ + INITIAL_CONSTRUCT = 0x40, /* == StackFrame::CONSTRUCTING, asserted below */ INITIAL_LOWERED = 0x200000 /* == StackFrame::LOWERED_CALL_APPLY, asserted below */ }; @@ -324,20 +328,22 @@ class StackFrame EVAL = 0x8, /* frame pushed for eval() or debugger eval */ DEBUGGER = 0x10, /* frame pushed for debugger eval */ GENERATOR = 0x20, /* frame is associated with a generator */ - FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */ - CONSTRUCTING = 0x80, /* frame is for a constructor invocation */ + CONSTRUCTING = 0x40, /* frame is for a constructor invocation */ /* Temporary frame states */ - YIELDING = 0x100, /* js::Interpret dispatched JSOP_YIELD */ - FINISHED_IN_INTERP = 0x200, /* set if frame finished in Interpret() */ + YIELDING = 0x80, /* Interpret dispatched JSOP_YIELD */ + FINISHED_IN_INTERP = 0x100, /* set if frame finished in Interpret() */ /* Function arguments */ - OVERFLOW_ARGS = 0x400, /* numActualArgs > numFormalArgs */ - UNDERFLOW_ARGS = 0x800, /* numActualArgs < numFormalArgs */ + OVERFLOW_ARGS = 0x200, /* numActualArgs > numFormalArgs */ + UNDERFLOW_ARGS = 0x400, /* numActualArgs < numFormalArgs */ + + /* Function prologue state */ + HAS_CALL_OBJ = 0x800, /* CallObject created for heavyweight fun */ + HAS_ARGS_OBJ = 0x1000, /* ArgumentsObject created for needsArgsObj script */ + HAS_NESTING = 0x2000, /* NestingPrologue called for frame */ /* Lazy frame initialization */ - HAS_CALL_OBJ = 0x1000, /* frame has a callobj reachable from scopeChain_ */ - HAS_ARGS_OBJ = 0x2000, /* frame has an argsobj in StackFrame::args */ HAS_HOOK_DATA = 0x4000, /* frame has hookData_ set */ HAS_ANNOTATION = 0x8000, /* frame has annotation_ set */ HAS_RVAL = 0x10000, /* frame has rval_ set */ @@ -360,22 +366,20 @@ class StackFrame JSFunction *fun; /* function frame, pre GetScopeChain */ } exec; union { /* describes the arguments of a function */ - unsigned nactual; /* for non-eval frames */ + unsigned nactual; /* for non-eval frames */ JSScript *evalScript; /* the script of an eval-in-function */ } u; - mutable JSObject *scopeChain_; /* current scope chain */ - StackFrame *prev_; /* previous cx->regs->fp */ - void *ncode_; /* return address for method JIT */ - - /* Lazily initialized */ - Value rval_; /* return value of the frame */ - StaticBlockObject *blockChain_; /* innermost let block */ - ArgumentsObject *argsObj_; /* if has HAS_ARGS_OBJ */ - jsbytecode *prevpc_; /* pc of previous frame*/ - JSInlinedSite *prevInline_; /* inlined site in previous frame */ - void *hookData_; /* closure returned by call hook */ - void *annotation_; /* perhaps remove with bug 546848 */ - JSRejoinState rejoin_; /* If rejoining into the interpreter + mutable JSObject *scopeChain_; /* if HAS_SCOPECHAIN, current scope chain */ + StackFrame *prev_; /* if HAS_PREVPC, previous cx->regs->fp */ + void *ncode_; /* for a jit frame, return address for method JIT */ + Value rval_; /* if HAS_RVAL, return value of the frame */ + StaticBlockObject *blockChain_; /* if HAS_BLOCKCHAIN, innermost let block */ + ArgumentsObject *argsObj_; /* if HAS_ARGS_OBJ, the call's arguments object */ + jsbytecode *prevpc_; /* if HAS_PREVPC, pc of previous frame*/ + InlinedSite *prevInline_; /* for a jit frame, inlined site in previous frame */ + void *hookData_; /* if HAS_HOOK_DATA, closure returned by call hook */ + void *annotation_; /* if HAS_ANNOTATION, perhaps remove with bug 546848 */ + FrameRejoinState rejoin_; /* for a jit frame rejoining the interpreter * from JIT code, state at rejoin. */ static void staticAsserts() { @@ -384,15 +388,39 @@ class StackFrame } inline void initPrev(JSContext *cx); - jsbytecode *prevpcSlow(JSInlinedSite **pinlined); + jsbytecode *prevpcSlow(InlinedSite **pinlined); + void writeBarrierPost(); - public: /* - * Frame initialization - * - * After acquiring a pointer to an uninitialized stack frame on the VM - * stack from StackSpace, these members are used to initialize the stack - * frame before officially pushing the frame into the context. + * These utilities provide raw access to the values associated with a + * StackFrame (see "VM stack layout" comment). The utilities are private + * since they are not able to assert that only unaliased vars/formals are + * accessed. Normal code should prefer the StackFrame::unaliased* members + * (or FrameRegs::stackDepth for the usual "depth is at least" assertions). + */ + Value *slots() const { return (Value *)(this + 1); } + Value *base() const { return slots() + script()->nfixed; } + Value *formals() const { return (Value *)this - fun()->nargs; } + Value *actuals() const { return formals() - (flags_ & OVERFLOW_ARGS ? 2 + u.nactual : 0); } + + friend class FrameRegs; + friend class ContextStack; + friend class StackSpace; + friend class StackIter; + friend class CallObject; + friend class ClonedBlockObject; + friend class ArgumentsObject; + friend void ::js_DumpStackFrame(JSContext *, StackFrame *); + friend void ::js_ReportIsNotFunction(JSContext *, const js::Value *, unsigned); +#ifdef JS_METHODJIT + friend class mjit::CallCompiler; + friend class mjit::GetPropCompiler; + friend class mjit::ic::GetElementIC; +#endif + + /* + * Frame initialization, called by ContextStack operations after acquiring + * the raw memory for the frame: */ /* Used for Invoke, Interpret, trace-jit LeaveTree, and method-jit stubs. */ @@ -406,19 +434,43 @@ class StackFrame void initExecuteFrame(JSScript *script, StackFrame *prev, FrameRegs *regs, const Value &thisv, JSObject &scopeChain, ExecuteType type); - /* Used when activating generators. */ - enum TriggerPostBarriers { - DoPostBarrier = true, - NoPostBarrier = false - }; - template - void stealFrameAndSlots(JSContext *cx, StackFrame *fp, T *vp, - StackFrame *otherfp, U *othervp, Value *othersp); - void writeBarrierPost(); - /* Perhaps one fine day we will remove dummy frames. */ void initDummyFrame(JSContext *cx, JSObject &chain); + public: + /* + * Frame prologue/epilogue + * + * Every stack frame must have 'prologue' called before executing the + * first op and 'epilogue' called after executing the last op and before + * popping the frame (whether the exit is exceptional or not). + * + * For inline JS calls/returns, it is easy to call the prologue/epilogue + * exactly once. When calling JS from C++, Invoke/Execute push the stack + * frame but do *not* call the prologue/epilogue. That means Interpret + * must call the prologue/epilogue for the entry frame. This scheme + * simplifies jit compilation. + * + * An important corner case is what happens when an error occurs (OOM, + * over-recursed) after pushing the stack frame but before 'prologue' is + * called or completes fully. To simplify usage, 'epilogue' does not assume + * 'prologue' has completed and handles all the intermediate state details. + * + * The 'newType' option indicates whether the constructed 'this' value (if + * there is one) should be given a new singleton type. + */ + + bool prologue(JSContext *cx, bool newType); + void epilogue(JSContext *cx); + + /* Subsets of 'prologue' called from jit code. */ + inline bool jitHeavyweightFunctionPrologue(JSContext *cx); + inline void jitTypeNestingPrologue(JSContext *cx); + bool jitStrictEvalPrologue(JSContext *cx); + + /* Initialize local variables of newly-pushed frame. */ + void initVarsToUndefined(); + /* * Stack frame type * @@ -507,39 +559,124 @@ class StackFrame } inline void resetGeneratorPrev(JSContext *cx); - inline void resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc); - inline void initInlineFrame(JSFunction *fun, StackFrame *prevfp, jsbytecode *prevpc); + /* + * (Unaliased) locals and arguments + * + * Only non-eval function frames have arguments. The arguments pushed by + * the caller are the 'actual' arguments. The declared arguments of the + * callee are the 'formal' arguments. When the caller passes less or equal + * actual arguments, the actual and formal arguments are the same array + * (but with different extents). When the caller passes too many arguments, + * the formal subset of the actual arguments is copied onto the top of the + * stack. This allows the engine to maintain a jit-time constant offset of + * arguments from the frame pointer. Since the formal subset of the actual + * arguments is potentially on the stack twice, it is important for all + * reads/writes to refer to the same canonical memory location. This is + * abstracted by the unaliased{Formal,Actual} methods. + * + * When a local/formal variable is "aliased" (accessed by nested closures, + * dynamic scope operations, or 'arguments), the canonical location for + * that value is the slot of an activation object (scope or arguments). + * Currently, all variables are given slots in *both* the stack frame and + * heap objects, even though, as just described, only one should ever be + * accessed. Thus, it is up to the code performing an access to access the + * correct value. These functions assert that accesses to stack values are + * unaliased. For more about canonical values locations. + */ + + inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing = CHECK_ALIASING); + inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING); + + bool hasArgs() const { return isNonEvalFunctionFrame(); } + inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING); + inline Value &unaliasedActual(unsigned i); + template inline void forEachUnaliasedActual(Op op); + + inline unsigned numFormalArgs() const; + inline unsigned numActualArgs() const; + + /* + * Arguments object + * + * If a non-eval function has script->needsArgsObj, an arguments object is + * created in the prologue and stored in the local variable for the + * 'arguments' binding (script->argumentsLocal). Since this local is + * mutable, the arguments object can be overwritten and we can "lose" the + * arguments object. Thus, StackFrame keeps an explicit argsObj_ field so + * that the original arguments object is always available. + */ + + ArgumentsObject &argsObj() const; + void initArgsObj(ArgumentsObject &argsobj); inline JSObject *createRestParameter(JSContext *cx); /* - * Frame slots + * Scope chain * - * A frame's 'slots' are the fixed slots associated with the frame (like - * local variables) followed by an expression stack holding temporary - * values. A frame's 'base' is the base of the expression stack. + * In theory, the scope chain would contain an object for every lexical + * scope. However, only objects that are required for dynamic lookup are + * actually created. + * + * Given that a (non-dummy) StackFrame corresponds roughly to a ES5 + * Execution Context (ES5 10.3), StackFrame::varObj corresponds to the + * VariableEnvironment component of a Exection Context. Intuitively, the + * variables object is where new bindings (variables and functions) are + * stored. One might expect that this is either the Call object or + * scopeChain.globalObj for function or global code, respectively, however + * the JSAPI allows calls of Execute to specify a variables object on the + * scope chain other than the call/global object. This allows embeddings to + * run multiple scripts under the same global, each time using a new + * variables object to collect and discard the script's global variables. */ - Value *slots() const { - return (Value *)(this + 1); + inline HandleObject scopeChain() const; + + inline ScopeObject &aliasedVarScope(ScopeCoordinate sc) const; + inline GlobalObject &global() const; + inline CallObject &callObj() const; + inline JSObject &varObj(); + + inline void pushOnScopeChain(ScopeObject &scope); + inline void popOffScopeChain(); + + /* + * Block chain + * + * Entering/leaving a let (or exception) block may do 1 or 2 things: First, + * a static block object (created at compiled time and stored in the + * script) is pushed on StackFrame::blockChain. Second, if the static block + * may be cloned to hold the dynamic values if this is needed for dynamic + * scope access. A clone is created for a static block iff + * StaticBlockObject::needsClone. + */ + + bool hasBlockChain() const { + return (flags_ & HAS_BLOCKCHAIN) && blockChain_; } - Value *base() const { - return slots() + script()->nfixed; + StaticBlockObject *maybeBlockChain() { + return (flags_ & HAS_BLOCKCHAIN) ? blockChain_ : NULL; } - Value &varSlot(unsigned i) { - JS_ASSERT(i < script()->nfixed); - JS_ASSERT_IF(maybeFun(), i < script()->bindings.numVars()); - return slots()[i]; + StaticBlockObject &blockChain() const { + JS_ASSERT(hasBlockChain()); + return *blockChain_; } - Value &localSlot(unsigned i) { - /* Let variables can be above script->nfixed. */ - JS_ASSERT(i < script()->nslots); - return slots()[i]; - } + bool pushBlock(JSContext *cx, StaticBlockObject &block); + void popBlock(JSContext *cx); + + /* + * With + * + * Entering/leaving a with (or E4X filter) block pushes/pops an object + * on the scope chain. Pushing uses pushOnScopeChain, popping should use + * popWith. + */ + + void popWith(JSContext *cx); /* * Script @@ -556,6 +693,17 @@ class StackFrame * the same VMFrame. Other calls force expansion of the inlined frames. */ + JSScript *script() const { + JS_ASSERT(isScriptFrame()); + return isFunctionFrame() + ? isEvalFrame() ? u.evalScript : fun()->script() + : exec.script; + } + + JSScript *maybeScript() const { + return isScriptFrame() ? script() : NULL; + } + /* * Get the frame's current bytecode, assuming |this| is in |cx|. next is * frame whose prev == this, NULL if not known or if this == cx->fp(). @@ -571,15 +719,12 @@ class StackFrame * * Using next can avoid this, but in most cases prefer ScriptFrameIter; * it is amortized O(1). - * - * When I get to the bottom I go back to the top of the stack - * Where I stop and I turn and I go right back - * Till I get to the bottom and I see you again... */ - jsbytecode *pcQuadratic(const ContextStack &stack, StackFrame *next = NULL, - JSInlinedSite **pinlined = NULL); - jsbytecode *prevpc(JSInlinedSite **pinlined) { + jsbytecode *pcQuadratic(const ContextStack &stack, StackFrame *next = NULL, + InlinedSite **pinlined = NULL); + + jsbytecode *prevpc(InlinedSite **pinlined) { if (flags_ & HAS_PREVPC) { if (pinlined) *pinlined = prevInline_; @@ -588,45 +733,11 @@ class StackFrame return prevpcSlow(pinlined); } - JSInlinedSite *prevInline() { + InlinedSite *prevInline() { JS_ASSERT(flags_ & HAS_PREVPC); return prevInline_; } - JSScript *script() const { - JS_ASSERT(isScriptFrame()); - return isFunctionFrame() - ? isEvalFrame() ? u.evalScript : fun()->script() - : exec.script; - } - - JSScript *functionScript() const { - JS_ASSERT(isFunctionFrame()); - return isEvalFrame() ? u.evalScript : fun()->script(); - } - - JSScript *globalScript() const { - JS_ASSERT(isGlobalFrame()); - return exec.script; - } - - JSScript *maybeScript() const { - return isScriptFrame() ? script() : NULL; - } - - size_t numFixed() const { - return script()->nfixed; - } - - size_t numSlots() const { - return script()->nslots; - } - - size_t numGlobalVars() const { - JS_ASSERT(isGlobalFrame()); - return exec.script->nfixed; - } - /* * Function * @@ -654,94 +765,6 @@ class StackFrame return fp->script()->function(); } - /* - * Arguments - * - * Only non-eval function frames have arguments. A frame follows its - * arguments contiguously in memory. The arguments pushed by the caller are - * the 'actual' arguments. The declared arguments of the callee are the - * 'formal' arguments. When the caller passes less or equal actual - * arguments, the actual and formal arguments are the same array (but with - * different extents). When the caller passes too many arguments, the - * formal subset of the actual arguments is copied onto the top of the - * stack. This allows the engine to maintain a jit-time constant offset of - * arguments from the frame pointer. Since the formal subset of the actual - * arguments is potentially on the stack twice, it is important for all - * reads/writes to refer to the same canonical memory location. - * - * An arguments object (the object returned by the 'arguments' keyword) is - * lazily created, so a given function frame may or may not have one. - */ - - /* True if this frame has arguments. Contrast with hasArgsObj. */ - bool hasArgs() const { - return isNonEvalFunctionFrame(); - } - - unsigned numFormalArgs() const { - JS_ASSERT(hasArgs()); - return fun()->nargs; - } - - Value &formalArg(unsigned i) const { - JS_ASSERT(i < numFormalArgs()); - return formalArgs()[i]; - } - - Value *formalArgs() const { - JS_ASSERT(hasArgs()); - return (Value *)this - numFormalArgs(); - } - - Value *formalArgsEnd() const { - JS_ASSERT(hasArgs()); - return (Value *)this; - } - - Value *maybeFormalArgs() const { - return (flags_ & (FUNCTION | EVAL)) == FUNCTION - ? formalArgs() - : NULL; - } - - inline unsigned numActualArgs() const; - inline Value *actualArgs() const; - inline Value *actualArgsEnd() const; - - inline Value &canonicalActualArg(unsigned i) const; - template - inline bool forEachCanonicalActualArg(Op op, unsigned start = 0, unsigned count = unsigned(-1)); - template inline bool forEachFormalArg(Op op); - - /* XXX: all these argsObj functions will be removed with bug 659577. */ - - bool hasArgsObj() const { - /* - * HAS_ARGS_OBJ is still technically not equivalent to - * script()->needsArgsObj() during functionPrologue (where GC can - * observe a frame that needsArgsObj but has not yet been given the - * args). This can be fixed by creating and rooting the args/call - * object before pushing the frame, which should be done eventually. - */ - return !!(flags_ & HAS_ARGS_OBJ); - } - - ArgumentsObject &argsObj() const { - JS_ASSERT(hasArgsObj()); - return *argsObj_; - } - - ArgumentsObject *maybeArgsObj() const { - return hasArgsObj() ? &argsObj() : NULL; - } - - void initArgsObj(ArgumentsObject &argsObj) { - JS_ASSERT(script()->needsArgsObj()); - JS_ASSERT(!hasArgsObj()); - argsObj_ = &argsObj; - flags_ |= HAS_ARGS_OBJ; - } - /* * This value * @@ -752,31 +775,25 @@ class StackFrame * frames and directly before the frame for global frames. The *Args * members assert !isEvalFrame(), so we implement specialized inline * methods for accessing 'this'. When the caller has static knowledge that - * a frame is a function or global frame, 'functionThis' and 'globalThis', - * respectively, allow more efficient access. + * a frame is a function, 'functionThis' allows more efficient access. */ Value &functionThis() const { JS_ASSERT(isFunctionFrame()); if (isEvalFrame()) return ((Value *)this)[-1]; - return formalArgs()[-1]; + return formals()[-1]; } JSObject &constructorThis() const { JS_ASSERT(hasArgs()); - return formalArgs()[-1].toObject(); - } - - Value &globalThis() const { - JS_ASSERT(isGlobalFrame()); - return ((Value *)this)[-1]; + return formals()[-1].toObject(); } Value &thisValue() const { if (flags_ & (EVAL | GLOBAL)) return ((Value *)this)[-1]; - return formalArgs()[-1]; + return formals()[-1]; } /* @@ -802,7 +819,7 @@ class StackFrame JS_ASSERT(isScriptFrame()); Value &calleev = flags_ & (EVAL | GLOBAL) ? ((Value *)this)[-2] - : formalArgs()[-2]; + : formals()[-2]; JS_ASSERT(calleev.isObjectOrNull()); return calleev; } @@ -811,118 +828,13 @@ class StackFrame JS_ASSERT(isFunctionFrame()); if (isEvalFrame()) return ((Value *)this)[-2]; - return formalArgs()[-2]; + return formals()[-2]; } CallReceiver callReceiver() const { - return CallReceiverFromArgv(formalArgs()); + return CallReceiverFromArgv(formals()); } - /* - * Scope chain - * - * Every frame has a scopeChain which, when traversed via the 'parent' link - * to the root, indicates the current global object. A 'call object' is a - * node on a scope chain representing a function's activation record. A - * call object is used for dynamically-scoped name lookup and lexically- - * scoped upvar access. The call object holds the values of locals and - * arguments when a function returns (and its stack frame is popped). For - * performance reasons, call objects are created lazily for 'lightweight' - * functions, i.e., functions which are not statically known to require a - * call object. Thus, a given function frame may or may not have a call - * object. When a function does have a call object, it is found by walking - * up the scope chain until the first call object. Thus, it is important, - * when setting the scope chain, to indicate whether the new scope chain - * contains a new call object and thus changes the 'hasCallObj' state. - * - * The method JIT requires that HAS_SCOPECHAIN be set for all frames which - * use NAME or related opcodes that can access the scope chain (so it does - * not have to test the bit). To ensure this, we always initialize the - * scope chain when pushing frames in the VM, and only initialize it when - * pushing frames in JIT code when the above situation applies. - * - * NB: 'fp->hasCallObj()' implies that fp->callObj() needs to be 'put' when - * the frame is popped. Since the scope chain of a non-strict eval frame - * contains the call object of the parent (function) frame, it is possible - * to have: - * !fp->hasCall() && fp->scopeChain().isCall() - */ - - inline HandleObject scopeChain() const; - inline ScopeObject &aliasedVarScope(ScopeCoordinate sc) const; - inline GlobalObject &global() const; - - bool hasCallObj() const { - bool ret = !!(flags_ & HAS_CALL_OBJ); - JS_ASSERT_IF(ret, !isNonStrictEvalFrame()); - return ret; - } - - inline CallObject &callObj() const; - inline void initScopeChain(CallObject &callobj); - inline void setScopeChain(JSObject &obj); - - /* - * Variables object - * - * Given that a (non-dummy) StackFrame corresponds roughly to a ES5 - * Execution Context (ES5 10.3), StackFrame::varObj corresponds to the - * VariableEnvironment component of a Exection Context. Intuitively, the - * variables object is where new bindings (variables and functions) are - * stored. One might expect that this is either the callObj or - * scopeChain.globalObj for function or global code, respectively, however - * the JSAPI allows calls of Execute to specify a variables object on the - * scope chain other than the call/global object. This allows embeddings to - * run multiple scripts under the same global, each time using a new - * variables object to collect and discard the script's global variables. - */ - - inline JSObject &varObj(); - - /* Block chain */ - - bool hasBlockChain() const { - return (flags_ & HAS_BLOCKCHAIN) && blockChain_; - } - - StaticBlockObject *maybeBlockChain() { - return (flags_ & HAS_BLOCKCHAIN) ? blockChain_ : NULL; - } - - StaticBlockObject &blockChain() const { - JS_ASSERT(hasBlockChain()); - return *blockChain_; - } - - /* Enter/exit execution of a lexical block. */ - bool pushBlock(JSContext *cx, StaticBlockObject &block); - void popBlock(JSContext *cx); - - /* Exits (via execution or exception) a with block. */ - void popWith(JSContext *cx); - - /* - * Prologue for function frames: make a call object for heavyweight - * functions, and maintain type nesting invariants. - */ - inline bool functionPrologue(JSContext *cx); - - /* - * Epilogue for function frames: put any args or call object for the frame - * which may still be live, and maintain type nesting invariants. Note: - * this does mark the epilogue as having been completed, since the frame is - * about to be popped. Use updateEpilogueFlags for this. - */ - inline void functionEpilogue(JSContext *cx); - - /* - * If callObj() or argsObj() have already been put, update our flags - * accordingly. This call must be followed by a later functionEpilogue. - */ - inline void updateEpilogueFlags(); - - inline bool maintainNestingState() const; - /* * Frame compartment * @@ -945,11 +857,11 @@ class StackFrame /* JIT rejoin state */ - JSRejoinState rejoin() const { + FrameRejoinState rejoin() const { return rejoin_; } - void setRejoin(JSRejoinState state) { + void setRejoin(FrameRejoinState state) { rejoin_ = state; } @@ -1024,35 +936,53 @@ class StackFrame } /* - * Generator-specific members - * - * A non-eval function frame may optionally be the activation of a - * generator. For the most part, generator frames act like ordinary frames. - * For exceptions, see js_FloatingFrameIfGenerator. + * A "generator" frame is a function frame associated with a generator. + * Since generators are not executed LIFO, the VM copies a single abstract + * generator frame back and forth between the LIFO VM stack (when the + * generator is active) and a snapshot stored in JSGenerator (when the + * generator is inactive). A generator frame is comprised of a StackFrame + * structure and the values that make up the arguments, locals, and + * expression stack. The layout in the JSGenerator snapshot matches the + * layout on the stack (see the "VM stack layout" comment above). */ bool isGeneratorFrame() const { - return !!(flags_ & GENERATOR); + bool ret = flags_ & GENERATOR; + JS_ASSERT_IF(ret, isNonEvalFunctionFrame()); + return ret; } - bool isFloatingGenerator() const { - JS_ASSERT_IF(flags_ & FLOATING_GENERATOR, isGeneratorFrame()); - return !!(flags_ & FLOATING_GENERATOR); + void initGeneratorFrame() const { + JS_ASSERT(!isGeneratorFrame()); + JS_ASSERT(isNonEvalFunctionFrame()); + flags_ |= GENERATOR; } - void initFloatingGenerator() { - JS_ASSERT(!(flags_ & GENERATOR)); - flags_ |= (GENERATOR | FLOATING_GENERATOR); + Value *generatorArgsSnapshotBegin() const { + JS_ASSERT(isGeneratorFrame()); + return actuals() - 2; } - void unsetFloatingGenerator() { - flags_ &= ~FLOATING_GENERATOR; + Value *generatorArgsSnapshotEnd() const { + JS_ASSERT(isGeneratorFrame()); + return (Value *)this; } - void setFloatingGenerator() { - flags_ |= FLOATING_GENERATOR; + Value *generatorSlotsSnapshotBegin() const { + JS_ASSERT(isGeneratorFrame()); + return (Value *)(this + 1); } + enum TriggerPostBarriers { + DoPostBarrier = true, + NoPostBarrier = false + }; + template + void copyFrameAndValues(JSContext *cx, StackFrame *fp, T *vp, + StackFrame *otherfp, U *othervp, Value *othersp); + + JSGenerator *maybeSuspendedGenerator(JSRuntime *rt); + /* * js::Execute pushes both global and function frames (since eval() in a * function pushes a frame with isFunctionFrame() && isEvalFrame()). Most @@ -1081,6 +1011,11 @@ class StackFrame return !!(flags_ & CONSTRUCTING); } + bool hasCallObj() const { + JS_ASSERT(isStrictEvalFrame() || fun()->isHeavyweight()); + return flags_ & HAS_CALL_OBJ; + } + /* * The method JIT call/apply optimization can erase Function.{call,apply} * invocations from the stack and push the callee frame directly. The base @@ -1103,10 +1038,6 @@ class StackFrame flags_ |= PREV_UP_TO_DATE; } - bool hasOverflowArgs() const { - return !!(flags_ & OVERFLOW_ARGS); - } - bool isYielding() { return !!(flags_ & YIELDING); } @@ -1130,6 +1061,9 @@ class StackFrame public: /* Public, but only for JIT use: */ + inline void resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc); + inline void initInlineFrame(JSFunction *fun, StackFrame *prevfp, jsbytecode *prevpc); + static size_t offsetOfFlags() { return offsetof(StackFrame, flags_); } @@ -1154,14 +1088,14 @@ class StackFrame return offsetof(StackFrame, rval_); } - static size_t offsetOfArgsObj() { - return offsetof(StackFrame, argsObj_); - } - static ptrdiff_t offsetOfNcode() { return offsetof(StackFrame, ncode_); } + static ptrdiff_t offsetOfArgsObj() { + return offsetof(StackFrame, argsObj_); + } + static ptrdiff_t offsetOfCallee(JSFunction *fun) { JS_ASSERT(fun != NULL); return -(fun->nargs + 2) * sizeof(Value); @@ -1235,11 +1169,11 @@ class FrameRegs Value *sp; jsbytecode *pc; private: - JSInlinedSite *inlined_; + InlinedSite *inlined_; StackFrame *fp_; public: StackFrame *fp() const { return fp_; } - JSInlinedSite *inlined() const { return inlined_; } + InlinedSite *inlined() const { return inlined_; } /* For jit use (need constant): */ static const size_t offsetOfFp = 3 * sizeof(void *); @@ -1250,6 +1184,16 @@ class FrameRegs } void clearInlined() { inlined_ = NULL; } + unsigned stackDepth() const { + JS_ASSERT(sp >= fp_->base()); + return sp - fp_->base(); + } + + Value *spForStackDepth(unsigned depth) const { + JS_ASSERT(fp_->script()->nfixed + depth <= fp_->script()->nslots); + return fp_->base() + depth; + } + /* For generator: */ void rebaseFromTo(const FrameRegs &from, StackFrame &to) { fp_ = &to; @@ -1496,6 +1440,10 @@ class StackSpace StackSegment &findContainingSegment(const StackFrame *target) const; + bool containsFast(StackFrame *fp) { + return (Value *)fp >= base_ && (Value *)fp <= trustedEnd_; + } + public: StackSpace(); bool init(); @@ -1548,7 +1496,7 @@ class StackSpace /* Called during GC: mark segments, frames, and slots under firstUnused. */ void mark(JSTracer *trc); - void markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc); + void markFrameValues(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc); /* Called during GC: sets active flag on compartments with active frames. */ void markActiveCompartments(); From d8228451d43c7be7a9bd569ee678b06a50cc5b2c Mon Sep 17 00:00:00 2001 From: Sriram Ramasubramanian Date: Mon, 4 Jun 2012 11:17:03 -0700 Subject: [PATCH 24/53] Bug 760187: Phone URL bar should have softer texture. [r=mfinkle] --- .../address_bar_texture_port.png | Bin 6365 -> 6274 bytes .../resources/drawable-hdpi/tabs_more.png | Bin 407 -> 1335 bytes .../resources/drawable-hdpi/tabs_normal.png | Bin 9680 -> 10857 bytes .../resources/drawable-hdpi/tabs_plus.png | Bin 609 -> 1464 bytes .../resources/drawable-hdpi/tabs_pressed.png | Bin 10362 -> 6075 bytes .../resources/drawable-hdpi/urlbar_stop.png | Bin 792 -> 2127 bytes .../address_bar_texture_land.png | Bin 4467 -> 4843 bytes .../drawable-land-hdpi-v14/tabs_more.png | Bin 333 -> 1280 bytes .../drawable-land-hdpi-v14/tabs_normal.png | Bin 7766 -> 8704 bytes .../drawable-land-hdpi-v14/tabs_plus.png | Bin 612 -> 1439 bytes .../drawable-land-hdpi-v14/tabs_pressed.png | Bin 8186 -> 5387 bytes .../drawable-land-hdpi-v14/urlbar_stop.png | Bin 707 -> 1911 bytes .../address_bar_texture_land.png | Bin 2169 -> 2810 bytes .../drawable-land-mdpi-v14/tabs_more.png | Bin 259 -> 1158 bytes .../drawable-land-mdpi-v14/tabs_normal.png | Bin 3597 -> 4311 bytes .../drawable-land-mdpi-v14/tabs_plus.png | Bin 466 -> 1219 bytes .../drawable-land-mdpi-v14/tabs_pressed.png | Bin 3776 -> 2898 bytes .../drawable-land-mdpi-v14/urlbar_stop.png | Bin 317 -> 1538 bytes .../address_bar_texture_land.png | Bin 7774 -> 7471 bytes .../drawable-land-xhdpi-v14/tabs_more.png | Bin 446 -> 1401 bytes .../drawable-land-xhdpi-v14/tabs_normal.png | Bin 13797 -> 13632 bytes .../drawable-land-xhdpi-v14/tabs_plus.png | Bin 639 -> 1505 bytes .../drawable-land-xhdpi-v14/tabs_pressed.png | Bin 14596 -> 7750 bytes .../drawable-land-xhdpi-v14/urlbar_stop.png | Bin 828 -> 2367 bytes .../address_bar_texture_port.png | Bin 11342 -> 9947 bytes .../drawable-xhdpi-v11/tabs_more.png | Bin 524 -> 1474 bytes .../drawable-xhdpi-v11/tabs_normal.png | Bin 15639 -> 17579 bytes .../drawable-xhdpi-v11/tabs_plus.png | Bin 783 -> 1653 bytes .../drawable-xhdpi-v11/tabs_pressed.png | Bin 17014 -> 8962 bytes .../drawable-xhdpi-v11/urlbar_stop.png | Bin 966 -> 2666 bytes .../drawable/address_bar_texture_port.png | Bin 3049 -> 3545 bytes .../base/resources/drawable/tabs_more.png | Bin 305 -> 1251 bytes .../base/resources/drawable/tabs_normal.png | Bin 5046 -> 5742 bytes .../base/resources/drawable/tabs_plus.png | Bin 512 -> 1240 bytes .../base/resources/drawable/tabs_pressed.png | Bin 5350 -> 3700 bytes .../base/resources/drawable/urlbar_stop.png | Bin 569 -> 1710 bytes .../base/resources/layout/browser_toolbar.xml | 2 +- 37 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/base/resources/drawable-hdpi/address_bar_texture_port.png b/mobile/android/base/resources/drawable-hdpi/address_bar_texture_port.png index 15d876a8cf2de415b7b903e03a24579cb8c2092c..603379b42fc7e956460ffab8230a11c880d9685d 100644 GIT binary patch literal 6274 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 delta 6349 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 P00000NkvXXu0mjfWx%Pp diff --git a/mobile/android/base/resources/drawable-hdpi/tabs_more.png b/mobile/android/base/resources/drawable-hdpi/tabs_more.png index 687ca0dc0d55742c2d83cfe7d489c130974dbb62..7ec72734bda7277c61402f6ae8ef70c8d14c09c0 100644 GIT binary patch literal 1335 zcmbVMZEV{_7LB%loi2#fk2=l*fdbbMnIj0n2^Tyg9)lhNEIK`1X4T7xlKBds{Oz^ z`_AX*dEWQl4?owR*w)mrp@ATXrdY3(#PcTiuCK+<^TdGzcv|m7Q_g@n`PHFZjHF;r2{VKza8x{EnQ%_0Y+(XeKO$zMM^ zN&+ntChzmbnRre_BUV|M!{mxnsdzsSO$z}Z#d%Z)LcsGB^!j)n-U(O+vNVGS?}1*y#|x|%j<*J#IKk(PP-{6$J^|s-@)|%`||k zsHDv?Crn~bSB{|P;_+2s!!8F3hm0;NIT}(7t?TZ&meID8L|5Ec6KxNU=MbGlwmD|0 zI3Gjp6*7+9)eX5o?2WM9(r{9gQOQ)tbYwU&DNN!oR7T4Pa=ixH2P+zDak)s3m+?l$pv3YJMq!X=WJ%)12on$^oXA(WF~fEgLq!$48n#>J z_FR=Kh!#>D(;76*(MkpMkC={WkC-_i4)9w-EZj%=zV?FzQ6iRM)ArO4R8 zwnJ}yaHb)DZS3}zmcIF=zb~WWr9ZBjInp`({2n{GptYjIXZ`Q*{PU-U>CN=Rq2a$S zURZbUiN`T;=G&QtwwkA((&i`IE+pPuWD3WBZk(LDwY{^U1ly*K2VecznEP;H>v{8S z;o1E!2cCInV;;Pcck(ygee$cOL@I1!far0}ZkM3OB`eNz+kokSn6L%#J)@DJ=RMozzy$_u` za`@fZ2R`i*Hu`QjR+rYS**e7%>uWcix`kM`K2x{9ny79hwr9UNK7YCXr28w2MHA9{ IJv(;&1H&c5O#lD@ delta 297 zcmV+^0oMMv3YPoYG9c>q335!Q|Ehr0Rb^wihln5@nzYP#ovKUHX!~(%P9MI zbSOn%-Qp^Y2L5721juHT3J8fP4?xv3Z3)Z#{GteDFj)NFU8PWsh8gxg2 vLP`aQrGWSi5Z?si_sD678`L2~fB*vk&0q#JxV-5`00000NkvXXu0mjf%pjHz diff --git a/mobile/android/base/resources/drawable-hdpi/tabs_normal.png b/mobile/android/base/resources/drawable-hdpi/tabs_normal.png index 40f1dc12bbe925016e1e780f4e2768b0fb58e320..3d094c69dc52b35aa4a7a8c2307365cc9b887172 100644 GIT binary patch literal 10857 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 E2R1QzW&i*H literal 9680 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 m&1Itw8Xa}eaCZ?_5JwHwa+cOhXcw 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 Y03?-$<6ZURjQ{`u07*qoM6N<$f}x$pod5s; diff --git a/mobile/android/base/resources/drawable-hdpi/urlbar_stop.png b/mobile/android/base/resources/drawable-hdpi/urlbar_stop.png index 27f0f12ef636d7c888a57594cf919f4c93690b12..74cb898e1f445353c680f75f85b8827706c2daab 100644 GIT binary patch literal 2127 zcmbVNX;>528V-vHp$KIWg=&WYl|_A9tQJbIzQ3-}n2@w>)zo zXv;<;v=thKLK*q{F@llVPIK$)AAF$8k~r8riipej8v3%XQft=Yz5 zfCUH~DRNWkHdL2?0Iscs}Hfeb8O z7{r>KFQ5i9Sc|rhH&2WZhGkS7E8z+9z^L}9z6 zz3OAM^<;9613GC1C#2{a= zd=a0@awoGuknD;l6YwN=5Ol}86Is3l3XMW%5(q?aN#k=|BFz_cck?Au7z7dsGC>Ln z&tfo0bQ<2BP9xGuOI&}60_IA1(2`vdVt0{C_)9L8E{C|VRL+q~W0xu*NGOG+3ZYa6 z&_hUo14zW;7ZQ&r;@z-ftSjiYSO-KL-i=BCsdzjx909P(`0{mcnAvStKF@1pf>Yjl?7|+{sKjoj|}Wa{2#HfN_X3I87z}Ph~A_ zA?2!Be(DqCsjy21Vo8b{eTUJx1kgtIF7W#xe<&6ef%BjFn| zTx}-W?N1h$Nh%8NS$A(wj&m~8d3z;u)0Ix4U+lv_+9PdEJOqKZzZ!iPd3d`p+qIOp zE2lcD*61d)ydrXR=2h>zHtW_qCo1dDXQrqsy{Wgn+TPE$mE>h`O>!T-G09c;YWHc+ z4Qjb@TKw`WjXV-DN!5-%xmnt${Gv9Mq{Ym!zV=d1U3@Cz&)-Tg+t}IMYyCHTJv8*mF8@ zir)M(-i$6T2b%oz8GfmLt6I2*YlMQ#L#NK5-DI-7k=_Xodi<*kuz7@yZV7o9f4w1f zF4I{(o;H8i;BTf6`u8`CHTeWIo;AKYl00hdetrDKi-3-pw4Ut|$F#m_8~yQgW8i>b zwcg;vp_`ZP^r!u{e}9mvPs)gk2(8;2mV5GCnQGqnY=`;uZFGB9!sB}Z{A&UWW=C&i z?J^FrhDN=A6E_V`^z<}+>CODoygR(9V0d!4Bi~G)o?oYRkRB4MUGKcvRCf|GeEyC8 zFzN13r7Nb^W?ur148BfIjn*$Ub4aJvZTj&O6W)g6h|HG|_P?yXIW1;O)tFLF4&#ldlBy`o=d90O2m%%2>-%a?%br3%eya}an7!f9aQ;QYCC~DcKZAEIfB}PmfZ51M|Q+0y78P&J+Wqn$kKoCyu3_6m;|R15E+DW3CjHvC^w#vHq;^}j##?RQ zhQ4vM=k)AlwcV*lvw5F&-Eneo%FB!^Mn}S) z1y$A7>WvMW)RbKJv&=p5Bzx@M1s&_!<_{J_Pb+F47v6C4y8F)^E}5^YQ<^?pmT0{% eNcmv#EvhTYVZ`p}g?Y^{-k-UJ(ct@S>VE;Dbzs&2 delta 732 zcmV<20wev;5SRv#NPhylNkle2b9xNU_30^As2RsQqRRl$B-re1rryDo*n`NVEvOD`o zM8O>xhRM$E{+OBXn+>(Mw}<|vLb)Iph;E>VyT?n z&KHoh`;GYEm(QQ7?fr*OW@6FFOsDf>vs5lG-&k6dN%zsDi$@Og$m8)O1xdqhuR~BfRd2x63ftU1759wm1Qaytx zD#b7ilB8Y4^M8j>A|6}gI1T|SjmHem6vo73Q4Q106^bPuFlgey1PTQFXFHwF77V-T z2vn;#_VoopR9hod4-*OoRg55tDn?PdsNQI(6$;~c$)LQ3x-y8`E)-F_-NvY2%SXcW zl~<(MF`Xf;tZHq_Xr`u498YU6Hp9%pW>-c9nWCbRNq@w$?Ax#TJP9*zhOq-8q7+40 zqbRB_N>YG;k*&PMV>55*qHqL4J`3RfKwh(jaRSms!M@QOXB%TB%1EfJZtABf+-y3* z*q$Mu*QQaVk*__6H-otU%UqBP`fou$1sDK*l-{nRkDw+1 O0000~NFWJS1*Av^0clcHI!JFy ziAXO}6aneIO9!QjC+@vH=RTb8JlyrowPso4|Hqi4Jj@w<^M>YGCT=Dg8k)1(S_mU* zulW0Aprw8*Qg2+Pc3fl)G#N#>Pj&1g&KONb z>+8u|6CA}czh%VT9i6CXDw&GA6UN#eM+REqZ0zt#p!J$M5YP^*1TvA)hv+-0<81A; zJc&4z=M7_PPkU=P7NnvKRCJf85;)?>7@)hO1D+)Bt_1pvSDrfly(|F&{v|@TR|5TQ z6k7i#P@O=;0cFIcz}65b6bOTfL#1V4FsK+%5(1T!fKVF@43(CbfyqnC0{?kHRBc4; zeR(4U@*iE)nG(pBOm>o&kZ^Nz6L*smClGBUpl~?+H;1Gom?{A#dEm(ycQBsB|AzsA zBUuyeoXBtn3#@V~Jlzhn8gYY;f1ohuHDBoZ8fe+5I{?!OodM{1}eVNwVv^gm8ggK5AJaXMS6f3Vp9kAo$s#z_3mr2msyf0n4}`g{2AI-ySfU1>NxwY-SbI(o$AT~9;9yrzv% zGj<;)-x-RVsXlu_+vE5b|8{h|qK#OT9+)O$EqO$0btbOL2h9Zdw0if~aStcu?Tp;f zN0Xy`il_bI;OgQYim)f-<@xQ=tEfZtff8i!q;yi*#vo~1D62DkfpelF;9_gc00p4T zgAV40AAbdLZd2B`>%1jGf?iUpz+NO9@v$mtWrfyBFZ(GU3HSy!qC0X8?z}^Z0i%V$oaOPj-=Ms6CV8N72=4i@%M;K*Dq=89bUI?(#zk=_Ws zL6b(wm+36}Y+FEBz1C4sPyro?4yLm-nzOQ}W%yFI@PyN;_Ae*Tl8#hj* zy32&M?l|)6F!9<-zi+Md@-q?hktOLUGK~(5_MQyz+r8(5DnNPus?W3&V z?Z^b3s=c1o%Lr~Ue7=68Jh>6jr zL*=lZLGj6>1HyL2j;(@0qPtl%WR6$TZU5wPE#YAQ4gg#tNcUW-EmY3x5dJ8gr)RCA zXySwG0ygO0DznCQ8uX9>6ZV2$FW*eu8x~X5;pt10EpX6q&?#xLQ?QY!m@_%xTAWCW z(~B+De43x(#s&RV%pR{G1()kjZWK)r`4S5(WEZU2_oto5TsIqAZHezWCFrj*^!AX` z#@V_1C^Y4#ooEd11Pnq9y~7 zwe~{haFx76U^d#9SMgvSA?Tg5-BSKcu4j@xSqA$$R&z|=dqTM@Z9tZEQ=+7S1rXD> z$z0TU#l>g!%WxPH&OG^L=99hFrk0ojBb)Wyv#fwu2?3-7rHqtb|G8(|9i>}R!`@^M zub2l&@pg+10a=yWlv}*Zgw^oK3wMTmOMEfzl)}RkIYBT-htE@3Jy66Bcy`SzvTiY# z&Yz#7Z>sGUvzYy&*+&tKXnM1_Md4iF_gqO2UG0p4qnuFQmCyqkj>IV?`>DrIEO(t* z3-q;72tS`O0(fHs@u!3`wK}G8 zsq+;HEjD2dh94GcyV4ktoTo=pDbvgyNqin3&jIC7+~+o<%9B}F60&#}0W`vTP18L0 zqfHp(bF^w+`gN#!JvgJR6nxQaiS~*6M6cmfm&kY?z26JTE;8XHo_Fix`UfGpf#(TybFpN%^6E)hF|c0#y9nj*F78Y$<)U1QVl@R(0M|ISi0_}#4K1OsR4ij;fFfulW- zAA8i};lf-rA(o(V|8~^;SmZ0yjw0!X5S67Jlg{CJA3HAVMr)5V$hLq)MA5R;HHDMr zil;d}X82K6{9D-%&gx%)8ATRul-xjqiqqDUzZL+;LyhD3p;3&EIy zcP@t4iJT8I72YTz;2$$SIPj$i7ZPc%wVMkDe4dhXeRph;!Eq3I@4cU@r6_UB}4K3*ICOC143!gK9GD^zIOb%SC(6J^WfNF(bGQ@ z!vmA9v{}=&-!90r6%Z(E;WF)8o#qL2>@9VTs6RD!u`<9oJI5+hdLHaPrP-Z9H;_>V zBM)Gj1q6OwdFLCxp;|A?f@1!R6fA~VWF#!n;^;}yL41H6O+X!^?$E-`gQh&b-Z2K4 z{Or(JsB^xe@wNaMRoB2-n`+W?#Q)We-SwLFJ|rGQ*BTllAAwx#xI(0khNT6=p&tTQqE3;JD8@2=hIW7ti)Ys`|P^Js=do z@zXNvI&pNB`9fFr31CxJt)cKYM#Uy1{m)(V*?>zz@Pz51nsfWgbRPp_LT}ry6>N}4 zeVGeRBt*zwFAHcc>FZ@uM|eX$H|!Kx4J`D}ou`E2KQ)89&gpqN<@9)5G$R@W<&>K1 zN|mrXGL=3R0VkkPmmjWiX#Pz0uG@{lflx-LUNX}g#cGhmrhpBGrf)QfxyDwkUCGI; zVbHt#J|U-v8En2CXlkCpis^CkJV;-ZDe2*^t!6JIzOdq@V6O~vbv9c$$77ED%_ zM}=l5Qm)2rl1I_!%pUH}`{{DRlF!k6>ezkAVz_2jcz#J!DO+V>sry-o3K9DCb>VGK ztc*+2&W7p7My)2ZSRX+4qJ4p$QRzmF;h!qVMxU`eO&5Ck<(* zVZHE{ZO7d&M%gG5Q2cRJin#(#S{Tug~e~)94&NvGy_1M3@hAoW1uwtEMU%4G%V1?lw4N|IGeeQ!q;s zXQexKO`p(`8Z4P+JshfAvpOakTJEw!pXGF11=7_T`KdW!$lXjF7&WTi(pwi;xEST6 zaO~oC7dUe$Q>7ys6lP_LnC=bNMB4bP#a>WM*X&_*(KiRv5QI( zFFBxjYOZ7A^tm1RmR0GB>}h+21+{H<(L)L;gP-=1J6hsJEjFgT0#)!T8@d%Yb=ab2 z{W~#}W-arDIZZd(>&<=|hIXS9sn!5^pD$RaVu)kB+Val8V58EuVj_eM5%9GjI>4;E zGK$o3iBEW->mt_xnEwFQmibyH{FiHRV%1a1YQ+TYtx8=^O#P2;8HIL6`@OyDkPpok z(weM!^pQYu$l$0eMKYeTNzUX-&#;0re>hKo-U(u4)in*+HyPBwp?oYc) zyxKR|!iMtw9Hz=||C|tcaItZIoiHHxYlr+k3Q)_2RYWaUaP z?y-S|9qX7CB*?8_EqzeT)(_R|`K2;qlIqQmzZci`*5&B^luK&^@7-gI@x2?>`qyf1 zd5WyMp{5s?V~^R}zV#cw!hvH-JOFK@HZ5`WLS=qyPb8PHGewmBhQ5NX?$8r&+J`nV z#w7OK{E;Aa<{zJ1zJKRpmLa)i-YX}*%Q;h}UmCgBVs!dqY|-b<8y4(gVI~~VH|1n#W>^kJ;dF(Ea2hswIGm+ zCt zkV0cghr?mJ9`|CietQ287c+Yi|Hy-glslB+f!Qy?>C@8D`<`2OGg0FSTBRleojR9~ z^N_O}ijj4Xt;NdTTOin5sptOG+v~22`yKXzCF!3wHBubxA#-a^bA_TGtols_HTD#4 zpP{urDt55Qxs@3c@7r0kE~+Rh*HLLck@`b$&E+Tldx~Q3&b5WZ z%Cfl=^}aT*EM+LWBlgZ=bWsnYxDMV&ina1PtEDO`?|+* z%t#*oi_Uul9>!s~Za5h}$EW?gMakp`&A6}gnkLBgul<;($$x7Kt>ZkH%d#Faea~cw zhID9d`?1W^=LpXi^KN$NMn+-oy!~p}j|)osp`@8f`S+U45@IXX*`}fx)x2-bexE#+xOFUA(0}d(}SG&y7GB5b3abY z>Fl#16V4FtOfv%3{JWkB^;qIPuh#A0`I3&i3}((Wj(l#rj0ZOO3Vk@t+wRtm6W@;W zTn6bBCZblGNBI}tS%LcaiuU0GDVzGur;jADO}5e4#ed-cpv)lKG~3{Lo<^)_GBumu zon0UjM>>mrcFoYUb;v?x5Xa1bCv5b*csSSt%Z{M@5K(ltd-m%i91pU59FW{K!R3A5 zO{)IO;5-ieWh4(QK`j^n&qJjqr|NC0LmxU!vrAlTnmL&3z8{bqbJknu5I@LZ<%Knt!MyJ&nPLAk1XnMf@<4Q(g6hotL-g=FKPup+jdH-}*eV(S7eIXRuCewLDAk zRnl;aqU3W$zkYaavh={sCGBG{y&bl>qkYKFkY2Yvo*F#z+727YOqPq8DtTmq%#i-- zUAjt;O)*_o$!pCLgFa;OPMfEmIh#yK)`;o&J%6SXKfw0cYPS#J6V0F2?QEvO2+lOm zQ*pAP5Rn(k&oncZbzfaPNh6*xOEcJE8C*<6(%r8(Xbie6H&igTZ4xhhPvL#;aTlBe zyst^(1;7gGufQz4<4F`F^+Ia|L;^a7+ybZw}aEmmr=Q7{b z)dCB$eXESGi^bOF%;QjJwg0*?uxLr&!hal?9`87Q-#=skI_lt18u+^maD(6CcD=p4 z(UlsEo1%H1R&D=UH)Jo_gd&o&LVN4~jyJ!yEzg;ATb1&0(5lnh%hLW`xA^W|kxN!# zC_w){^CmDok3RVW26~id0;DWc8qhz+D|Qi~kL<-aM9Uv+i2h@lR|QOY!)P1bjDIyK zWy76E88mB{BM$5!2?pq{ABNYawGeSM?qX7}eUBARLa52a=d3!#<&jreB2$K^>tdWw z`&IAQddHnI^RgpliSR{wjAiPDea#R?&R|GZ$Yf4{Os6*t?T$f@Wol_gToB2PqW+FF z=pk!I#~N5+grUGItR6z?i{vC(hkwHb(}t_SoYw}O4WM}5(I6~d;@~MyPi_$J!7n9F zk7tPyCQf$bA>i1&?XZWj;~>|>E@h@KxtcV?+aMjzI!no8%Tm_$uq#Wi5Qkb}^6C;% zWZjW6X7u~o5th}h@bi|h=b2FdDPIwc%OW#HX(gPB9e+YyKty)m@z~`?~jN=I< zom&T?mT9VqNmmb0NXcsP6K9SH_o@fvBvE6_7UQFWd53WX%mg+C!Ps}O8!b}Ppj0sS zENiPI!iu&Tryn0Ln`N9;F@Ge-@4l^yT{)2SXN7Yp#Gnl|3i%mtNX%chX!PX`r=pW{ z=G!|O2$}P= zyw${fnG6!m=BF$XFXC@egVlBIQe6_cbnjwzV8}mbWOZAR~pg z0xSe(CEY?RVaipKP9-JdXoRYzfQu?tI&)VRKWak%PA}`s&sCB%${kbF>J>>3ekKZ= zs>zHyO7;%*x5QxwOMkgAyBfG{v7-X}SSlB|znls~E_oNuB+ng(dVnFh4JpCbqwtMG z@cdE3b`qpQ)KKm3cE%%`3JuCs6aQ~Jw=n8({>GV}Gi1x#BoUB>V4f#O|76_y`sa7; z9sLBt72 zHgWt-qap*#!S%7`)2GA_{7n<;fCK)dh`Zx!)Di8Z5%HPejzfx5Z4elVLc4#Y zPoJl=j?hLhMGo7u&DT_ z=^^V>?hDO^KN(C}d02<3DKV{w-N05M$ohUhE~WXsQ-Az!wB0_IxfYrZvA4@oXMoOH z1nJ@)Zc4jI#sfpgUtf>fR6xIr@%xHF=aW-7-rw>1zkgooNjz+|F;-|l>=>|xvxS*B zPiO3dPAr&*2vkmZD@{dgQ`!$sn)i6XGRHYi;_bJA07&MPdD}cmJ%&C(YmBS$xmF^C zp-7HBuz!aDS*fLsUq8R=ml+}hfwEJ{XyEerAW z1k0GCKhB(F9q}!bSg#0BcX6_g>{q3a*Qm5XPP8d;Uw;k!-@D{5WB+=t`E(s|pBT#m9 zy?6cmzR2>vAIl2P%++sVt7*5@{D#F#QnUDLpe_A4+mF;|*d7D4SQMF$dL7E7k1vCF z@P9ZdRDy8myB^bEnii>WTbxQ{%@#}La5p3=E4(5+A*i~#gp~kp0D4yiId&!W38<;U zYlB9~!v%!Oxa0|P?#I+3J11l>htj)kWP-{heDsY!#wi*M;`Nz1&KlU1cQzycRY1M zIzI-xlXX1(-qH)l%O_Sg3#uh@5Y6DQ7UZ#&>>RmZ>k`*-WpYJX7o zS`!8ijYN^||NeQkpxuJ=-#=@sAlaR1DFiWwhl>bDd!Y@e>}i5_1~KuU*DJ6H5$!ni zY!RqtPO79<7a~-qDK3_(v=81RZ{uKv+PfTB6(z*}_5Dny)&O!dTJMfJYHs&K!`iMU z5-o@R>+5N7eL622ZNy6&7mXlW$bTB$^$Jd(O2TGzNI*z5xrAU!?y@SO10uvPMj}=< zgm9pz%HtFGOAyK)%6HvzRg1&@@ISvVwX2JDzT3D-=T$^H4{4jJ8{{U=%Soog+wj@0 zR|@J#1W=rnGR(DeqQJyp4jhglHMqMvx^*q|VRon_uEH4tL&^z7YIqOti+`p!JdMtM z?|<~6bNG3l68YGkPo5)Y#L1B!AG%_9=D2IxD9b{Su^NcJPC#mS-Js@Q-zAr4Zx(HC zHwIHjC$m@^L}3egKsMscrNl?ie6U1`zz#zer1wK|&-6bLL8Ju-U&=B1G%}%y>q9dZ z(!1?#F|Rc|Zj)^y0Ow}mMdn9d;52OP)IC`;VmM{VZ zM8XCk-i$3$NFwE{v#aG{m)$1$W@6SUAQrU86Ou4`TGcgFkfOb<50|n1X2FAtAB8AS zz}a8!1Qf${D#!fa*OoFPuOdZvE4xMtjl(FK%tJgrRtJ~Pc$Iw5bARa0gBemhjVNeeK zlW^AR<(edx%iqDiI|QEMr?X|IBz>MxZS%Rn9NNycUBvUwRL?U_1*V1LC=f;i8m+>R zUAoqMIT?(_uP)2g#(x#?>xP2yc#hIt*E^{ga#hy{dXoW$GsqEmIKW=3@zfNd63P9k zeijD@<|9{Mc*+oC{hSRwK#K94Q$*YZi#SuvC$~<=A~4Tn2&UrBMsebHkvTXOoRjRw zn7sH=Z>Nj;hU)e0qC5YTAJ_cEH#S4&v#a`2ug&<{1%usSE`L_xCegqIH@?bs9$)!V zG3W9Beqi8^v5Z;i#LFJmVoFq2lhr$J9@|YKHhlbEAu>(~2)es7n|{UkC>^jNHrm%3 z^sW~jh|O)@L5%iF4fy-2QV8H|zF`Td555u@8lX0u_pwTJEDHKKF(a;Pw&o~7o7hkF zeZ!*Bu*E`m;D6^BLzeS4K{s+WhV;R^NTFq&%`bEQA%?MhWE8>hP%q*%#YV*!!F|J~ z@EvcC`f^~bE|>nr_9_TAAI>=gh|LZe#0G=8u&0JewZ`ly9Y(*v1;Tb|ITt+sw5POk z(jh6Ag*RDs;%IEz&A2V`r76v;3WlmOt#*i9-M7!2DSu|v~rQ6Lf?Wb?S*w`ZXB~yff!$`t15OEINX9gc(U zT4G-Pg9*98;5_(l{jB?=d;2+6QoPj-gYPQBUVq$N(Mf=GtUup~a#955%m_Yu7_zte zyhZhQZUkedO5#3#GZuG73e9QQ??Wwpz>bKM`YN|O?QIdZ*ZRjbLTK0uqFwGCCwN6_ zzHjdv)F!d%(#H;RU8OGSKcT}}Z}(Y51lIy{v6;_eBu5p7_@aef5quVkv%4!8SGK>? z7JrKY=$^o?kMd(bmosU^v>ANt6}p(4T4!Xx&rrl9!goNo#q9hf#XmjKk7Aq~bZL$1 zeobvL^)J)dRysE8E=#|8s;Ve9HjXvFBXbhYHoZlV004hzKKMhWlI!tz3`$87+YbW3 z@f*f%36|@fYpA9NcPL8i+`F*S9LjdQ*pRI{R4nRzHcX0pFo)(_bHQh zk`yOSm6U>aNy7E0&>Mz+3nHHRC0Gl4O2O_Tc{Sj)v7GG7soblkF1t&qG>)NwAZll# zSSng&Nq{fEEvTHSis4*tR2<>N*NVbnWsA`m-olr`nAIRQ9gkd`HCCSP2jurM7){(9 zJzBIR?-;Rz_R&(@RzMgEx0>O+N@=%l<4}A$S0%Pu!MrXJ@6ttwtV##N4ksy1j@R~o a0t^5Y2Lp7d9u{x_0000-}N=r*Zp=nwunhIMwX6a70WlM{jIg+({oipPYW(rv*%jZN(B)O7O zJ8st`+uH2o#|Ya>e+-f~6w+z1KHgDXqksyf8(S1?^&%4}r!+QLE0$ezar)DRTayredlUFQ6 zgfnIukx^agK?$T}1`mFPS_z{5Z7rE{Qn6;5^VL_&I?MkkyC6 z)~rlcNJw(k7G8y@UdPD^43p32>AaUVtsVyQJnwR_tOsj&>_Nj(3LeAWU1N}tty)^n z(M*GM8I`m-;Djjb>B<%KTr9RqY}nO6;gB%}CC5M-FuLyEtDwKSX*rC&1D0Ua4mR0>h}gwALgK@J9F2m?M4U;!6| zFbINPxt-<1ycl6wFRXE_g^dIQ0j?eRd5QHy7=b(oWJ%)0FbIlaugKM~QNwl=Lq#>a z8n#=-`W}cCL<=d7X(dgwzg7Y9Ueht{UNc9EogCQ$y)>vK9(aMD)@dK~SL?vb0KdRO z0RTMqkYr0tQ8mNG?s0Ru5*i6v+98yYEmJ2e$q=+PoaN<+D05y3!h1mqa}iDo1|p)! zvQ!nD`9A?>urrKXN%vJ&Z3~yHE3WnlUaWQ+GH`oYxQ~p(UEKt+u0AS-lZBttOUuh` zr6-9;j<2hm-1gRi))(ieKD$r&e%JdAldp}9H6D9YZ2tJt)BWe(J(g-(_;cawZ=S!h zI6XYkFf%+%zHxoDJh%Oq*`e~okA2&@^UIgyYZKX}g?~Q!sdTq|^T^_zkzY%r<(3mi z7yq7Le&ulfX5FRJpB7&oJ2^43{-Up8zY}|}@zI&7cfKfyI{hwClw92ODnvb+-HJk>dx7JF~y{P3@SzyZxb)r}j4Kw{LA)DwpTR zKmX&qYw`W##C%(NYtz|nlc_Dgl{{yn({kO=$eqT9q0#KAz>OQ~Fi}sO|Kwl{>0O81 Pe^NBkAzf&H;pP7TAu72H delta 236 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 X9Snd>$D1Sp00000NkvXXu0mjfv5@Ct diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_plus.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_plus.png index b76c1a208e03eb136fb2514edb8c341de566ac80..045db497e5fa247e58f8e3d27fc97f8541fe71d9 100644 GIT binary patch literal 1439 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m?vk3M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWv2L<~p`n7AnVzAE zshOFfj)IYap^?4;5Si&3npl~dSs9rtK!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh zUb(Seeo?xx^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal@=Hr> zm4GgVcpk{1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdn za}xt|BLg!FLqiJ#3u8AYBTGk1XICR5V?&r3*z~$um>avf7`j@z7?~Oxx*A%V8MwK) zm^nKdSU5WxJDb7udgc|EB<3Zj!tBii+6&d|f>*DVb5UwyNq$jCetr%t1q5W|m*f{` zeK|#YeF*!32q*oIZ zmyn=wNiE7OOHFYr%Fk5*M}}1<7ROq;xjMU<8M_!7A_B?L%+<`r!rax_*~mx4L%EHb@c?w&l1!7CFk2#+Q_f?V7_$^w-I;7GbN`&9e1CP<$oT%HO}Zf z)xu%Ehw0X5iSPjX_GM0iGOo&z^Vl9;clg5;FVo!g!*D}abk`1+3?d77Lt z_m8~0YNPOhFArArx93In-kIc(A9~@+qkeh&1GjzW+t)6NQ+2%Xi2r?k{jVR5qSO2{ z-z8@}`uYFI!@oBjxa$=}`TlQIb<6twqck(_n2mxhe`JrGV{hDv1YMa9#-1rl&RjIR hzT)T)28RYlhJ&{mmd-e^_YJ7X^mO%eS?83{1OT*u@-YAa delta 551 zcmV+?0@(eZ3*-clNPhwbNklg6ZQIZ!=&6AoX!3E#FdkYc+S^S?^gMXMvwfNuPf6VBDfB*bt zfm+N!D~qWHMlGfrz?!O+WyKkonXso7R#s*PE)F(^Z$Ey4`Mg{l3~a2B^rj{+L3}Dj zD?m7}-hQ}8TvW)45o-a!!0_e!4~8#ae=vOh_5&=&$HNJ>oQs2JT z7oc6=ars#E(|@;LR^OhyX87~>FHtW4^yNDk;|x+3W`;k1{#t>|2I5D!;+P*q5Njzh z0B9+S*|;qJfA7w%d(=)yP&5DIi(^?JW*1JK!_h*94L1G5ySn9Kz)DlRg0rV=BUMk(&GP@E}Z@F;ND$$ z(Rcgije8(5Qkp&Fw7Ecrzl#j?s0Y%TP(G+|cuT6qjM$pD1OO+rz~_fr2J-D2Xc>Ut p)yQ@sb09_&*QmwA!eW2`0{~31#bk6u>Ye}q002ovPDHLkV1o8t3>yFd diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_pressed.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_pressed.png index db791bfe5c9903bb834d3d6a8b0aed2d5cfcd8ca..9a699a3277da056c8074e67fd9657dd08049b871 100644 GIT binary patch literal 5387 zcmbVQX*iT^`^VUYP(qeL*|N;oO$K9^HG4?L7)y+inX&Ie$QmM9vu{}|Yh=$Z*|(A< zdkiDQtLJ%o|L=$Qct8B_e{m%W%9ciGaK}*d>O+-XQtEH)Gc(Gbsyz-Rf z7vB}Kal+1BA6Z8775fs!5xr>NVuK%qh6#u5fQ-N$=DoguB!t< zpi!dm-#VgRD7Opr1(~9k8yw+`!~$)R4oEn(x z^3gL!_&6iv?06Ivfbw3D3j!1p3kQ0kTwE~_FDTDnypW6i?_)6@;9n|OXDH9#PMPZ( z09DZLNT8G`NCW|r1_7nPqF@P085tR2pg0H&5(9~gfyG6@G7t%I2nYoH=i#}q=5A*X zF;rFm$JT`e<#EJf-5_FOo}Qkfo)V&HcLy=BoSfWm4smgj3k?yBw<{LzCE|+V{llP& z#30KX%Gkol2n2H!D_i;uy9ud@{e7o-**4T!u}@~qT-H(W6|!$ zXtc|p4lr;;W6>B#v>Q;xND8P6M>x6umVcM$?`Tz#?oJ*^J9T$73iwxkAx{6rK1f^^ z^q+Cd$x6f2)uoliVG?p6ISFx|f3SA{pPY$ZI3xDEIsT(r{v2I&;P36fTmM4%_wXQH zFDAzQVl;^PefEin7;bB+!i>G9XRZ97T7AYT66OgjhzTy|$|@}m%50LmR9b92jBpdO zv8cp67|I}j*c4_mQ%igk#UyB$boyB_SM%<4k<;}$-AGO2{P-b8i+nBTVv)rs1&gF0 zXC^?G$9SW2Q{Q&~X1_1t@Fixb9^>Fadpc6oxIaF$gP3oW*l%1t8{B#6JD(~M-6!*S zQEWpb;~o2P>2pA9-LFoEisIY*$U1j6@_l_}|3iVKuwcH5t?=bK6E?>yDMOZkbe}Y6 zGx;s((21h#d>B(SzzbeQAIHAYn(*vCC3g@w{H@yEU7XLLFa7v*!r@w7L&c}MrPm`b z7F1BFh@l~PD3KJ$qTY9Q)XY2IP|P-S)3%IDUG;m+*UNZ4d6EqNmP-}BY|}Seu>c!O zCa?FwJN1IZGIWaO+%w`8bc)!KuUk{GDy@yX!y}@zgkc`}#x)Js*Co`KDdtmwos%kj!P5^!81-?r*=Un^dfE7=vpWpQf`s!5%U2*m9JJE zUV5A0kHOc=DP3+O%2A*E;HDTuJY)qMS;Z;as1}rFjYE=)@?(@iXPSP;EgEJzgaEVlY zHkRXuSxjzIr7$}_;PiFn(c&EFepWC|VK5BsYPuazM+0bKYVhFqJM_JOGzM_UxlQR( z^_V934$CsT!Z!O9>!8BPGrQ(UgfjLi-Ymfr=i0IE%(d&&&heOF9YP2IT=&J4M&4-l zpd|Cphl}op*Q|}Nm)p%PxsS;I?AIbs2qy~ed(}C$2A5c@pRmM+UmidXm_l+~vAAJX*Eyks$-A7e zXgX_o$1jX&t2eTqL22BZ<{`JNQy(`z3-<@qEh;Xh s(T#_nx%L%W{-*X+h#z|J^ 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 delta 8184 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 B;Q;^u delta 646 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 delta 2120 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 diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_normal.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_normal.png index dbfba2b35574a9c23917e4954778c68dbd891532..31df822dcb99a0be2f3ee00632559cfdc107c862 100644 GIT binary patch literal 4311 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 delta 3559 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 delta 404 zcmV;F0c-xl3DN_QNPhuzNklP5s+M8TWL4qnBZf5V^V z&rm!Ho}7X(b+#5kaBWw++NpG{?}c_|!!{H>=!36Gn!GQ0`94CDBq0SMb&N;T@dioP zda|~6T1wtRf zF(1cC<)?(DgG(rhHQFkYNNTe)TtWer5d;C%yjpD3b#^ic-vMvLe;pE4o~NXeI0x&$ z);OMjz0q800Z)kIDx;<6VFc&^j)BKyOMb?mfb%J#)&XNeSy4`b@B$r_ISFqg z%_l4&UZ}|{QPUO-ix_R_j{c4hf15D&`mRU)X7~E{cQ=Eghk;c&Z$48W#pwc00LFKu y*)zx^l+g64&w^CVFz-Da6aH&aO2?-F0|4~9pv=Q~%neQe0000nYIcE~x_B*Po z=%_#-5LIUY6r|53Ep8 zB?U#{k{F>(rzjrdK-7LuT2vSfONZI+f$kRJqyj94fC?3{!r6SB2oL+Li<7R`wvjOC zXNVvS5BuVj55)~i;_w(yO9W_6LjeF3gFyfmmKY2GhoVsc8i|q)j5%O|v&7)gR?x2( zOlpls55{?r9lqLr z3S$A^`*n$zrXY>ob}! z@L>Gy#y_I@o{?Mz(u2Y0MDS?Rd<5@UCre}Z?}pZZQg3jsJf<`$)NnF~7Qte$1aMxU}b@_LZdL&0AP)>1|5iKECEZhN25VtUE`m)L4vFAQEMXLjyPzN;*uTP!kH3#$>N?P1kby zB{XCPkNG2m?!e=)pr4b0WB!A)SOZen75Qw6eGnwEi>hJMmCHZ@4AMa|b z18XG%Q|yh2ay2C{9c>NM9X=MvLIDDdT+*0+aHYsW)tIbBY8Y16l2?thBgQbD42{U= zEDbVyJ+EH&O!YHsP4Fl;A7BcrY;qT_9POHm?#{6}`b@I|goDo?PUJ`}EN72L<}O5c zYaiiN*0}eE_TTSR&vb~mc{8VG2(I^HTc^He;gWagvnD4KcT+~5p2|r-qDpb^=AEWG zmq;a}ZUGjeH^q&Yv^J})RzToP#u)WWz^>vlP1Z ztWW3GSI73**G>*R^)o40!M5EGAw2sqk^|X#VPt3b&@bi3Am@I6X09iaE2*DsNDP-v@S~iw3T^3 z(?4^77*+v3S~9S*l@!*Dzj1q#hO%E61$6GUUF93y(3A;GFidZ_6>YwIu^roCsPFwdd61JGFo07eI!3z@WlGDUUQnzYo;m5 z_uG2=cU$GGY0Fca3tqEJUSI!1F_%o67M4{ezq(dN0CGkO)79HvHaQ>Txaz9gdcV0} z8k6<9>qvBC?8n9BvJ{zwRdAHIIKf}uZokqbTP?~?H?C}tGD@1%5%;-J$M@Vj9YCh- zKP;li)~qN>w&OJ5oD%f)8?AO=yLL= zjkej6I@#ciN39oH%l<6fB4f-xnyRuPfp3n`Q|P!IlKJW4jq|6cdwNCAi9~;xQuB}u zKfCY)v|yzNSLGd0uKfqerU4?PqErQuC%U(Yc3RMQR=$`*3w+4yh9TAPDsDx&v2w>dn1TkRy0+~V!>cuRWoK!!QG_xJ?9IxuUY?yxLFZ-PEMIofMwX-Il1Ud3j>{pxN-r;C%*R zV!ALg!F%g#_wylMz8h78A(DMq^ViXyZWBfu%9oz>FM7>e#!NCV)B+pOhCn&aT@iykv!X1}KgN*8m+xE=b zm&cpJJw~@=G~VaMnCZ(I3z-_SmOU$rJ(y>`b)o|6%A>;?U%_m{-JPNanrGrU4OJPLXRiid9G}vD_sKiB=2WW0Clu}>SbDXxu*Ekn zd5hWPAGcCUBQ?{XjD5=exolebKmE??)tdA}rE!yxw2YT$nhehnAYH<~=ue$#?&W*M z>@Em?z(YW*dr4u8Tt$q*je6C=EAcL>`ONv2clGky YAXQPiM?_Td=f7NM`~Bow#KR~43->PN0{{R3 delta 3740 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 delta 253 zcmVyZaWI-2*h))*43IoW7WnpnWRs%tx14?5v6a><7g)hEX26h=*hDAIbPh=5HHt(>A z{USFVCS&m`12jn`kZNE8nqetGTuh9i*diqsssRQPfp`HDzZc0+P&!>q$c5o}4C_O4 zsUI;ejDzNYmFTu38TuWFU7;4D0LGD5d<}jB0RjvFoANK_NYlLQ00000NkvXXu0mjf DQ66IR diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/address_bar_texture_land.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/address_bar_texture_land.png index 2cea1f0f3b36335408fbac8c101a87e79133ad53..305d7445198d988278b9aedb1afb613c5a5cee43 100644 GIT binary patch literal 7471 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 diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_more.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_more.png index 42b9b0b1e01a838646de0885f2c99ea6eeb704e1..ecaab55582e06ed8cfd70e2b4eb7190e9d985419 100644 GIT binary patch literal 1401 zcmbVMZA{c=9IuiALm4y1I1G-aV1k=mUykctI}SM7JG{)}J&|loD0c-q=nHM(4kj_+ zNVdRkAtr_p$TTys83J4O0TRvFCL7U>?8~+|kOk0aoKtWpMqsd~aEJRq{IKR}pQlfM zzu*7={9pQEer`@|%z+pPf@0lA*+MX<7oh5paT&epxm4_TYxq^q? zB3H#1@|>@+?kb-SK@n$!;u5{YbBy-NqKPvwrhupbHUy<-1{BU)!|QMbUnNL(Wd719 z0t-Gna@^vG8IGqTFV7Lz&Ei{Us-k|sROLX!9qn80uX#lRp_@if{((u5TbT?nwI z`YP!{))le^-t0)Vt}8T(`u%>B-)xfADio(E%FrN)RDej;8YP_zq)J*+Sb^m=uPP|I zAWN{J$W_Sox*Y+YZXQ8YJf1CKNecxEgbWRE3W}RBR1}SKZJ;&1kbmaJwrH)mQQ^@- zUX$xpFUUt_QkV>4_k2SJ5O_o9sRBp}SIf%YdXblOH)}`07n4u$(Jq_Sh2z#V%t~OS z4aaSm&Fso1CbNS?EO+$4?jgNB6b; z{%c~!<(#_Y>vcmXS`QAtw{o`Ug|GTs5}xe*;FHe1tsNI`zjmSYr>L=u+20`py?gtH z7k5S56t&L0y7stz_Ri0VWlMkE=(hToZ@rm6Za-w*Uo@Ac=QRBNaB*q}voN(b{f1iQ z=~ebj*G0@`jU+WTKJ8lk@nY#v>1Cz)O836FFDdC~1lBhHhsrJD6SG`Y%nq`x^iN delta 351 zcmV-l0igc*3cdr7ND%>GNklPTxAR{9q>yc9z zY7`aZDmmC#SqZ5J8UOy%r+YJ}Pq*ypXnFmgLglrtDDMHpV#qN? zvV9ad5Ck}ZSP$8eV8?m*ECq^tqC1Wp2a+4b=#E2F1xB}Bd~$~G<%{RJP xMRy=Q(jYcR%0Tf~AifX8@6a7bjspP#3;@>Vd!r~l#cu!r002ovPDHLkV1lB#t%Lvo diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_normal.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_normal.png index a5480fc747a99138f93047383f57b9925acaea65..6b29ecc0b99faab5d993df773da502e8e470a6cb 100644 GIT binary patch literal 13632 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 F{{l(dyiNcB delta 768 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 QGXMYp07*qoM6N<$f*{DGY5)KL diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/tabs_more.png b/mobile/android/base/resources/drawable-xhdpi-v11/tabs_more.png index e0980bf8918d4050ced9c018f681195e593edf6c..e9105f8993084cfbc441651ab1bec26469f7acd5 100644 GIT binary patch literal 1474 zcmbVMe@q)y9KS(aVS+3((ao@V9!43i*Sl+bZ4U~RyLKzAfTap9OXTPsa6)_KdWt3$>pHLjhMSM;H*s)H)N06;@fL6H(*y-mCf*YOR4--<*( z97SM(vm(_-7v>7ke50_VUE-_S%RS!qCa;AkxQJMQ*Yp%TCp}Dq&ibc-V;QwO$OzVUk2~gOMchZ7_l1gbo9P)ZzxpNK%9ePCN*( zCUNzYn{gy;ft?j;l;r@W)3vp=p>29plp1un#bQx82to@qw84;HW)-bJn3H5+_@Gx3 z0}s6I*2~0z6&5f-m55tq}Wzi9msn=@d4g!%f`;gld&S;1my&da+pmH95)#- z6M>Ot95-WTy`zM%*etZ2AoO^WV>K*E*lDK3L|7Pt#Bn=rAu$KTkhBdm(>6U#Cb3R` zP-gvJK516~b`x0qj#!G8cvcoAk0>@LE1*sW?VmqWwwlCX#89FpjRmy$sVt2k?M*l7o;XK?&> zkZh!#WXvWzO%nu?z;gd5z&hZJPOYSWRaR02%2i#i^a8iMNG{5?@5+Uv7Zw#T+q50v->8YulC!*K3XZ3c+PR~KdqME$)mS8{{_-OC!{^;Mc z(T9bOnQ7zLXlG|8XsPoWA}b)j|7~<`Zffik)5z1r`Wxv-u8lqyi$|}X(!W@2y}~_G zG^9*U%!)rPymCMHWXJs6R4#tJD}Nz=EOP79h_!gI|MSqk@D}K)j_VUYnno}Fp)V_Z zc3#PN{n2pA=FZsJQvz_L>*&zVv%F z`r1g-$&o8}wZ?NwwGD4^@2uH{=RxPb*zl6O`J}aPZzwjmt-IU4={t*gV|cVvb5HEu ze$-$Xe^nftR-_4=E9;E)A#KjZ@MX(j?}7gD?8pb5=CEe+_>rT1 z*H1M4I+WUe_GaXlvU_*k$lG(ZjC|ojDh#KcD{ZV(zK++ coe!mCKsn*>`Q8e+RQ;|fRqRjKN+Yb#8_35d-BG$ zEB8p%`0wAp{|jbMTMcBg4P+kp_5Ito$2lpn6R%#r_>2_C&z#b~bKcA;f9rtUj|1s} zKcMLU`t{4fy!80K>sK#7C(`k|7R{Y82gp4?&>jGR??8O}+t;sqi?WjY@p%H|cwngS zg*yHu5Wj>5!hjc}-+=hmhY#=f6lNt&xOx5R3tWz$J7e-JAom0izo69d(BkYr*%&=T z12Gp68}bVXlrLJf`Ni>zcenq;aB6nJ9-v$(5X+*MeiXTZiXK4sMA_uoi|%jRf8twm zM(%E)SQs|PQ|bXmN>-}?D>7W3-~?h-AT|PGK_I>h&9Kj~B^!#|Km!lJJi!jcLQwh> jw6ytyD;bju00ImEU@Tt7K?eKF00000NkvXXu0mjfFi*e( diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/tabs_normal.png b/mobile/android/base/resources/drawable-xhdpi-v11/tabs_normal.png index 8a6a25b917d9df9a9a2a6df84d1841788b7a763c..6559d40b82cac18d5450fca818c7c39008103f53 100644 GIT binary patch literal 17579 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 b{}W&UuPFVT#{6Ut00000NkvXXu0mjfcxt8> literal 15639 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 FV1kwOS_l9D diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/tabs_pressed.png b/mobile/android/base/resources/drawable-xhdpi-v11/tabs_pressed.png index b32449c2c297bfe9b068cbf671910c4ddf163e9a..9e9af23f57fb365f1a68917201976001e34c4ae6 100644 GIT binary patch literal 8962 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 delta 907 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 delta 3007 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 diff --git a/mobile/android/base/resources/drawable/tabs_more.png b/mobile/android/base/resources/drawable/tabs_more.png index 97e870267b6cf6d69c5037934e247e53dc1a5d39..74376487fc6130dc7d8cb8d5d3fbd8d9eaf1f94e 100644 GIT binary patch literal 1251 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

*Ck;gnjGVuEn) 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 Ozot?i)juh{diq}*29$aL delta 450 zcmV;z0X_cM34jEUNPhvMNkl2EgLjwJ@r_W#h8Jh!vY8hbSOe8o)?A@pD^7o#;W_b1fi!2|%ppu223L_y+ zq*%ZQBL4jO3+8;s6Kn|= z2Rj40JKlcybWKe`+7xK+H*7utB}FA5#_R1*U%rDeMy3K<26V3$kSPkp53$7o&)YYz z-;f*Lpum9Y=YPQ!L<&I41&GzL_>Kpd!&6`!Zzszo@7}(73o;i;%^x7X3B-GV=03m{ zM6W=SKzs^|?^J*oZUGN3?|z^K7eH}~oIOAx2sH<5Dgs5!0~}=$3SU4#=>8*y`xk*~ z|Kd|S^fTI^vf$r`_wPP{Gt-;b@9*8Y^%*S%5noi`$~#}44(6rM)N~h!-%;BFSQ0(~ sDmg%WUsUjUvb1$?8``@ej6676g(M1|yp004j} z9*1$@&N%K3*(bn#R$nz-;7&g?%v~9dR9{9ofkpzD`cS<|Ks<%uM{*z$d?G`hk_-WW zJsD&tSB9(gaU_vS0TXsH;0Q`Emkj_I8b<^Zhyf%9(3|8(4nl#JIgKD7*#`x3(XobD z2ct>;WLy-Did9fZrgD z02Js?r(CV=fM_a>1k?e;HHi=?6o^28q1rkK1XKeEgFsmKS5Q4R!V2BolvU{#? zXgb4z^tT)Th^9M529vZLNOWo_jmXW1uhI`PH+KJSXcx%!25CzpbCW^{#88Q$6jBfa zk3oUBU%)!7Yl{zYD08k5QH8Sst3`7W6fatrut}e7z_^mq47^#7}`u<2W}46 z$G{L!s5w+00l{K02(&3g4{ZuZBYtr4L39Qoh)DWjm&~>MoeTR{E)q>65g1gO6O|hH zqXO*wsSGOJpBfBAJ0gH;P&gR!E%6XILcK>x7`x7eQ%eDGc=jt z@n2)AP4K6kOf#`Rc7%fKcdm}RRBFnfez7QDFl^X0adC5Is9}I(!0FV78$@p))#n9p z18xEJ3)!^`*Qkwa*XX{}tg58)+>5vAXG&vJLY@y54M{%0!e{Pd`kK#AybigYm=P>d zFeZ6>1K)opQBHbHI=F}_{&2qC>{7u&)^eM#KX=2=p{d&h+SnJxgPSf!! zR+Bs_ZIcQfY0Gm>d$&~$kiGz?CL5$G887RvDi-xle@wguS!*f`_O&6WT^?Za@cthD z{(j}$Mf9qC;oh}eCxMXp*p@eF$;~glZr$~*K}Mm=o!|#Dxy$**Vo9mIv|AxsgpM9lP4h1M zk8H*r1>9wOpRkff1>?i4_m7N|(Z#U6i9M&Ke&tA+sP5=k?pgkM%eii)kI#Wk-v;>p zWR#HkMbTMQ9Cy~-bn?7TX$*hrwY93XtPI&3)=@cwT{TyGU9EW5fA838vff`%h#g13 zYW)O@NQ-?vd7+jE zlGVI}5RfI?#dM@=x_#a}*|8_x@(`;)Hbu+`u=3^;R7b39KQ6?3+of80UEsjYs{3!+ zzTWMxECAn&E5h)B&$?-av9xEqQ~Tpgd!Zzn{p_zG$%)z3VU$N z7Jqt0@MZJ1gUF;9%^s7aXY)ZvIL5ihHAbCvvDWp~^ZFV4?mU@HwF*d*Mn;p{2uE;p zRi)9TjOGLI4D zMO`K)qCE~SRK2*&r}nZ8508$8)C(zP4%p`#PsL03I%`vzBQ<;Ie0JjYJ*Dh~cB#Nh#SSYNFyqGr(*BHv6u60b-n_$W&^jb_mx$+o=f~)_tDJH;pbd&-6skLx2T7|=jPT2(!J}ESwNR+|rVDcWLg?CSWl}~-Z+Th0t+Yotv5yEyQbmr`HxkP2lsPihbGBm`yYy9nvc~@-t zyyABX*%OBtdSC2SzT9qbwUAxUs6Gec1Qg$kC*OXQm3;&;ggq`a*c^JQMIlp3!lFnw zaH1q;acSy^;wvoJaxW_?RXI13I9kP{bRgBJ_R2%G82R`lp`TsQB=5k1_e;>&YVNQ2f1C}P;n&Wh2O z{;;%&h7xX}X4^Z5LLIEGr^dFiuTTBQYxKjgxS_4DCGaK6(zf*Kgx@7KesQ?!O{rLR zWY|^{w9H##vOji#!JBKw?oh6T-LSgY`ARXUtl4Z6DYfUV)8V|;r$^aw>=BJv8{t5L ztis$Z8}G##P!R#bPY)m%1;tZKot&+H%=4rJV|s^J>=QgQF!qO|!h)Z3mtFvVwQ3p7 zvUQI91G?cf`q=(%Sdm-Xjq>P#d~gk%`DS}qB0=CtrO1#@Tb^?6d%{M;l_OQ2?)!&E z*<0CNXG6dih{cyo`Q=xGD7ISdWm#o7+Z*U}fBc4w2^$FG$eLV;%Ncen%VfbFlO`H> zj3~aplwPmDyy_iRoos!av(+U!NCH+6?aHs%6tq3cCfq%PLe|CDTPFR?HkbSPVAb=NmtP6RrqsF(2GZPU%rR?6L`t|A; zcetH+ME3%-d!x`C(9O26s^Ce#AJu&REe{<1E;S*@Q2E|qi5|GcWID$>Ss2cmD%gHS z%~#4r-8p16+^zbE!v;zFWgM)G%7``)NH@QhY-h3eH_FWvQ<1`bU#m|9KUiuL;nDW! zEzYL}84Z^{dF*n%;Scvlmj8!%Z4(9g6BNxx zDHFrsPCngSF_=kh?av|g#3yx_kptO<2;Hc-=~N3yRzKwFol5E4*IL~`UuNhB!yQM) zr$`$aRsAFeB)gpXy4xj6-ui_Ham|_1GVXWyi4!oms*mI#eZ0&mL4|Q2OrN-C^9Iv7 zeJ^(qOTLM%wsw{=Tv*DEMI0T_m#_UYq&X~Md!za7#Np{R{D~{@qkGfTDk@o5HOmYT zZB^saAKGpz2YRPYO;=^4+^=n5i+g(w50q#=X;m`D9;Y1J&kk+NWV#9gpjM|jQHs?y z=MD(L9VhUom!@h*om#;5s&3=1uj>Y;B(~_nJm=PXsZAbLKV^JsObR~hx$Gdn-fi^m z!FlUqgx#a}8!qqz<*Twd%dP1E|4}|&P1v+?tLy3h?T-5@@z5>KXxf3)!a4agxpgF} z{av)w3BK9Zte%e%z%>ui{K2N-mE=y{rLi2Fn{MRZepX(NW@|zFTWxqrYNOZ-qiwzE z)X#ipdPU^ohM9g1U&ryps2ysh<(`%|9qd!$>OSjRo>PHY@h^+Y#Fi6#&uAvVB-dIA zaUU-Yo{1PwIca>F?~1`T-%0eR@vhYQcQ>pWiN|}SeLJg0D?p0_`V|P1n6C?DIAy*z zi@!a`GbAc*uhkjHI~I@X`X0q!4?b3D1BYzHI*etR;;^ZT$g|=rPn*-q>2knRa@fdh z8>q>%oqa{eUI2;S9xBp5dv#kauUI9A7nij1M%iImGQIQvT>s!PlFNp9~9&jsRK;i||(vSvfAW>+OP!}huJ)w;q-^X*G z|9Y;hZ>_b@e`Y*0B+YO}zy8ZPXP>>-{?@m?we}vbC<=1NT7RoM&2LAOBpGja+7G8m zdUkzn?U(N@EIjn?JMYlK!UEN5b!s#l)EpY3W}`ukdXxMhpePEZ4YYk|FUe;%L2eNh-ln+ac!Bjfu+e(w6lI<;FZ zx_$c=ZLF`+t$&*z(4AX1DUM^gCg5xGJeSW=6cLY2-ra%kxW?x`x_0s1efFvbsvZl= z>(a?kZuTDH*RQuboo8-bzxIX8m*1v0-h7jq%^@+=@bEA-8clB4jD*4RtKaYQz(VXmoIfM^#+K;JyiBR6h*#xue&+%$gthBkLJ(4ECqz0hU~2O9}! zm}JBKF+<|{x88bl{NxxE)+OxKA%4-!Vo%zxeR8wMP(I{{tz9UV>B#qi!|BZh25 z^f|M3(0!oK_tZstJOR#NIDm|yW>aWkp3!vim6sWvof19bMrJ7IW_qpzC)Q zDKg~9?4&w~8amJSV3q|H9(}G^tNrcb;{5|(``TZM0h-NWnwXf7+4N*4a{1hI=qao- zg@2*~#>agyO3cuXj5ktzXH-P&y8R?JgL&lhpSU5r9gyNUPf?Tzvf#o|#cj~u#J+um z$A0IfZ_<17SELUPEdwBYNDjJjcUcSoazsZ#v~V~1p5|=fL8ENx1N`<6UXeX@{`}YJ z=FOWlIzG-2ALoInF~n^QMKB6bfr;z&`hS7|3@R5QkJSyt#rpCr=VIU>{1&poU~Kdq zM!<|aLjyf%5A9cx=Z=Tmu^Nqz zGQTiXtJaR=l%rZGFy{_6hnlr-@Lo|se0+fo_wALX#o#Yqe33@j=O^|}k{1Lj z48;{xv}J|56SxQ+b|^xGOMi@TRa3<#_7q8QQwUTg>PS$AdmL#yt%V5$606iuJ!*VC zuKADeeur*cf4?-gGkEaA3omSYW4qlhFLW6>bSbFBFI%|=*gQ{UCE_2Z@?!dEzM}Rtnbv_ScrGGYP9k5Oe&;)k} zCpq2$QKM}LQy31v13f`CGABt%-UsFm(e?NLN097LBnq2$IJO$6`T`L?eBv0LJa&kd zmKN#Wy}L5tL=B9ND{EL>d{Lk$;i;08uUqRuA;8#=)j)94A;gLtsJKpilkWrv;gXiCR2iM+1GB zV|xE2oj!StR+g9PK66wZ5e?y(XZRCG4>0QUucDj3^rh#h!-$Mo=s_{NbVI^!;LCSG z02{DguT>@@5>159P|m&u1BVKH2kKz(3_6XQg(!46;ntAt$bVW~D~d`qp*`F`cla1h zPR*Jc*XaCHA*lKq`{p{%(jrNAp_57HtLjHTQDTJ#Q0B;;oKFj=F%h={+(;V6GVk`doAu8xbLZ_ zKO;&W-S9+|et%2@;dO9kigJGN^2#bB1kkO{T=7**+UK8nR#4R1*bozx8MLP+NsMot zpzOzqxP(`tM7g2C2m^XB>w)hn8a)-2YFJO&7L8=72--zka6gA0MVSg$JX-`NPsrr{ zDVmv`lgUQgAIrt6$I0V|sMTuo!vhY*{qpyRkIuZxNPqaZ;n6WVd-fbB5T zj4Fwes00Ll8QFjeKVUurm-&Mr;P?g+4hE>WwF7Zh!uNxC1W544x0`GuId z;(yE|XDcpNNT=)OW?lvU1KF=-75pyfvO*aQBDs>U6C)8$NIDQi;Z}#nIvW+=T_RhP z^S){(@&*WW^&tLSuQzEwhx|P?P-q>7p|&24dh|M`Aubpcxh1uk>Mtv=;#q|i;&9LO^z7an2sYX&0gjXOTYn(% zgNKg_2PJS9A!y|q&7V+B)KHCcQbDwW8}5~Y8c5i#2f9LE$<{CDrVyzh!cc@_p;ZUZ z)K8(hNyMm>Rti%^x#%oR6#9hn@&5yY*th%1wrys4@e&p?<~T9*rSR?w_^O6wRm4-7 zUyJI<=h!%bpv(11G>{<<=W^pH2!BfqvnMHtFDB~swK@p{V(CcAMTHZOp&$sK;ksCg zqQWcD47aQEv-V6VmL-uQFS%pu@u{=Nmvf080X_84iLx+HmV3I{mmCYmfOvEqWOXDg zB}vjNX-7^8e}@5-qB)#Pl=I|!lhJ_U93oX$}ew;hgv*MO&o6<-g$%11lD=1cB^a@qN9KAeq6%aeVCwzasp~}0E zC8t#KG%FD3>P4PNTe6Ue8WGuoft5<&iuetAp>Pq(G04;Q+CTzde`jC{sb&QooIAoZ z8Oxx26N$h;A{xp{A?ALv4u6&)%6XPDXqd(l5C|OZ3Co~%4x`FKffz*xjXp(TUEEOC z>#&3rC*o$A=&MwolV*A8g8E|a+RZ>8^}xf1hZ<3UbvxR2NcV$R$0p*!w_sZzfNrq0?k03=*ZU)m5!Y_CE*_WMmIKaXLY<}FJ+acW#v6HZYYDoV9ofU64q zE_x}|?|-S)v4y{o)TVo&q+uM0yWCW3w-=YoI@@!QSMK+*{EVh&574Por>Wa%v#WKD zaC0MLlK1LX7TtBmDD3qIeKAx4eQ+cAndev6e+KLJE?V_1X9TxlM;qR?e5-m0b?J}g zVt4MZ(t4{a^_x{D=ytbnySu{ON!kP;jL_}%C4Z@W`m>*x48OhJ5@jpvSDsfYY4SCE zC$@P(G*Po*dx(-!2LO@S%Y<7%Pq;n>adW>4%Vi)?K?hpQ*FBQhV1>REH1J3Sfu9ON zP|P>)tuP_?X=-weR@U3%Rt;MtPqvg?tA}&HK}l2-$?2&ndiEE;NbPouU2Q``FqM^Q z<$o4HAJ=A;yiGJ!pbM5sta6}^x>Bm85V$Ic9{C5td}5m>GyxtI*x*ud*=nvKI_skt z2*=%}HJZP6SCBF~+@#wJtJG@uBy&c2qS=VHtth%;PRC#yZ@ww( z&qO^(^xT(!MLM>&wnnX1OZX@-rVXSvq#LGmMKrK=u;hW&3b)M$=YX2NAh#&10e>(S zHh5x}3i^VmCHpUJcdnFplU-cwNAKUJ`RjM-*8LTZP8~_;4o>Z3{}1Tq!ZIzcZfLfP zRZJc94=>R~&--qMk=b$E4=tssg%GEtYWXcBUn^#)S=8Zq-DViY(=D_aH%r ziw2c@t7~JSEiS zhr78ocom1Ca9rd|t|`t7|K?yt*R)qX8sf^HXkVNa1$3Mp|i<3a8bS zkh}(17ziUvGivgCjxsB^t2^Fu-3*ax#6&wgy4a$FoJ(V z8@Q6I%7@4{le;x9w;@zkGHlH)&y}}yi?RMA4Z?n8`y4R=;s2$U9sj^Mb^DJV_h5If zX3E&D61ZJlJL#*sC5b>^vr)5BMNpP)-CCIA0{qtIj^jCVM}JS!A3Xm@lyFLN>-J6h z;iXG7fAtD;PGTD&BB=|-ac-#aBmyG(N!wPg^}NFB*`c6J{`~+G0W?`PQP$~pGY)1k zvw>=N zgGcEXrsn9`FGoJd3VcI!6O{Pc$|`MaY_OJErTYsDwv)s&m9Ja($Worb*RiA1TeOT9Q`kEEZa&2VO^L1Fg`cq|p}8Au1y1 zaJch}b0SVuj^R{>sNlpyrw$qTHHV&95kEG)W1dsgbGQ^i_lM^n%e~3_=FRgwzu)`& zxD;#S=Z^N9@I^cm2tfc0^C7VWhM{Oc2tq;u$PSnXi4h5m2&KT_#bvG0 z=5!2^F6f#sP6pElBjrVbdXe=l}K~#nbVF*$}G8j~07>p{w7*rub z;UTV?bTBw+B8Kc*S-XSW*bj0MlqPV7qV*J&HB!= zN3}iXYaEW(AvLDZyRJW4*qRxL2fT)R+sgN?3L2j9xXf?Up4#k`8A@fsbY)&t$W;U8~Ij-D{KA@H2}67pii zs|Vi|Ijf&|Z#CIVTb$6^%Cc~^{@%m;7UU`EpO%Jt`M3DT?`sX>Hm+@(Fr)a+vw52$ z-O|t9!jZWUja6^Z3}|C)=}KZMT;-{yDwB%U$MNC2 zfgS0=lSres{YrOx)~LmymNH@+vjh$vvukWA(Lr|^UC;Wx_b$>tH1_VD15TV*f21t` zNY>5Ye62@~PYYm zBQ!V2s8;??e{^?5R%h^ Bfhqt1 delta 507 zcmVr6NPhv_Nkl}u;u#nI+Ha1qp z4<9~;Hr1BD!(~8g*Mv+iF3xbEx|GJ6vO7fi;NANVlV7}imHg)IJ10g)#$7dy?Lyep zRW-EbfBW`*+S|A9?15?zWagLi6J^2IuirR<7BJkq|B&I+=YKE8OiWA|mVgZZ{rmR> zkh(kf9x%Lp_nz(jhYxJT#z8s|?*K8Lzj(>;`O8$h(p zq1Qm{ykgrgR@#&mEY8?=JfcTOU;tWE90%w8ovK|;5Em#b{jLjTId>IXB z3CPPEVU`FA2!AmA2f|-Je=&Uf{+*!V1TDa32@)V^I8pfkXuvOEu7uxaYn1EZ_5`K6YXU~vf%IEe+=B*T*kn7!I^}KvH+YE|6rt+edwtRpCvdg zsH|_rniPT96NtB>TLMhFLPSS$RzZ0hGc)r{U@pa)6m+2xzZ!`BKzs>tF@`^X|DI*| z|KDm#U;8g&iVBa{Z{Ffe=b(rOQlUV+3B(8G<~MKNY60^HKe0iS0>o$WB}Ft#K$*e^ xTTW&G1raVB9+$?0Po5ZcjH6ZN@V5XUzyP;hP^<^yIV1o8002ovPDHLkV1fiE_6Yz0 diff --git a/mobile/android/base/resources/layout/browser_toolbar.xml b/mobile/android/base/resources/layout/browser_toolbar.xml index a7a14256353f..f4cb930c78d1 100644 --- a/mobile/android/base/resources/layout/browser_toolbar.xml +++ b/mobile/android/base/resources/layout/browser_toolbar.xml @@ -46,7 +46,7 @@ android:gravity="center_vertical" android:src="@drawable/tabs_level" android:paddingTop="3dip" - android:paddingLeft="37dip" + android:paddingLeft="38dip" android:paddingRight="10dip"/> Date: Fri, 4 May 2012 14:22:55 +0200 Subject: [PATCH 25/53] Bug 751858 - Actually throw when we deny access. r=bholley --- js/xpconnect/wrappers/AccessCheck.cpp | 6 ++---- js/xpconnect/wrappers/AccessCheck.h | 9 ++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index ce93bdf1ef63..5aa59cd9ca67 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -455,12 +455,10 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: perm = PermitObjectAccess; return true; } - if (act == Wrapper::PUNCTURE) { - perm = DenyAccess; - return false; - } perm = DenyAccess; + if (act == Wrapper::PUNCTURE) + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS); diff --git a/js/xpconnect/wrappers/AccessCheck.h b/js/xpconnect/wrappers/AccessCheck.h index 703bd70bdcc4..75a85ee99dc8 100644 --- a/js/xpconnect/wrappers/AccessCheck.h +++ b/js/xpconnect/wrappers/AccessCheck.h @@ -120,14 +120,13 @@ struct LocationPolicy : public Policy { perm = DenyAccess; // Location object security is complicated enough. Don't allow punctures. - if (act == js::Wrapper::PUNCTURE) - return false; - - if (AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act) || - AccessCheck::isLocationObjectSameOrigin(cx, wrapper)) { + if (act != js::Wrapper::PUNCTURE && + (AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act) || + AccessCheck::isLocationObjectSameOrigin(cx, wrapper))) { perm = PermitPropertyAccess; return true; } + JSAutoEnterCompartment ac; if (!ac.enter(cx, wrapper)) return false; From 3781be717ab7d9b6be5286677bbd4b713146ffd1 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 4 Jun 2012 12:00:51 -0700 Subject: [PATCH 26/53] Bug 659577 - Add missing weak-pointer incremental barriers to DebugScopes (r=billm) --HG-- extra : rebase_source : c98293c420177def6186f1487283bb888ef03e04 --- js/src/jsgc.cpp | 2 +- js/src/vm/ScopeObject.cpp | 28 +++++++++++++++++++++++----- js/src/vm/ScopeObject.h | 6 ++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 016354870475..35d28233a1c5 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3241,7 +3241,7 @@ SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep) /* Finalize unreachable (key,value) pairs in all weak maps. */ WeakMapBase::sweepAll(&rt->gcMarker); - rt->debugScopes->sweep(rt); + rt->debugScopes->sweep(); SweepAtomState(rt); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 6e55030ebdf3..72142bd011da 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1418,7 +1418,8 @@ js_IsDebugScopeSlow(const JSObject *obj) /*****************************************************************************/ DebugScopes::DebugScopes(JSRuntime *rt) - : proxiedScopes(rt), + : rt(rt), + proxiedScopes(rt), missingScopes(rt), liveScopes(rt) {} @@ -1447,7 +1448,7 @@ DebugScopes::mark(JSTracer *trc) } void -DebugScopes::sweep(JSRuntime *rt) +DebugScopes::sweep() { /* * Note: missingScopes points to debug scopes weakly not just so that debug @@ -1455,7 +1456,7 @@ DebugScopes::sweep(JSRuntime *rt) * creating an uncollectable cycle with suspended generator frames. */ for (MissingScopeMap::Enum e(missingScopes); !e.empty(); e.popFront()) { - if (!IsObjectMarked(&e.front().value)) + if (!IsObjectMarked(e.front().value.unsafeGet())) e.removeFront(); } @@ -1700,8 +1701,25 @@ DebugScopes::updateLiveScopes(JSContext *cx) StackFrame * DebugScopes::hasLiveFrame(ScopeObject &scope) { - if (LiveScopeMap::Ptr p = liveScopes.lookup(&scope)) - return p->value; + if (LiveScopeMap::Ptr p = liveScopes.lookup(&scope)) { + StackFrame *fp = p->value; + + /* + * Since liveScopes is effectively a weak pointer, we need a read + * barrier. The scenario where this is necessary is: + * 1. GC starts, a suspended generator is not live + * 2. hasLiveFrame returns a StackFrame* to the (soon to be dead) + * suspended generator + * 3. stack frame values (which will neve be marked) are read from the + * StackFrame + * 4. GC completes, live objects may now point to values that weren't + * marked and thus may point to swept GC things + */ + if (JSGenerator *gen = fp->maybeSuspendedGenerator(rt)) + JSObject::readBarrier(gen->obj); + + return fp; + } return NULL; } diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 9e4aeeeff307..f25a7e82dd9d 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -414,6 +414,8 @@ class DebugScopeObject : public JSObject /* Maintains runtime-wide debug scope bookkeeping information. */ class DebugScopes { + JSRuntime *rt; + /* The map from (non-debug) scopes to debug scopes. */ typedef WeakMap ObjectWeakMap; ObjectWeakMap proxiedScopes; @@ -423,7 +425,7 @@ class DebugScopes * corresponding debug scopes. */ typedef HashMap, ScopeIter, RuntimeAllocPolicy> MissingScopeMap; MissingScopeMap missingScopes; @@ -447,7 +449,7 @@ class DebugScopes bool init(); void mark(JSTracer *trc); - void sweep(JSRuntime *rt); + void sweep(); DebugScopeObject *hasDebugScope(JSContext *cx, ScopeObject &scope) const; bool addDebugScope(JSContext *cx, ScopeObject &scope, DebugScopeObject &debugScope); From 155a08f0226de411f1675569232d1be8ae28c2c4 Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Mon, 4 Jun 2012 12:22:23 -0700 Subject: [PATCH 27/53] Backout of 2f4307a63c18 - Bug 759989. --- content/events/test/Makefile.in | 1 - content/events/test/test_bug742376.html | 58 ------------------------- dom/base/nsGlobalWindow.cpp | 23 +++------- dom/system/nsDeviceSensors.cpp | 11 ----- xpcom/system/nsIDeviceSensors.idl | 5 +-- 5 files changed, 8 insertions(+), 90 deletions(-) delete mode 100644 content/events/test/test_bug742376.html diff --git a/content/events/test/Makefile.in b/content/events/test/Makefile.in index 5d7c62ec7f7a..488085373624 100644 --- a/content/events/test/Makefile.in +++ b/content/events/test/Makefile.in @@ -85,7 +85,6 @@ _TEST_FILES = \ test_bug741666.html \ test_dom_keyboard_event.html \ test_dom_mouse_event.html \ - test_bug742376.html \ $(NULL) #bug 585630 diff --git a/content/events/test/test_bug742376.html b/content/events/test/test_bug742376.html deleted file mode 100644 index 156a679d4b28..000000000000 --- a/content/events/test/test_bug742376.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - Test for Bug 742376 - - - - - - -Mozilla Bug 742376 - - - - - diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 2ce84bc30ee8..4b19d71d5217 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -10040,44 +10040,35 @@ nsGlobalWindow::EnableDeviceSensor(PRUint32 aType) } } + if (alreadyEnabled) + return; + mEnabledSensors.AppendElement(aType); - if (alreadyEnabled) { - return; - } - nsCOMPtr ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); - if (ac) { + if (ac) ac->AddWindowListener(aType, this); - } } void nsGlobalWindow::DisableDeviceSensor(PRUint32 aType) { PRInt32 doomedElement = -1; - PRInt32 listenerCount = 0; for (PRUint32 i = 0; i < mEnabledSensors.Length(); i++) { if (mEnabledSensors[i] == aType) { doomedElement = i; - listenerCount++; + break; } } - if (doomedElement == -1) { + if (doomedElement == -1) return; - } mEnabledSensors.RemoveElementAt(doomedElement); - if (listenerCount > 1) { - return; - } - nsCOMPtr ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); - if (ac) { + if (ac) ac->RemoveWindowListener(aType, this); - } } NS_IMETHODIMP diff --git a/dom/system/nsDeviceSensors.cpp b/dom/system/nsDeviceSensors.cpp index c69cefb29bf4..8722c0b29a72 100644 --- a/dom/system/nsDeviceSensors.cpp +++ b/dom/system/nsDeviceSensors.cpp @@ -118,17 +118,6 @@ nsDeviceSensors::~nsDeviceSensors() } } -NS_IMETHODIMP nsDeviceSensors::ListenerCount(PRUint32 aType, PRInt32 *aRetVal) -{ - if (!mEnabled) { - *aRetVal = 0; - return NS_OK; - } - - *aRetVal = mWindowListeners[aType]->Length(); - return NS_OK; -} - NS_IMETHODIMP nsDeviceSensors::AddWindowListener(PRUint32 aType, nsIDOMWindow *aWindow) { if (!mEnabled) diff --git a/xpcom/system/nsIDeviceSensors.idl b/xpcom/system/nsIDeviceSensors.idl index b57f878afc30..482c168e2c04 100644 --- a/xpcom/system/nsIDeviceSensors.idl +++ b/xpcom/system/nsIDeviceSensors.idl @@ -24,14 +24,11 @@ interface nsIDeviceSensorData : nsISupports readonly attribute double z; }; -[scriptable, uuid(83306c9f-1c8f-43c4-900a-245d7f219511)] +[scriptable, uuid(b672bfe0-4479-4094-a9ef-1b6847720d07)] interface nsIDeviceSensors : nsISupports { - long listenerCount(in unsigned long aType); - // Holds pointers, not AddRef objects -- it is up to the caller // to call RemoveWindowListener before the window is deleted. - [noscript] void addWindowListener(in unsigned long aType, in nsIDOMWindow aWindow); [noscript] void removeWindowListener(in unsigned long aType, in nsIDOMWindow aWindow); [noscript] void removeWindowAsListener(in nsIDOMWindow aWindow); From 6d009115f5ba01dbec1370f32ff8deadd10b3d98 Mon Sep 17 00:00:00 2001 From: George Wright Date: Thu, 31 May 2012 14:56:33 -0400 Subject: [PATCH 28/53] Bug 761201 - Trigger Skia's RGB565 blitter fast path by using SrcOver instead of Src. r=jrmuizel --- gfx/2d/DrawTargetSkia.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 222bf0e4ea1d..39a3df176e6a 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -630,7 +630,17 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface, SkIRect source = IntRectToSkIRect(aSourceRect); mCanvas->clipRect(dest, SkRegion::kReplace_Op); SkPaint paint; - paint.setXfermodeMode(GfxOpToSkiaOp(OP_SOURCE)); + + if (mBitmap.config() == SkBitmap::kRGB_565_Config && + mCanvas->getDevice()->config() == SkBitmap::kRGB_565_Config) { + // Set the xfermode to SOURCE_OVER to workaround + // http://code.google.com/p/skia/issues/detail?id=628 + // RGB565 is opaque so they're equivalent anyway + paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + } else { + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + } + mCanvas->drawBitmapRect(bitmap, &source, dest, &paint); mCanvas->restore(); } From 44c25428b619d5c25b741e318b9fb432b7f65dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hub=20Figui=C3=A8re?= Date: Mon, 4 Jun 2012 13:29:15 -0700 Subject: [PATCH 29/53] Bug 761256 - Disable a11y on Mac for Aurora. (back out of the enabling patch) r=tbsaunde --- configure.in | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 1fe49d1ee776..41dda5cd0489 100644 --- a/configure.in +++ b/configure.in @@ -4597,7 +4597,15 @@ MOZ_USE_NATIVE_POPUP_WINDOWS= MOZ_ANDROID_HISTORY= MOZ_WEBSMS_BACKEND= MOZ_GRAPHITE=1 -ACCESSIBILITY=1 + +case "${target}" in +*darwin*) + ACCESSIBILITY= + ;; +*) + ACCESSIBILITY=1 + ;; +esac case "$target_os" in mingw*) @@ -5530,9 +5538,10 @@ AC_DEFINE(IBMBIDI) dnl ======================================================== dnl accessibility support on by default on all platforms +dnl except OS X. dnl ======================================================== MOZ_ARG_DISABLE_BOOL(accessibility, -[ --disable-accessibility Disable accessibility support], +[ --disable-accessibility Disable accessibility support (off by default on OS X)], ACCESSIBILITY=, ACCESSIBILITY=1 ) if test "$ACCESSIBILITY"; then From bbbf2ebf500b305f97f5cbcaacd9e1f83774282e Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 4 Jun 2012 15:14:41 -0700 Subject: [PATCH 30/53] Bug 760007, part 1: Fix the IPDL C++ test harness. r=bent --- ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp index 8a29d5bdf868..4663e5a64fb7 100644 --- a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp +++ b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp @@ -164,10 +164,6 @@ ${PARENT_ENABLED_CASES_PROC} return; // unreached } - // Create the two processes: - if (NS_FAILED(nsRegion::InitStatic())) - fail("initializing nsRegion"); - printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); std::vector testCaseArgs; @@ -219,10 +215,6 @@ ${PARENT_ENABLED_CASES_THREAD} return; // unreached } - // Create the two threads: - if (NS_FAILED(nsRegion::InitStatic())) - fail("initializing nsRegion"); - printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); std::vector testCaseArgs; From 107bf169a8527849d96ce81dc019b5ca71eb289a Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 4 Jun 2012 15:14:41 -0700 Subject: [PATCH 31/53] Bug 760007, part 2: Fix shutdown race condition in cross-process TestOpens. r=bent --- ipc/ipdl/test/cxx/TestOpens.cpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/ipc/ipdl/test/cxx/TestOpens.cpp b/ipc/ipdl/test/cxx/TestOpens.cpp index 4b17b42c7683..a8d2ec97e4cf 100644 --- a/ipc/ipdl/test/cxx/TestOpens.cpp +++ b/ipc/ipdl/test/cxx/TestOpens.cpp @@ -238,6 +238,24 @@ TestOpensOpenedChild::AnswerHiRpc() return true; } +static void +ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child, + Transport* transport) +{ + delete child; + + // Now delete the transport, which has to happen after the + // top-level actor is deleted. + XRE_GetIOMessageLoop()->PostTask( + FROM_HERE, + new DeleteTask(transport)); + + // Kick off main-thread shutdown. + gMainThread->PostTask( + FROM_HERE, + NewRunnableMethod(gOpensChild, &TestOpensChild::Close)); +} + void TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) { @@ -248,18 +266,12 @@ TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) // ActorDestroy() is just a callback from IPDL-generated code, // which needs the top-level actor (this) to stay alive a little - // longer so other things can be cleaned up. + // longer so other things can be cleaned up. Defer shutdown to + // let cleanup finish. MessageLoop::current()->PostTask( FROM_HERE, - new DeleteTask(this)); - XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(mTransport)); - - // Kick off main-thread shutdown. - gMainThread->PostTask( - FROM_HERE, - NewRunnableMethod(gOpensChild, &TestOpensChild::Close)); + NewRunnableFunction(ShutdownTestOpensOpenedChild, + this, mTransport)); } } // namespace _ipdltest From 30348c2a2473b4a9f27a146b4db75498e01827a0 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Mon, 4 Jun 2012 15:23:07 -0700 Subject: [PATCH 32/53] Bug 757485 followup: Remove reference to recently-deleted /content/xbl/public from toolkit-makefiles.sh. standing-rs=ted --- toolkit/toolkit-makefiles.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 256ba53470af..3f6ccd3239a9 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -202,7 +202,6 @@ MAKEFILES_content=" content/xul/document/public/Makefile content/xul/document/src/Makefile content/xbl/Makefile - content/xbl/public/Makefile content/xbl/src/Makefile content/xbl/builtin/Makefile content/xslt/Makefile From cec2715e6ce2a176751a59e7df6cc463b95db99d Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Mon, 4 Jun 2012 15:23:22 -0700 Subject: [PATCH 33/53] Bug 760795 - Remove MOZ_MEDIA protection on GkAtoms - r=bz Remove the #ifdef MOZ_MEDIA conditionalization on media- related nsGkAtoms. Saving the small amount of space associated with these isn't worth the trouble of maintaining the list. --- content/base/src/nsGkAtomList.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 20d850b07d9d..c3d9619997be 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -95,9 +95,7 @@ GK_ATOM(_auto, "auto") GK_ATOM(autocheck, "autocheck") GK_ATOM(autocomplete, "autocomplete") GK_ATOM(autofocus, "autofocus") -#ifdef MOZ_MEDIA GK_ATOM(autoplay, "autoplay") -#endif GK_ATOM(autorepeatbutton, "autorepeatbutton") GK_ATOM(axis, "axis") GK_ATOM(b, "b") @@ -220,9 +218,7 @@ GK_ATOM(context, "context") GK_ATOM(contextmenu, "contextmenu") GK_ATOM(contextmenulistener, "contextmenulistener") GK_ATOM(control, "control") -#ifdef MOZ_MEDIA GK_ATOM(controls, "controls") -#endif GK_ATOM(coords, "coords") GK_ATOM(copy, "copy") GK_ATOM(copyOf, "copy-of") @@ -253,9 +249,7 @@ GK_ATOM(defaultchecked, "defaultchecked") GK_ATOM(defaultLabel, "defaultLabel") GK_ATOM(defaultselected, "defaultselected") GK_ATOM(defaultvalue, "defaultvalue") -#ifdef MOZ_MEDIA GK_ATOM(defaultplaybackrate, "defaultplaybackrate") -#endif GK_ATOM(defer, "defer") GK_ATOM(del, "del") GK_ATOM(descendant, "descendant") @@ -505,9 +499,7 @@ GK_ATOM(load, "load") GK_ATOM(localedir, "localedir") GK_ATOM(localName, "local-name") GK_ATOM(longdesc, "longdesc") -#ifdef MOZ_MEDIA GK_ATOM(loop, "loop") -#endif GK_ATOM(low, "low") GK_ATOM(lowerFirst, "lower-first") GK_ATOM(lowest, "lowest") @@ -571,9 +563,7 @@ GK_ATOM(x_moz_errormessage, "x-moz-errormessage") GK_ATOM(msthemecompatible, "msthemecompatible") GK_ATOM(multicol, "multicol") GK_ATOM(multiple, "multiple") -#ifdef MOZ_MEDIA GK_ATOM(muted, "muted") -#endif GK_ATOM(name, "name") GK_ATOM(_namespace, "namespace") GK_ATOM(namespaceAlias, "namespace-alias") @@ -761,9 +751,7 @@ GK_ATOM(phase, "phase") GK_ATOM(ping, "ping") GK_ATOM(placeholder, "placeholder") GK_ATOM(plaintext, "plaintext") -#ifdef MOZ_MEDIA GK_ATOM(playbackrate, "playbackrate") -#endif GK_ATOM(pointSize, "point-size") GK_ATOM(poly, "poly") GK_ATOM(polygon, "polygon") @@ -779,17 +767,13 @@ GK_ATOM(popupshowing, "popupshowing") GK_ATOM(popupshown, "popupshown") GK_ATOM(popupsinherittooltip, "popupsinherittooltip") GK_ATOM(position, "position") -#ifdef MOZ_MEDIA GK_ATOM(poster, "poster") -#endif GK_ATOM(pre, "pre") GK_ATOM(preceding, "preceding") GK_ATOM(precedingSibling, "preceding-sibling") GK_ATOM(predicate, "predicate") GK_ATOM(prefix, "prefix") -#ifdef MOZ_MEDIA GK_ATOM(preload, "preload") -#endif GK_ATOM(preserve, "preserve") GK_ATOM(preserveSpace, "preserve-space") GK_ATOM(preventdefault, "preventdefault") @@ -910,9 +894,7 @@ GK_ATOM(sortResource, "sortResource") GK_ATOM(sortResource2, "sortResource2") GK_ATOM(sortSeparators, "sortSeparators") GK_ATOM(sortStaticsLast, "sortStaticsLast") -#ifdef MOZ_MEDIA GK_ATOM(source, "source") -#endif GK_ATOM(space, "space") GK_ATOM(spacer, "spacer") GK_ATOM(span, "span") @@ -1048,11 +1030,9 @@ GK_ATOM(vendorUrl, "vendor-url") GK_ATOM(version, "version") GK_ATOM(vert, "vert") GK_ATOM(vertical, "vertical") -#ifdef MOZ_MEDIA GK_ATOM(audio, "audio") GK_ATOM(video, "video") GK_ATOM(videocontrols, "videocontrols") -#endif GK_ATOM(viewport, "viewport") GK_ATOM(viewport_height, "viewport-height") GK_ATOM(viewport_initial_scale, "viewport-initial-scale") From b06853949dd20257fdb0453b9632238bcb44b69c Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Mon, 4 Jun 2012 16:12:24 -0700 Subject: [PATCH 34/53] Bug 753862 - Settings API: electrolysis support. r=fabrice --- b2g/chrome/content/shell.js | 1 + dom/settings/Makefile.in | 1 + dom/settings/SettingsChangeNotifier.jsm | 56 +++++++++++++++++++++++ dom/settings/SettingsManager.js | 59 ++++++++++++++----------- 4 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 dom/settings/SettingsChangeNotifier.jsm diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index c702d4e6c88c..e1d621bcff7f 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -12,6 +12,7 @@ const Cr = Components.results; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/ContactService.jsm'); +Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm'); Cu.import('resource://gre/modules/Webapps.jsm'); XPCOMUtils.defineLazyServiceGetter(Services, 'env', diff --git a/dom/settings/Makefile.in b/dom/settings/Makefile.in index b096c07fd388..899c57b7e9ed 100644 --- a/dom/settings/Makefile.in +++ b/dom/settings/Makefile.in @@ -25,6 +25,7 @@ EXTRA_COMPONENTS = \ EXTRA_JS_MODULES = \ SettingsQueue.jsm \ SettingsDB.jsm \ + SettingsChangeNotifier.jsm \ $(NULL) ifdef ENABLE_TESTS diff --git a/dom/settings/SettingsChangeNotifier.jsm b/dom/settings/SettingsChangeNotifier.jsm new file mode 100644 index 000000000000..a92c3b75441a --- /dev/null +++ b/dom/settings/SettingsChangeNotifier.jsm @@ -0,0 +1,56 @@ +/* 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" + +function debug(s) { +// dump("-*- SettingsChangeNotifier: " + s + "\n"); +} + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +let EXPORTED_SYMBOLS = ["SettingsChangeNotifier"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "ppmm", function() { + return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); +}); + + +let SettingsChangeNotifier = { + init: function() { + debug("init"); + ppmm.addMessageListener("Settings:Changed", this); + Services.obs.addObserver(this, "xpcom-shutdown", false); + }, + + observe: function(aSubject, aTopic, aData) { + debug("observe"); + ppmm.removeMessageListener("Settings:Changed", this); + Services.obs.removeObserver(this, "xpcom-shutdown"); + ppmm = null; + }, + + receiveMessage: function(aMessage) { + debug("receiveMessage"); + let msg = aMessage.json; + switch (aMessage.name) { + case "Settings:Changed": + ppmm.sendAsyncMessage("Settings:Change:Return:OK", { key: msg.key, value: msg.value }); + Services.obs.notifyObservers(this, "mozsettings-changed", JSON.stringify({ + key: msg.key, + value: msg.value + })); + break; + default: + debug("Wrong message: " + aMessage.name); + } + } +} + +SettingsChangeNotifier.init(); diff --git a/dom/settings/SettingsManager.js b/dom/settings/SettingsManager.js index 0bdc1a5cd7b3..4060fd7330fc 100644 --- a/dom/settings/SettingsManager.js +++ b/dom/settings/SettingsManager.js @@ -4,12 +4,9 @@ "use strict"; -/* static functions */ -let DEBUG = false; -if (DEBUG) - debug = function (s) { dump("-*- SettingsManager: " + s + "\n"); }; -else - debug = function (s) {}; +function debug(s) { +// dump("-*- SettingsManager: " + s + "\n"); +} const Cc = Components.classes; const Ci = Components.interfaces; @@ -20,6 +17,10 @@ Cu.import("resource://gre/modules/SettingsDB.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyGetter(this, "cpmm", function() { + return Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); +}); + const nsIClassInfo = Ci.nsIClassInfo; const SETTINGSLOCK_CONTRACTID = "@mozilla.org/settingsLock;1"; const SETTINGSLOCK_CID = Components.ID("{ef95ddd0-6308-11e1-b86c-0800200c9a66}"); @@ -67,10 +68,7 @@ SettingsLock.prototype = { req.onsuccess = function() { lock._open = true; Services.DOMRequest.fireSuccess(request, 0); - Services.obs.notifyObservers(lock, "mozsettings-changed", JSON.stringify({ - key: key, - value: info.settings[key] - })); + cpmm.sendAsyncMessage("Settings:Changed", { key: key, value: info.settings[key] }); lock._open = false; }; @@ -227,14 +225,37 @@ SettingsManager.prototype = { return lock; }, + receiveMessage: function(aMessage) { + debug("Settings::receiveMessage: " + aMessage.name); + let msg = aMessage.json; + + switch (aMessage.name) { + case "Settings:Change:Return:OK": + debug("Settings:Change:Return:OK"); + if (!this._onsettingchange) + return; + + debug('key:' + msg.key + ', value:' + msg.value + '\n'); + let event = new this._window.MozSettingsEvent("settingchanged", { + settingName: msg.key, + settingValue: msg.value + }); + + this._onsettingchange.handleEvent(event); + break; + default: + debug("Wrong message: " + aMessage.name); + } + }, + init: function(aWindow) { // Set navigator.mozSettings to null. if (!Services.prefs.getBoolPref("dom.mozSettings.enabled")) return null; + cpmm.addMessageListener("Settings:Change:Return:OK", this); this._window = aWindow; Services.obs.addObserver(this, "inner-window-destroyed", false); - Services.obs.addObserver(this, "mozsettings-changed", false); let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); this.innerWindowID = util.currentInnerWindowID; @@ -253,26 +274,14 @@ SettingsManager.prototype = { let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data; if (wId == this.innerWindowID) { Services.obs.removeObserver(this, "inner-window-destroyed"); - Services.obs.removeObserver(this, "mozsettings-changed"); + cpmm.removeMessageListener("Settings:Change:Return:OK", this); this._requests = null; this._window = null; this._innerWindowID = null; this._onsettingchange = null; this._settingsDB.close(); + cpmm = null; } - } else if (aTopic == "mozsettings-changed") { - if (!this._onsettingchange) - return; - - let data = JSON.parse(aData); - debug('data:' + data.key + ':' + data.value + '\n'); - - let event = new this._window.MozSettingsEvent("settingchanged", { - settingName: data.key, - settingValue: data.value - }); - - this._onsettingchange.handleEvent(event); } }, From 9ebd0616c4aa1ad6009247387dea07ba9663b60c Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Mon, 4 Jun 2012 16:26:30 -0700 Subject: [PATCH 35/53] Restore application of font size inflation to radios and checkboxes. (Bug 757937) r=roc --- content/base/src/nsGkAtomList.h | 1 + layout/base/nsLayoutUtils.cpp | 7 ++++++- layout/forms/nsFormControlFrame.cpp | 6 ++++++ layout/forms/nsFormControlFrame.h | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index c3d9619997be..f25b95077f0d 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1681,6 +1681,7 @@ GK_ATOM(comboboxControlFrame, "ComboboxControlFrame") GK_ATOM(comboboxDisplayFrame, "ComboboxDisplayFrame") GK_ATOM(deckFrame, "DeckFrame") GK_ATOM(fieldSetFrame, "FieldSetFrame") +GK_ATOM(formControlFrame, "FormControlFrame") // radio or checkbox GK_ATOM(frameSetFrame, "FrameSetFrame") GK_ATOM(gfxButtonControlFrame, "gfxButtonControlFrame") GK_ATOM(HTMLButtonControlFrame, "HTMLButtonControlFrame") diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index dd2abca8aba9..e665fa9f509b 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4758,10 +4758,15 @@ nsLayoutUtils::FontSizeInflationInner(const nsIFrame *aFrame, f && !IsContainerForFontSizeInflation(f); f = f->GetParent()) { nsIContent* content = f->GetContent(); + nsIAtom* fType = f->GetType(); // Also, if there is more than one frame corresponding to a single // content node, we want the outermost one. if (!(f->GetParent() && f->GetParent()->GetContent() == content) && - f->GetType() != nsGkAtoms::inlineFrame) { + // ignore width/height on inlines since they don't apply + fType != nsGkAtoms::inlineFrame && + // ignore width on radios and checkboxes since we enlarge them and + // they have width/height in ua.css + fType != nsGkAtoms::formControlFrame) { nsStyleCoord stylePosWidth = f->GetStylePosition()->mWidth; nsStyleCoord stylePosHeight = f->GetStylePosition()->mHeight; if (stylePosWidth.GetUnit() != eStyleUnit_Auto || diff --git a/layout/forms/nsFormControlFrame.cpp b/layout/forms/nsFormControlFrame.cpp index db363d2dfab4..a97eacc4ef54 100644 --- a/layout/forms/nsFormControlFrame.cpp +++ b/layout/forms/nsFormControlFrame.cpp @@ -25,6 +25,12 @@ nsFormControlFrame::~nsFormControlFrame() { } +nsIAtom* +nsFormControlFrame::GetType() const +{ + return nsGkAtoms::formControlFrame; +} + void nsFormControlFrame::DestroyFrom(nsIFrame* aDestructRoot) { diff --git a/layout/forms/nsFormControlFrame.h b/layout/forms/nsFormControlFrame.h index 8f02ca7b90eb..a3d32e80ffb1 100644 --- a/layout/forms/nsFormControlFrame.h +++ b/layout/forms/nsFormControlFrame.h @@ -25,6 +25,8 @@ public: */ nsFormControlFrame(nsStyleContext*); + virtual nsIAtom* GetType() const; + virtual bool IsFrameOfType(PRUint32 aFlags) const { return nsLeafFrame::IsFrameOfType(aFlags & From b678bd5e171b4630eb57eca8832d0bcf8ce76327 Mon Sep 17 00:00:00 2001 From: Stephen Moehle Date: Tue, 5 Jun 2012 11:31:13 +1200 Subject: [PATCH 36/53] Bug 761030 - Fix crash with HTML 5 video with GStreamer enabled - r=kinetik --HG-- extra : rebase_source : 5e884550f9870bd2fda247d50bebd472e8368588 --- content/media/gstreamer/nsGStreamerReader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/media/gstreamer/nsGStreamerReader.cpp b/content/media/gstreamer/nsGStreamerReader.cpp index 17374a31c1db..6a50e096452f 100644 --- a/content/media/gstreamer/nsGStreamerReader.cpp +++ b/content/media/gstreamer/nsGStreamerReader.cpp @@ -452,6 +452,8 @@ bool nsGStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip, i, height); b.mPlanes[i].mWidth = gst_video_format_get_component_width(format, i, width); + b.mPlanes[i].mOffset = 0; + b.mPlanes[i].mSkip = 0; } bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, From 44fadb2ceffa7ae93915c2f45de9dd3fc3238d83 Mon Sep 17 00:00:00 2001 From: Stephen Moehle Date: Tue, 5 Jun 2012 11:32:36 +1200 Subject: [PATCH 37/53] Bug 760899 - Fix debug builds with gstreamer enabled - r=kinetik --HG-- extra : rebase_source : 22598bc470d35d94991ea9f1b14df11ba19a461a --- content/media/gstreamer/nsGStreamerReader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/media/gstreamer/nsGStreamerReader.cpp b/content/media/gstreamer/nsGStreamerReader.cpp index 6a50e096452f..164fb2ec9dbd 100644 --- a/content/media/gstreamer/nsGStreamerReader.cpp +++ b/content/media/gstreamer/nsGStreamerReader.cpp @@ -278,7 +278,7 @@ nsresult nsGStreamerReader::ReadMetadata(nsVideoInfo* aInfo) if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration) && format == GST_FORMAT_TIME) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - LOG(PR_LOG_DEBUG, ("returning duration %"GST_TIME_FORMAT, + LOG(PR_LOG_DEBUG, ("returning duration %" GST_TIME_FORMAT, GST_TIME_ARGS (duration))); duration = GST_TIME_AS_USECONDS (duration); mDecoder->GetStateMachine()->SetDuration(duration); @@ -422,8 +422,8 @@ bool nsGStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip, nextTimestamp += gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen); if (timestamp < aTimeThreshold) { - LOG(PR_LOG_DEBUG, ("skipping frame %"GST_TIME_FORMAT - " threshold %"GST_TIME_FORMAT, + LOG(PR_LOG_DEBUG, ("skipping frame %" GST_TIME_FORMAT + " threshold %" GST_TIME_FORMAT, GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold))); gst_buffer_unref(buffer); buffer = NULL; @@ -489,7 +489,7 @@ nsresult nsGStreamerReader::Seek(PRInt64 aTarget, NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); gint64 seekPos = aTarget * GST_USECOND; - LOG(PR_LOG_DEBUG, ("%p About to seek to %"GST_TIME_FORMAT, + LOG(PR_LOG_DEBUG, ("%p About to seek to %" GST_TIME_FORMAT, mDecoder, GST_TIME_ARGS(seekPos))); if (!gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME, @@ -592,7 +592,7 @@ PRInt64 nsGStreamerReader::QueryDuration() if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration)) { if (format == GST_FORMAT_TIME) { - LOG(PR_LOG_DEBUG, ("pipeline duration %"GST_TIME_FORMAT, + LOG(PR_LOG_DEBUG, ("pipeline duration %" GST_TIME_FORMAT, GST_TIME_ARGS (duration))); duration = GST_TIME_AS_USECONDS (duration); } From 7bd3d2eeae3ba971c82d26fe1c45396b9d27a420 Mon Sep 17 00:00:00 2001 From: Jason Duell Date: Mon, 4 Jun 2012 16:38:32 -0700 Subject: [PATCH 38/53] Bug 695636 - Update close steps to adhere to WS spec. r=smaug --- content/base/src/nsWebSocket.cpp | 313 +++++++++++++------------- content/base/src/nsWebSocket.h | 22 +- content/base/test/test_websocket.html | 39 +++- 3 files changed, 209 insertions(+), 165 deletions(-) diff --git a/content/base/src/nsWebSocket.cpp b/content/base/src/nsWebSocket.cpp index 8353c3e7a32c..f0e121a85853 100644 --- a/content/base/src/nsWebSocket.cpp +++ b/content/base/src/nsWebSocket.cpp @@ -74,6 +74,27 @@ using namespace mozilla; } \ PR_END_MACRO +class CallDispatchConnectionCloseEvents: public nsRunnable +{ +public: +CallDispatchConnectionCloseEvents(nsWebSocket *aWebSocket) + : mWebSocket(aWebSocket) + {} + + NS_IMETHOD Run() + { + mWebSocket->DispatchConnectionCloseEvents(); + return NS_OK; + } + +private: + nsRefPtr mWebSocket; +}; + +//----------------------------------------------------------------------------- +// nsWebSocket +//----------------------------------------------------------------------------- + nsresult nsWebSocket::PrintErrorOnConsole(const char *aBundleURI, const PRUnichar *aError, @@ -124,37 +145,43 @@ nsWebSocket::PrintErrorOnConsole(const char *aBundleURI, return NS_OK; } -// when this is called the browser side wants no more part of it nsresult nsWebSocket::CloseConnection(PRUint16 aReasonCode, const nsACString& aReasonString) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mDisconnected) - return NS_OK; - - // Disconnect() can release this object, so we keep a - // reference until the end of the method - nsRefPtr kungfuDeathGrip = this; - - if (mReadyState == nsIWebSocket::CONNECTING) { - SetReadyState(nsIWebSocket::CLOSED); - if (mChannel) { - mChannel->Close(aReasonCode, aReasonString); - } - Disconnect(); + if (mReadyState == nsIWebSocket::CLOSING || + mReadyState == nsIWebSocket::CLOSED) { return NS_OK; } - SetReadyState(nsIWebSocket::CLOSING); - - if (mDisconnected) { - SetReadyState(nsIWebSocket::CLOSED); - Disconnect(); - return NS_OK; + // The common case... + if (mChannel) { + mReadyState = nsIWebSocket::CLOSING; + return mChannel->Close(aReasonCode, aReasonString); } - return mChannel->Close(aReasonCode, aReasonString); + // No channel, but not disconnected: canceled or failed early + // + MOZ_ASSERT(mReadyState == nsIWebSocket::CONNECTING, + "Should only get here for early websocket cancel/error"); + + // Server won't be sending us a close code, so use what's passed in here. + mCloseEventCode = aReasonCode; + CopyUTF8toUTF16(aReasonString, mCloseEventReason); + + mReadyState = nsIWebSocket::CLOSING; + + // Can be called from Cancel() or Init() codepaths, so need to dispatch + // onerror/onclose asynchronously + ScheduleConnectionCloseEvents( + nsnull, + (aReasonCode == nsIWebSocketChannel::CLOSE_NORMAL || + aReasonCode == nsIWebSocketChannel::CLOSE_GOING_AWAY) ? + NS_OK : NS_ERROR_FAILURE, + false); + + return NS_OK; } nsresult @@ -191,14 +218,11 @@ nsWebSocket::FailConnection(PRUint16 aReasonCode, const nsACString& aReasonString) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); + ConsoleError(); - + mFailed = true; CloseConnection(aReasonCode, aReasonString); - nsresult rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error")); - if (NS_FAILED(rv)) - NS_WARNING("Failed to dispatch the error event"); - return NS_OK; } @@ -240,7 +264,11 @@ nsresult nsWebSocket::DoOnMessageAvailable(const nsACString & aMsg, bool isBinary) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(!mDisconnected, "Received message after disconnecting"); + + if (mReadyState == nsIWebSocket::CLOSED) { + NS_ERROR("Received message after CLOSED"); + return NS_ERROR_UNEXPECTED; + } if (mReadyState == nsIWebSocket::OPEN) { // Dispatch New Message @@ -251,8 +279,8 @@ nsWebSocket::DoOnMessageAvailable(const nsACString & aMsg, bool isBinary) } else { // CLOSING should be the only other state where it's possible to get msgs // from channel: Spec says to drop them. - NS_ASSERTION(mReadyState == nsIWebSocket::CLOSING, - "Received message while CONNECTING or CLOSED"); + MOZ_ASSERT(mReadyState == nsIWebSocket::CLOSING, + "Received message while CONNECTING or CLOSED"); } return NS_OK; @@ -275,13 +303,20 @@ NS_IMETHODIMP nsWebSocket::OnStart(nsISupports *aContext) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mDisconnected) + + // This is the only function that sets OPEN, and should be called only once + MOZ_ASSERT(mReadyState != nsIWebSocket::OPEN, + "readyState already OPEN! OnStart called twice?"); + + // Nothing to do if we've already closed/closing + if (mReadyState != nsIWebSocket::CONNECTING) { return NS_OK; + } // Attempt to kill "ghost" websocket: but usually too early for check to fail nsresult rv = CheckInnerWindowCorrectness(); if (NS_FAILED(rv)) { - FailConnectionQuietly(); + CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY); return rv; } @@ -292,35 +327,63 @@ nsWebSocket::OnStart(nsISupports *aContext) mChannel->GetExtensions(mEstablishedExtensions); UpdateURI(); - SetReadyState(nsIWebSocket::OPEN); + mReadyState = nsIWebSocket::OPEN; + + // Call 'onopen' + rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open")); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the open event"); + } + + UpdateMustKeepAlive(); + return NS_OK; } NS_IMETHODIMP nsWebSocket::OnStop(nsISupports *aContext, nsresult aStatusCode) +{ + // We can be CONNECTING here if connection failed. + // We can be OPEN if we have encountered a fatal protocol error + // We can be CLOSING if close() was called and/or server initiated close. + MOZ_ASSERT(mReadyState != nsIWebSocket::CLOSED, + "Shouldn't already be CLOSED when OnStop called"); + + // called by network stack, not JS, so can dispatch JS events synchronously + return ScheduleConnectionCloseEvents(aContext, aStatusCode, true); +} + +nsresult +nsWebSocket::ScheduleConnectionCloseEvents(nsISupports *aContext, + nsresult aStatusCode, + bool sync) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mDisconnected) - return NS_OK; - mCloseEventWasClean = NS_SUCCEEDED(aStatusCode); + // no-op if some other code has already initiated close event + if (!mOnCloseScheduled) { + mCloseEventWasClean = NS_SUCCEEDED(aStatusCode); - if (aStatusCode == NS_BASE_STREAM_CLOSED && - mReadyState >= nsIWebSocket::CLOSING) { - // don't generate an error event just because of an unclean close - aStatusCode = NS_OK; + if (aStatusCode == NS_BASE_STREAM_CLOSED) { + // don't generate an error event just because of an unclean close + aStatusCode = NS_OK; + } + + if (NS_FAILED(aStatusCode)) { + ConsoleError(); + mFailed = true; + } + + mOnCloseScheduled = true; + + if (sync) { + DispatchConnectionCloseEvents(); + } else { + NS_DispatchToMainThread(new CallDispatchConnectionCloseEvents(this), + NS_DISPATCH_NORMAL); + } } - if (NS_FAILED(aStatusCode)) { - ConsoleError(); - nsresult rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error")); - if (NS_FAILED(rv)) - NS_WARNING("Failed to dispatch the error event"); - } - - SetReadyState(nsIWebSocket::CLOSED); - Disconnect(); - return NS_OK; } @@ -342,19 +405,17 @@ nsWebSocket::OnServerClose(nsISupports *aContext, PRUint16 aCode, { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(mReadyState != nsIWebSocket::CONNECTING, - "Received server close before connected?"); - - if (mReadyState == nsIWebSocket::CLOSED) { - NS_WARNING("Received server close after already closed!"); - return NS_ERROR_UNEXPECTED; - } + MOZ_ASSERT(mReadyState != nsIWebSocket::CONNECTING, + "Received server close before connected?"); + MOZ_ASSERT(mReadyState != nsIWebSocket::CLOSED, + "Received server close after already closed!"); // store code/string for onclose DOM event mCloseEventCode = aCode; CopyUTF8toUTF16(aReason, mCloseEventReason); if (mReadyState == nsIWebSocket::OPEN) { + // Server initiating close. // RFC 6455, 5.5.1: "When sending a Close frame in response, the endpoint // typically echos the status code it received". // But never send certain codes, per section 7.4.1 @@ -364,9 +425,8 @@ nsWebSocket::OnServerClose(nsISupports *aContext, PRUint16 aCode, CloseConnection(aCode, aReason); } } else { - // Nothing else to do: OnStop does the rest of the work. - NS_ASSERTION (mReadyState == nsIWebSocket::CLOSING, "unknown state"); - NS_ASSERTION(!mDisconnected, "should not be disconnected during CLOSING"); + // We initiated close, and server has replied: OnStop does rest of the work. + MOZ_ASSERT(mReadyState == nsIWebSocket::CLOSING, "unknown state"); } return NS_OK; @@ -381,7 +441,7 @@ nsWebSocket::GetInterface(const nsIID &aIID, void **aResult) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mDisconnected) + if (mReadyState == nsIWebSocket::CLOSED) return NS_ERROR_FAILURE; if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || @@ -411,7 +471,8 @@ nsWebSocket::GetInterface(const nsIID &aIID, void **aResult) nsWebSocket::nsWebSocket() : mKeepingAlive(false), mCheckMustKeepAlive(true), - mTriggeredCloseEvent(false), + mOnCloseScheduled(false), + mFailed(false), mDisconnected(false), mCloseEventWasClean(false), mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL), @@ -429,7 +490,10 @@ nsWebSocket::~nsWebSocket() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - Disconnect(); + // If we threw during Init we never called disconnect + if (!mDisconnected) { + Disconnect(); + } nsLayoutStatics::Release(); } @@ -511,7 +575,7 @@ nsWebSocket::DisconnectFromOwner() NS_DISCONNECT_EVENT_HANDLER(Message) NS_DISCONNECT_EVENT_HANDLER(Close) NS_DISCONNECT_EVENT_HANDLER(Error) - FailConnectionQuietly(); + CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY); DontKeepAliveAnyMore(); } @@ -705,31 +769,30 @@ nsWebSocket::EstablishConnection() return NS_OK; } -class nsWSCloseEvent : public nsRunnable +void +nsWebSocket::DispatchConnectionCloseEvents() { -public: -nsWSCloseEvent(nsWebSocket *aWebSocket, bool aWasClean, - PRUint16 aCode, const nsString &aReason) - : mWebSocket(aWebSocket), - mWasClean(aWasClean), - mCode(aCode), - mReason(aReason) - {} + nsresult rv; - NS_IMETHOD Run() - { - nsresult rv = mWebSocket->CreateAndDispatchCloseEvent(mWasClean, - mCode, mReason); - mWebSocket->UpdateMustKeepAlive(); - return rv; + mReadyState = nsIWebSocket::CLOSED; + + // Call 'onerror' if needed + if (mFailed) { + nsresult rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error")); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the error event"); + } } -private: - nsRefPtr mWebSocket; - bool mWasClean; - PRUint16 mCode; - nsString mReason; -}; + rv = CreateAndDispatchCloseEvent(mCloseEventWasClean, mCloseEventCode, + mCloseEventReason); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the close event"); + } + + UpdateMustKeepAlive(); + Disconnect(); +} nsresult nsWebSocket::CreateAndDispatchSimpleEvent(const nsString& aName) @@ -855,8 +918,6 @@ nsWebSocket::CreateAndDispatchCloseEvent(bool aWasClean, NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); nsresult rv; - mTriggeredCloseEvent = true; - rv = CheckInnerWindowCorrectness(); if (NS_FAILED(rv)) { return NS_OK; @@ -888,58 +949,6 @@ nsWebSocket::PrefEnabled() return Preferences::GetBool("network.websocket.enabled", true); } -void -nsWebSocket::SetReadyState(PRUint16 aNewReadyState) -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - nsresult rv; - - if (mReadyState == aNewReadyState) { - return; - } - - NS_ABORT_IF_FALSE((aNewReadyState == nsIWebSocket::OPEN) || - (aNewReadyState == nsIWebSocket::CLOSING) || - (aNewReadyState == nsIWebSocket::CLOSED), - "unexpected readyState"); - - if (aNewReadyState == nsIWebSocket::OPEN) { - NS_ABORT_IF_FALSE(mReadyState == nsIWebSocket::CONNECTING, - "unexpected readyState transition"); - mReadyState = aNewReadyState; - - rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open")); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch the open event"); - } - UpdateMustKeepAlive(); - return; - } - - if (aNewReadyState == nsIWebSocket::CLOSING) { - NS_ABORT_IF_FALSE((mReadyState == nsIWebSocket::CONNECTING) || - (mReadyState == nsIWebSocket::OPEN), - "unexpected readyState transition"); - mReadyState = aNewReadyState; - return; - } - - if (aNewReadyState == nsIWebSocket::CLOSED) { - mReadyState = aNewReadyState; - - // The close event must be dispatched asynchronously. - rv = NS_DispatchToMainThread(new nsWSCloseEvent(this, mCloseEventWasClean, - mCloseEventCode, - mCloseEventReason), - NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch the close event"); - mTriggeredCloseEvent = true; - UpdateMustKeepAlive(); - } - } -} - nsresult nsWebSocket::ParseURL(const nsString& aURL) { @@ -1066,9 +1075,7 @@ nsWebSocket::UpdateMustKeepAlive() case nsIWebSocket::CLOSED: { - shouldKeepAlive = - (!mTriggeredCloseEvent && - mListenerManager->HasListenersFor(NS_LITERAL_STRING("close"))); + shouldKeepAlive = false; } } } @@ -1093,14 +1100,6 @@ nsWebSocket::DontKeepAliveAnyMore() mCheckMustKeepAlive = false; } -void -nsWebSocket::FailConnectionQuietly() -{ - // Fail without console error or JS onerror message: onmessage/onclose will - // also be blocked so long as CheckInnerWindowCorrectness is failing. - CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY); -} - nsresult nsWebSocket::UpdateURI() { @@ -1292,8 +1291,8 @@ nsWebSocket::Send(nsIVariant *aData, JSContext *aCx) return NS_OK; } - NS_ASSERTION(mReadyState == nsIWebSocket::OPEN, - "Unknown state in nsWebSocket::Send"); + MOZ_ASSERT(mReadyState == nsIWebSocket::OPEN, + "Unknown state in nsWebSocket::Send"); if (msgStream) { rv = mChannel->SendBinaryStream(msgStream, msgLen); @@ -1471,10 +1470,6 @@ nsWebSocket::Close(PRUint16 code, const nsAString & reason, PRUint8 argc) } if (mReadyState == nsIWebSocket::CONNECTING) { - // FailConnection() can release the object, so we keep a reference - // before calling it - nsRefPtr kungfuDeathGrip = this; - FailConnection(closeCode, closeReason); return NS_OK; } @@ -1618,7 +1613,7 @@ nsWebSocket::Observe(nsISupports* aSubject, if ((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) || (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0)) { - FailConnectionQuietly(); + CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY); } return NS_OK; @@ -1639,7 +1634,7 @@ nsWebSocket::GetName(nsACString &aName) NS_IMETHODIMP nsWebSocket::IsPending(bool *aValue) { - *aValue = !mDisconnected; + *aValue = (mReadyState != nsIWebSocket::CLOSED); return NS_OK; } @@ -1656,10 +1651,12 @@ nsWebSocket::Cancel(nsresult aStatus) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mDisconnected) + if (mReadyState == CLOSING || mReadyState == CLOSED) { return NS_OK; + } ConsoleError(); + return CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY); } diff --git a/content/base/src/nsWebSocket.h b/content/base/src/nsWebSocket.h index bdb2effbe49d..d93acdd6be79 100644 --- a/content/base/src/nsWebSocket.h +++ b/content/base/src/nsWebSocket.h @@ -35,7 +35,7 @@ #define NS_WEBSOCKET_CONTRACTID "@mozilla.org/websocket;1" -class nsWSCloseEvent; +class CallDispatchConnectionCloseEvents; class nsAutoCloseWS; class nsWebSocket: public nsDOMEventTargetHelper, @@ -47,7 +47,7 @@ class nsWebSocket: public nsDOMEventTargetHelper, public nsSupportsWeakReference, public nsIRequest { -friend class nsWSCloseEvent; +friend class CallDispatchConnectionCloseEvents; friend class nsAutoCloseWS; public: @@ -87,7 +87,6 @@ protected: // These methods when called can release the WebSocket object nsresult FailConnection(PRUint16 reasonCode, const nsACString& aReasonString = EmptyCString()); - void FailConnectionQuietly(); nsresult CloseConnection(PRUint16 reasonCode, const nsACString& aReasonString = EmptyCString()); nsresult Disconnect(); @@ -107,6 +106,18 @@ protected: JSContext *aCx); nsresult DoOnMessageAvailable(const nsACString & aMsg, bool isBinary); + + // ConnectionCloseEvents: 'error' event if needed, then 'close' event. + // - These must not be dispatched while we are still within an incoming call + // from JS (ex: close()). Set 'sync' to false in that case to dispatch in a + // separate new event. + nsresult ScheduleConnectionCloseEvents(nsISupports *aContext, + nsresult aStatusCode, + bool sync); + // 2nd half of ScheduleConnectionCloseEvents, sometimes run in its own event. + void DispatchConnectionCloseEvents(); + + // These methods actually do the dispatch for various events. nsresult CreateAndDispatchSimpleEvent(const nsString& aName); nsresult CreateAndDispatchMessageEvent(const nsACString& aData, bool isBinary); @@ -115,8 +126,6 @@ protected: nsresult CreateResponseBlob(const nsACString& aData, JSContext *aCx, jsval &jsData); - void SetReadyState(PRUint16 aNewReadyState); - // if there are "strong event listeners" (see comment in nsWebSocket.cpp) or // outgoing not sent messages then this method keeps the object alive // when js doesn't have strong references to it. @@ -142,7 +151,8 @@ protected: bool mKeepingAlive; bool mCheckMustKeepAlive; - bool mTriggeredCloseEvent; + bool mOnCloseScheduled; + bool mFailed; bool mDisconnected; // Set attributes of DOM 'onclose' message diff --git a/content/base/test/test_websocket.html b/content/base/test/test_websocket.html index fec2c068cd1e..28889b848a59 100644 --- a/content/base/test/test_websocket.html +++ b/content/base/test/test_websocket.html @@ -69,10 +69,11 @@ * 44. Test sending/receving binary ArrayBuffer * 45. Test sending/receving binary Blob * 46. Test that we don't dispatch incoming msgs once in CLOSING state + * 47. Make sure onerror/onclose aren't called during close() */ var first_test = 1; -var last_test = 46; +var last_test = 47; // Set this to >1 if you want to run the suite multiple times to probe for @@ -282,6 +283,7 @@ function test3() { shouldCloseNotCleanly(e); ok(hasError, "rcvd onerror event"); + ok(e.code == 1006, "test-3 close code should be 1006 but is:" + e.code); doTest(4); }; } @@ -1435,6 +1437,41 @@ function test46() } } +function test47() +{ + var hasError = false; + var ws = CreateTestWS("ws://another.websocket.server.that.probably.does.not.exist"); + ws.onopen = shouldNotOpen; + + ws.onerror = function (e) + { + ok(ws.readyState == 3, "test-47: readyState should be CLOSED(3) in onerror: got " + + ws.readyState); + ok(!ws._withinClose, "onerror() called during close()!"); + hasError = true; + } + + ws.onclose = function(e) + { + shouldCloseNotCleanly(e); + ok(hasError, "test-47: should have called onerror before onclose"); + ok(ws.readyState == 3, "test-47: readyState should be CLOSED(3) in onclose: got " + + ws.readyState); + ok(!ws._withinClose, "onclose() called during close()!"); + ok(e.code == 1006, "test-47 close code should be 1006 but is:" + e.code); + doTest(48); + }; + + // Call close before we're connected: throws error + // Make sure we call onerror/onclose asynchronously + ws._withinClose = 1; + ws.close(3333, "Closed before we were open: error"); + ws._withinClose = 0; + ok(ws.readyState == 2, "test-47: readyState should be CLOSING(2) after close(): got " + + ws.readyState); +} + + var ranAllTests = false; function maybeFinished() From 7f14e0990a295ccbd9d2056f1f7d6c6cdaf0961b Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Mon, 4 Jun 2012 16:17:37 -0700 Subject: [PATCH 39/53] =?UTF-8?q?Bug=20760804:=20add=20some=20localization?= =?UTF-8?q?=20notes=20to=20pdf.js=20strings,=20and=20use=20"=E2=80=A6"=20i?= =?UTF-8?q?nstead=20of=20"...",=20feedback=3Dpike/bdahl/yury?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --HG-- extra : transplant_source : 6%06m%D5%889sk%89F%DD%CDiw%1CF%20%18Z%9A --- .../locales/en-US/pdfviewer/viewer.properties | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/browser/locales/en-US/pdfviewer/viewer.properties b/browser/locales/en-US/pdfviewer/viewer.properties index 25abd9275aed..cdb84d05fd70 100644 --- a/browser/locales/en-US/pdfviewer/viewer.properties +++ b/browser/locales/en-US/pdfviewer/viewer.properties @@ -3,8 +3,14 @@ previous.title=Previous Page previous_label=Previous next.title=Next Page next_label=Next + +# LOCALIZATION NOTE (page_label, page_of): +# These strings are concatenated to form the "Page: X of Y" string. +# Do not translate "{{pageCount}}", it will be substituted with a number +# representing the total number of pages. page_label=Page: page_of=of {{pageCount}} + zoom_out.title=Zoom Out zoom_out_label=Zoom Out zoom_in.title=Zoom In @@ -19,7 +25,9 @@ download_label=Download bookmark.title=Current view (copy or open in new window) bookmark_label=Current View -# Side panel toolbar buttons (tooltips and alt text for images) +# Tooltips and alt text for side panel toolbar buttons +# (the _label strings are alt text for the buttons, the .title strings are +# tooltips) toggle_slider.title=Toggle Slider toggle_slider_label=Toggle Slider outline.title=Show Document Outline @@ -33,7 +41,11 @@ search_panel_label=Search no_outline=No Outline Available # Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. thumb_page_title=Page {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. thumb_page_canvas=Thumbnail of Page {{page}} # Search panel button title and messages @@ -44,10 +56,18 @@ search_terms_not_found=(Not found) error_more_info=More Information error_less_info=Less Information error_close=Close +# LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS +# build ID. error_build=PDF.JS Build: {{build}} +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. error_message=Message: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. error_stack=Stack: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename error_file=File: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=Line: {{line}} rendering_error=An error occurred while rendering the page. @@ -58,10 +78,14 @@ page_scale_auto=Automatic Zoom page_scale_actual=Actual Size # Loading indicator messages -loading=Loading... {{percent}}% +# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage +loading=Loading… {{percent}}% loading_error_indicator=Error loading_error=An error occurred while loading the PDF. -# Misc labels and messages +# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip. +# "{{[type}}" will be replaced with an annotation type from a list defined in +# the PDF spec (32000-1:2008 Table 169 – Annotation types). +# Some common types are e.g.: "Check", "Text", "Comment", "Note" text_annotation_type=[{{type}} Annotation] request_password=PDF is protected by a password: From b6b455f9224a1c37773e85b16fc0d58180417e68 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Mon, 4 Jun 2012 16:49:57 -0700 Subject: [PATCH 40/53] Bug 591467 - Implement HTML5 Microdata API r=bz --- content/base/src/nsDOMLists.h | 5 + content/base/src/nsDOMSettableTokenList.h | 3 +- content/base/src/nsDOMTokenList.h | 8 +- content/base/src/nsGenericElement.cpp | 40 +- content/base/src/nsGkAtomList.h | 1 + .../html/content/public/nsHTMLAudioElement.h | 4 + .../html/content/public/nsHTMLVideoElement.h | 4 + .../content/src/HTMLPropertiesCollection.cpp | 610 ++++++++++++++++++ .../content/src/HTMLPropertiesCollection.h | 175 +++++ content/html/content/src/Makefile.in | 1 + .../html/content/src/nsGenericHTMLElement.cpp | 185 +++++- .../html/content/src/nsGenericHTMLElement.h | 65 +- .../html/content/src/nsHTMLAnchorElement.cpp | 16 + .../html/content/src/nsHTMLAreaElement.cpp | 16 + .../html/content/src/nsHTMLAudioElement.cpp | 14 + .../html/content/src/nsHTMLIFrameElement.cpp | 16 + .../html/content/src/nsHTMLImageElement.cpp | 12 + content/html/content/src/nsHTMLImageElement.h | 2 + .../html/content/src/nsHTMLLinkElement.cpp | 15 + .../html/content/src/nsHTMLMetaElement.cpp | 17 + .../html/content/src/nsHTMLObjectElement.cpp | 15 + .../content/src/nsHTMLSharedObjectElement.cpp | 23 + .../html/content/src/nsHTMLSourceElement.cpp | 16 + .../html/content/src/nsHTMLVideoElement.cpp | 14 + content/html/document/src/nsHTMLDocument.cpp | 78 +++ content/html/document/src/nsHTMLDocument.h | 1 - dom/base/nsDOMClassInfo.cpp | 15 + dom/base/nsDOMClassInfoClasses.h | 2 + dom/interfaces/html/Makefile.in | 2 + dom/interfaces/html/nsIDOMHTMLDocument.idl | 3 +- dom/interfaces/html/nsIDOMHTMLElement.idl | 14 +- .../html/nsIDOMHTMLPropertiesCollection.idl | 32 + .../html/nsIDOMPropertyNodeList.idl | 23 + js/xpconnect/src/codegen.py | 3 +- js/xpconnect/src/dom_quickstubs.qsconf | 30 +- js/xpconnect/src/dombindings.conf | 11 + 36 files changed, 1467 insertions(+), 24 deletions(-) create mode 100644 content/html/content/src/HTMLPropertiesCollection.cpp create mode 100644 content/html/content/src/HTMLPropertiesCollection.h create mode 100644 dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl create mode 100644 dom/interfaces/html/nsIDOMPropertyNodeList.idl diff --git a/content/base/src/nsDOMLists.h b/content/base/src/nsDOMLists.h index b1ab7610422d..c9bbe5f94dc5 100644 --- a/content/base/src/nsDOMLists.h +++ b/content/base/src/nsDOMLists.h @@ -28,6 +28,11 @@ public: return mNames.AppendElement(aName) != nsnull; } + void Clear() + { + mNames.Clear(); + } + private: nsTArray mNames; }; diff --git a/content/base/src/nsDOMSettableTokenList.h b/content/base/src/nsDOMSettableTokenList.h index 867bf1753d6f..3ca8a08ec8e6 100644 --- a/content/base/src/nsDOMSettableTokenList.h +++ b/content/base/src/nsDOMSettableTokenList.h @@ -16,6 +16,8 @@ class nsGenericElement; class nsIAtom; +// nsISupports must be on the primary inheritance chain +// because nsDOMSettableTokenList is traversed by nsGenericElement. class nsDOMSettableTokenList : public nsDOMTokenList, public nsIDOMDOMSettableTokenList { @@ -30,7 +32,6 @@ public: virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap); -protected: virtual ~nsDOMSettableTokenList(); }; diff --git a/content/base/src/nsDOMTokenList.h b/content/base/src/nsDOMTokenList.h index 1924613e397b..72befdd37ba9 100644 --- a/content/base/src/nsDOMTokenList.h +++ b/content/base/src/nsDOMTokenList.h @@ -14,6 +14,8 @@ class nsAttrValue; +// nsISupports must be on the primary inheritance chain +// because nsDOMSettableTokenList is traversed by nsGenericElement. class nsDOMTokenList : public nsIDOMDOMTokenList, public nsWrapperCache { @@ -34,9 +36,6 @@ public: return mElement; } -protected: - ~nsDOMTokenList(); - const nsAttrValue* GetParsedAttr() { if (!mElement) { return nsnull; @@ -44,6 +43,9 @@ protected: return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue; } +protected: + ~nsDOMTokenList(); + nsresult CheckToken(const nsAString& aStr); void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken); void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken); diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 5dd1576292fa..c082991d4c0b 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -4487,9 +4487,16 @@ ContentUnbinder* ContentUnbinder::sContentUnbinder = nsnull; NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement) nsINode::Unlink(tmp); - if (tmp->HasProperties() && tmp->IsXUL()) { - tmp->DeleteProperty(nsGkAtoms::contextmenulistener); - tmp->DeleteProperty(nsGkAtoms::popuplistener); + if (tmp->HasProperties()) { + if (tmp->IsHTML()) { + tmp->DeleteProperty(nsGkAtoms::microdataProperties); + tmp->DeleteProperty(nsGkAtoms::itemtype); + tmp->DeleteProperty(nsGkAtoms::itemref); + tmp->DeleteProperty(nsGkAtoms::itemprop); + } else if (tmp->IsXUL()) { + tmp->DeleteProperty(nsGkAtoms::contextmenulistener); + tmp->DeleteProperty(nsGkAtoms::popuplistener); + } } // Unlink child content (and unbind our subtree). @@ -4987,14 +4994,25 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericElement) tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb); - if (tmp->HasProperties() && tmp->IsXUL()) { - nsISupports* property = - static_cast - (tmp->GetProperty(nsGkAtoms::contextmenulistener)); - cb.NoteXPCOMChild(property); - property = static_cast - (tmp->GetProperty(nsGkAtoms::popuplistener)); - cb.NoteXPCOMChild(property); + if (tmp->HasProperties()) { + if (tmp->IsHTML()) { + nsISupports* property = static_cast + (tmp->GetProperty(nsGkAtoms::microdataProperties)); + cb.NoteXPCOMChild(property); + property = static_cast(tmp->GetProperty(nsGkAtoms::itemref)); + cb.NoteXPCOMChild(property); + property = static_cast(tmp->GetProperty(nsGkAtoms::itemprop)); + cb.NoteXPCOMChild(property); + property = static_cast(tmp->GetProperty(nsGkAtoms::itemtype)); + cb.NoteXPCOMChild(property); + } else if (tmp->IsXUL()) { + nsISupports* property = static_cast + (tmp->GetProperty(nsGkAtoms::contextmenulistener)); + cb.NoteXPCOMChild(property); + property = static_cast + (tmp->GetProperty(nsGkAtoms::popuplistener)); + cb.NoteXPCOMChild(property); + } } // Traverse attribute names and child content. diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index f25b95077f0d..ebd1c5d614b6 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -536,6 +536,7 @@ GK_ATOM(message, "message") GK_ATOM(meta, "meta") GK_ATOM(meter, "meter") GK_ATOM(method, "method") +GK_ATOM(microdataProperties, "microdataProperties") GK_ATOM(middle, "middle") GK_ATOM(min, "min") GK_ATOM(minheight, "minheight") diff --git a/content/html/content/public/nsHTMLAudioElement.h b/content/html/content/public/nsHTMLAudioElement.h index 1538c234134f..0aab9fc804cd 100644 --- a/content/html/content/public/nsHTMLAudioElement.h +++ b/content/html/content/public/nsHTMLAudioElement.h @@ -49,6 +49,10 @@ public: virtual nsXPCClassInfo* GetClassInfo(); virtual nsIDOMNode* AsDOMNode() { return this; } + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; #endif diff --git a/content/html/content/public/nsHTMLVideoElement.h b/content/html/content/public/nsHTMLVideoElement.h index 4dfad6316ac2..1a66fd925743 100644 --- a/content/html/content/public/nsHTMLVideoElement.h +++ b/content/html/content/public/nsHTMLVideoElement.h @@ -60,6 +60,10 @@ public: virtual nsXPCClassInfo* GetClassInfo(); virtual nsIDOMNode* AsDOMNode() { return this; } + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; #endif diff --git a/content/html/content/src/HTMLPropertiesCollection.cpp b/content/html/content/src/HTMLPropertiesCollection.cpp new file mode 100644 index 000000000000..7504ea6d6c22 --- /dev/null +++ b/content/html/content/src/HTMLPropertiesCollection.cpp @@ -0,0 +1,610 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */ +/* 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 "HTMLPropertiesCollection.h" +#include "dombindings.h" +#include "nsIDocument.h" +#include "nsContentUtils.h" +#include "nsGenericHTMLElement.h" +#include "nsVariant.h" +#include "nsDOMSettableTokenList.h" +#include "nsAttrValue.h" + +DOMCI_DATA(HTMLPropertiesCollection, mozilla::dom::HTMLPropertiesCollection) +DOMCI_DATA(PropertyNodeList, mozilla::dom::PropertyNodeList) + +namespace mozilla { +namespace dom { + +static PLDHashOperator +TraverseNamedProperties(const nsAString& aKey, PropertyNodeList* aEntry, void* aData) +{ + nsCycleCollectionTraversalCallback* cb = static_cast(aData); + cb->NoteXPCOMChild(static_cast(aEntry)); + return PL_DHASH_NEXT; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLPropertiesCollection) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLPropertiesCollection) + // SetDocument(nsnull) ensures that we remove ourselves as a mutation observer + tmp->SetDocument(nsnull); + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNames) + tmp->mNamedItemEntries.Clear(); + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mProperties) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLPropertiesCollection) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNames) + tmp->mNamedItemEntries.EnumerateRead(TraverseNamedProperties, &cb); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mProperties) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLPropertiesCollection) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +HTMLPropertiesCollection::HTMLPropertiesCollection(nsGenericHTMLElement* aRoot) + : mRoot(aRoot) + , mDoc(aRoot->GetCurrentDoc()) + , mIsDirty(true) +{ + SetIsDOMBinding(); + mNames = new PropertyStringList(this); + if (mDoc) { + mDoc->AddMutationObserver(this); + } + mNamedItemEntries.Init(); +} + +HTMLPropertiesCollection::~HTMLPropertiesCollection() +{ + if (mDoc) { + mDoc->RemoveMutationObserver(this); + } +} + +NS_INTERFACE_TABLE_HEAD(HTMLPropertiesCollection) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_TABLE4(HTMLPropertiesCollection, + nsIDOMHTMLPropertiesCollection, + nsIDOMHTMLCollection, + nsIHTMLCollection, + nsIMutationObserver) + NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLPropertiesCollection) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLPropertiesCollection) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLPropertiesCollection) +NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLPropertiesCollection) + + +static PLDHashOperator +SetPropertyListDocument(const nsAString& aKey, PropertyNodeList* aEntry, void* aData) +{ + aEntry->SetDocument(static_cast(aData)); + return PL_DHASH_NEXT; +} + +void +HTMLPropertiesCollection::SetDocument(nsIDocument* aDocument) { + if (mDoc) { + mDoc->RemoveMutationObserver(this); + } + mDoc = aDocument; + if (mDoc) { + mDoc->AddMutationObserver(this); + } + mNamedItemEntries.EnumerateRead(SetPropertyListDocument, aDocument); + mIsDirty = true; +} + +JSObject* +HTMLPropertiesCollection::WrapObject(JSContext* cx, JSObject* scope, + bool* triedToWrap) +{ + return mozilla::dom::binding::HTMLPropertiesCollection::create(cx, scope, this, + triedToWrap); +} + +NS_IMETHODIMP +HTMLPropertiesCollection::GetLength(PRUint32* aLength) +{ + EnsureFresh(); + *aLength = mProperties.Length(); + return NS_OK; +} + +NS_IMETHODIMP +HTMLPropertiesCollection::Item(PRUint32 aIndex, nsIDOMNode** aResult) +{ + EnsureFresh(); + nsGenericHTMLElement* property = mProperties.SafeElementAt(aIndex); + *aResult = property ? property->AsDOMNode() : NULL; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +HTMLPropertiesCollection::NamedItem(const nsAString& aName, + nsIDOMNode** aResult) +{ + *aResult = NULL; + return NS_OK; +} + +nsISupports* +HTMLPropertiesCollection::GetNamedItem(const nsAString& aName, + nsWrapperCache **aCache) +{ + EnsureFresh(); + if (!mNames->ContainsInternal(aName)) { + *aCache = NULL; + return NULL; + } + + nsRefPtr propertyList; + if (!mNamedItemEntries.Get(aName, getter_AddRefs(propertyList))) { + propertyList = new PropertyNodeList(this, mRoot, aName); + mNamedItemEntries.Put(aName, propertyList); + } + *aCache = propertyList; + return static_cast(propertyList); +} + +nsIContent* +HTMLPropertiesCollection::GetNodeAt(PRUint32 aIndex) +{ + EnsureFresh(); + return mProperties.SafeElementAt(aIndex); +} + +nsINode* +HTMLPropertiesCollection::GetParentObject() +{ + return mRoot; +} + +NS_IMETHODIMP +HTMLPropertiesCollection::NamedItem(const nsAString& aName, + nsIDOMPropertyNodeList** aResult) +{ + EnsureFresh(); + + nsRefPtr propertyList; + if (!mNamedItemEntries.Get(aName, getter_AddRefs(propertyList))) { + propertyList = new PropertyNodeList(this, mRoot, aName); + mNamedItemEntries.Put(aName, propertyList); + } + propertyList.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +HTMLPropertiesCollection::GetNames(nsIDOMDOMStringList** aResult) +{ + EnsureFresh(); + NS_ADDREF(*aResult = mNames); + return NS_OK; +} + +void +HTMLPropertiesCollection::AttributeChanged(nsIDocument *aDocument, Element* aElement, + PRInt32 aNameSpaceID, nsIAtom* aAttribute, + PRInt32 aModType) +{ + mIsDirty = true; +} + +void +HTMLPropertiesCollection::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer, + nsIContent* aFirstNewContent, + PRInt32 aNewIndexInContainer) +{ + mIsDirty = true; +} + +void +HTMLPropertiesCollection::ContentInserted(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + mIsDirty = true; +} + +void +HTMLPropertiesCollection::ContentRemoved(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer, + nsIContent* aPreviousSibling) +{ + mIsDirty = true; +} + +class TreeOrderComparator { + public: + bool Equals(const nsGenericHTMLElement* aElem1, + const nsGenericHTMLElement* aElem2) const { + return aElem1 == aElem2; + } + bool LessThan(const nsGenericHTMLElement* aElem1, + const nsGenericHTMLElement* aElem2) const { + return nsContentUtils::PositionIsBefore(const_cast(aElem1), + const_cast(aElem2)); + } +}; + +static PLDHashOperator +MarkDirty(const nsAString& aKey, PropertyNodeList* aEntry, void* aData) +{ + aEntry->SetDirty(); + return PL_DHASH_NEXT; +} + +void +HTMLPropertiesCollection::EnsureFresh() +{ + if (mDoc && !mIsDirty) { + return; + } + mIsDirty = false; + + mProperties.Clear(); + mNames->Clear(); + // We don't clear NamedItemEntries because the PropertyNodeLists must be live. + mNamedItemEntries.EnumerateRead(MarkDirty, NULL); + if (!mRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) { + return; + } + + CrawlProperties(); + TreeOrderComparator comparator; + mProperties.Sort(comparator); + + // Create the names DOMStringList + PRUint32 count = mProperties.Length(); + for (PRUint32 i = 0; i < count; ++i) { + const nsAttrValue* attr = mProperties.ElementAt(i)->GetParsedAttr(nsGkAtoms::itemprop); + for (PRUint32 i = 0; i < attr->GetAtomCount(); i++) { + nsDependentAtomString propName(attr->AtomAt(i)); + // ContainsInternal must not call EnsureFresh + bool contains = mNames->ContainsInternal(propName); + if (!contains) { + mNames->Add(propName); + } + } + } +} + +static Element* +GetElementByIdForConnectedSubtree(nsIContent* aContent, const nsIAtom* aId) +{ + aContent = static_cast(aContent->SubtreeRoot()); + do { + if (aContent->GetID() == aId) { + return aContent->AsElement(); + } + aContent = aContent->GetNextNode(); + } while(aContent); + + return NULL; +} + +void +HTMLPropertiesCollection::CrawlProperties() +{ + nsIDocument* doc = mRoot->GetCurrentDoc(); + + const nsAttrValue* attr = mRoot->GetParsedAttr(nsGkAtoms::itemref); + if (attr) { + for (PRUint32 i = 0; i < attr->GetAtomCount(); i++) { + nsIAtom* ref = attr->AtomAt(i); + Element* element; + if (doc) { + element = doc->GetElementById(nsDependentAtomString(ref)); + } else { + element = GetElementByIdForConnectedSubtree(mRoot, ref); + } + if (element && element != mRoot) { + CrawlSubtree(element); + } + } + } + + CrawlSubtree(mRoot); +} + +void +HTMLPropertiesCollection::CrawlSubtree(Element* aElement) +{ + nsIContent* aContent = aElement; + while (aContent) { + // We must check aContent against mRoot because + // an element must not be its own property + if (aContent == mRoot || !aContent->IsHTML()) { + // Move on to the next node in the tree + aContent = aContent->GetNextNode(aElement); + } else { + MOZ_ASSERT(aContent->IsElement(), "IsHTML() returned true!"); + Element* element = aContent->AsElement(); + if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) && + !mProperties.Contains(element)) { + mProperties.AppendElement(static_cast(element)); + } + + if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) { + aContent = element->GetNextNonChildNode(aElement); + } else { + aContent = element->GetNextNode(aElement); + } + } + } +} + +PropertyNodeList::PropertyNodeList(HTMLPropertiesCollection* aCollection, + nsIContent* aParent, const nsAString& aName) + : mName(aName), + mDoc(aParent->GetCurrentDoc()), + mCollection(aCollection), + mParent(aParent), + mIsDirty(true) +{ + SetIsDOMBinding(); + if (mDoc) { + mDoc->AddMutationObserver(this); + } +} + +PropertyNodeList::~PropertyNodeList() +{ + if (mDoc) { + mDoc->RemoveMutationObserver(this); + } +} + +void +PropertyNodeList::SetDocument(nsIDocument* aDoc) +{ + if (mDoc) { + mDoc->RemoveMutationObserver(this); + } + mDoc = aDoc; + if (mDoc) { + mDoc->AddMutationObserver(this); + } + mIsDirty = true; +} + +NS_IMETHODIMP +PropertyNodeList::GetLength(PRUint32* aLength) +{ + EnsureFresh(); + *aLength = mElements.Length(); + return NS_OK; +} + +NS_IMETHODIMP +PropertyNodeList::Item(PRUint32 aIndex, nsIDOMNode** aReturn) +{ + EnsureFresh(); + nsINode* element = mElements.SafeElementAt(aIndex); + if (!element) { + *aReturn = NULL; + return NS_OK; + } + return CallQueryInterface(element, aReturn); +} + +nsIContent* +PropertyNodeList::GetNodeAt(PRUint32 aIndex) +{ + EnsureFresh(); + return mElements.SafeElementAt(aIndex); +} + +PRInt32 +PropertyNodeList::IndexOf(nsIContent* aContent) +{ + EnsureFresh(); + return mElements.IndexOf(aContent); +} + +nsINode* +PropertyNodeList::GetParentObject() +{ + return mParent; +} + +JSObject* +PropertyNodeList::WrapObject(JSContext *cx, JSObject *scope, + bool *triedToWrap) +{ + return mozilla::dom::binding::PropertyNodeList::create(cx, scope, this, + triedToWrap); +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyNodeList) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyNodeList) + // SetDocument(nsnull) ensures that we remove ourselves as a mutation observer + tmp->SetDocument(nsnull); + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCollection) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PropertyNodeList) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCollection, nsIDOMHTMLPropertiesCollection) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mElements) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PropertyNodeList) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyNodeList) +NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyNodeList) + +NS_INTERFACE_TABLE_HEAD(PropertyNodeList) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_TABLE4(PropertyNodeList, + nsIDOMPropertyNodeList, + nsIDOMNodeList, + nsINodeList, + nsIMutationObserver) + NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PropertyNodeList) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PropertyNodeList) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +PropertyNodeList::GetValues(nsIVariant** aValues) +{ + EnsureFresh(); + nsCOMPtr out = new nsVariant(); + + // We have to use an nsTArray here and do manual refcounting because + // nsWritableVariant::SetAsArray takes an nsIVariant**. + nsTArray values; + + PRUint32 length = mElements.Length(); + if (length == 0) { + out->SetAsEmptyArray(); + } else { + for (PRUint32 i = 0; i < length; ++i) { + nsIVariant* itemValue; + mElements.ElementAt(i)->GetItemValue(&itemValue); + values.AppendElement(itemValue); + } + out->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS, + &NS_GET_IID(nsIVariant), + values.Length(), + values.Elements()); + } + + out.forget(aValues); + + for (PRUint32 i = 0; i < values.Length(); ++i) { + NS_RELEASE(values[i]); + } + + return NS_OK; +} + +void +PropertyNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement, + PRInt32 aNameSpaceID, nsIAtom* aAttribute, + PRInt32 aModType) +{ + mIsDirty = true; +} + +void +PropertyNodeList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer, + nsIContent* aFirstNewContent, + PRInt32 aNewIndexInContainer) +{ + mIsDirty = true; +} + +void +PropertyNodeList::ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + mIsDirty = true; +} + +void +PropertyNodeList::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer, + nsIContent* aPreviousSibling) +{ + mIsDirty = true; +} + +void +PropertyNodeList::EnsureFresh() +{ + if (mDoc && !mIsDirty) { + return; + } + mIsDirty = false; + + mCollection->EnsureFresh(); + Clear(); + + PRUint32 count = mCollection->mProperties.Length(); + for (PRUint32 i = 0; i < count; ++i) { + nsGenericHTMLElement* element = mCollection->mProperties.ElementAt(i); + const nsAttrValue* attr = element->GetParsedAttr(nsGkAtoms::itemprop); + if (attr->Contains(mName)) { + AppendElement(element); + } + } +} + +PropertyStringList::PropertyStringList(HTMLPropertiesCollection* aCollection) + : nsDOMStringList() + , mCollection(aCollection) +{ } + +NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyStringList) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyStringList) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCollection) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PropertyStringList) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCollection, nsIDOMHTMLPropertiesCollection) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyStringList) +NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyStringList) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PropertyStringList) + NS_INTERFACE_MAP_ENTRY(nsIDOMDOMStringList) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMStringList) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +PropertyStringList::Item(PRUint32 aIndex, nsAString& aResult) +{ + mCollection->EnsureFresh(); + return nsDOMStringList::Item(aIndex, aResult); +} + +NS_IMETHODIMP +PropertyStringList::GetLength(PRUint32* aLength) +{ + mCollection->EnsureFresh(); + return nsDOMStringList::GetLength(aLength); +} + +NS_IMETHODIMP +PropertyStringList::Contains(const nsAString& aString, bool* aResult) +{ + mCollection->EnsureFresh(); + return nsDOMStringList::Contains(aString, aResult); +} + +bool +PropertyStringList::ContainsInternal(const nsAString& aString) +{ + // This method should not call EnsureFresh, otherwise we may become stuck in an infinite loop. + bool result; + nsDOMStringList::Contains(aString, &result); + return result; +} + +} // namespace dom +} // namespace mozilla diff --git a/content/html/content/src/HTMLPropertiesCollection.h b/content/html/content/src/HTMLPropertiesCollection.h new file mode 100644 index 000000000000..7d1d8d099c42 --- /dev/null +++ b/content/html/content/src/HTMLPropertiesCollection.h @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */ +/* 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 HTMLPropertiesCollection_h_ +#define HTMLPropertiesCollection_h_ + +#include "nsDOMLists.h" +#include "nsCycleCollectionParticipant.h" +#include "nsAutoPtr.h" +#include "nsIDOMHTMLPropertiesCollection.h" +#include "nsIDOMPropertyNodeList.h" +#include "nsCOMArray.h" +#include "nsIMutationObserver.h" +#include "nsStubMutationObserver.h" +#include "nsBaseHashtable.h" +#include "nsINodeList.h" +#include "nsIHTMLCollection.h" +#include "nsHashKeys.h" +#include "nsGenericHTMLElement.h" + +class nsXPCClassInfo; +class nsIDocument; +class nsINode; + +namespace mozilla { +namespace dom { + +class HTMLPropertiesCollection; +class PropertyNodeList; + +class PropertyStringList : public nsDOMStringList +{ +public: + PropertyStringList(HTMLPropertiesCollection* aCollection); + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(PropertyStringList) + NS_DECL_NSIDOMDOMSTRINGLIST + + bool ContainsInternal(const nsAString& aString); + +protected: + nsRefPtr mCollection; +}; + +class HTMLPropertiesCollection : public nsIDOMHTMLPropertiesCollection, + public nsStubMutationObserver, + public nsWrapperCache, + public nsIHTMLCollection +{ + friend class PropertyNodeList; + friend class PropertyStringList; +public: + HTMLPropertiesCollection(nsGenericHTMLElement* aRoot); + virtual ~HTMLPropertiesCollection(); + + virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, + bool *triedToWrap); + + NS_IMETHOD NamedItem(const nsAString& aName, nsIDOMNode** aResult); + void SetDocument(nsIDocument* aDocument); + nsINode* GetParentObject(); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_NSIDOMHTMLPROPERTIESCOLLECTION + + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(HTMLPropertiesCollection, + nsIHTMLCollection) + + nsXPCClassInfo* GetClassInfo(); + +protected: + // Make sure this collection is up to date, in case the DOM has been mutated. + void EnsureFresh(); + + // Crawl the properties of mRoot, following any itemRefs it may have + void CrawlProperties(); + + // Crawl startNode and its descendants, looking for items + void CrawlSubtree(Element* startNode); + + // the items that make up this collection + nsTArray > mProperties; + + // the itemprop attribute of the properties + nsRefPtr mNames; + + // The cached PropertyNodeLists that are NamedItems of this collection + nsRefPtrHashtable mNamedItemEntries; + + // The element this collection is rooted at + nsCOMPtr mRoot; + + // The document mRoot is in, if any + nsCOMPtr mDoc; + + // True if there have been DOM modifications since the last EnsureFresh call. + bool mIsDirty; +}; + +class PropertyNodeList : public nsINodeList, + public nsIDOMPropertyNodeList, + public nsStubMutationObserver +{ +public: + PropertyNodeList(HTMLPropertiesCollection* aCollection, + nsIContent* aRoot, const nsAString& aName); + virtual ~PropertyNodeList(); + + virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, + bool *triedToWrap); + + void SetDocument(nsIDocument* aDocument); + + NS_DECL_NSIDOMPROPERTYNODELIST + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(PropertyNodeList, + nsINodeList) + + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + + // nsINodeList interface + virtual PRInt32 IndexOf(nsIContent* aContent); + virtual nsINode* GetParentObject(); + + void AppendElement(nsGenericHTMLElement* aElement) + { + mElements.AppendElement(aElement); + } + + void Clear() + { + mElements.Clear(); + } + + void SetDirty() { mIsDirty = true; } + +protected: + // Make sure this list is up to date, in case the DOM has been mutated. + void EnsureFresh(); + + // the the name that this list corresponds to + nsString mName; + + // the document mParent is in, if any + nsCOMPtr mDoc; + + // the collection that this list is a named item of + nsRefPtr mCollection; + + // the node this list is rooted at + nsCOMPtr mParent; + + // the properties that make up this list + nsTArray > mElements; + + // True if there have been DOM modifications since the last EnsureFresh call. + bool mIsDirty; +}; + +} // namespace dom +} // namespace mozilla +#endif // HTMLPropertiesCollection_h_ diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in index c225b544fb0e..54be7d9bf154 100644 --- a/content/html/content/src/Makefile.in +++ b/content/html/content/src/Makefile.in @@ -22,6 +22,7 @@ EXPORTS = \ $(NULL) CPPSRCS = \ + HTMLPropertiesCollection.cpp \ nsClientRect.cpp \ nsHTMLDNSPrefetch.cpp \ nsGenericHTMLElement.cpp \ diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index ba71914ecdbf..ad4479b24e1e 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -91,6 +91,9 @@ #include "mozilla/dom/FromParser.h" #include "mozilla/BloomFilter.h" +#include "HTMLPropertiesCollection.h" +#include "nsVariant.h" + using namespace mozilla; using namespace mozilla::dom; @@ -248,7 +251,6 @@ NS_INTERFACE_TABLE_HEAD(nsGenericHTMLElementTearoff) NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLElementTearoff) NS_INTERFACE_MAP_END_AGGREGATED(mElement) - NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLElement, TabIndex, tabindex, -1) NS_IMPL_BOOL_ATTR(nsGenericHTMLElement, Hidden, hidden) @@ -1699,6 +1701,13 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, NS_ENSURE_SUCCESS(rv, rv); if (aDocument) { + if (HasProperties()) { + HTMLPropertiesCollection* properties = + static_cast(GetProperty(nsGkAtoms::microdataProperties)); + if (properties) { + properties->SetDocument(aDocument); + } + } RegAccessKey(); if (HasName()) { aDocument-> @@ -1721,6 +1730,14 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent) if (IsInDoc()) { UnregAccessKey(); } + + if(HasProperties()) { + HTMLPropertiesCollection* properties = + static_cast(GetProperty(nsGkAtoms::microdataProperties)); + if (properties) { + properties->SetDocument(nsnull); + } + } RemoveFromNameTable(); @@ -2073,6 +2090,13 @@ nsGenericHTMLElement::ParseAttribute(PRInt32 aNamespaceID, aResult.ParseAtom(aValue); return true; } + + if (aAttribute == nsGkAtoms::itemref || + aAttribute == nsGkAtoms::itemprop || + aAttribute == nsGkAtoms::itemtype) { + aResult.ParseAtomArray(aValue); + return true; + } } return nsGenericHTMLElementBase::ParseAttribute(aNamespaceID, aAttribute, @@ -4081,3 +4105,162 @@ nsGenericHTMLElement::ChangeEditableState(PRInt32 aChange) nsAutoScriptBlocker scriptBlocker; MakeContentDescendantsEditable(this, document); } + +NS_IMPL_BOOL_ATTR(nsGenericHTMLElement, ItemScope, itemscope) +NS_IMPL_URI_ATTR(nsGenericHTMLElement, ItemId, itemid) + +NS_IMETHODIMP +nsGenericHTMLElement::GetItemValue(nsIVariant** aValue) +{ + nsCOMPtr out = new nsVariant(); + + if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) { + out->SetAsEmpty(); + out.forget(aValue); + return NS_OK; + } + + bool itemScope; + GetItemScope(&itemScope); + if (itemScope) { + out->SetAsISupports(static_cast(this)); + } else { + nsAutoString string; + GetItemValueText(string); + out->SetAsAString(string); + } + + out.forget(aValue); + return NS_OK; +} + +NS_IMETHODIMP +nsGenericHTMLElement::SetItemValue(nsIVariant* aValue) +{ + if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) || + HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) { + return NS_ERROR_DOM_INVALID_ACCESS_ERR; + } + + nsAutoString string; + aValue->GetAsAString(string); + SetItemValueText(string); + return NS_OK; +} + +void +nsGenericHTMLElement::GetItemValueText(nsAString& text) +{ + GetTextContent(text); +} + +void +nsGenericHTMLElement::SetItemValueText(const nsAString& text) +{ + SetTextContent(text); +} + +static void +nsDOMSettableTokenListPropertyDestructor(void *aObject, nsIAtom *aProperty, + void *aPropertyValue, void *aData) +{ + nsDOMSettableTokenList* list = + static_cast(aPropertyValue); + NS_IF_RELEASE(list); +} + +nsDOMSettableTokenList* +nsGenericHTMLElement::GetTokenList(nsIAtom* aAtom) +{ + nsDOMSettableTokenList* list = NULL; + if (HasProperties()) { + list = static_cast(GetProperty(aAtom)); + } + if (!list) { + list = new nsDOMSettableTokenList(this, aAtom); + NS_ADDREF(list); + SetProperty(aAtom, list, nsDOMSettableTokenListPropertyDestructor); + } + return list; +} + +NS_IMETHODIMP +nsGenericHTMLElement::GetItemRef(nsIVariant** aResult) +{ + nsIDOMDOMSettableTokenList* itemRef = GetTokenList(nsGkAtoms::itemref); + nsCOMPtr out = new nsVariant(); + out->SetAsInterface(NS_GET_IID(nsIDOMDOMSettableTokenList), itemRef); + out.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsGenericHTMLElement::SetItemRef(nsIVariant* aValue) +{ + nsDOMSettableTokenList* itemRef = GetTokenList(nsGkAtoms::itemref); + nsAutoString string; + aValue->GetAsAString(string); + return itemRef->SetValue(string); +} + +NS_IMETHODIMP +nsGenericHTMLElement::GetItemProp(nsIVariant** aResult) +{ + nsIDOMDOMSettableTokenList* itemProp = GetTokenList(nsGkAtoms::itemprop); + nsCOMPtr out = new nsVariant(); + out->SetAsInterface(NS_GET_IID(nsIDOMDOMSettableTokenList), itemProp); + out.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsGenericHTMLElement::SetItemProp(nsIVariant* aValue) +{ + nsDOMSettableTokenList* itemProp = GetTokenList(nsGkAtoms::itemprop); + nsAutoString string; + aValue->GetAsAString(string); + return itemProp->SetValue(string); +} + +NS_IMETHODIMP +nsGenericHTMLElement::GetItemType(nsIVariant** aResult) +{ + nsIDOMDOMSettableTokenList* itemType = GetTokenList(nsGkAtoms::itemtype); + nsCOMPtr out = new nsVariant(); + out->SetAsInterface(NS_GET_IID(nsIDOMDOMSettableTokenList), itemType); + out.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsGenericHTMLElement::SetItemType(nsIVariant* aValue) +{ + nsDOMSettableTokenList* itemType = GetTokenList(nsGkAtoms::itemtype); + nsAutoString string; + aValue->GetAsAString(string); + return itemType->SetValue(string); +} + +static void +nsIDOMHTMLPropertiesCollectionDestructor(void *aObject, nsIAtom *aProperty, + void *aPropertyValue, void *aData) +{ + nsIDOMHTMLPropertiesCollection* properties = + static_cast(aPropertyValue); + NS_IF_RELEASE(properties); +} + +NS_IMETHODIMP +nsGenericHTMLElement::GetProperties(nsIDOMHTMLPropertiesCollection** aReturn) +{ + nsIDOMHTMLPropertiesCollection* properties = + static_cast(GetProperty(nsGkAtoms::microdataProperties)); + if (!properties) { + properties = new HTMLPropertiesCollection(this); + NS_ADDREF(properties); + SetProperty(nsGkAtoms::microdataProperties, properties, nsIDOMHTMLPropertiesCollectionDestructor); + } + NS_ADDREF(*aReturn = properties); + return NS_OK; +} + diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 49c8fb1f6e14..cf970b5466b3 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -13,6 +13,8 @@ #include "nsFrameLoader.h" #include "nsGkAtoms.h" #include "nsContentCreatorFunctions.h" +#include "nsDOMSettableTokenList.h" +#include "nsIDOMHTMLPropertiesCollection.h" class nsIDOMAttr; class nsIDOMEventListener; @@ -33,6 +35,7 @@ struct nsSize; class nsHTMLFormElement; class nsIDOMDOMStringMap; class nsIDOMHTMLMenuElement; +class nsIDOMHTMLCollection; typedef nsMappedAttributeElement nsGenericHTMLElementBase; @@ -114,6 +117,26 @@ public: NS_IMETHOD SetSpellcheck(bool aSpellcheck); NS_IMETHOD GetDraggable(bool* aDraggable); NS_IMETHOD SetDraggable(bool aDraggable); + NS_IMETHOD GetItemScope(bool* aItemScope); + NS_IMETHOD SetItemScope(bool aItemScope); + NS_IMETHOD GetItemValue(nsIVariant** aValue); + NS_IMETHOD SetItemValue(nsIVariant* aValue); +protected: + // These methods are used to implement element-specific behavior of Get/SetItemValue + // when an element has @itemprop but no @itemscope. + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); + nsDOMSettableTokenList* GetTokenList(nsIAtom* aAtom); +public: + NS_IMETHOD GetItemType(nsIVariant** aType); + NS_IMETHOD SetItemType(nsIVariant* aType); + NS_IMETHOD GetItemId(nsAString& aId); + NS_IMETHOD SetItemId(const nsAString& aId); + NS_IMETHOD GetItemRef(nsIVariant** aRef); + NS_IMETHOD SetItemRef(nsIVariant* aValue); + NS_IMETHOD GetItemProp(nsIVariant** aProp); + NS_IMETHOD SetItemProp(nsIVariant* aValue); + NS_IMETHOD GetProperties(nsIDOMHTMLPropertiesCollection** aReturn); NS_IMETHOD GetAccessKey(nsAString &aAccessKey); NS_IMETHOD SetAccessKey(const nsAString& aAccessKey); NS_IMETHOD GetAccessKeyLabel(nsAString& aLabel); @@ -771,9 +794,6 @@ private: void ChangeEditableState(PRInt32 aChange); }; - -//---------------------------------------------------------------------- - class nsHTMLFieldSetElement; /** @@ -1376,6 +1396,45 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32); NS_SCRIPTABLE NS_IMETHOD Blur() { \ return _to Blur(); \ } \ + NS_SCRIPTABLE NS_IMETHOD GetItemScope(bool* aItemScope) { \ + return _to GetItemScope(aItemScope); \ + } \ + NS_SCRIPTABLE NS_IMETHOD SetItemScope(bool aItemScope) { \ + return _to SetItemScope(aItemScope); \ + } \ + NS_SCRIPTABLE NS_IMETHOD GetItemType(nsIVariant** aType) { \ + return _to GetItemType(aType); \ + } \ + NS_SCRIPTABLE NS_IMETHOD SetItemType(nsIVariant* aType) { \ + return _to SetItemType(aType); \ + } \ + NS_SCRIPTABLE NS_IMETHOD GetItemId(nsAString& aId) { \ + return _to GetItemId(aId); \ + } \ + NS_SCRIPTABLE NS_IMETHOD SetItemId(const nsAString& aId) { \ + return _to SetItemId(aId); \ + } \ + NS_SCRIPTABLE NS_IMETHOD GetProperties(nsIDOMHTMLPropertiesCollection** aReturn) { \ + return _to GetProperties(aReturn); \ + } \ + NS_SCRIPTABLE NS_IMETHOD GetItemValue(nsIVariant** aValue) { \ + return _to GetItemValue(aValue); \ + } \ + NS_SCRIPTABLE NS_IMETHOD SetItemValue(nsIVariant* aValue) { \ + return _to SetItemValue(aValue); \ + } \ + NS_SCRIPTABLE NS_IMETHOD GetItemRef(nsIVariant** aRef) { \ + return _to GetItemRef(aRef); \ + } \ + NS_SCRIPTABLE NS_IMETHOD SetItemRef(nsIVariant* aRef) { \ + return _to SetItemRef(aRef); \ + } \ + NS_SCRIPTABLE NS_IMETHOD GetItemProp(nsIVariant** aProp) { \ + return _to GetItemProp(aProp); \ + } \ + NS_SCRIPTABLE NS_IMETHOD SetItemProp(nsIVariant* aProp) { \ + return _to SetItemProp(aProp); \ + } \ NS_SCRIPTABLE NS_IMETHOD GetAccessKey(nsAString& aAccessKey) { \ return _to GetAccessKey(aAccessKey); \ } \ diff --git a/content/html/content/src/nsHTMLAnchorElement.cpp b/content/html/content/src/nsHTMLAnchorElement.cpp index 533098e0da67..2794c88e59a1 100644 --- a/content/html/content/src/nsHTMLAnchorElement.cpp +++ b/content/html/content/src/nsHTMLAnchorElement.cpp @@ -110,6 +110,10 @@ public: virtual void OnDNSPrefetchDeferred(); virtual void OnDNSPrefetchRequested(); virtual bool HasDeferredDNSPrefetchRequest(); + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; // Indicates that a DNS Prefetch has been requested from this Anchor elem @@ -166,6 +170,18 @@ NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, Shape, shape) NS_IMPL_INT_ATTR(nsHTMLAnchorElement, TabIndex, tabindex) NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, Type, type) +void +nsHTMLAnchorElement::GetItemValueText(nsAString& aValue) +{ + GetHref(aValue); +} + +void +nsHTMLAnchorElement::SetItemValueText(const nsAString& aValue) +{ + SetHref(aValue); +} + NS_IMETHODIMP nsHTMLAnchorElement::GetDraggable(bool* aDraggable) { diff --git a/content/html/content/src/nsHTMLAreaElement.cpp b/content/html/content/src/nsHTMLAreaElement.cpp index 47bdfe0f96da..1eb3d0d8c3f5 100644 --- a/content/html/content/src/nsHTMLAreaElement.cpp +++ b/content/html/content/src/nsHTMLAreaElement.cpp @@ -95,6 +95,10 @@ public: virtual nsXPCClassInfo* GetClassInfo(); virtual nsIDOMNode* AsDOMNode() { return this; } + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; @@ -137,6 +141,18 @@ NS_IMPL_BOOL_ATTR(nsHTMLAreaElement, NoHref, nohref) NS_IMPL_STRING_ATTR(nsHTMLAreaElement, Shape, shape) NS_IMPL_INT_ATTR(nsHTMLAreaElement, TabIndex, tabindex) +void +nsHTMLAreaElement::GetItemValueText(nsAString& aValue) +{ + GetHref(aValue); +} + +void +nsHTMLAreaElement::SetItemValueText(const nsAString& aValue) +{ + SetHref(aValue); +} + NS_IMETHODIMP nsHTMLAreaElement::GetTarget(nsAString& aValue) { diff --git a/content/html/content/src/nsHTMLAudioElement.cpp b/content/html/content/src/nsHTMLAudioElement.cpp index ee3177a92cd5..229f0c806b6a 100644 --- a/content/html/content/src/nsHTMLAudioElement.cpp +++ b/content/html/content/src/nsHTMLAudioElement.cpp @@ -83,6 +83,20 @@ nsHTMLAudioElement::~nsHTMLAudioElement() { } +void +nsHTMLAudioElement::GetItemValueText(nsAString& aValue) +{ + // Can't call GetSrc because we don't have a JSContext + GetURIAttr(nsGkAtoms::src, nsnull, aValue); +} + +void +nsHTMLAudioElement::SetItemValueText(const nsAString& aValue) +{ + // Can't call SetSrc because we don't have a JSContext + SetAttr(kNameSpaceID_None, nsGkAtoms::src, aValue, true); +} + NS_IMETHODIMP nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext, JSObject *aObj, PRUint32 argc, jsval *argv) diff --git a/content/html/content/src/nsHTMLIFrameElement.cpp b/content/html/content/src/nsHTMLIFrameElement.cpp index 9d9cb7ec2d50..69bb73fa09a0 100644 --- a/content/html/content/src/nsHTMLIFrameElement.cpp +++ b/content/html/content/src/nsHTMLIFrameElement.cpp @@ -58,6 +58,10 @@ public: virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; virtual nsXPCClassInfo* GetClassInfo(); virtual nsIDOMNode* AsDOMNode() { return this; } + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; @@ -106,6 +110,18 @@ NS_IMPL_URI_ATTR(nsHTMLIFrameElement, Src, src) NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Width, width) NS_IMPL_BOOL_ATTR(nsHTMLIFrameElement, MozAllowFullScreen, mozallowfullscreen) +void +nsHTMLIFrameElement::GetItemValueText(nsAString& aValue) +{ + GetSrc(aValue); +} + +void +nsHTMLIFrameElement::SetItemValueText(const nsAString& aValue) +{ + SetSrc(aValue); +} + NS_IMETHODIMP nsHTMLIFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument) { diff --git a/content/html/content/src/nsHTMLImageElement.cpp b/content/html/content/src/nsHTMLImageElement.cpp index 6a2a089f4ab9..812334e48de6 100644 --- a/content/html/content/src/nsHTMLImageElement.cpp +++ b/content/html/content/src/nsHTMLImageElement.cpp @@ -116,6 +116,18 @@ NS_IMPL_URI_ATTR(nsHTMLImageElement, Src, src) NS_IMPL_STRING_ATTR(nsHTMLImageElement, UseMap, usemap) NS_IMPL_INT_ATTR(nsHTMLImageElement, Vspace, vspace) +void +nsHTMLImageElement::GetItemValueText(nsAString& aValue) +{ + GetSrc(aValue); +} + +void +nsHTMLImageElement::SetItemValueText(const nsAString& aValue) +{ + SetSrc(aValue); +} + // crossorigin is not "limited to only known values" per spec, so it's // just a string attr purposes of the DOM crossOrigin property. NS_IMPL_STRING_ATTR(nsHTMLImageElement, CrossOrigin, crossorigin) diff --git a/content/html/content/src/nsHTMLImageElement.h b/content/html/content/src/nsHTMLImageElement.h index e230f0f7bef7..99c0a00a31a9 100644 --- a/content/html/content/src/nsHTMLImageElement.h +++ b/content/html/content/src/nsHTMLImageElement.h @@ -103,6 +103,8 @@ public: protected: nsIntPoint GetXY(); nsSize GetWidthHeight(); + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; #endif /* nsHTMLImageElement_h */ diff --git a/content/html/content/src/nsHTMLLinkElement.cpp b/content/html/content/src/nsHTMLLinkElement.cpp index 6ae52fb16cd8..2e72964081fa 100644 --- a/content/html/content/src/nsHTMLLinkElement.cpp +++ b/content/html/content/src/nsHTMLLinkElement.cpp @@ -95,6 +95,9 @@ protected: nsAString& aType, nsAString& aMedia, bool* aIsAlternate); +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; @@ -172,6 +175,18 @@ NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rev, rev) NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Target, target) NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Type, type) +void +nsHTMLLinkElement::GetItemValueText(nsAString& aValue) +{ + GetHref(aValue); +} + +void +nsHTMLLinkElement::SetItemValueText(const nsAString& aValue) +{ + SetHref(aValue); +} + nsresult nsHTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, diff --git a/content/html/content/src/nsHTMLMetaElement.cpp b/content/html/content/src/nsHTMLMetaElement.cpp index d5c8bf76772e..f82bafa21b2c 100644 --- a/content/html/content/src/nsHTMLMetaElement.cpp +++ b/content/html/content/src/nsHTMLMetaElement.cpp @@ -45,6 +45,10 @@ public: virtual nsXPCClassInfo* GetClassInfo(); virtual nsIDOMNode* AsDOMNode() { return this; } + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; @@ -83,6 +87,19 @@ NS_IMPL_STRING_ATTR(nsHTMLMetaElement, HttpEquiv, httpEquiv) NS_IMPL_STRING_ATTR(nsHTMLMetaElement, Name, name) NS_IMPL_STRING_ATTR(nsHTMLMetaElement, Scheme, scheme) +void +nsHTMLMetaElement::GetItemValueText(nsAString& aValue) +{ + GetContent(aValue); +} + +void +nsHTMLMetaElement::SetItemValueText(const nsAString& aValue) +{ + SetContent(aValue); +} + + nsresult nsHTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, diff --git a/content/html/content/src/nsHTMLObjectElement.cpp b/content/html/content/src/nsHTMLObjectElement.cpp index 6d6611827b7d..6559d1b24317 100644 --- a/content/html/content/src/nsHTMLObjectElement.cpp +++ b/content/html/content/src/nsHTMLObjectElement.cpp @@ -136,6 +136,9 @@ private: * value. This is used to know the default tabindex value. */ bool IsFocusableForTabIndex(); + + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); bool mIsDoneAddingChildren; }; @@ -224,6 +227,18 @@ nsHTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm) return nsGenericHTMLFormElement::GetForm(aForm); } +void +nsHTMLObjectElement::GetItemValueText(nsAString& aValue) +{ + GetData(aValue); +} + +void +nsHTMLObjectElement::SetItemValueText(const nsAString& aValue) +{ + SetData(aValue); +} + nsresult nsHTMLObjectElement::BindToTree(nsIDocument *aDocument, nsIContent *aParent, diff --git a/content/html/content/src/nsHTMLSharedObjectElement.cpp b/content/html/content/src/nsHTMLSharedObjectElement.cpp index d2e8e6ba5066..13c500d5d191 100644 --- a/content/html/content/src/nsHTMLSharedObjectElement.cpp +++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp @@ -153,6 +153,9 @@ private: // mIsDoneAddingChildren is only really used for . This boolean is // always true for , per the documentation in nsIContent.h. bool mIsDoneAddingChildren; + + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; @@ -171,6 +174,26 @@ nsHTMLSharedObjectElement::nsHTMLSharedObjectElement(already_AddRefedEquals(nsGkAtoms::applet)) { + nsGenericHTMLElement::GetItemValueText(aValue); + } else { + GetSrc(aValue); + } +} + +void +nsHTMLSharedObjectElement::SetItemValueText(const nsAString& aValue) +{ + if (mNodeInfo->Equals(nsGkAtoms::applet)) { + nsGenericHTMLElement::SetItemValueText(aValue); + } else { + SetSrc(aValue); + } +} + nsHTMLSharedObjectElement::~nsHTMLSharedObjectElement() { UnregisterFreezableElement(); diff --git a/content/html/content/src/nsHTMLSourceElement.cpp b/content/html/content/src/nsHTMLSourceElement.cpp index 3263956004df..64e4a24b08ae 100644 --- a/content/html/content/src/nsHTMLSourceElement.cpp +++ b/content/html/content/src/nsHTMLSourceElement.cpp @@ -47,6 +47,10 @@ public: virtual nsXPCClassInfo* GetClassInfo(); virtual nsIDOMNode* AsDOMNode() { return this; } + +protected: + virtual void GetItemValueText(nsAString& text); + virtual void SetItemValueText(const nsAString& text); }; @@ -84,6 +88,18 @@ NS_IMPL_URI_ATTR(nsHTMLSourceElement, Src, src) NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Type, type) NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Media, media) +void +nsHTMLSourceElement::GetItemValueText(nsAString& aValue) +{ + GetSrc(aValue); +} + +void +nsHTMLSourceElement::SetItemValueText(const nsAString& aValue) +{ + SetSrc(aValue); +} + nsresult nsHTMLSourceElement::BindToTree(nsIDocument *aDocument, nsIContent *aParent, diff --git a/content/html/content/src/nsHTMLVideoElement.cpp b/content/html/content/src/nsHTMLVideoElement.cpp index 956d6c6123db..72d03ae80e86 100644 --- a/content/html/content/src/nsHTMLVideoElement.cpp +++ b/content/html/content/src/nsHTMLVideoElement.cpp @@ -80,6 +80,20 @@ nsHTMLVideoElement::~nsHTMLVideoElement() { } +void +nsHTMLVideoElement::GetItemValueText(nsAString& aValue) +{ + // Can't call GetSrc because we don't have a JSContext + GetURIAttr(nsGkAtoms::src, nsnull, aValue); +} + +void +nsHTMLVideoElement::SetItemValueText(const nsAString& aValue) +{ + // Can't call SetSrc because we don't have a JSContext + SetAttr(kNameSpaceID_None, nsGkAtoms::src, aValue, true); +} + nsresult nsHTMLVideoElement::GetVideoSize(nsIntSize* size) { if (mMediaSize.width == -1 && mMediaSize.height == -1) { diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 3634df795190..e4aba11fd8bd 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -1765,6 +1765,84 @@ nsHTMLDocument::GetElementsByName(const nsAString& aElementName, return NS_OK; } +static bool MatchItems(nsIContent* aContent, PRInt32 aNameSpaceID, + nsIAtom* aAtom, void* aData) +{ + if (!(aContent->IsElement() && aContent->AsElement()->IsHTML())) { + return false; + } + + nsGenericHTMLElement* elem = static_cast(aContent); + if (!elem->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope) || + elem->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) { + return false; + } + + nsTArray >* tokens = static_cast >*>(aData); + if (tokens->IsEmpty()) { + return true; + } + + const nsAttrValue* attr = elem->GetParsedAttr(nsGkAtoms::itemtype); + if (!attr) + return false; + + for (PRUint32 i = 0; i < tokens->Length(); i++) { + if (!attr->Contains(tokens->ElementAt(i), eCaseMatters)) { + return false; + } + } + return true; +} + +static void DestroyTokens(void* aData) +{ + nsTArray >* tokens = static_cast >*>(aData); + delete tokens; +} + +static void* CreateTokens(nsINode* aRootNode, const nsString* types) +{ + nsTArray >* tokens = new nsTArray >(); + nsAString::const_iterator iter, end; + types->BeginReading(iter); + types->EndReading(end); + + // skip initial whitespace + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { + ++iter; + } + + // parse the tokens + while (iter != end) { + nsAString::const_iterator start(iter); + + do { + ++iter; + } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); + + tokens->AppendElement(do_GetAtom(Substring(start, iter))); + + // skip whitespace + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { + ++iter; + } + } + return tokens; +} + +NS_IMETHODIMP +nsHTMLDocument::GetItems(const nsAString& types, nsIDOMNodeList** aReturn) +{ + nsRefPtr elements = + NS_GetFuncStringContentList(this, MatchItems, DestroyTokens, + CreateTokens, types); + NS_ENSURE_TRUE(elements, NS_ERROR_OUT_OF_MEMORY); + elements.forget(aReturn); + return NS_OK; +} + + void nsHTMLDocument::AddedForm() { diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 288629e86c8b..cf7a1b17fa1e 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -112,7 +112,6 @@ public: UseExistingNameString, aName); } - virtual nsresult ResolveName(const nsAString& aName, nsIContent *aForm, nsISupports **aResult, diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 92a0a708213a..99233e6422c0 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -828,6 +828,11 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(HTMLCollection, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(HTMLPropertiesCollection, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(PropertyNodeList, + nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) // HTML element classes NS_DEFINE_CLASSINFO_DATA(HTMLElement, nsElementSH, @@ -2731,6 +2736,16 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLCollection) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(HTMLPropertiesCollection, nsIDOMHTMLPropertiesCollection) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLPropertiesCollection) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLCollection) + DOM_CLASSINFO_MAP_END + + DOM_CLASSINFO_MAP_BEGIN(PropertyNodeList, nsIDOMPropertyNodeList) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMPropertyNodeList) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeList) + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(HTMLElement, nsIDOMHTMLElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLElement) DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h index 02b0814fcecf..ad155afaaa92 100644 --- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -58,6 +58,8 @@ DOMCI_CLASS(DeviceRotationRate) DOMCI_CLASS(HTMLDocument) DOMCI_CLASS(HTMLOptionsCollection) DOMCI_CLASS(HTMLCollection) +DOMCI_CLASS(HTMLPropertiesCollection) +DOMCI_CLASS(PropertyNodeList) // HTML element classes DOMCI_CLASS(HTMLElement) diff --git a/dom/interfaces/html/Makefile.in b/dom/interfaces/html/Makefile.in index 5d9e08a2c2e9..098fa2ed1410 100644 --- a/dom/interfaces/html/Makefile.in +++ b/dom/interfaces/html/Makefile.in @@ -61,6 +61,8 @@ SDK_XPIDLSRCS = \ nsIDOMHTMLParagraphElement.idl \ nsIDOMHTMLParamElement.idl \ nsIDOMHTMLPreElement.idl \ + nsIDOMHTMLPropertiesCollection.idl \ + nsIDOMPropertyNodeList.idl \ nsIDOMHTMLProgressElement.idl \ nsIDOMHTMLQuoteElement.idl \ nsIDOMHTMLScriptElement.idl \ diff --git a/dom/interfaces/html/nsIDOMHTMLDocument.idl b/dom/interfaces/html/nsIDOMHTMLDocument.idl index 36255bf89cdb..406c74b7c455 100644 --- a/dom/interfaces/html/nsIDOMHTMLDocument.idl +++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl @@ -13,7 +13,7 @@ */ interface nsISelection; -[scriptable, uuid(1B93973F-28CC-4F33-8E7B-B89C63AA9200)] +[scriptable, uuid(ecae54c6-2ab9-4167-b0ef-61960aadbb68)] interface nsIDOMHTMLDocument : nsIDOMDocument { readonly attribute DOMString URL; @@ -34,6 +34,7 @@ interface nsIDOMHTMLDocument : nsIDOMDocument readonly attribute nsIDOMHTMLCollection forms; readonly attribute nsIDOMHTMLCollection scripts; nsIDOMNodeList getElementsByName(in DOMString elementName); + nsIDOMNodeList getItems([optional] in DOMString types); // If aContentType is not something supported by nsHTMLDocument and // the HTML content sink, trying to write to the document will diff --git a/dom/interfaces/html/nsIDOMHTMLElement.idl b/dom/interfaces/html/nsIDOMHTMLElement.idl index 91c689211441..9b08411ae173 100644 --- a/dom/interfaces/html/nsIDOMHTMLElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLElement.idl @@ -4,9 +4,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDOMElement.idl" +#include "nsIVariant.idl" interface nsIDOMDOMStringMap; interface nsIDOMHTMLMenuElement; +interface nsIDOMHTMLPropertiesCollection; /** * The nsIDOMHTMLElement interface is the primary [X]HTML element @@ -19,7 +21,7 @@ interface nsIDOMHTMLMenuElement; * with changes from the work-in-progress WHATWG HTML specification: * http://www.whatwg.org/specs/web-apps/current-work/ */ -[scriptable, uuid(5C8B21BC-EF6E-4599-A26F-FACC05B4ADBE)] +[scriptable, uuid(9a677a5b-e6f7-4e2e-9ef9-22c2ac9967b3)] interface nsIDOMHTMLElement : nsIDOMElement { // metadata attributes @@ -30,6 +32,16 @@ interface nsIDOMHTMLElement : nsIDOMElement attribute DOMString className; readonly attribute nsIDOMDOMStringMap dataset; + attribute boolean itemScope; + attribute nsIVariant itemType; + attribute DOMString itemId; + readonly attribute nsIDOMHTMLPropertiesCollection properties; + // The following attributes are really nsDOMSettableTokenList, which has + // PutForwards, so we express them as nsIVariants to deal with this. + attribute nsIVariant itemValue; + attribute nsIVariant itemProp; + attribute nsIVariant itemRef; + // user interaction /** * Indicates that the element is not yet, or is no longer, relevant. diff --git a/dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl b/dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl new file mode 100644 index 000000000000..0e949b3db056 --- /dev/null +++ b/dom/interfaces/html/nsIDOMHTMLPropertiesCollection.idl @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */ +/* 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 "nsIDOMHTMLElement.idl" +#include "nsIDOMPropertyNodeList.idl" +#include "nsIDOMDOMStringList.idl" + +// This interface should extend nsIDOMHTMLCollection, which will be fixed when +// it is converted to webidl. +[scriptable, uuid(da1101db-d1d7-465d-9fd6-49ec9960cb20)] +interface nsIDOMHTMLPropertiesCollection : nsISupports +{ + readonly attribute unsigned long length; + readonly attribute nsIDOMDOMStringList names; + + [getter,forward(getNodeAt)] nsIDOMNode item(in unsigned long index); + nsIDOMPropertyNodeList namedItem(in DOMString name); + + /** + * Get the node at the index. Returns null if the index is out of bounds. + */ + [noscript,notxpcom,nostdcall] nsIContent getNodeAt(in unsigned long index); + + /** + * Get the node for the name. Returns null if no node exists for the name. + */ + [noscript,notxpcom,nostdcall] nsISupports getNamedItem(in DOMString name, + out nsWrapperCachePtr cache); +}; diff --git a/dom/interfaces/html/nsIDOMPropertyNodeList.idl b/dom/interfaces/html/nsIDOMPropertyNodeList.idl new file mode 100644 index 000000000000..2b69cc1f3b06 --- /dev/null +++ b/dom/interfaces/html/nsIDOMPropertyNodeList.idl @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */ +/* 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 "nsIVariant.idl" + +interface nsIDOMNode; +interface nsIContent; + +[scriptable, uuid(255cc828-49e8-4fb0-8e36-875e6e072da3)] +interface nsIDOMPropertyNodeList : nsISupports { + [getter,forward(getNodeAt)] nsIDOMNode item(in unsigned long index); + readonly attribute unsigned long length; + + /** + * Get the node at the index. Returns null if the index is out of bounds + */ + [noscript,notxpcom,nostdcall] nsIContent getNodeAt(in unsigned long index); + + nsIVariant getValues(); +}; diff --git a/js/xpconnect/src/codegen.py b/js/xpconnect/src/codegen.py index 3a610491c5a9..00b13b7bc3ca 100644 --- a/js/xpconnect/src/codegen.py +++ b/js/xpconnect/src/codegen.py @@ -365,7 +365,8 @@ def writeResultConv(f, type, interfaceResultTemplate, jsvalPtr, jsvalRef): template = resultConvTemplates.get(typeName) elif isInterfaceType(type): if isVariantType(type): - template = " return xpc_qsVariantToJsval(lccx, result, ${jsvalPtr});\n" + template = (" XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n" + " return xpc_qsVariantToJsval(lccx, result, ${jsvalPtr});\n") else: template = (" if (!result) {\n" " *${jsvalPtr} = JSVAL_NULL;\n" diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf index 83bfd35b8416..4a1da7e979ca 100644 --- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -219,7 +219,33 @@ members = [ 'nsIDOMHTMLDocument.getSelection', 'nsIDOMHTMLDocument.designMode', 'nsIDOMHTMLDocument.head', - 'nsIDOMHTMLElement.*', + # We can't quick stub nsIDOMHTMLElement.* because we don't + # generate quick stubs for nsIVariant attributes. + 'nsIDOMHTMLElement.id', + 'nsIDOMHTMLElement.title', + 'nsIDOMHTMLElement.lang', + 'nsIDOMHTMLElement.dir', + 'nsIDOMHTMLElement.className', + 'nsIDOMHTMLElement.dataset', + 'nsIDOMHTMLElement.itemScope', + 'nsIDOMHTMLElement.itemId', + 'nsIDOMHTMLElement.properties', + 'nsIDOMHTMLElement.hidden', + 'nsIDOMHTMLElement.tabIndex', + 'nsIDOMHTMLElement.accessKey', + 'nsIDOMHTMLElement.accessKeyLabel', + 'nsIDOMHTMLElement.draggable', + 'nsIDOMHTMLElement.contentEditable', + 'nsIDOMHTMLElement.isContentEditable', + 'nsIDOMHTMLElement.contextMenu', + 'nsIDOMHTMLElement.spellcheck', + 'nsIDOMHTMLElement.innerHTML', + 'nsIDOMHTMLElement.outerHTML', + 'nsIDOMHTMLElement.offsetParent', + 'nsIDOMHTMLElement.offsetTop', + 'nsIDOMHTMLElement.offsetLeft', + 'nsIDOMHTMLElement.offsetWidth', + 'nsIDOMHTMLElement.offsetHeight', 'nsIDOMHTMLFormElement.elements', 'nsIDOMHTMLFormElement.name', 'nsIDOMHTMLFormElement.submit', @@ -269,6 +295,8 @@ members = [ 'nsIDOMHTMLOptionsCollection.item', 'nsIDOMHTMLOptionsCollection.length', 'nsIDOMHTMLProgressElement.*', + 'nsIDOMHTMLPropertiesCollection.*', + 'nsIDOMPropertyNodeList.*', 'nsIDOMHTMLSelectElement.name', 'nsIDOMHTMLSelectElement.form', 'nsIDOMHTMLSelectElement.add', diff --git a/js/xpconnect/src/dombindings.conf b/js/xpconnect/src/dombindings.conf index a1b709663b3c..83a4ed6759c9 100644 --- a/js/xpconnect/src/dombindings.conf +++ b/js/xpconnect/src/dombindings.conf @@ -8,6 +8,10 @@ list_classes = [ 'name': 'NodeList', 'nativeClass': 'nsINodeList' }, + { + 'name': 'PropertyNodeList', + 'nativeClass': 'mozilla::dom::PropertyNodeList' + }, { 'name': 'HTMLCollection', 'nativeClass': 'nsIHTMLCollection' @@ -15,6 +19,10 @@ list_classes = [ { 'name': 'HTMLOptionsCollection', 'nativeClass': 'nsHTMLOptionCollection' + }, + { + 'name': 'HTMLPropertiesCollection', + 'nativeClass': 'mozilla::dom::HTMLPropertiesCollection' } ] @@ -33,11 +41,14 @@ prefableClasses = { irregularFilenames = { 'nsHTMLOptionCollection': 'nsHTMLSelectElement', + 'mozilla::dom::PropertyNodeList': 'HTMLPropertiesCollection', 'nsClientRectList': 'nsClientRect', 'nsPaintRequestList': 'nsPaintRequest', 'nsDOMFileList': 'nsDOMFile', } customInheritance = { + 'nsIDOMPropertyNodeList': 'nsIDOMNodeList', 'nsIDOMHTMLOptionsCollection': 'nsIDOMHTMLCollection', + 'nsIDOMHTMLPropertiesCollection': 'nsIDOMHTMLCollection', } From d677ade2f9992c7c9584f905d62ef110731c0326 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Mon, 4 Jun 2012 16:49:57 -0700 Subject: [PATCH 41/53] Bug 591467 - Add tests for microdata --- dom/imptests/Makefile.in | 1 + .../submission/Opera/microdata/Makefile.in | 19 + .../Opera/microdata/test_001.html.json | 8 + dom/imptests/html.mk | 1 + dom/imptests/html.txt | 1 + .../submission/Opera/microdata/Makefile.in | 24 + .../submission/Opera/microdata/test_001.html | 3652 +++++++++++++++++ 7 files changed, 3706 insertions(+) create mode 100644 dom/imptests/failures/html/tests/submission/Opera/microdata/Makefile.in create mode 100644 dom/imptests/failures/html/tests/submission/Opera/microdata/test_001.html.json create mode 100644 dom/imptests/html/tests/submission/Opera/microdata/Makefile.in create mode 100644 dom/imptests/html/tests/submission/Opera/microdata/test_001.html diff --git a/dom/imptests/Makefile.in b/dom/imptests/Makefile.in index f41498cf5c01..221f6f3b189d 100644 --- a/dom/imptests/Makefile.in +++ b/dom/imptests/Makefile.in @@ -14,6 +14,7 @@ DIRS = \ failures/webapps/WebStorage/tests/submissions/Ms2ger \ failures/webapps/WebStorage/tests/submissions/Infraware \ failures/webapps/DOMCore/tests/submissions/Opera \ + failures/html/tests/submission/Opera/microdata \ $(NULL) include $(srcdir)/editing.mk diff --git a/dom/imptests/failures/html/tests/submission/Opera/microdata/Makefile.in b/dom/imptests/failures/html/tests/submission/Opera/microdata/Makefile.in new file mode 100644 index 000000000000..cb8d8f6ebbce --- /dev/null +++ b/dom/imptests/failures/html/tests/submission/Opera/microdata/Makefile.in @@ -0,0 +1,19 @@ +DEPTH = ../../../../../../../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = dom/imptests/failures/html/tests/submission/Opera/microdata + +DIRS = \ + $(NULL) + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_TESTS = \ + test_001.html.json \ + $(NULL) + +libs:: $(_TESTS) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) diff --git a/dom/imptests/failures/html/tests/submission/Opera/microdata/test_001.html.json b/dom/imptests/failures/html/tests/submission/Opera/microdata/test_001.html.json new file mode 100644 index 000000000000..c2bb1886df44 --- /dev/null +++ b/dom/imptests/failures/html/tests/submission/Opera/microdata/test_001.html.json @@ -0,0 +1,8 @@ +{ + "document.getItems must return a NodeList": true, + "itemValue must reflect the src attribute on track elements": true, + "itemValue must reflect the textContent of time elements with no datetime attribute": true, + "itemValue must reflect the datetime attribute of time elements with a datetime attribute": true, + "the namedItem property must be read/write": true +} + diff --git a/dom/imptests/html.mk b/dom/imptests/html.mk index 14ee9edf4673..c5ca3fd42f3c 100644 --- a/dom/imptests/html.mk +++ b/dom/imptests/html.mk @@ -1,3 +1,4 @@ DIRS += \ html/tests/submission/Mozilla \ + html/tests/submission/Opera/microdata \ $(NULL) diff --git a/dom/imptests/html.txt b/dom/imptests/html.txt index f45a59dba915..c3c92caf36c7 100644 --- a/dom/imptests/html.txt +++ b/dom/imptests/html.txt @@ -1,2 +1,3 @@ https://dvcs.w3.org/hg/html|html tests/submission/Mozilla +tests/submission/Opera/microdata diff --git a/dom/imptests/html/tests/submission/Opera/microdata/Makefile.in b/dom/imptests/html/tests/submission/Opera/microdata/Makefile.in new file mode 100644 index 000000000000..1b42abe7288b --- /dev/null +++ b/dom/imptests/html/tests/submission/Opera/microdata/Makefile.in @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +DEPTH = ../../../../../../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = dom/imptests/html/tests/submission/Opera/microdata + +DIRS = \ + $(NULL) + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_TESTS = \ + test_001.html \ + $(NULL) + +_TESTS += \ + $(NULL) + +libs:: $(_TESTS) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) diff --git a/dom/imptests/html/tests/submission/Opera/microdata/test_001.html b/dom/imptests/html/tests/submission/Opera/microdata/test_001.html new file mode 100644 index 000000000000..cf583293be2d --- /dev/null +++ b/dom/imptests/html/tests/submission/Opera/microdata/test_001.html @@ -0,0 +1,3652 @@ + + + + + Microdata tests + + + + + +
Running test...
+
+
+
+
+
+
+ + + From f78342fd1de84a1b12d40fde54c1ab2ea9bd3116 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Mon, 4 Jun 2012 16:49:57 -0700 Subject: [PATCH 42/53] Bug 749520 - Use new mozHasAudio API to let users know that the video being watched does not have an audio track r=jaws --- toolkit/content/widgets/videocontrols.xml | 5 ++++- toolkit/themes/pinstripe/global/jar.mn | 1 + toolkit/themes/pinstripe/global/media/noAudio.png | Bin 0 -> 930 bytes .../pinstripe/global/media/videocontrols.css | 4 ++++ toolkit/themes/winstripe/global/jar.mn | 2 ++ toolkit/themes/winstripe/global/media/noAudio.png | Bin 0 -> 930 bytes .../winstripe/global/media/videocontrols.css | 4 ++++ 7 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 toolkit/themes/pinstripe/global/media/noAudio.png create mode 100644 toolkit/themes/winstripe/global/media/noAudio.png diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index 446cf7231d09..f68e86ee5d67 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -534,6 +534,9 @@ this.startFadeIn(this.controlBar); } this.showDuration(Math.round(this.video.duration * 1000)); + if (!this.isAudioOnly && !this.video.mozHasAudio) { + this.muteButton.setAttribute("noAudio", "true"); + } break; case "loadeddata": this.firstFrameShown = true; @@ -1388,7 +1391,7 @@ addListener(this.clickToPlay, "click", this.clickToPlayClickHandler); addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler); - if (!this.isAudioOnly) { + if (!this.isAudioOnly && this.video.mozHasAudio) { addListener(this.muteButton, "mouseover", this.onVolumeMouseInOut); addListener(this.muteButton, "mouseout", this.onVolumeMouseInOut); addListener(this.volumeStack, "mouseover", this.onVolumeMouseInOut); diff --git a/toolkit/themes/pinstripe/global/jar.mn b/toolkit/themes/pinstripe/global/jar.mn index 2228072af861..e677cb27b28a 100644 --- a/toolkit/themes/pinstripe/global/jar.mn +++ b/toolkit/themes/pinstripe/global/jar.mn @@ -146,6 +146,7 @@ toolkit.jar: skin/classic/global/media/playButton.png (media/playButton.png) skin/classic/global/media/muteButton.png (media/muteButton.png) skin/classic/global/media/unmuteButton.png (media/unmuteButton.png) + skin/classic/global/media/noAudio.png (media/noAudio.png) skin/classic/global/media/fullscreenButton.png (media/fullscreenButton.png) skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png) skin/classic/global/media/scrubberThumbWide.png (media/scrubberThumbWide.png) diff --git a/toolkit/themes/pinstripe/global/media/noAudio.png b/toolkit/themes/pinstripe/global/media/noAudio.png new file mode 100644 index 0000000000000000000000000000000000000000..3db8c973b6594cb8820661564eb8dacb673c09b9 GIT binary patch literal 930 zcmV;T16}-yP)i zTie@T^vAvTINcVvw|ljB+x~;SAWP;I%- zxZ&i$`I&1XUtW_1-U2l{0KBbo5;6O5d=h%03*Lhku;2~&0D8wKvkwvFq__30kO_T( zLnR(GJHQG}po3bd|NZhmkHHLvV@ESFR8T2!7aOV*YGadF%81qh3fWybtM1P)7&3$d zw~d7mmLxG9$5MQf(Asv%q@*za>3IUwR~G92_?#(B`8Cvgq_~EKbfn|VxpB-ZsY|9R zIS3apC;FhBGS~vRSdkTfiP$Ej2v1KQ<_S6w7K{1b(SvsQ=R}ZC6ivO0CtrRI@^b- zf&h(L2!kqO!rVqFT3E8|KN27kRirf6HTVKR<(k_tp^9M8LNv<}6hC~QZo?4 zdTM!|t!yDK@6Fwyy*s8J&{rKZF!l}QmT)!gaeZ8AbCMQLi(gSbHQ~;}9IocPeM4ZZ zI%Z_Mz;a|HaR+_4lE0F42&Q3Od;3X;cQk(mSJ0R6d^8M}mp!8Wi zTie@T^vAvTINcVvw|ljB+x~;SAWP;I%- zxZ&i$`I&1XUtW_1-U2l{0KBbo5;6O5d=h%03*Lhku;2~&0D8wKvkwvFq__30kO_T( zLnR(GJHQG}po3bd|NZhmkHHLvV@ESFR8T2!7aOV*YGadF%81qh3fWybtM1P)7&3$d zw~d7mmLxG9$5MQf(Asv%q@*za>3IUwR~G92_?#(B`8Cvgq_~EKbfn|VxpB-ZsY|9R zIS3apC;FhBGS~vRSdkTfiP$Ej2v1KQ<_S6w7K{1b(SvsQ=R}ZC6ivO0CtrRI@^b- zf&h(L2!kqO!rVqFT3E8|KN27kRirf6HTVKR<(k_tp^9M8LNv<}6hC~QZo?4 zdTM!|t!yDK@6Fwyy*s8J&{rKZF!l}QmT)!gaeZ8AbCMQLi(gSbHQ~;}9IocPeM4ZZ zI%Z_Mz;a|HaR+_4lE0F42&Q3Od;3X;cQk(mSJ0R6d^8M}mp!8W Date: Mon, 4 Jun 2012 16:49:57 -0700 Subject: [PATCH 43/53] Bug 760834 - Fix mIterationCallback initialization order warning. r=Cwiis --- gfx/gl/GLContext.cpp | 2 +- gfx/gl/GLLibraryEGL.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 1a906bc03095..fbfec353c2aa 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -909,12 +909,12 @@ TiledTextureImage::TiledTextureImage(GLContext* aGL, TextureImage::Flags aFlags) : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags) , mCurrentImage(0) + , mIterationCallback(nsnull) , mInUpdate(false) , mRows(0) , mColumns(0) , mGL(aGL) , mTextureState(Created) - , mIterationCallback(nsnull) { mTileSize = (!(aFlags & TextureImage::ForceSingleTile) && mGL->WantsSmallTiles()) ? 256 : mGL->GetMaxTextureSize(); diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 492ba3052bd7..73bb77e16fa9 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -48,8 +48,6 @@ static PRLibrary* LoadApitraceLibrary() bool GLLibraryEGL::EnsureInitialized() { - nsresult rv; - if (mInitialized) { return true; } @@ -62,6 +60,7 @@ GLLibraryEGL::EnsureInitialized() // we should look for them there. We have to load the libs in this // order, because libEGL.dll depends on libGLESv2.dll. + nsresult rv; nsCOMPtr libraryFile; nsCOMPtr dirService = From d9cb19e028094bca966327e01eb4ded40c45c630 Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Mon, 4 Jun 2012 17:02:04 -0700 Subject: [PATCH 44/53] Bug 761444 - Remove unnecessary white space in xul.css. r=fryn --- toolkit/content/xul.css | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css index d5cd6ce238b0..146b55143f99 100644 --- a/toolkit/content/xul.css +++ b/toolkit/content/xul.css @@ -42,7 +42,7 @@ } /* hide the content, but don't destroy the frames */ -[collapsed="true"], +[collapsed="true"], [moz-collapsed="true"] { visibility: collapse; } @@ -79,7 +79,7 @@ xbl|children, commands, commandset, command, broadcasterset, broadcaster, observes, keyset, key, toolbarpalette, toolbarset, -template, rule, conditions, action, +template, rule, conditions, action, bindings, binding, content, member, triple, treechildren, treeitem, treeseparator, treerow, treecell { display: none; @@ -106,7 +106,7 @@ menulist[editable="true"] { /******** window & page ******/ -window, +window, page { overflow: -moz-hidden-unscrollable; -moz-box-orient: vertical; @@ -255,11 +255,11 @@ caption { /******* toolbar *******/ -toolbox { +toolbox { -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbox"); -moz-box-orient: vertical; } - + toolbar { -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar"); } @@ -336,7 +336,7 @@ menubar > menu.menu-iconic { menu { -moz-binding: url("chrome://global/content/bindings/menu.xml#menu"); } - + menu.menu-iconic { -moz-binding: url("chrome://global/content/bindings/menu.xml#menu-iconic"); } @@ -388,7 +388,7 @@ menuseparator { /********* popup & menupopup ***********/ -/* is deprecated. Only and are still valid. */ +/* is deprecated. Only and are still valid. */ popup, menupopup { @@ -437,7 +437,7 @@ grid { display: -moz-grid; } -rows, +rows, columns { display: -moz-grid-group; } @@ -854,7 +854,7 @@ popup[type="autocomplete"][hidden="true"] { visibility: hidden; } -/* The following rule is here to fix bug 96899 (and now 117952). +/* The following rule is here to fix bug 96899 (and now 117952). Somehow trees create a situation in which a popupset flows itself as if its popup child is directly within it instead of the placeholder child that should actually be inside the popupset. @@ -1093,12 +1093,12 @@ wizardpage { prefwindow, prefwindow:root /* override :root from above */ { - -moz-binding: url("chrome://global/content/bindings/preferences.xml#prefwindow"); + -moz-binding: url("chrome://global/content/bindings/preferences.xml#prefwindow"); -moz-box-orient: vertical; } prefpane { - -moz-binding: url("chrome://global/content/bindings/preferences.xml#prefpane"); + -moz-binding: url("chrome://global/content/bindings/preferences.xml#prefpane"); -moz-box-orient: vertical; } @@ -1125,12 +1125,12 @@ preferences { } preference { - -moz-binding: url("chrome://global/content/bindings/preferences.xml#preference"); + -moz-binding: url("chrome://global/content/bindings/preferences.xml#preference"); visibility: collapse; } radio[pane] { - -moz-binding: url("chrome://global/content/bindings/preferences.xml#panebutton") !important; + -moz-binding: url("chrome://global/content/bindings/preferences.xml#panebutton") !important; -moz-box-orient: vertical; -moz-box-align: center; } From 4c5a2be2666048e30c512995eaa4f78b9c16ede7 Mon Sep 17 00:00:00 2001 From: Jonathan Wilde Date: Mon, 4 Jun 2012 17:37:53 -0700 Subject: [PATCH 45/53] Bug 761446 - Remove extraneous space characters from videocontrols.xml. r=fryn --- toolkit/content/widgets/videocontrols.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index f68e86ee5d67..5a2c81e2af03 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -150,11 +150,11 @@ else if (this.type == "volumeControl") this.Utils.setVolume(newValue / 100); break; - + case "minpos": this.setAttribute("min", newValue); break; - + case "maxpos": if (this.type == "scrubber") { // Update the value bar to match the thumb position. @@ -481,7 +481,7 @@ return enabled; }, - + handleEvent : function (aEvent) { this.log("Got media event ----> " + aEvent.type); @@ -612,8 +612,8 @@ // We'll show the error status icon when we receive an error event // under either of the following conditions: // 1. The video has its error attribute set; this means we're loading - // from our src attribute, and the load failed, or we we're loading - // from source children and the decode or playback failed after we + // from our src attribute, and the load failed, or we we're loading + // from source children and the decode or playback failed after we // determined our selected resource was playable. // 2. The video's networkState is NETWORK_NO_SOURCE. This means we we're // loading from child source elements, but we were unable to select @@ -644,7 +644,7 @@ for each(let element in this.controlListeners) element.item.removeEventListener(element.event, element.func, false); - + delete this.controlListeners; this.video.removeEventListener("media-showStatistics", this._handleCustomEventsBound, false); @@ -1430,7 +1430,7 @@ - + @@ -1521,7 +1521,7 @@ this.delayHideControls(this.controlsTimeout); } }, - + delayHideControls : function(aTimeout) { if (this.controlsTimer) { clearTimeout(this.controlsTimer); @@ -1566,7 +1566,7 @@ this.Utils.playButton.addEventListener("command", function() { if (!self.Utils.video.paused) self.delayHideControls(0); - else + else self.showControls(); }, false); this.Utils.scrubber.addEventListener("click", function() { self.delayHideControls(self.controlsTimeout); }, false); From c7a3ba74b1cc683d56914ed2273b2cb28ec09c9c Mon Sep 17 00:00:00 2001 From: Chenxia Liu Date: Mon, 4 Jun 2012 18:07:31 -0700 Subject: [PATCH 46/53] Bug 760614 - Retry on connection failures, to address transient network errors. r=nalexander --- .../android/base/sync/net/BaseResource.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/sync/net/BaseResource.java b/mobile/android/base/sync/net/BaseResource.java index fa3762cfda84..5f86df4b2017 100644 --- a/mobile/android/base/sync/net/BaseResource.java +++ b/mobile/android/base/sync/net/BaseResource.java @@ -61,6 +61,8 @@ public class BaseResource implements Resource { private static final int MAX_TOTAL_CONNECTIONS = 20; private static final int MAX_CONNECTIONS_PER_ROUTE = 10; + private boolean retryOnFailedRequest = true; + public static boolean rewriteLocalhost = true; private static final String LOG_TAG = "BaseResource"; @@ -249,14 +251,30 @@ public class BaseResource implements Resource { } catch (ClientProtocolException e) { delegate.handleHttpProtocolException(e); } catch (IOException e) { - delegate.handleHttpIOException(e); + Logger.debug(LOG_TAG, "I/O exception returned from execute."); + if (!retryOnFailedRequest) { + delegate.handleHttpIOException(e); + } else { + retryRequest(); + } } catch (Exception e) { // Bug 740731: Don't let an exception fall through. Wrapping isn't // optimal, but often the exception is treated as an Exception anyway. - delegate.handleHttpIOException(new IOException(e)); + if (!retryOnFailedRequest) { + delegate.handleHttpIOException(new IOException(e)); + } else { + retryRequest(); + } } } + private void retryRequest() { + // Only retry once. + retryOnFailedRequest = false; + Logger.debug(LOG_TAG, "Retrying request..."); + this.execute(); + } + private void go(HttpRequestBase request) { if (delegate == null) { throw new IllegalArgumentException("No delegate provided."); From ad056ade928b5149f82dbaf2a3f28fd680aab276 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Jun 2012 00:00:24 -0700 Subject: [PATCH 47/53] Bug 760337 - Add JS_ASSERT(table) where appropriate in HashTable.h. r=luke. --HG-- extra : rebase_source : ab85f7061f79605afe54a6341612cededef35558 --- js/public/HashTable.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 9e2caab51375..b427240357f4 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -508,8 +508,9 @@ class HashTable : private AllocPolicy */ Entry &findFreeEntry(HashNumber keyHash) { - METER(stats.searches++); JS_ASSERT(!(keyHash & sCollisionBit)); + JS_ASSERT(table); + METER(stats.searches++); /* N.B. the |keyHash| has already been distributed. */ @@ -577,6 +578,8 @@ class HashTable : private AllocPolicy void add(const Lookup &l, const Entry &e) { + JS_ASSERT(table); + HashNumber keyHash = prepareHash(l); Entry &entry = lookup(l, keyHash, sCollisionBit); @@ -612,7 +615,9 @@ class HashTable : private AllocPolicy void remove(Entry &e) { + JS_ASSERT(table); METER(stats.removes++); + if (e.hasCollision()) { e.setRemoved(); removedCount++; @@ -663,22 +668,27 @@ class HashTable : private AllocPolicy } Range all() const { + JS_ASSERT(table); return Range(table, table + capacity()); } bool empty() const { + JS_ASSERT(table); return !entryCount; } uint32_t count() const { + JS_ASSERT(table); return entryCount; } uint32_t capacity() const { + JS_ASSERT(table); return JS_BIT(sHashBits - hashShift); } uint32_t generation() const { + JS_ASSERT(table); return gen; } @@ -766,6 +776,7 @@ class HashTable : private AllocPolicy void remove(Ptr p) { + JS_ASSERT(table); ReentrancyGuard g(*this); JS_ASSERT(p.found()); remove(*p.entry); From 48970d949a1a3a879dfaa7b711f0dc5d968face4 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Mon, 4 Jun 2012 21:29:56 -0400 Subject: [PATCH 48/53] Fix for bug 743666 (Add back deprecated XHR.onuploadprogress). r=bzbarsky --- .../base/public/nsDeprecatedOperationList.h | 1 + content/base/src/nsXMLHttpRequest.h | 18 ++++++++ content/base/test/Makefile.in | 1 + .../base/test/test_XHR_onuploadprogress.html | 41 +++++++++++++++++++ dom/bindings/Bindings.conf | 2 +- dom/locales/en-US/chrome/dom/dom.properties | 1 + dom/webidl/XMLHttpRequest.webidl | 1 + dom/workers/XMLHttpRequest.h | 12 ++++++ 8 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 content/base/test/test_XHR_onuploadprogress.html diff --git a/content/base/public/nsDeprecatedOperationList.h b/content/base/public/nsDeprecatedOperationList.h index e75b70c4e117..46d4f6b53bc4 100644 --- a/content/base/public/nsDeprecatedOperationList.h +++ b/content/base/public/nsDeprecatedOperationList.h @@ -48,3 +48,4 @@ DEPRECATED_OPERATION(DOMExceptionCode) DEPRECATED_OPERATION(NoExposedProps) DEPRECATED_OPERATION(MutationEvent) DEPRECATED_OPERATION(MozSlice) +DEPRECATED_OPERATION(Onuploadprogress) diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 23328ee672f7..e79d3005c461 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -246,6 +246,24 @@ public: // event handler IMPL_EVENT_HANDLER(readystatechange, Readystatechange) + JSObject* GetOnuploadprogress(JSContext* /* unused */) + { + nsIDocument* doc = GetOwner() ? GetOwner()->GetExtantDoc() : NULL; + if (doc) { + doc->WarnOnceAbout(nsIDocument::eOnuploadprogress); + } + return GetListenerAsJSObject(mOnUploadProgressListener); + } + void SetOnuploadprogress(JSContext* aCx, JSObject* aCallback, + ErrorResult& aRv) + { + nsIDocument* doc = GetOwner() ? GetOwner()->GetExtantDoc() : NULL; + if (doc) { + doc->WarnOnceAbout(nsIDocument::eOnuploadprogress); + } + aRv = SetJSObjectListener(aCx, NS_LITERAL_STRING("uploadprogress"), + mOnUploadProgressListener, aCallback); + } // states uint16_t GetReadyState(); diff --git a/content/base/test/Makefile.in b/content/base/test/Makefile.in index 23c1480d9d08..861e885087c8 100644 --- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -549,6 +549,7 @@ _TEST_FILES2 = \ test_bug433662.html \ test_bug749367.html \ test_bug753278.html \ + test_XHR_onuploadprogress.html \ $(NULL) _CHROME_FILES = \ diff --git a/content/base/test/test_XHR_onuploadprogress.html b/content/base/test/test_XHR_onuploadprogress.html new file mode 100644 index 000000000000..5c52727f1c8c --- /dev/null +++ b/content/base/test/test_XHR_onuploadprogress.html @@ -0,0 +1,41 @@ + + + + + + Test for Bug 743666 + + + + +Mozilla Bug 743666 +

+ +
+
+
+ + diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index de2006fdb3b0..0d1185b6d5ab 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -232,7 +232,7 @@ DOMInterfaces = { 'multipart', 'channel', 'upload', 'status' ], 'getterOnly': [ - 'responseType', 'timeout', 'onreadystatechange' + 'responseType', 'timeout', 'onreadystatechange', 'onuploadprogress' ] }, # XXXbz need a JSContext for send() and sendAsBinary because of diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 6ab13388a311..e43a732fbba7 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -125,3 +125,4 @@ NoExposedPropsWarning=Exposing chrome JS objects to content without __exposedPro MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver instead. # LOCALIZATION NOTE: Do not translate "Blob", "mozSlice", or "slice" MozSliceWarning=Use of mozSlice on the Blob object is deprecated. Use slice instead. +OnuploadprogressWarning=Use of XMLHttpRequest's onuploadprogress attribute is deprecated. diff --git a/dom/webidl/XMLHttpRequest.webidl b/dom/webidl/XMLHttpRequest.webidl index 9d6d5e5ef82a..fe0b49f0e533 100644 --- a/dom/webidl/XMLHttpRequest.webidl +++ b/dom/webidl/XMLHttpRequest.webidl @@ -79,4 +79,5 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget { [ChromeOnly] readonly attribute MozChannel channel; void sendAsBinary(DOMString body); any getInterface(IID iid); + [TreatNonCallableAsNull] attribute Function? onuploadprogress; }; diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index 87917dca7946..1e762f885031 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -95,6 +95,18 @@ public: #undef IMPL_GETTER_AND_SETTER + JSObject* + GetOnuploadprogress(JSContext* /* unused */, ErrorResult& aRv) + { + aRv = NS_ERROR_NOT_IMPLEMENTED; + return NULL; + } + void + SetOnuploadprogress(JSContext* /* unused */, JSObject* aListener, ErrorResult& aRv) + { + aRv = NS_ERROR_NOT_IMPLEMENTED; + } + uint16_t GetReadyState() const { From bcf9d165aea87ecc80e264d61b1c0c21c09ba653 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 4 Jun 2012 21:30:00 -0400 Subject: [PATCH 49/53] Bug 760749. Make interface type constructor args work in WebIDL bindings. r=khuey --- dom/bindings/parser/WebIDL.py | 4 ++++ dom/bindings/test/TestBindingHeader.h | 7 +++++++ dom/bindings/test/TestCodeGen.webidl | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 7b7fcc1b966f..5f1fa0a26e98 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -460,6 +460,10 @@ class IDLInterface(IDLObjectWithScope): for member in self.members: member.finish(scope) + ctor = self.ctor() + if ctor is not None: + ctor.finish(scope) + def isInterface(self): return True diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index 7743c931f359..64d8c98dbee9 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -64,6 +64,13 @@ public: static already_AddRefed Constructor(nsISupports*, uint32_t, Nullable&, ErrorResult&); + static + already_AddRefed Constructor(nsISupports*, TestInterface*, + ErrorResult&); + static + already_AddRefed Constructor(nsISupports*, + NonNull&, + ErrorResult&); // Integer types int8_t GetReadonlyByte(ErrorResult&); diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index ee4807e36316..7b66732a43b8 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -18,7 +18,9 @@ callback TestCallback = void(); [Constructor, Constructor(DOMString str), - Constructor(unsigned long num, boolean? bool)] + Constructor(unsigned long num, boolean? bool), + Constructor(TestInterface? iface), + Constructor(TestNonCastableInterface iface)] interface TestInterface { // Integer types // XXXbz add tests for infallible versions of all the integer stuff From 60872f999b158b9b537dc07f6e3f9f74d936b57b Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 4 Jun 2012 21:30:03 -0400 Subject: [PATCH 50/53] Bug 742151. Fix the error reporting in the WebIDL parser to list correct line numbers. r=khuey There are two changes here. One is to pass tracking=True to our parser. This makes it properly track positions of all productions, not just of lexer tokens. The second is to properly count up our newlines in the lex data, since the lexer seems to report the line number of the start of the lex data, which is always 1 in our case. --- dom/bindings/parser/WebIDL.py | 7 +++-- .../parser/tests/test_error_lineno.py | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 dom/bindings/parser/tests/test_error_lineno.py diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 5f1fa0a26e98..c720f2596892 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -88,6 +88,9 @@ class Location(object): self._line = self._lexdata[startofline:] self._colno = self._lexpos - startofline + # Our line number seems to point to the start of self._lexdata + self._lineno += self._lexdata.count('\n', 0, startofline) + def get(self): self.resolve() return "%s line %s:%s" % (self._file, self._lineno, self._colno) @@ -2923,7 +2926,7 @@ class Parser(Tokenizer): self.lexer.input(Parser._builtins) self._filename = None - self.parser.parse(lexer=self.lexer) + self.parser.parse(lexer=self.lexer,tracking=True) def _installBuiltins(self, scope): assert isinstance(scope, IDLScope) @@ -2943,7 +2946,7 @@ class Parser(Tokenizer): # print tok self._filename = filename - self._productions.extend(self.parser.parse(lexer=self.lexer)) + self._productions.extend(self.parser.parse(lexer=self.lexer,tracking=True)) self._filename = None def finish(self): diff --git a/dom/bindings/parser/tests/test_error_lineno.py b/dom/bindings/parser/tests/test_error_lineno.py new file mode 100644 index 000000000000..65a1ce1f0dcc --- /dev/null +++ b/dom/bindings/parser/tests/test_error_lineno.py @@ -0,0 +1,29 @@ +import WebIDL + +def WebIDLTest(parser, harness): + # Check that error messages put the '^' in the right place. + + threw = False + input = """\ +// This is a comment. +interface Foo { +}; + +/* This is also a comment. */ +interface ?""" + try: + parser.parse(input) + results = parser.finish() + except WebIDL.WebIDLError as e: + threw = True + lines = str(e).split('\n') + print lines + + harness.check(len(lines), 3, 'Expected number of lines in error message') + harness.ok(lines[0].endswith('line 6:10'), 'First line of error should end with "line 6:10", but was "%s".' % lines[0]) + harness.check(lines[1], 'interface ?', 'Second line of error message is the line which caused the error.') + harness.check(lines[2], ' ' * (len('interface ?') - 1) + '^', + 'Correct column pointer in error message.') + + harness.ok(threw, "Should have thrown.") + From 26d46956df226f51d9fc799e602730c675ce3738 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 4 Jun 2012 19:51:57 -0700 Subject: [PATCH 51/53] Watch for script JIT handle invalidation after MakeJITScript, bug 759719. r=dvander --- js/src/methodjit/Compiler.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 7d7e2a045f34..d3e299deb55c 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -944,15 +944,20 @@ mjit::CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc, jit = MakeJITScript(cx, script); if (!jit) return Compile_Error; + + // Script analysis can trigger GC, watch in case needsBarrier() changed. + if (gcNumber != cx->runtime->gcNumber) { + FreeOp *fop = cx->runtime->defaultFreeOp(); + jit->destroy(fop); + fop->free_(jit); + goto restart; + } + jith->setValid(jit); } else { jit = jith->getValid(); } - // Script analysis can trigger GC, watch in case needsBarrier() changed. - if (gcNumber != cx->runtime->gcNumber) - goto restart; - unsigned chunkIndex = jit->chunkIndex(pc); ChunkDescriptor &desc = jit->chunkDescriptor(chunkIndex); From a4975e4ccc1c32f49792795e9031829c7cbf70ff Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Jun 2012 23:08:10 -0700 Subject: [PATCH 52/53] Bug 761504 - Remove FunctionBoxQueue. r=luke. --HG-- extra : rebase_source : a29c928103bac3a22897ace27b7b47a1350adf4d --- js/src/frontend/ParseNode.h | 38 ------------------------------------- js/src/frontend/Parser.cpp | 1 - 2 files changed, 39 deletions(-) diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index e48010d1f0d3..efb3e5c496c0 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -1512,7 +1512,6 @@ struct FunctionBox : public ObjectBox Bindings bindings; /* bindings for this function */ uint32_t level:JSFB_LEVEL_BITS; uint16_t ndefaults; - bool queued:1; bool inLoop:1; /* in a loop in parent function */ bool inWith:1; /* some enclosing scope is a with-statement or E4X filter-expression */ @@ -1537,43 +1536,6 @@ struct FunctionBox : public ObjectBox bool inAnyDynamicScope() const; }; -struct FunctionBoxQueue { - FunctionBox **vector; - size_t head, tail; - size_t lengthMask; - - size_t count() { return head - tail; } - size_t length() { return lengthMask + 1; } - - FunctionBoxQueue() - : vector(NULL), head(0), tail(0), lengthMask(0) { } - - bool init(uint32_t count) { - lengthMask = JS_BITMASK(JS_CEILING_LOG2W(count)); - vector = (FunctionBox **) OffTheBooks::malloc_(sizeof(FunctionBox) * length()); - return !!vector; - } - - ~FunctionBoxQueue() { UnwantedForeground::free_(vector); } - - void push(FunctionBox *funbox) { - if (!funbox->queued) { - JS_ASSERT(count() < length()); - vector[head++ & lengthMask] = funbox; - funbox->queued = true; - } - } - - FunctionBox *pull() { - if (tail == head) - return NULL; - JS_ASSERT(tail < head); - FunctionBox *funbox = vector[tail++ & lengthMask]; - funbox->queued = false; - return funbox; - } -}; - } /* namespace js */ #endif /* ParseNode_h__ */ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 31d132758ec9..21b5f99886b8 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -179,7 +179,6 @@ FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, bindings(tc->sc->context), level(tc->sc->staticLevel), ndefaults(0), - queued(false), inLoop(false), inWith(!!tc->innermostWith), inGenexpLambda(false), From 7d616322e4cd7fedc72e1453f713f5cd1171ecc6 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 5 Jun 2012 00:36:25 -0700 Subject: [PATCH 53/53] Support chained assignments in definite property analysis, bug 759978. r=bhackett --- js/src/jsinfer.cpp | 99 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 22 deletions(-) diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index adef366cf3e0..17d4dabdf784 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -4264,6 +4264,11 @@ public: } }; +static bool +AnalyzePoppedThis(JSContext *cx, Vector *pendingPoppedThis, + TypeObject *type, JSFunction *fun, JSObject **pbaseobj, + Vector *initializerList); + static bool AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSObject **pbaseobj, Vector *initializerList) @@ -4302,14 +4307,23 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO /* * Offset of the last bytecode which popped 'this' and which we have - * processed. For simplicity, we scan for places where 'this' is pushed - * and immediately analyze the place where that pushed value is popped. - * This runs the risk of doing things out of order, if the script looks - * something like 'this.f = (this.g = ...)', so we watch and bail out if - * a 'this' is pushed before the previous 'this' value was popped. + * processed. To support compound inline assignments to properties like + * 'this.f = (this.g = ...)' where multiple 'this' values are pushed + * and popped en masse, we keep a stack of 'this' values that have yet to + * be processed. If a 'this' is pushed before the previous 'this' value + * was popped, we defer processing it until we see a 'this' that is popped + * after the previous 'this' was popped, i.e. the end of the compound + * inline assignment, or we encounter a return from the script. + */ + Vector pendingPoppedThis(cx); + + /* + * lastThisPopped is the largest use offset of a 'this' value we've + * processed so far. */ uint32_t lastThisPopped = 0; + bool entirelyAnalyzed = true; unsigned nextOffset = 0; while (nextOffset < script->length) { unsigned offset = nextOffset; @@ -4330,16 +4344,20 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO if (op == JSOP_RETURN || op == JSOP_STOP || op == JSOP_RETRVAL) { if (offset < lastThisPopped) { *pbaseobj = NULL; - return false; + entirelyAnalyzed = false; + break; } - return code->unconditional; + + entirelyAnalyzed = code->unconditional; + break; } /* 'this' can escape through a call to eval. */ if (op == JSOP_EVAL) { if (offset < lastThisPopped) *pbaseobj = NULL; - return false; + entirelyAnalyzed = false; + break; } /* @@ -4349,30 +4367,68 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO if (op != JSOP_THIS) continue; - /* Maintain ordering property on how 'this' is used, as described above. */ - if (offset < lastThisPopped) { - *pbaseobj = NULL; - return false; - } - SSAValue thisv = SSAValue::PushedValue(offset, 0); SSAUseChain *uses = analysis->useChain(thisv); JS_ASSERT(uses); if (uses->next || !uses->popped) { /* 'this' value popped in more than one place. */ - return false; + entirelyAnalyzed = false; + break; } - lastThisPopped = uses->offset; - /* Only handle 'this' values popped in unconditional code. */ Bytecode *poppedCode = analysis->maybeCode(uses->offset); - if (!poppedCode || !poppedCode->unconditional) - return false; + if (!poppedCode || !poppedCode->unconditional) { + entirelyAnalyzed = false; + break; + } - pc = script->code + uses->offset; - op = JSOp(*pc); + /* + * If offset >= the offset at the top of the pending stack, we either + * encountered the end of a compound inline assignment or a 'this' was + * immediately popped and used. In either case, handle the use. + */ + if (!pendingPoppedThis.empty() && + offset >= pendingPoppedThis.back()->offset) { + lastThisPopped = pendingPoppedThis[0]->offset; + if (!AnalyzePoppedThis(cx, &pendingPoppedThis, type, fun, pbaseobj, + initializerList)) { + return false; + } + } + + if (!pendingPoppedThis.append(uses)) { + entirelyAnalyzed = false; + break; + } + } + + /* Handle any remaining 'this' uses on the stack. */ + if (!pendingPoppedThis.empty() && + !AnalyzePoppedThis(cx, &pendingPoppedThis, type, fun, pbaseobj, + initializerList)) { + return false; + } + + /* Will have hit a STOP or similar, unless the script always throws. */ + return entirelyAnalyzed; +} + +static bool +AnalyzePoppedThis(JSContext *cx, Vector *pendingPoppedThis, + TypeObject *type, JSFunction *fun, JSObject **pbaseobj, + Vector *initializerList) +{ + JSScript *script = fun->script(); + ScriptAnalysis *analysis = script->analysis(); + + while (!pendingPoppedThis->empty()) { + SSAUseChain *uses = pendingPoppedThis->back(); + pendingPoppedThis->popBack(); + + jsbytecode *pc = script->code + uses->offset; + JSOp op = JSOp(*pc); RootedObject obj(cx, *pbaseobj); @@ -4514,7 +4570,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO } } - /* Will have hit a STOP or similar, unless the script always throws. */ return true; }