From 5504409f46bf0fd549125fbfa63c2d676efc56ae Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Mon, 16 Jun 2014 14:43:04 -0400 Subject: [PATCH 01/64] Bug 994117, add method to check if an element has current animations, r=bbirtles --- layout/base/nsLayoutUtils.cpp | 15 +++++++++++++++ layout/base/nsLayoutUtils.h | 9 +++++++++ layout/style/AnimationCommon.cpp | 28 ++++++++++++++++++++++++++++ layout/style/AnimationCommon.h | 5 +++++ 4 files changed, 57 insertions(+) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 6ed48f7637ca..e45f8307717a 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -330,6 +330,21 @@ nsLayoutUtils::HasAnimations(nsIContent* aContent, (aContent, nsGkAtoms::transitionsProperty, aProperty); } +bool +nsLayoutUtils::HasCurrentAnimations(nsIContent* aContent, + nsIAtom* aAnimationProperty, + nsPresContext* aPresContext) +{ + if (!aContent->MayHaveAnimations()) + return false; + + TimeStamp now = aPresContext->RefreshDriver()->MostRecentRefresh(); + + CommonElementAnimationData* animations = + static_cast(aContent->GetProperty(aAnimationProperty)); + return (animations && animations->HasCurrentAnimationsAt(now)); +} + static gfxSize GetScaleForValue(const nsStyleAnimation::Value& aValue, nsIFrame* aFrame) diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 1ab73a93416c..b38802a980ed 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1877,6 +1877,15 @@ public: */ static bool HasAnimations(nsIContent* aContent, nsCSSProperty aProperty); + /** + * Returns true if the content node has any current animations or transitions. + * A current animation is any animation that has not yet finished playing + * including paused animations. + */ + static bool HasCurrentAnimations(nsIContent* aContent, + nsIAtom* aAnimationProperty, + nsPresContext* aPresContext); + /** * Checks if off-main-thread animations are enabled. */ diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp index bbf5a39d54d9..b74a6d423d0d 100644 --- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -381,6 +381,22 @@ ElementAnimation::IsRunningAt(TimeStamp aTime) const iterationsElapsed < mTiming.mIterationCount; } +bool +ElementAnimation::IsCurrentAt(TimeStamp aTime) const +{ + if (!mStartTime.IsNull()) { + TimeDuration elapsedDuration = ElapsedDurationAt(aTime); + ComputedTiming computedTiming = + ElementAnimation::GetComputedTimingAt(elapsedDuration, mTiming); + if (computedTiming.mPhase == ComputedTiming::AnimationPhase_Before || + computedTiming.mPhase == ComputedTiming::AnimationPhase_Active) { + return true; + } + } + + return false; +} + bool ElementAnimation::HasAnimationOfProperty(nsCSSProperty aProperty) const { @@ -675,5 +691,17 @@ CommonElementAnimationData::UpdateAnimationGeneration(nsPresContext* aPresContex aPresContext->RestyleManager()->GetAnimationGeneration(); } +bool +CommonElementAnimationData::HasCurrentAnimationsAt(TimeStamp aTime) +{ + for (uint32_t animIdx = mAnimations.Length(); animIdx-- != 0; ) { + if (mAnimations[animIdx]->IsCurrentAt(aTime)) { + return true; + } + } + + return false; +} + } } diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index 8adb4e9b8da5..adf49e6b7403 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -303,6 +303,7 @@ struct ElementAnimation bool HasAnimationOfProperty(nsCSSProperty aProperty) const; bool IsRunningAt(mozilla::TimeStamp aTime) const; + bool IsCurrentAt(mozilla::TimeStamp aTime) const; // Return the duration, at aTime (or, if paused, mPauseStart), since // the *end* of the delay period. May be negative. @@ -459,6 +460,10 @@ struct CommonElementAnimationData : public PRCList // Update mAnimationGeneration to nsCSSFrameConstructor's count void UpdateAnimationGeneration(nsPresContext* aPresContext); + // Returns true if there is an animation in the before or active phase at + // the given time. + bool HasCurrentAnimationsAt(mozilla::TimeStamp aTime); + // The refresh time associated with mStyleRule. TimeStamp mStyleRuleRefreshTime; From 3884a72e08bcc9e22508503fb9e74c9c17444fbc Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Mon, 16 Jun 2014 14:43:07 -0400 Subject: [PATCH 02/64] Bug 994117, delay popupshown event until after the opening transition has finished, if one exists, which also fixes the issue causing bug 989991, so enable the animation on the main panel, r=neil --- .../customizableui/content/panelUI.inc.xul | 1 - layout/xul/nsMenuPopupFrame.cpp | 63 ++++++++++++++----- layout/xul/nsMenuPopupFrame.h | 38 +++++++++++ .../content/tests/chrome/test_arrowpanel.xul | 7 +++ 4 files changed, 92 insertions(+), 17 deletions(-) diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul index 1d1740ee5ee7..38e446355087 100644 --- a/browser/components/customizableui/content/panelUI.inc.xul +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -7,7 +7,6 @@ type="arrow" hidden="true" flip="slide" - animate="false" position="bottomcenter topright" noautofocus="true"> diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp index 790e8c30077c..2723941efa52 100644 --- a/layout/xul/nsMenuPopupFrame.cpp +++ b/layout/xul/nsMenuPopupFrame.cpp @@ -44,6 +44,7 @@ #include "nsIScreenManager.h" #include "nsIServiceManager.h" #include "nsThemeConstants.h" +#include "nsTransitionManager.h" #include "nsDisplayList.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventStateManager.h" @@ -330,26 +331,37 @@ nsMenuPopupFrame::GetShadowStyle() return NS_STYLE_WINDOW_SHADOW_DEFAULT; } -// this class is used for dispatching popupshown events asynchronously. -class nsXULPopupShownEvent : public nsRunnable +NS_IMETHODIMP nsXULPopupShownEvent::Run() { -public: - nsXULPopupShownEvent(nsIContent *aPopup, nsPresContext* aPresContext) - : mPopup(aPopup), mPresContext(aPresContext) - { + WidgetMouseEvent event(true, NS_XUL_POPUP_SHOWN, nullptr, + WidgetMouseEvent::eReal); + return EventDispatcher::Dispatch(mPopup, mPresContext, &event); +} + +NS_IMETHODIMP nsXULPopupShownEvent::HandleEvent(nsIDOMEvent* aEvent) +{ + nsMenuPopupFrame* popup = do_QueryFrame(mPopup->GetPrimaryFrame()); + if (popup) { + // ResetPopupShownDispatcher will delete the reference to this, so keep + // another one until Run is finished. + nsRefPtr event = this; + // Only call Run if it the dispatcher was assigned. This avoids calling the + // Run method if the transitionend event fires multiple times. + if (popup->ClearPopupShownDispatcher()) { + return Run(); + } } - NS_IMETHOD Run() MOZ_OVERRIDE - { - WidgetMouseEvent event(true, NS_XUL_POPUP_SHOWN, nullptr, - WidgetMouseEvent::eReal); - return EventDispatcher::Dispatch(mPopup, mPresContext, &event); - } + CancelListener(); + return NS_OK; +} -private: - nsCOMPtr mPopup; - nsRefPtr mPresContext; -}; +void nsXULPopupShownEvent::CancelListener() +{ + mPopup->RemoveSystemEventListener(NS_LITERAL_STRING("transitionend"), this, false); +} + +NS_IMPL_ISUPPORTS_INHERITED(nsXULPopupShownEvent, nsRunnable, nsIDOMEventListener); void nsMenuPopupFrame::SetInitialChildList(ChildListID aListID, @@ -482,6 +494,21 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu, // finally, if the popup just opened, send a popupshown event if (mIsOpenChanged) { mIsOpenChanged = false; + +#ifndef MOZ_WIDGET_GTK + // If the animate attribute is set to open, check for a transition and wait + // for it to finish before firing the popupshown event. + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::animate, + nsGkAtoms::open, eCaseMatters) && + nsLayoutUtils::HasCurrentAnimations(mContent, nsGkAtoms::transitionsProperty, pc)) { + mPopupShownDispatcher = new nsXULPopupShownEvent(mContent, pc); + mContent->AddSystemEventListener(NS_LITERAL_STRING("transitionend"), + mPopupShownDispatcher, false, false); + return; + } +#endif + + // If there are no transitions, fire the popupshown event right away. nsCOMPtr event = new nsXULPopupShownEvent(GetContent(), pc); NS_DispatchToCurrentThread(event); } @@ -779,6 +806,8 @@ nsMenuPopupFrame::HidePopup(bool aDeselectMenu, nsPopupState aNewState) NS_ASSERTION(aNewState == ePopupClosed || aNewState == ePopupInvisible, "popup being set to unexpected state"); + ClearPopupShownDispatcher(); + // don't hide the popup when it isn't open if (mPopupState == ePopupClosed || mPopupState == ePopupShowing) return; @@ -1887,6 +1916,8 @@ nsMenuPopupFrame::DestroyFrom(nsIFrame* aDestructRoot) new nsUnsetAttrRunnable(menu->GetContent(), nsGkAtoms::open)); } + ClearPopupShownDispatcher(); + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) pm->PopupDestroyed(this); diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h index 0dbbd14c660f..865ce2bc8333 100644 --- a/layout/xul/nsMenuPopupFrame.h +++ b/layout/xul/nsMenuPopupFrame.h @@ -118,6 +118,28 @@ class nsViewManager; class nsView; class nsMenuPopupFrame; +// this class is used for dispatching popupshown events asynchronously. +class nsXULPopupShownEvent : public nsRunnable, public nsIDOMEventListener +{ +public: + nsXULPopupShownEvent(nsIContent *aPopup, nsPresContext* aPresContext) + : mPopup(aPopup), mPresContext(aPresContext) + { + } + + virtual ~nsXULPopupShownEvent() { } + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIRUNNABLE + NS_DECL_NSIDOMEVENTLISTENER + + void CancelListener(); + +private: + nsCOMPtr mPopup; + nsRefPtr mPresContext; +}; + class nsMenuPopupFrame : public nsBoxFrame, public nsMenuParent { public: @@ -345,6 +367,20 @@ public: // Return the offset applied to the alignment of the popup nscoord GetAlignmentOffset() const { return mAlignmentOffset; } + + // Clear the mPopupShownDispatcher, remove the listener and return true if + // mPopupShownDispatcher was non-null. + bool ClearPopupShownDispatcher() + { + if (mPopupShownDispatcher) { + mPopupShownDispatcher->CancelListener(); + mPopupShownDispatcher = nullptr; + return true; + } + + return false; + } + protected: // returns the popup's level. @@ -434,6 +470,8 @@ protected: nsMenuFrame* mCurrentMenu; // The current menu that is active. + nsRefPtr mPopupShownDispatcher; + // A popup's preferred size may be different than its actual size stored in // mRect in the case where the popup was resized because it was too large // for the screen. The preferred size mPrefSize holds the full size the popup diff --git a/toolkit/content/tests/chrome/test_arrowpanel.xul b/toolkit/content/tests/chrome/test_arrowpanel.xul index 6f5d5a06b3c7..e0a809d0e88e 100644 --- a/toolkit/content/tests/chrome/test_arrowpanel.xul +++ b/toolkit/content/tests/chrome/test_arrowpanel.xul @@ -34,6 +34,7 @@ @@ -46,6 +47,7 @@ SimpleTest.waitForExplicitFinish(); var expectedAnchor = null; var expectedSide = "", expectedAnchorEdge = "", expectedPack = "", expectedAlignment = ""; var zoomFactor = 1; +var animatedPopupShown = false; var animatedPopupHidden = false; var runNextTest; @@ -184,8 +186,12 @@ function nextTest() transitions++; // Two properties transition so continue on the second one finishing. if (!(transitions % 2)) { + ok(animatedPopupShown, "popupshown now fired") SimpleTest.executeSoon(() => runNextTest.next()); } + else { + ok(!animatedPopupShown, "popupshown not fired yet") + } } // Check that the transition occurs for an arrow panel with animate="true" @@ -193,6 +199,7 @@ function nextTest() $("animatepanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start"); yield; window.removeEventListener("transitionend", transitionEnded, false); + synthesizeKey("VK_ESCAPE", { }); ok(!animatedPopupHidden, "animated popup not hidden yet"); yield; From 139c38b2dfe02c78cb3cf0e72b4010182c9e1580 Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Mon, 16 Jun 2014 14:43:10 -0400 Subject: [PATCH 03/64] Bug 994117, disable transition for popups in social tests, r=mixedpuppy --- browser/base/content/test/social/browser_social_status.js | 7 ++++++- browser/base/content/test/social/head.js | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/browser/base/content/test/social/browser_social_status.js b/browser/base/content/test/social/browser_social_status.js index 3e59e2dc0d55..7eaf99d36d45 100644 --- a/browser/base/content/test/social/browser_social_status.js +++ b/browser/base/content/test/social/browser_social_status.js @@ -112,6 +112,11 @@ var tests = { iconURL: "chrome://browser/skin/Info.png", counter: 1 }; + + // Disable the transition + let panel = document.getElementById("social-notification-panel"); + panel.setAttribute("animate", "false"); + // click on panel to open and wait for visibility let provider = Social._getProviderFromOrigin(manifest2.origin); let id = SocialStatus._toolbarHelper.idFromOrigin(manifest2.origin); @@ -131,8 +136,8 @@ var tests = { case "got-social-panel-visibility": ok(true, "got the panel message " + e.data.result); if (e.data.result == "shown") { - let panel = document.getElementById("social-notification-panel"); panel.hidePopup(); + panel.removeAttribute("animate"); } else { port.postMessage({topic: "test-ambient-notification", data: icon}); port.close(); diff --git a/browser/base/content/test/social/head.js b/browser/base/content/test/social/head.js index 53cc7e25c419..61a1105abc7f 100644 --- a/browser/base/content/test/social/head.js +++ b/browser/base/content/test/social/head.js @@ -63,11 +63,14 @@ function checkProviderPrefsEmpty(isError) { } function defaultFinishChecks() { + PopupNotifications.transitionsEnabled = true; checkProviderPrefsEmpty(true); finish(); } function runSocialTestWithProvider(manifest, callback, finishcallback) { + PopupNotifications.transitionsEnabled = false; + let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; let manifests = Array.isArray(manifest) ? manifest : [manifest]; @@ -158,6 +161,8 @@ function runSocialTests(tests, cbPreTest, cbPostTest, cbFinish) { let providersAtStart = Social.providers.length; info("runSocialTests: start test run with " + providersAtStart + " providers"); + PopupNotifications.transitionsEnabled = false; + if (cbPreTest === undefined) { cbPreTest = function(cb) {cb()}; } From 93d68b29e050b5937c7607d04cf463ccbf79f980 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Mon, 16 Jun 2014 14:51:22 -0400 Subject: [PATCH 04/64] Bug 989583 - Install all tests (even disabled) from manifests. r=jmaher --- dom/browser-element/mochitest/mochitest.ini | 4 --- python/mozbuild/mozbuild/frontend/emitter.py | 2 +- .../mochitest.ini | 3 -- .../test-manifest-inactive-ignored/moz.build | 4 --- .../test_active.html | 0 .../foo.txt | 1 - .../moz.build | 4 --- .../support-disabled-tests.ini | 5 ---- .../test_blah.html | 1 - .../mozbuild/test/frontend/test_emitter.py | 28 ------------------- testing/mochitest/runtests.py | 16 +++++++---- testing/mochitest/runtestsb2g.py | 19 ++++++++----- 12 files changed, 24 insertions(+), 63 deletions(-) delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/mochitest.ini delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/moz.build delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_active.html delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/foo.txt delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/moz.build delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/support-disabled-tests.ini delete mode 100644 python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/test_blah.html diff --git a/dom/browser-element/mochitest/mochitest.ini b/dom/browser-element/mochitest/mochitest.ini index 92d44aa41fe5..0e5e97f13d65 100644 --- a/dom/browser-element/mochitest/mochitest.ini +++ b/dom/browser-element/mochitest/mochitest.ini @@ -196,7 +196,3 @@ disabled = bug 774100 # Disabled due to focus issues (no bug that I'm aware of) [test_browserElement_oop_KeyEvents.html] disabled = -# Disable due to certificate issue (no bug that I'm aware of) -[test_browserElement_inproc_ErrorSecurity.html] -skip-if = buildapp=='b2g' -disabled = diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index adee6ce1f29c..0dad810d7344 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -481,7 +481,7 @@ class TreeMetadataEmitter(LoggingMixin): if filter_inactive: # We return tests that don't exist because we want manifests # defining tests that don't exist to result in error. - filtered = m.active_tests(exists=False, disabled=False, + filtered = m.active_tests(exists=False, disabled=True, **self.info) missing = [t['name'] for t in filtered if not os.path.exists(t['path'])] diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/mochitest.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/mochitest.ini deleted file mode 100644 index 86f59f5c157a..000000000000 --- a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/mochitest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[test_active.html] -[test_inactive.html] -skip-if = true diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/moz.build deleted file mode 100644 index 4e7e9ff4ebbd..000000000000 --- a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/moz.build +++ /dev/null @@ -1,4 +0,0 @@ -# Any copyright is dedicated to the Public Domain. -# http://creativecommons.org/publicdomain/zero/1.0/ - -MOCHITEST_MANIFESTS += ['mochitest.ini'] diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_active.html b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-inactive-ignored/test_active.html deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/foo.txt b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/foo.txt deleted file mode 100644 index ce013625030b..000000000000 --- a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/foo.txt +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/moz.build b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/moz.build deleted file mode 100644 index ae4da55e8754..000000000000 --- a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/moz.build +++ /dev/null @@ -1,4 +0,0 @@ -# Any copyright is dedicated to the Public Domain. -# http://creativecommons.org/publicdomain/zero/1.0/ - -MOCHITEST_MANIFESTS += ['support-disabled-tests.ini'] diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/support-disabled-tests.ini b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/support-disabled-tests.ini deleted file mode 100644 index 0943617b2f0e..000000000000 --- a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/support-disabled-tests.ini +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -support-files = foo.txt - -[test_blah.html] -disabled = diff --git a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/test_blah.html b/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/test_blah.html deleted file mode 100644 index 18ecdcb795c3..000000000000 --- a/python/mozbuild/mozbuild/test/frontend/data/test-manifest-support-disabled-tests/test_blah.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py index 25b69d489089..43c27ede2341 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -321,17 +321,6 @@ class TestEmitterBasic(unittest.TestCase): paths = sorted([k[len(o.directory)+1:] for k in o.installs.keys()]) self.assertEqual(paths, ["foo.txt", "just-support.ini"]) - def test_test_manifest_support_files_disabled_test(self): - """A test manifest with just disabled tests and support-files is supported.""" - reader = self.reader('test-manifest-support-disabled-tests') - - objs = self.read_topsrcdir(reader) - self.assertEqual(len(objs), 1) - o = objs[0] - self.assertEqual(len(o.installs), 2) - paths = sorted([k[len(o.directory)+1:] for k in o.installs.keys()]) - self.assertEqual(paths, ["foo.txt", "support-disabled-tests.ini"]) - def test_test_manifest_absolute_support_files(self): """Support files starting with '/' are placed relative to the install root""" reader = self.reader('test-manifest-absolute-support') @@ -478,23 +467,6 @@ class TestEmitterBasic(unittest.TestCase): 'entry in generated-files not present elsewhere'): self.read_topsrcdir(reader), - # This test is only needed until all harnesses support filtering from - # manifests. - def test_test_manifest_inactive_ignored(self): - """Inactive tests should not be installed.""" - reader = self.reader('test-manifest-inactive-ignored') - - objs = [o for o in self.read_topsrcdir(reader) - if isinstance(o, TestManifest)] - - self.assertEqual(len(objs), 1) - - o = objs[0] - - self.assertEqual(o.flavor, 'mochitest') - basenames = set(mozpath.basename(k) for k in o.installs.keys()) - self.assertEqual(basenames, {'mochitest.ini', 'test_active.html'}) - def test_test_manifest_parent_support_files_dir(self): """support-files referencing a file in a parent directory works.""" reader = self.reader('test-manifest-parent-support-files-dir') diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index fa918b9193f8..48856030305d 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -446,11 +446,17 @@ class MochitestUtilsMixin(object): testURL = "about:blank" return testURL - def buildTestPath(self, options): + def buildTestPath(self, options, disabled=True): """ Build the url path to the specific test harness and test file or directory Build a manifest of tests to run and write out a json file for the harness to read + + disabled -- This allows to add all disabled tests on the build side + and then on the run side to only run the enabled ones """ - manifest = None + # This would normally get set in runTests() but b2g mochitests + # call this function first + self.testRoot = self.getTestRoot(options) + self.testRootAbs = os.path.join(SCRIPT_DIR, self.testRoot) manifest = self.getTestManifest(options) if manifest: @@ -471,12 +477,12 @@ class MochitestUtilsMixin(object): testPath.endswith('.xul') or \ testPath.endswith('.js'): # In the case where we have a single file, we don't want to filter based on options such as subsuite. - tests = manifest.active_tests(disabled=True, options=None, **info) + tests = manifest.active_tests(disabled=disabled, options=None, **info) for test in tests: if 'disabled' in test: del test['disabled'] else: - tests = manifest.active_tests(disabled=True, options=options, **info) + tests = manifest.active_tests(disabled=disabled, options=options, **info) paths = [] for test in tests: @@ -489,7 +495,7 @@ class MochitestUtilsMixin(object): continue if not self.isTest(options, tp): - print 'Warning: %s from manifest %s is not a valid test' % (test['name'], test['manifest']) + log.warning('Warning: %s from manifest %s is not a valid test' % (test['name'], test['manifest'])) continue testob = {'path': tp} diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index db3c520cce46..53a565fef337 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -61,12 +61,19 @@ class B2GMochitest(MochitestUtilsMixin): def setup_common_options(self, options): test_url = self.buildTestPath(options) + # For B2G emulators buildURLOptions has been called + # without calling buildTestPath first and that + # causes manifestFile not to be set + if not "manifestFile=tests.json" in self.urlOpts: + self.urlOpts.append("manifestFile=%s" % options.manifestFile) + if len(self.urlOpts) > 0: test_url += "?" + "&".join(self.urlOpts) self.test_script_args.append(test_url) def buildTestPath(self, options): - # Skip over the manifest building that happens on desktop. + if options.manifestFile != 'tests.json': + super(B2GMochitest, self).buildTestPath(options, disabled=False) return self.buildTestURL(options) def build_profile(self, options): @@ -163,13 +170,14 @@ class B2GMochitest(MochitestUtilsMixin): return status -class B2GDeviceMochitest(B2GMochitest): +class B2GDeviceMochitest(B2GMochitest, Mochitest): _dm = None def __init__(self, marionette, devicemanager, profile_data_dir, local_binary_dir, remote_test_root=None, remote_log_file=None): B2GMochitest.__init__(self, marionette, out_of_process=True, profile_data_dir=profile_data_dir) + Mochitest.__init__(self) self._dm = devicemanager self.remote_test_root = remote_test_root or self._dm.getDeviceRoot() self.remote_profile = posixpath.join(self.remote_test_root, 'profile') @@ -216,13 +224,12 @@ class B2GDeviceMochitest(B2GMochitest): self.local_log = options.logFile options.logFile = self.remote_log options.profilePath = self.profile.profile - retVal = super(B2GDeviceMochitest, self).buildURLOptions(options, env) + super(B2GDeviceMochitest, self).buildURLOptions(options, env) self.setup_common_options(options) options.profilePath = self.remote_profile options.logFile = self.local_log - return retVal class B2GDesktopMochitest(B2GMochitest, Mochitest): @@ -255,7 +262,7 @@ class B2GDesktopMochitest(B2GMochitest, Mochitest): thread.start() def buildURLOptions(self, options, env): - retVal = super(B2GDesktopMochitest, self).buildURLOptions(options, env) + super(B2GDesktopMochitest, self).buildURLOptions(options, env) self.setup_common_options(options) @@ -269,8 +276,6 @@ class B2GDesktopMochitest(B2GMochitest, Mochitest): shutil.copytree(os.path.join(extensionDir, filename), os.path.join(bundlesDir, filename)) - return retVal - def buildProfile(self, options): return self.build_profile(options) From d3279fdd5d1a1c7cf0b34dab260a79e38444a83b Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 13 Jun 2014 14:16:13 -0400 Subject: [PATCH 05/64] Bug 1025139 - use the correct symbol for CERT_AddTempCertToPerm in WifiCertService.cpp; r=bz --- dom/wifi/WifiCertService.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dom/wifi/WifiCertService.cpp b/dom/wifi/WifiCertService.cpp index c1a23d963ccc..685f2d105d9f 100644 --- a/dom/wifi/WifiCertService.cpp +++ b/dom/wifi/WifiCertService.cpp @@ -3,6 +3,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// XXX: This must be done prior to including cert.h (directly or indirectly). +// CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm. +#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm + #include "WifiCertService.h" #include "mozilla/ClearOnShutdown.h" From 6103a76c7100a714b9a252a0c35af6f4771c190b Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 30 May 2014 14:12:20 -0400 Subject: [PATCH 06/64] Bug 1018375 - part 1 - add LD_VERSION_SCRIPT build variable; r=glandium --- config/config.mk | 1 + config/rules.mk | 4 ++++ python/mozbuild/mozbuild/frontend/emitter.py | 1 + python/mozbuild/mozbuild/frontend/sandbox_symbols.py | 6 ++++++ 4 files changed, 12 insertions(+) diff --git a/config/config.mk b/config/config.mk index a9fa56a95f2c..be861dc7470a 100644 --- a/config/config.mk +++ b/config/config.mk @@ -54,6 +54,7 @@ _MOZBUILD_EXTERNAL_VARIABLES := \ JAR_MANIFEST \ JAVA_JAR_TARGETS \ JS_MODULES_PATH \ + LD_VERSION_SCRIPT \ LIBRARY_NAME \ MODULE \ MSVC_ENABLE_PGO \ diff --git a/config/rules.mk b/config/rules.mk index c9cb9f2a0fe6..b7503a84122a 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -510,6 +510,10 @@ ifeq ($(OS_ARCH),Linux) ifdef IS_COMPONENT EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic endif +ifdef LD_VERSION_SCRIPT +EXTRA_DSO_LDOPTS += -Wl,--version-script,$(LD_VERSION_SCRIPT) +EXTRA_DEPS += $(LD_VERSION_SCRIPT) +endif endif # diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index 0dad810d7344..eb60dca362b7 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -249,6 +249,7 @@ class TreeMetadataEmitter(LoggingMixin): 'DEFFILE', 'SDK_LIBRARY', 'WIN32_EXE_LDFLAGS', + 'LD_VERSION_SCRIPT', ] for v in varlist: if v in sandbox and sandbox[v]: diff --git a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py index d5d794bc9583..b2e7981f7124 100644 --- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py +++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py @@ -359,6 +359,12 @@ VARIABLES = { This variable can only be used on Windows. """, None), + 'LD_VERSION_SCRIPT': (unicode, unicode, + """The linker version script for shared libraries. + + This variable can only be used on Linux. + """, None), + 'RESOURCE_FILES': (HierarchicalStringListWithFlagsFactory({'preprocess': bool}), list, """List of resources to be exported, and in which subdirectories. From a14320ae86189aad422089c47aaf322c0bd31f27 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 11 Jun 2014 14:48:37 -0400 Subject: [PATCH 07/64] Bug 1018375 - part 2a - export GCC_USE_GNU_LD from configure; r=glandium --- configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.in b/configure.in index 063133ab8d2c..1ab79d050e8c 100644 --- a/configure.in +++ b/configure.in @@ -8803,6 +8803,7 @@ AC_SUBST(CPU_ARCH) AC_SUBST(INTEL_ARCHITECTURE) AC_SUBST(HAVE_TOOLCHAIN_SUPPORT_MSSSE3) AC_SUBST(HAVE_TOOLCHAIN_SUPPORT_MSSE4_1) +AC_SUBST(GCC_USE_GNU_LD) AC_SUBST(MOZ_CHROME_FILE_FORMAT) From 9d9500952db31abb868bddbd8ee5da0d8cb017e8 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 30 May 2014 14:12:51 -0400 Subject: [PATCH 08/64] Bug 1018375 - part 2 - make db/sqlite3/src/ produce a version script for Linux-like OSes; r=glandium --- db/sqlite3/src/Makefile.in | 19 +++- db/sqlite3/src/moz.build | 5 + db/sqlite3/src/sqlite.def | 5 +- .../mozbuild/action/convert_def_file.py | 107 ++++++++++++++++++ 4 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 python/mozbuild/mozbuild/action/convert_def_file.py diff --git a/db/sqlite3/src/Makefile.in b/db/sqlite3/src/Makefile.in index 4b5041cd2fcd..12364e94025f 100644 --- a/db/sqlite3/src/Makefile.in +++ b/db/sqlite3/src/Makefile.in @@ -5,6 +5,8 @@ LIB_IS_C_ONLY = 1 +include $(topsrcdir)/config/config.mk + ifeq ($(OS_ARCH),WINNT) DEFFILE = $(CURDIR)/sqlite-processed.def @@ -20,10 +22,25 @@ sqlite-version.h: sqlite-version.py sqlite3.h # We have to preprocess our def file because we need different symbols in debug # builds exposed that are not built in non-debug builds. $(DEFFILE): sqlite.def - @$(call py_action,preprocessor,$(DEFINES) \ + @$(call py_action,preprocessor,$(DEFINES) $(XULPPFLAGS) \ $(srcdir)/sqlite.def -o $(DEFFILE)) export:: sqlite-version.h +else +ifndef MOZ_FOLD_LIBS +ifdef GCC_USE_GNU_LD + +GARBAGE += \ + $(LD_VERSION_SCRIPT) \ + $(NULL) + +# Convert to the format we need for ld. +$(LD_VERSION_SCRIPT): $(srcdir)/sqlite.def + @$(call py_action,convert_def_file, \ + $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ $^) + +endif +endif endif ifeq (Darwin,$(OS_TARGET)) diff --git a/db/sqlite3/src/moz.build b/db/sqlite3/src/moz.build index f899190436ea..14c79b48f067 100644 --- a/db/sqlite3/src/moz.build +++ b/db/sqlite3/src/moz.build @@ -74,6 +74,11 @@ if CONFIG['OS_ARCH'] == 'WINNT': RCFILE = 'sqlite.rc' RESFILE = 'sqlite.res' +if CONFIG['OS_ARCH'] == 'Linux' and \ + not CONFIG['MOZ_FOLD_LIBS'] and \ + CONFIG['GCC_USE_GNU_LD']: + LD_VERSION_SCRIPT = 'sqlite-processed.def' + # Suppress warnings in third-party code. if CONFIG['GNU_CC']: CFLAGS += [ diff --git a/db/sqlite3/src/sqlite.def b/db/sqlite3/src/sqlite.def index 5eeb52257ae1..c9f741a5796f 100644 --- a/db/sqlite3/src/sqlite.def +++ b/db/sqlite3/src/sqlite.def @@ -126,6 +126,9 @@ EXPORTS sqlite3_step sqlite3_stmt_readonly sqlite3_stmt_status +#ifdef XP_UNIX + sqlite3_temp_directory +#endif sqlite3_thread_cleanup sqlite3_total_changes sqlite3_trace @@ -151,7 +154,7 @@ EXPORTS sqlite3_vfs_unregister sqlite3_vfs_register sqlite3_vmprintf -#ifdef SQLITE_DEBUG +#ifdef DEBUG sqlite3_mutex_held sqlite3_mutex_notheld #endif diff --git a/python/mozbuild/mozbuild/action/convert_def_file.py b/python/mozbuild/mozbuild/action/convert_def_file.py new file mode 100644 index 000000000000..e0a87a6f10b2 --- /dev/null +++ b/python/mozbuild/mozbuild/action/convert_def_file.py @@ -0,0 +1,107 @@ +# 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/. + +# Convert Windows-style export files into a single Unix-style linker +# script, applying any necessary preprocessing. + +import itertools +import re +import sys +from StringIO import StringIO + +from mozbuild.preprocessor import Preprocessor +from mozbuild.util import FileAvoidWrite + +def preprocess_file(pp, deffile): + output = StringIO() + with open(deffile, 'r') as input: + pp.processFile(input=input, output=output) + return output.getvalue().splitlines() + +# NSS .def files serve multiple masters, as this copied comment indicates: +# +# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS +# 1. For all unix platforms, the string ";-" means "remove this line" +# 2. For all unix platforms, the string " DATA " will be removed from any +# line on which it occurs. +# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +# On AIX, lines containing ";+" will be removed. +# 4. For all unix platforms, the string ";;" will have the ";;" removed. +# 5. For all unix platforms, after the above processing has taken place, +# all characters after the first ";" on the line will be removed. +# And for AIX, the first ";" will also be removed. +# This file is passed directly to windows. Since ';' is a comment, all UNIX +# directives are hidden behind ";", ";+", and ";-" +# +# We don't care about rule 1, as that mainly serves to eliminate LIBRARY +# and EXPORTS lines. We don't want to enforce rule 3, as we know how to +# eliminate comments. ';+' also tends to hide Unix linker-script specific +# things, which we don't want to deal with here. Rule 5 is also unnecessary; +# later comment-aware processing will deal with that. +# +# We do need to handle rule 2, since our symbol extraction doesn't want to +# see DATA keywords. We also need to handle rule 4, since ';;' often hides +# things marked with DATA. +def nss_preprocess_file(deffile): + with open(deffile, 'r') as input: + for line in input: + # Rule 2, and then rule 4. + yield line.replace(' DATA ', '').replace(';;', '') + +COMMENT = re.compile(';.*') + +def extract_symbols(lines): + # Filter comments. + nocomments = iter(COMMENT.sub('', s).strip() for s in lines) + lines = iter(s for s in nocomments if len(s)) + + exports = itertools.dropwhile(lambda s: 'EXPORTS' not in s, lines) + symbols = set() + for line in exports: + if 'EXPORTS' in line: + # Handle the case where symbols are specified along with EXPORT. + fields = line.split()[1:] + if len(fields) == 0: + continue + else: + fields = line.split() + + # We don't support aliases or keywords (ordinals, PRIVATE, etc.) for + # symbols. But since aliases can also be specified as 'SYM=ALIAS' + # with no whitespace, we need extra checks on the original symbol. + if len(fields) != 1 or '=' in fields[0]: + raise 'aliases and keywords are not supported' + + symbols.add(fields[0]) + + return symbols + +def main(args): + pp = Preprocessor() + optparser = pp.getCommandLineParser() + optparser.add_option('--nss-file', action='append', + type='string', dest='nss_files', default=[], + help='Specify a .def file that should have NSS\'s processing rules applied to it') + options, deffiles = optparser.parse_args(args) + + symbols = set() + for f in options.nss_files: + symbols |= extract_symbols(nss_preprocess_file(f)) + for f in deffiles: + # Start each deffile off with a clean slate. + defpp = pp.clone() + symbols |= extract_symbols(preprocess_file(defpp, f)) + + script = """{ +global: + %s +local: + *; +}; +""" + with FileAvoidWrite(options.output) as f: + f.write(script % '\n '.join("%s;" % s for s in sorted(symbols))) + +if __name__ == '__main__': + main(sys.argv[1:]) From f2878a277f03869b473e815078cb43a6dbe535a0 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Jun 2014 14:23:06 -0400 Subject: [PATCH 09/64] Bug 1018375 - part 3 - use a static list of NSS def files for MOZ_FOLD_LIBS groveling; r=glandium --- security/build/Makefile.in | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/security/build/Makefile.in b/security/build/Makefile.in index 3109cfa5636d..4be03a8c991f 100644 --- a/security/build/Makefile.in +++ b/security/build/Makefile.in @@ -333,12 +333,22 @@ EXTRA_DSO_LDOPTS += $(DEPTH)/db/sqlite3/src/$(LIB_PREFIX)mozsqlite3.$(LIB_SUFFIX # Add all static libraries for nss, smime, ssl and nssutil SHARED_LIBRARY_LIBS = $(addprefix ../,$(NSS_STATIC_LIBS)) +nss_def_files := $(addprefix $(srcdir)/../, \ + nss/lib/util/nssutil.def \ + nss/lib/nss/nss.def \ + nss/lib/ssl/ssl.def \ + nss/lib/smime/smime.def \ +) + +# Try to guard against NSS renaming things out from underneath us. +ifneq ($(nss_def_files),$(wildcard $(nss_def_files))) +$(error Need to update list of NSS def files) +endif + ifeq (WINNT,$(OS_TARGET)) # Create a .def file based on the various .def files for nss, smime, ssl and # nssutil. -NSS_STATIC_LIBS_DEFS := $(wildcard $(addprefix $(srcdir)/../,$(NSS_STATIC_LIBS:.$(LIB_SUFFIX)=.def))) - -nss3.def: $(NSS_STATIC_LIBS_DEFS) $(DEPTH)/db/sqlite3/src/sqlite-processed.def +nss3.def: $(nss_def_files) $(DEPTH)/db/sqlite3/src/sqlite-processed.def echo LIBRARY nss3$(DLL_SUFFIX) > $@.tmp echo EXPORTS >> $@.tmp grep -v -h -e ^LIBRARY -e ^EXPORTS -e ^\; $^ >> $@.tmp From 6020c3fe5e590c2608567aa21d713f3d454523ee Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 30 May 2014 14:34:54 -0400 Subject: [PATCH 10/64] Bug 1018375 - part 4 - use a linker script for libnss3 on Linux-like OSes; r=glandium --- security/build/Makefile.in | 17 ++++++++++++++++- security/build/moz.build | 5 +++++ security/build/nspr-dummy.def | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 security/build/nspr-dummy.def diff --git a/security/build/Makefile.in b/security/build/Makefile.in index 4be03a8c991f..a764de160c60 100644 --- a/security/build/Makefile.in +++ b/security/build/Makefile.in @@ -353,7 +353,22 @@ nss3.def: $(nss_def_files) $(DEPTH)/db/sqlite3/src/sqlite-processed.def echo EXPORTS >> $@.tmp grep -v -h -e ^LIBRARY -e ^EXPORTS -e ^\; $^ >> $@.tmp mv $@.tmp $@ -endif +else +ifdef GCC_USE_GNU_LD +sqlite_def_file := $(topsrcdir)/db/sqlite3/src/sqlite.def +nspr_def_file := $(srcdir)/nspr-dummy.def + +nss3.def: $(nss_def_files) $(sqlite_def_file) $(nspr_def_file) + @$(call py_action,convert_def_file, \ + $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ \ + $(addprefix --nss-file=,$(nss_def_files)) \ + $(sqlite_def_file) $(nspr_def_file)) + +GARBAGE += \ + nss3.def \ + $(NULL) +endif # GCC_USE_GNU_LD +endif # WINNT ifneq (,$(filter WINNT,$(OS_ARCH))) SDK_LIBRARY = $(IMPORT_LIBRARY) diff --git a/security/build/moz.build b/security/build/moz.build index 99fe8d6de1e4..da294e026242 100644 --- a/security/build/moz.build +++ b/security/build/moz.build @@ -12,3 +12,8 @@ if CONFIG['MOZ_FOLD_LIBS']: if CONFIG['OS_TARGET'] == 'WINNT': DEFFILE = 'nss3.def' + +if CONFIG['OS_ARCH'] == 'Linux' and \ + CONFIG['MOZ_FOLD_LIBS'] and \ + CONFIG['GCC_USE_GNU_LD']: + LD_VERSION_SCRIPT = 'nss3.def' diff --git a/security/build/nspr-dummy.def b/security/build/nspr-dummy.def new file mode 100644 index 000000000000..b14fcf82c84f --- /dev/null +++ b/security/build/nspr-dummy.def @@ -0,0 +1,15 @@ +; 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/. +; +; This is a fake .def file, to be used for generating linker scripts +; for our folded libnss when MOZ_FOLD_LIBS. NSPR, unlike NSS, exports +; symbols with symbol visibility (Unix) or __declspec (Windows). When +; using a linker script, however, we need to explicitly specify that +; NSPR's symbols should be globally visible. Otherwise, NSPR's exported +; symbols would match the |local: *| rule and be hidden. +LIBRARY libnsprdummy +EXPORTS +PR_* ; Actual .def files don't allow wildcards, of course. +_PR_* +PL_* From d1e6d153b79a0558c65dee0e1653831039ca5c9c Mon Sep 17 00:00:00 2001 From: Susanna Bowen Date: Mon, 16 Jun 2014 11:58:25 -0700 Subject: [PATCH 11/64] Bug 727125 - Lazily compute LineBaselineOffset when needed so it is present after a dynamic change of 'text-decoration'. r=dbaron This fixes the positioning of underlines set on a block or its ancestor when drawn on children of a block that have a vertical-align != baseline. The lazy computation is done all at once for all children of a block to avoid O(N^2) searches for the line containing a frame. --- layout/generic/nsLineLayout.cpp | 26 +++++------ layout/generic/nsTextFrame.cpp | 45 +++++++++++++++++-- ...underline-vertical-align-quirks-1-ref.html | 21 +++++++++ ...mic-underline-vertical-align-quirks-1.html | 26 +++++++++++ ...underline-vertical-align-quirks-2-ref.html | 21 +++++++++ ...mic-underline-vertical-align-quirks-2.html | 26 +++++++++++ ...erline-vertical-align-standards-1-ref.html | 22 +++++++++ ...-underline-vertical-align-standards-1.html | 27 +++++++++++ ...erline-vertical-align-standards-2-ref.html | 22 +++++++++ ...-underline-vertical-align-standards-2.html | 27 +++++++++++ layout/reftests/text-decoration/reftest.list | 4 ++ 11 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html create mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 605b164e7ada..4784b15895e9 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -731,6 +731,16 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, printf("\n"); #endif + if (mCurrentSpan == mRootSpan) { + pfd->mFrame->Properties().Remove(nsIFrame::LineBaselineOffset()); + } else { +#ifdef DEBUG + bool hasLineOffset; + pfd->mFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &hasLineOffset); + NS_ASSERTION(!hasLineOffset, "LineBaselineOffset was set but was not expected"); +#endif + } + mTextJustificationNumSpaces = 0; mTextJustificationNumLetters = 0; @@ -1452,22 +1462,6 @@ nsLineLayout::BlockDirAlignLine() } PlaceStartEndFrames(psd, -mBStartEdge, lineBSize); - // If the frame being reflowed has text decorations, we simulate the - // propagation of those decorations to a line-level element by storing the - // offset in a frame property on any child frames that are aligned in the - // block direction somewhere other than the baseline. This property is then - // used by nsTextFrame::GetTextDecorations when the same conditions are met. - if (rootPFD.mFrame->StyleContext()->HasTextDecorationLines()) { - for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) { - const nsIFrame *const f = pfd->mFrame; - if (f->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { - const nscoord offset = baselineBCoord - pfd->mBounds.BStart(lineWM); - f->Properties().Set(nsIFrame::LineBaselineOffset(), - NS_INT32_TO_PTR(offset)); - } - } - } - // Fill in returned line-box and max-element-width data mLineBox->SetBounds(lineWM, psd->mIStart, mBStartEdge, diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index b692b6cd81c0..76e3cb12fe1b 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -4620,6 +4620,40 @@ PaintSelectionBackground(gfxContext* aCtx, nsPresContext* aPresContext, } } +// Attempt to get the LineBaselineOffset property of aChildFrame +// If not set, calculate this value for all child frames of aBlockFrame +static nscoord +LazyGetLineBaselineOffset(nsIFrame* aChildFrame, nsBlockFrame* aBlockFrame) +{ + bool offsetFound; + nscoord offset = NS_PTR_TO_INT32( + aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound) + ); + + if (!offsetFound) { + for (nsBlockFrame::line_iterator line = aBlockFrame->begin_lines(), + line_end = aBlockFrame->end_lines(); + line != line_end; line++) { + if (line->IsInline()) { + int32_t n = line->GetChildCount(); + nscoord lineBaseline = line->BStart() + line->GetAscent(); + for (nsIFrame* lineFrame = line->mFirstChild; + n > 0; lineFrame = lineFrame->GetNextSibling(), --n) { + offset = lineBaseline - lineFrame->GetNormalPosition().y; + lineFrame->Properties().Set(nsIFrame::LineBaselineOffset(), + NS_INT32_TO_PTR(offset)); + } + } + } + return NS_PTR_TO_INT32( + aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound) + ); + + } else { + return offset; + } +} + void nsTextFrame::GetTextDecorations( nsPresContext* aPresContext, @@ -4663,7 +4697,8 @@ nsTextFrame::GetTextDecorations( nsLayoutUtils::GetColor(f, eCSSProperty_text_decoration_color); } - const bool firstBlock = !nearestBlockFound && nsLayoutUtils::GetAsBlock(f); + nsBlockFrame* fBlock = nsLayoutUtils::GetAsBlock(f); + const bool firstBlock = !nearestBlockFound && fBlock; // Not updating positions once we hit a parent block is equivalent to // the CSS 2.1 spec that blocks should propagate decorations down to their @@ -4674,13 +4709,15 @@ nsTextFrame::GetTextDecorations( if (firstBlock) { // At this point, fChild can't be null since TextFrames can't be blocks if (fChild->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { + // Since offset is the offset in the child's coordinate space, we have // to undo the accumulation to bring the transform out of the block's // coordinate space + const nscoord lineBaselineOffset = LazyGetLineBaselineOffset(fChild, + fBlock); + baselineOffset = - frameTopOffset - fChild->GetNormalPosition().y - - NS_PTR_TO_INT32( - fChild->Properties().Get(nsIFrame::LineBaselineOffset())); + frameTopOffset - fChild->GetNormalPosition().y - lineBaselineOffset; } } else if (!nearestBlockFound) { diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html new file mode 100644 index 000000000000..915f3a7bb8f7 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html @@ -0,0 +1,21 @@ + + + + + +

+This line has a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html new file mode 100644 index 000000000000..eccaa3eb17e3 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html @@ -0,0 +1,26 @@ + + + + + + +

+This line has a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html new file mode 100644 index 000000000000..7a1ba472fe5c --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html @@ -0,0 +1,21 @@ + + + + + +

+This line has only a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html new file mode 100644 index 000000000000..52d5c5b62e05 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html @@ -0,0 +1,26 @@ + + + + + + +

+This line has only a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html new file mode 100644 index 000000000000..01ba4d9b6c96 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html @@ -0,0 +1,22 @@ + + + + + + +

+This line has a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html new file mode 100644 index 000000000000..c285c02466b9 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html @@ -0,0 +1,27 @@ + + + + + + + +

+This line has a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html new file mode 100644 index 000000000000..fb465cce22b3 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html @@ -0,0 +1,22 @@ + + + + + + +

+This line has only a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html new file mode 100644 index 000000000000..e48816365a85 --- /dev/null +++ b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html @@ -0,0 +1,27 @@ + + + + + + + +

+This line has only a bottom vertical align span.
+This line has a top vertical align span. +

+ + diff --git a/layout/reftests/text-decoration/reftest.list b/layout/reftests/text-decoration/reftest.list index d4d5cca48db3..ca5f05db9643 100644 --- a/layout/reftests/text-decoration/reftest.list +++ b/layout/reftests/text-decoration/reftest.list @@ -4,6 +4,10 @@ skip-if(B2G) == complex-decoration-style-standards.html complex-decoration-style == decoration-color-standards.html decoration-color-standards-ref.html == decoration-style-quirks.html decoration-style-quirks-ref.html == decoration-style-standards.html decoration-style-standards-ref.html +fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-quirks-1.html dynamic-underline-vertical-align-quirks-1-ref.html +fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-1.html dynamic-underline-vertical-align-standards-1-ref.html +fails == dynamic-underline-vertical-align-quirks-2.html dynamic-underline-vertical-align-quirks-2-ref.html +fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-2.html dynamic-underline-vertical-align-standards-2-ref.html == line-through-style-block-solid-quirks.html line-through-style-block-quirks-ref.html != line-through-style-block-dotted-quirks.html line-through-style-block-quirks-ref.html != line-through-style-block-dashed-quirks.html line-through-style-block-quirks-ref.html From dc169c8b4866ce2864d99594b05ab4d2d6bf7705 Mon Sep 17 00:00:00 2001 From: Susanna Bowen Date: Mon, 16 Jun 2014 11:58:29 -0700 Subject: [PATCH 12/64] Bug 727125 - Update overflow areas for text frames on text-decoration change to ensure text-decoration on hover is visible. r=dbaron --- layout/base/RestyleManager.cpp | 26 ++++++++++- layout/base/RestyleManager.h | 3 ++ layout/base/nsChangeHint.h | 21 +++++---- layout/generic/nsTextFrame.cpp | 45 +++++++++++++++++--- layout/generic/nsTextFrame.h | 4 +- layout/reftests/text-decoration/reftest.list | 2 +- layout/style/nsStyleStruct.h | 4 +- 7 files changed, 86 insertions(+), 19 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 883186dc348b..7019d949ea81 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -513,6 +513,22 @@ RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint) return; } +void +RestyleManager::AddSubtreeToOverflowTracker(nsIFrame* aFrame) +{ + mOverflowChangedTracker.AddFrame( + aFrame, + OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED); + nsIFrame::ChildListIterator lists(aFrame); + for (; !lists.IsDone(); lists.Next()) { + nsFrameList::Enumerator childFrames(lists.CurrentList()); + for (; !childFrames.AtEnd(); childFrames.Next()) { + nsIFrame* child = childFrames.get(); + AddSubtreeToOverflowTracker(child); + } + } +} + NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nullptr) /** @@ -716,6 +732,7 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) StyleChangeReflow(frame, hint); didReflowThisFrame = true; } + if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView | nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer | nsChangeHint_ChildrenOnlyTransform)) { @@ -733,7 +750,11 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) "nsChangeHint_UpdateOverflow should be passed too"); if (!didReflowThisFrame && (hint & (nsChangeHint_UpdateOverflow | - nsChangeHint_UpdatePostTransformOverflow))) { + nsChangeHint_UpdatePostTransformOverflow | + nsChangeHint_UpdateSubtreeOverflow))) { + if (hint & nsChangeHint_UpdateSubtreeOverflow) { + AddSubtreeToOverflowTracker(frame); + } OverflowChangedTracker::ChangeKind changeKind; if (hint & nsChangeHint_ChildrenOnlyTransform) { // The overflow areas of the child frames need to be updated: @@ -769,7 +790,8 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) // If we have both nsChangeHint_UpdateOverflow and // nsChangeHint_UpdatePostTransformOverflow, CHILDREN_AND_PARENT_CHANGED // is selected as it is stronger. - if (hint & nsChangeHint_UpdateOverflow) { + if (hint & (nsChangeHint_UpdateOverflow | + nsChangeHint_UpdateSubtreeOverflow)) { changeKind = OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED; } else { changeKind = OverflowChangedTracker::TRANSFORM_CHANGED; diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index 027886fb00b1..f632e33bba90 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -245,6 +245,9 @@ private: void StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint); + // Recursively add all the given frame and all children to the tracker. + void AddSubtreeToOverflowTracker(nsIFrame* aFrame); + // Returns true if this function managed to successfully move a frame, and // false if it could not process the position change, and a reflow should // be performed instead. diff --git a/layout/base/nsChangeHint.h b/layout/base/nsChangeHint.h index 79d5632a620c..7acc5a2437c4 100644 --- a/layout/base/nsChangeHint.h +++ b/layout/base/nsChangeHint.h @@ -72,23 +72,28 @@ enum nsChangeHint { nsChangeHint_ReconstructFrame = 0x400, /** - * The frame's overflow area has changed, either through a change in its - * transform or a change in its position. Does not update any descendant + * The frame's overflow area has changed. Does not update any descendant * frames. */ nsChangeHint_UpdateOverflow = 0x800, + /** + * The overflow area of the frame and all of its descendants has changed. This + * can happen through a text-decoration change. + */ + nsChangeHint_UpdateSubtreeOverflow = 0x1000, + /** * The frame's overflow area has changed, through a change in its transform. * Does not update any descendant frames. */ - nsChangeHint_UpdatePostTransformOverflow = 0x1000, + nsChangeHint_UpdatePostTransformOverflow = 0x2000, /** * The children-only transform of an SVG frame changed, requiring the * overflow rects of the frame's immediate children to be updated. */ - nsChangeHint_ChildrenOnlyTransform = 0x2000, + nsChangeHint_ChildrenOnlyTransform = 0x4000, /** * The frame's offsets have changed, while its dimensions might have @@ -100,7 +105,7 @@ enum nsChangeHint { * nsChangeHint_UpdateOverflow in order to get the overflow areas of * the ancestors updated as well. */ - nsChangeHint_RecomputePosition = 0x4000, + nsChangeHint_RecomputePosition = 0x8000, /** * Behaves like ReconstructFrame, but only if the frame has descendants @@ -108,7 +113,7 @@ enum nsChangeHint { * has changed whether the frame is a container for fixed-pos or abs-pos * elements, but reframing is otherwise not needed. */ - nsChangeHint_AddOrRemoveTransform = 0x8000, + nsChangeHint_AddOrRemoveTransform = 0x10000, /** * This change hint has *no* change handling behavior. However, it @@ -116,13 +121,13 @@ enum nsChangeHint { * changes, and it's inherited by a child, that might require a reflow * due to the border-width change on the child. */ - nsChangeHint_BorderStyleNoneChange = 0x10000, + nsChangeHint_BorderStyleNoneChange = 0x20000, /** * SVG textPath needs to be recomputed because the path has changed. * This means that the glyph positions of the text need to be recomputed. */ - nsChangeHint_UpdateTextPath = 0x20000 + nsChangeHint_UpdateTextPath = 0x40000 // IMPORTANT NOTE: When adding new hints, consider whether you need to // add them to NS_HintsNotHandledForDescendantsIn() below. diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 76e3cb12fe1b..aab6d8ba77aa 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -4801,7 +4801,7 @@ GetInflationForTextDecorations(nsIFrame* aFrame, nscoord aInflationMinFontSize) void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, - const nsHTMLReflowState& aBlockReflowState, + nsIFrame* aBlock, PropertyProvider& aProvider, nsRect* aVisualOverflowRect, bool aIncludeTextDecorations) @@ -4814,8 +4814,8 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, if (IsFloatingFirstLetterChild()) { // The underline/overline drawable area must be contained in the overflow // rect when this is in floating first letter frame at *both* modes. - nsIFrame* firstLetterFrame = aBlockReflowState.frame; - uint8_t decorationStyle = firstLetterFrame->StyleContext()-> + // In this case, aBlock is the ::first-letter frame. + uint8_t decorationStyle = aBlock->StyleContext()-> StyleTextReset()->GetDecorationStyle(); // If the style is none, let's include decoration line rect as solid style // since changing the style from none to solid/dotted/dashed doesn't cause @@ -4859,7 +4859,7 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, GetTextDecorations(aPresContext, eResolvedColors, textDecs); if (textDecs.HasDecorationLines()) { nscoord inflationMinFontSize = - nsLayoutUtils::InflationMinFontSizeFor(aBlockReflowState.frame); + nsLayoutUtils::InflationMinFontSizeFor(aBlock); const nscoord width = GetSize().width; const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(), @@ -8044,7 +8044,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, // When we have text decorations, we don't need to compute their overflow now // because we're guaranteed to do it later // (see nsLineLayout::RelativePositionFrames) - UnionAdditionalOverflow(presContext, *aLineLayout.LineContainerRS(), + UnionAdditionalOverflow(presContext, aLineLayout.LineContainerRS()->frame, provider, &aMetrics.VisualOverflow(), false); ///////////////////////////////////////////////////////////////////// @@ -8286,7 +8286,7 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) &provider); nsRect &vis = result.VisualOverflow(); vis.UnionRect(vis, RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent)); - UnionAdditionalOverflow(PresContext(), aBlockReflowState, provider, + UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider, &vis, true); return result; } @@ -8577,3 +8577,36 @@ nsTextFrame::HasAnyNoncollapsedCharacters() int32_t skippedOffsetEnd = iter.ConvertOriginalToSkipped(offsetEnd); return skippedOffset != skippedOffsetEnd; } + +bool +nsTextFrame::UpdateOverflow() +{ + nsRect rect(nsPoint(0, 0), GetSize()); + nsOverflowAreas overflowAreas(rect, rect); + + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { + return false; + } + gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated); + if (!mTextRun) { + return false; + } + PropertyProvider provider(this, iter, nsTextFrame::eInflated); + provider.InitializeForDisplay(true); + + nsIFrame*decorationsBlock; + if (IsFloatingFirstLetterChild()) { + decorationsBlock = GetParent(); + } else { + for (nsIFrame* f = this; f; f = f->GetParent()) { + nsBlockFrame* fBlock = nsLayoutUtils::GetAsBlock(f); + if (fBlock) { + decorationsBlock = fBlock; + break; + } + } + } + UnionAdditionalOverflow(PresContext(), decorationsBlock, provider, + &overflowAreas.VisualOverflow(), true); + return FinishAndStoreOverflow(overflowAreas, GetSize()); +} diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index e7a28d1d981f..5b9575c19245 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -519,6 +519,8 @@ public: bool IsFloatingFirstLetterChild() const; + virtual bool UpdateOverflow() MOZ_OVERRIDE; + protected: virtual ~nsTextFrame(); @@ -552,7 +554,7 @@ protected: SelectionDetails* GetSelectionDetails(); void UnionAdditionalOverflow(nsPresContext* aPresContext, - const nsHTMLReflowState& aBlockReflowState, + nsIFrame* aBlock, PropertyProvider& aProvider, nsRect* aVisualOverflowRect, bool aIncludeTextDecorations); diff --git a/layout/reftests/text-decoration/reftest.list b/layout/reftests/text-decoration/reftest.list index ca5f05db9643..a737269a2d70 100644 --- a/layout/reftests/text-decoration/reftest.list +++ b/layout/reftests/text-decoration/reftest.list @@ -6,7 +6,7 @@ skip-if(B2G) == complex-decoration-style-standards.html complex-decoration-style == decoration-style-standards.html decoration-style-standards-ref.html fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-quirks-1.html dynamic-underline-vertical-align-quirks-1-ref.html fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-1.html dynamic-underline-vertical-align-standards-1-ref.html -fails == dynamic-underline-vertical-align-quirks-2.html dynamic-underline-vertical-align-quirks-2-ref.html +fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-quirks-2.html dynamic-underline-vertical-align-quirks-2-ref.html fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-2.html dynamic-underline-vertical-align-standards-2-ref.html == line-through-style-block-solid-quirks.html line-through-style-block-quirks-ref.html != line-through-style-block-dotted-quirks.html line-through-style-block-quirks-ref.html diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index f162bf7a4ca2..f4c4383d9d09 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1480,7 +1480,9 @@ struct nsStyleTextReset { nsChangeHint CalcDifference(const nsStyleTextReset& aOther) const; static nsChangeHint MaxDifference() { - return NS_STYLE_HINT_REFLOW; + return nsChangeHint( + NS_STYLE_HINT_REFLOW | + nsChangeHint_UpdateSubtreeOverflow); } static nsChangeHint MaxDifferenceNeverInherited() { // CalcDifference never returns nsChangeHint_NeedReflow or From 2cfeae1d9ed6f64fac2849da1a00c2156941840b Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 16 Jun 2014 11:59:45 -0700 Subject: [PATCH 13/64] Bug 1017650 - Re-arrange the GC API include dependency ordering; r=jonco --HG-- extra : rebase_source : bc27b7206c674ef2247169dd700b9fbf61e5bd74 --- js/public/GCAPI.h | 50 ------------------------------------------ js/public/RootingAPI.h | 42 +++++++++++++++++++++++++++++++++++ js/public/Value.h | 8 +++++++ 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 5924d79c13dd..c58d62d029b3 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -10,8 +10,6 @@ #include "mozilla/NullPtr.h" #include "js/HeapAPI.h" -#include "js/RootingAPI.h" -#include "js/Value.h" namespace js { namespace gc { @@ -432,47 +430,6 @@ class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC explicit AutoCheckCannotGC(JSRuntime *rt) : AutoAssertOnGC(rt) {} }; -class JS_PUBLIC_API(ObjectPtr) -{ - Heap value; - - public: - ObjectPtr() : value(nullptr) {} - - explicit ObjectPtr(JSObject *obj) : value(obj) {} - - /* Always call finalize before the destructor. */ - ~ObjectPtr() { MOZ_ASSERT(!value); } - - void finalize(JSRuntime *rt) { - if (IsIncrementalBarrierNeeded(rt)) - IncrementalObjectBarrier(value); - value = nullptr; - } - - void init(JSObject *obj) { value = obj; } - - JSObject *get() const { return value; } - - void writeBarrierPre(JSRuntime *rt) { - IncrementalObjectBarrier(value); - } - - bool isAboutToBeFinalized(); - - ObjectPtr &operator=(JSObject *obj) { - IncrementalObjectBarrier(value); - value = obj; - return *this; - } - - void trace(JSTracer *trc, const char *name); - - JSObject &operator*() const { return *value; } - JSObject *operator->() const { return value; } - operator JSObject *() const { return value; } -}; - /* * Unsets the gray bit for anything reachable from |thing|. |kind| should not be * JSTRACE_SHAPE. |thing| should be non-null. @@ -507,13 +464,6 @@ ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind) UnmarkGrayGCThingRecursively(thing, kind); } -static MOZ_ALWAYS_INLINE void -ExposeValueToActiveJS(const Value &v) -{ - if (v.isMarkable()) - ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind()); -} - static MOZ_ALWAYS_INLINE void ExposeObjectToActiveJS(JSObject *obj) { diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 47396394ba0f..b392848ee98a 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -15,6 +15,7 @@ #include "jspubtd.h" +#include "js/GCAPI.h" #include "js/HeapAPI.h" #include "js/TypeDecls.h" #include "js/Utility.h" @@ -1165,6 +1166,47 @@ class PersistentRooted : private mozilla::LinkedListElement T ptr; }; +class JS_PUBLIC_API(ObjectPtr) +{ + Heap value; + + public: + ObjectPtr() : value(nullptr) {} + + explicit ObjectPtr(JSObject *obj) : value(obj) {} + + /* Always call finalize before the destructor. */ + ~ObjectPtr() { MOZ_ASSERT(!value); } + + void finalize(JSRuntime *rt) { + if (IsIncrementalBarrierNeeded(rt)) + IncrementalObjectBarrier(value); + value = nullptr; + } + + void init(JSObject *obj) { value = obj; } + + JSObject *get() const { return value; } + + void writeBarrierPre(JSRuntime *rt) { + IncrementalObjectBarrier(value); + } + + bool isAboutToBeFinalized(); + + ObjectPtr &operator=(JSObject *obj) { + IncrementalObjectBarrier(value); + value = obj; + return *this; + } + + void trace(JSTracer *trc, const char *name); + + JSObject &operator*() const { return *value; } + JSObject *operator->() const { return value; } + operator JSObject *() const { return value; } +}; + } /* namespace JS */ namespace js { diff --git a/js/public/Value.h b/js/public/Value.h index 1952f7951141..7b0fa0914e07 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -19,6 +19,7 @@ #include "jstypes.h" #include "js/Anchor.h" +#include "js/GCAPI.h" #include "js/RootingAPI.h" #include "js/Utility.h" @@ -1288,6 +1289,13 @@ IsOptimizedPlaceholderMagicValue(const Value &v) return false; } +static MOZ_ALWAYS_INLINE void +ExposeValueToActiveJS(const Value &v) +{ + if (v.isMarkable()) + ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind()); +} + /************************************************************************/ static inline Value From 5590758a7541c37d52c345b707bf38e409f2de3a Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 16 Jun 2014 11:59:59 -0700 Subject: [PATCH 14/64] Bug 1017650 - Remove the unused |proto| arg from the wrapping machinery; r=efaust --- js/src/jsapi-tests/testBug604087.cpp | 2 +- js/src/jsapi.h | 3 +-- js/src/jscompartment.cpp | 3 +-- js/src/jswrapper.cpp | 4 +--- js/src/jswrapper.h | 3 +-- js/xpconnect/wrappers/WrapperFactory.cpp | 3 +-- js/xpconnect/wrappers/WrapperFactory.h | 1 - 7 files changed, 6 insertions(+), 13 deletions(-) diff --git a/js/src/jsapi-tests/testBug604087.cpp b/js/src/jsapi-tests/testBug604087.cpp index 3d08729e60e5..4e7a9fcc762c 100644 --- a/js/src/jsapi-tests/testBug604087.cpp +++ b/js/src/jsapi-tests/testBug604087.cpp @@ -47,7 +47,7 @@ PreWrap(JSContext *cx, JS::HandleObject scope, JS::HandleObject obj, unsigned fl static JSObject * Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj, - JS::HandleObject proto, JS::HandleObject parent, unsigned flags) + JS::HandleObject parent, unsigned flags) { return js::Wrapper::New(cx, obj, parent, &js::CrossCompartmentWrapper::singleton); } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index d5ec0f635ca2..1dca2219ccaf 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -758,8 +758,7 @@ typedef bool */ typedef JSObject * (* JSWrapObjectCallback)(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj, - JS::HandleObject proto, JS::HandleObject parent, - unsigned flags); + JS::HandleObject parent, unsigned flags); /* * Callback used by the wrap hook to ask the embedding to prepare an object diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index b50edc31ecae..97515875dd2e 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -402,7 +402,6 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin return true; } - RootedObject proto(cx, TaggedProto::LazyProto); RootedObject existing(cx, existingArg); if (existing) { // Is it possible to reuse |existing|? @@ -416,7 +415,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin } } - obj.set(cb->wrap(cx, existing, obj, proto, global, flags)); + obj.set(cb->wrap(cx, existing, obj, global, flags)); if (!obj) return false; diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index e5e3b706d7bc..5db847b4548b 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -145,12 +145,10 @@ JSObject *Wrapper::defaultProto = TaggedProto::LazyProto; extern JSObject * js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj, - HandleObject wrappedProto, HandleObject parent, - unsigned flags) + HandleObject parent, unsigned flags) { // Allow wrapping outer window proxies. JS_ASSERT(!obj->is() || obj->getClass()->ext.innerObject); - JS_ASSERT(wrappedProto == TaggedProto::LazyProto); return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton); } diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index ec67447f8e1a..a7561958bf42 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -245,8 +245,7 @@ class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler extern JSObject * TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj, - HandleObject wrappedProto, HandleObject parent, - unsigned flags); + HandleObject parent, unsigned flags); // Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by // jsfriendapi users. diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index bdf6bc2d9220..3a3b8d9df04c 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -396,8 +396,7 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType, JSObject * WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj, - HandleObject wrappedProto, HandleObject parent, - unsigned flags) + HandleObject parent, unsigned flags) { MOZ_ASSERT(!IsWrapper(obj) || GetProxyHandler(obj) == &XrayWaiver || diff --git a/js/xpconnect/wrappers/WrapperFactory.h b/js/xpconnect/wrappers/WrapperFactory.h index 2a9b45173f55..9a23520a04a7 100644 --- a/js/xpconnect/wrappers/WrapperFactory.h +++ b/js/xpconnect/wrappers/WrapperFactory.h @@ -53,7 +53,6 @@ class WrapperFactory { static JSObject *Rewrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj, - JS::HandleObject wrappedProto, JS::HandleObject parent, unsigned flags); From 3d446408a68f187404933e1d9b169d65a624fd7a Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Mon, 16 Jun 2014 11:52:52 -0400 Subject: [PATCH 15/64] Bug 1023670 - Fix DeviceManager.mkDirs with a Windows path. r=wlach --- testing/mozbase/mozdevice/mozdevice/devicemanager.py | 10 +++++++++- testing/mozbase/mozdevice/tests/sut_mkdir.py | 3 +++ testing/mozbase/mozdevice/tests/sut_push.py | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanager.py b/testing/mozbase/mozdevice/mozdevice/devicemanager.py index 8a79510599a5..7b5974a2fac3 100644 --- a/testing/mozbase/mozdevice/mozdevice/devicemanager.py +++ b/testing/mozbase/mozdevice/mozdevice/devicemanager.py @@ -6,6 +6,7 @@ import hashlib import mozlog import socket import os +import ntpath import posixpath import re import struct @@ -52,6 +53,13 @@ class DeviceManager(object): self._logger = mozlog.getLogger("DeviceManager") self._logLevel = logLevel self._logger.setLevel(logLevel) + self._remoteIsWin = None + + @property + def remoteIsWin(self): + if self._remoteIsWin is None: + self._remoteIsWin = self.getInfo("os")["os"][0] == "windows" + return self._remoteIsWin @property def logLevel(self): @@ -243,7 +251,7 @@ class DeviceManager(object): containing = posixpath.dirname(filename) if not self.dirExists(containing): parts = filename.split('/') - name = "/" + name = "/" if not self.remoteIsWin else parts.pop(0) for part in parts[:-1]: if part != "": name = posixpath.join(name, part) diff --git a/testing/mozbase/mozdevice/tests/sut_mkdir.py b/testing/mozbase/mozdevice/tests/sut_mkdir.py index 43ab0d251d8c..85752e9d1ff5 100644 --- a/testing/mozbase/mozdevice/tests/sut_mkdir.py +++ b/testing/mozbase/mozdevice/tests/sut_mkdir.py @@ -10,6 +10,7 @@ class MkDirsTest(unittest.TestCase): def test_mkdirs(self): subTests = [{'cmds': [('isdir /mnt/sdcard/baz/boop', 'FALSE'), + ('info os', 'android'), ('isdir /mnt', 'TRUE'), ('isdir /mnt/sdcard', 'TRUE'), ('isdir /mnt/sdcard/baz', 'FALSE'), @@ -20,6 +21,7 @@ class MkDirsTest(unittest.TestCase): '/mnt/sdcard/baz/boop successfully created')], 'expectException': False}, {'cmds': [('isdir /mnt/sdcard/baz/boop', 'FALSE'), + ('info os', 'android'), ('isdir /mnt', 'TRUE'), ('isdir /mnt/sdcard', 'TRUE'), ('isdir /mnt/sdcard/baz', 'FALSE'), @@ -48,6 +50,7 @@ class MkDirsTest(unittest.TestCase): """ cmds = [('isdir /mnt/sdcard/foo', 'FALSE'), + ('info os', 'android'), ('isdir /mnt', 'TRUE'), ('isdir /mnt/sdcard', 'TRUE'), ('isdir /mnt/sdcard/foo', 'FALSE'), diff --git a/testing/mozbase/mozdevice/tests/sut_push.py b/testing/mozbase/mozdevice/tests/sut_push.py index 0eacc163383a..558ed477b338 100644 --- a/testing/mozbase/mozdevice/tests/sut_push.py +++ b/testing/mozbase/mozdevice/tests/sut_push.py @@ -57,6 +57,7 @@ class PushTest(unittest.TestCase): "BADHASH") ], 'expectException': True }, { 'cmds': [ ("isdir /mnt/sdcard/baz", "FALSE"), + ('info os', 'android'), ("isdir /mnt", "FALSE"), ("mkdr /mnt", "##AGENT-WARNING## Could not create the directory /mnt") ], From 1a344c3441a08dac8803cb65ce4d8f589400dc13 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Mon, 16 Jun 2014 11:52:52 -0400 Subject: [PATCH 16/64] Bug 1025181 - [mozlog] Fix structured logging HTML formatter to actually produce results. r=jgraham --- .../mozlog/structured/formatters/html/html.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py b/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py index 9bfc10dbf56e..e40b040a9c4f 100755 --- a/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py +++ b/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py @@ -67,12 +67,9 @@ class HTMLFormatter(base.BaseFormatter): expected = data.get("expected", status) if status != expected: - if status == "PASS": - status_name = "UNEXPECTED_" + status - else: - status_name = "EXPECTED_" + status - else: - status_name = status + status_name = "UNEXPECTED_" + status + elif status != "PASS": + status_name = "EXPECTED_" + status self.test_count[status_name] += 1 @@ -141,8 +138,8 @@ class HTMLFormatter(base.BaseFormatter): html.br(), html.span('%i passed' % self.test_count["PASS"], class_='pass'), ', ', html.span('%i skipped' % self.test_count["SKIP"], class_='skip'), ', ', - html.span('%i failed' % self.test_count["FAIL"], class_='fail'), ', ', - html.span('%i errors' % self.test_count["ERROR"], class_='error'), '.', + html.span('%i failed' % self.test_count["UNEXPECTED_FAIL"], class_='fail'), ', ', + html.span('%i errors' % self.test_count["UNEXPECTED_ERROR"], class_='error'), '.', html.br(), html.span('%i expected failures' % self.test_count["EXPECTED_FAIL"], class_='expected_fail'), ', ', @@ -158,4 +155,4 @@ class HTMLFormatter(base.BaseFormatter): html.th('Links')]), id='results-table-head'), html.tbody(self.result_rows, id='results-table-body')], id='results-table')))) - return doc.unicode(indent=2) + return u"\n" + doc.unicode(indent=2) From 586275c808b0693770892d15f4f0d174eebd0f17 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Mon, 16 Jun 2014 15:10:05 -0400 Subject: [PATCH 17/64] Bug 1025354: fix out-of-sync name array for SIPCC logs r=ehugg --- media/webrtc/signaling/src/sipcc/core/gsm/ccapi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/ccapi.c b/media/webrtc/signaling/src/sipcc/core/gsm/ccapi.c index 01c13407d587..29884ffe429c 100755 --- a/media/webrtc/signaling/src/sipcc/core/gsm/ccapi.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/ccapi.c @@ -26,6 +26,7 @@ static const char *cc_src_names[] = { "UI", "SIP", "MISC_APP", + "RCC", "CCAPP" }; From 29b465940b9fc439667c1cfd9bd80131e755cdb2 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Mon, 16 Jun 2014 15:10:16 -0400 Subject: [PATCH 18/64] Bug 1025349: fix error in ccsnap line label indexes r=ehugg --- media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_snapshot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_snapshot.c b/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_snapshot.c index f35ed675dcb7..78d43c8d4c9f 100644 --- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_snapshot.c +++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_snapshot.c @@ -31,7 +31,7 @@ cc_string_t lineLabels[MAX_CONFIG_LINES+1] = {0}; void ccsnap_set_line_label(int btn, cc_string_t label) { CCAPP_DEBUG(DEB_F_PREFIX"btn=%d label=%s", DEB_F_PREFIX_ARGS(SIP_CC_PROV, "ccsnap_set_line_label"), btn, label); - if ( btn > 0 && btn <= MAX_CONFIG_LINES+1 ) { + if ( btn > 0 && btn < MAX_CONFIG_LINES+1 ) { if ( label == NULL ) { label = strlib_empty(); } @@ -43,7 +43,7 @@ void ccsnap_set_line_label(int btn, cc_string_t label) { } cc_string_t ccsnap_get_line_label(int btn) { - if ( btn > 0 && btn <= MAX_CONFIG_LINES+1 ) { + if ( btn > 0 && btn < MAX_CONFIG_LINES+1 ) { return lineLabels[btn]; } return strlib_empty(); From 7e56500dffc3df72bfcf5ab4d70e0fbbd712f9e4 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Mon, 16 Jun 2014 13:16:58 -0600 Subject: [PATCH 19/64] Bug 983440 - Allow for NoSuchMethodException thrown from getDeclaredField, pre-Honeycomb; r=jchen --- mobile/android/base/tests/helpers/FrameworkHelper.java | 8 +++++++- mobile/android/base/tests/robocop.ini | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/tests/helpers/FrameworkHelper.java b/mobile/android/base/tests/helpers/FrameworkHelper.java index df85aed9c4a4..d3c4d6390547 100644 --- a/mobile/android/base/tests/helpers/FrameworkHelper.java +++ b/mobile/android/base/tests/helpers/FrameworkHelper.java @@ -29,7 +29,13 @@ public final class FrameworkHelper { do { try { return cls.getDeclaredField(fieldName); - } catch (final NoSuchFieldException e) { + } catch (final Exception e) { + // NoSuchFieldException is a documented exception of getDeclaredField + // and is frequently observed here. No other exceptions are documented + // for getDeclaredField. However, on Android 2.3, NoSuchMethodException + // is also observed, when called on some classes. This appears to be + // an Android bug reportedly fixed in Honeycomb. Since NoSuchMethodException + // is not declared, it cannot be caught, so we catch all Exceptions. cls = cls.getSuperclass(); } } while (cls != null); diff --git a/mobile/android/base/tests/robocop.ini b/mobile/android/base/tests/robocop.ini index 7d24b50c044b..89b951403928 100644 --- a/mobile/android/base/tests/robocop.ini +++ b/mobile/android/base/tests/robocop.ini @@ -125,7 +125,7 @@ skip-if = android_version == "10" [testAboutHomeVisibility] [testEventDispatcher] [testInputConnection] -# disabled on Android 2.3; bug 983440 +# disabled on Android 2.3; bug 1025968 skip-if = android_version == "10" [testJavascriptBridge] [testNativeCrypto] From 33d24a493fe4e6ce95783e03ef77e4ef0bb06301 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Mon, 16 Jun 2014 13:16:59 -0600 Subject: [PATCH 20/64] Bug 979603 - Enable robocop testBrowserProvider on Android 2.3; r=me --- mobile/android/base/tests/robocop.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/mobile/android/base/tests/robocop.ini b/mobile/android/base/tests/robocop.ini index 89b951403928..da011fdcc27d 100644 --- a/mobile/android/base/tests/robocop.ini +++ b/mobile/android/base/tests/robocop.ini @@ -25,8 +25,6 @@ skip-if = android_version == "10" # [testBookmarklets] # see bug 915350 # [testBookmarkKeyword] # see bug 915350 [testBrowserProvider] -# disabled on 2.3; bug 979603 -skip-if = android_version == "10" [testBrowserSearchVisibility] [testClearPrivateData] # disabled on x86 and 2.3; bug 948591 From f242029fed1bc128f3d75aac1af05f8333049557 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Mon, 16 Jun 2014 04:54:00 -0400 Subject: [PATCH 21/64] Bug 968196 - Use GDK error handler for X window error events. r=karlt --- toolkit/xre/moz.build | 5 ++ toolkit/xre/nsAppRunner.cpp | 3 +- toolkit/xre/nsEmbedFunctions.cpp | 5 ++ toolkit/xre/nsGDKErrorHandler.cpp | 96 +++++++++++++++++++++++++++++++ toolkit/xre/nsGDKErrorHandler.h | 8 +++ toolkit/xre/nsX11ErrorHandler.cpp | 4 +- toolkit/xre/nsX11ErrorHandler.h | 4 ++ 7 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 toolkit/xre/nsGDKErrorHandler.cpp create mode 100644 toolkit/xre/nsGDKErrorHandler.h diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index a13a9ef3bfc1..77abd2f67155 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -56,6 +56,11 @@ else: 'nsNativeAppSupportDefault.cpp', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3': + UNIFIED_SOURCES += [ + 'nsGDKErrorHandler.cpp', + ] + if CONFIG['MOZ_X11']: UNIFIED_SOURCES += [ 'nsX11ErrorHandler.cpp', diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 66b9e38d8cc4..d4c5bdc2012b 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -191,7 +191,6 @@ extern uint32_t gRestartMode; extern void InstallSignalHandlers(const char *ProgramName); -#include "nsX11ErrorHandler.h" #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini") #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches") @@ -3533,7 +3532,7 @@ XREMain::XRE_mainStartup(bool* aExitFlag) #endif /* defined(MOZ_WIDGET_GTK) */ #ifdef MOZ_X11 // Do this after initializing GDK, or GDK will install its own handler. - InstallX11ErrorHandler(); + XRE_InstallX11ErrorHandler(); #endif // Call the code to install our handler diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 57ca85618873..4a8556426a07 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -48,6 +48,7 @@ #include "chrome/common/mach_ipc_mac.h" #endif #include "nsX11ErrorHandler.h" +#include "nsGDKErrorHandler.h" #include "base/at_exit.h" #include "base/command_line.h" #include "base/message_loop.h" @@ -789,7 +790,11 @@ XRE_ShutdownTestShell() void XRE_InstallX11ErrorHandler() { +#if (MOZ_WIDGET_GTK == 3) + InstallGdkErrorHandler(); +#else InstallX11ErrorHandler(); +#endif } #endif diff --git a/toolkit/xre/nsGDKErrorHandler.cpp b/toolkit/xre/nsGDKErrorHandler.cpp new file mode 100644 index 000000000000..0f0e2d5573ca --- /dev/null +++ b/toolkit/xre/nsGDKErrorHandler.cpp @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 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 "nsGDKErrorHandler.h" + +#include +#include +#include + +#include "nsX11ErrorHandler.h" + +#include "prenv.h" + + +/* See https://bugzilla.gnome.org/show_bug.cgi?id=629608#c8 + * + * GDK implements X11 error traps to ignore X11 errors. + * Unfortunatelly We don't know which X11 events can be ignored + * so we have to utilize the Gdk error handler to avoid + * false alarms in Gtk3. + */ +static void +GdkErrorHandler(const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ + if (strstr(message, "X Window System error")) { + XErrorEvent event; + nsDependentCString buffer(message); + char *endptr; + + /* Parse Gdk X Window error message which has this format: + * (Details: serial XXXX error_code XXXX request_code XXXX (XXXX) minor_code XXXX) + */ + NS_NAMED_LITERAL_CSTRING(serialString, "(Details: serial "); + int32_t start = buffer.Find(serialString); + if (start == kNotFound) + NS_RUNTIMEABORT(message); + + start += serialString.Length(); + errno = 0; + event.serial = strtol(buffer.BeginReading() + start, &endptr, 10); + if (errno) + NS_RUNTIMEABORT(message); + + NS_NAMED_LITERAL_CSTRING(errorCodeString, " error_code "); + if (!StringBeginsWith(Substring(endptr, buffer.EndReading()), errorCodeString)) + NS_RUNTIMEABORT(message); + + errno = 0; + event.error_code = strtol(endptr + errorCodeString.Length(), &endptr, 10); + if (errno) + NS_RUNTIMEABORT(message); + + NS_NAMED_LITERAL_CSTRING(requestCodeString, " request_code "); + if (!StringBeginsWith(Substring(endptr, buffer.EndReading()), requestCodeString)) + NS_RUNTIMEABORT(message); + + errno = 0; + event.request_code = strtol(endptr + requestCodeString.Length(), &endptr, 10); + if (errno) + NS_RUNTIMEABORT(message); + + NS_NAMED_LITERAL_CSTRING(minorCodeString, " minor_code "); + start = buffer.Find(minorCodeString, endptr - buffer.BeginReading()); + if (!start) + NS_RUNTIMEABORT(message); + + errno = 0; + event.minor_code = strtol(buffer.BeginReading() + start + minorCodeString.Length(), nullptr, 10); + if (errno) + NS_RUNTIMEABORT(message); + + event.display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); + // Gdk does not provide resource ID + event.resourceid = 0; + + X11Error(event.display, &event); + } else { + g_log_default_handler(log_domain, log_level, message, user_data); + NS_RUNTIMEABORT(message); + } +} + +void +InstallGdkErrorHandler() +{ + g_log_set_handler("Gdk", + (GLogLevelFlags)(G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), + GdkErrorHandler, + nullptr); + if (PR_GetEnv("MOZ_X_SYNC")) { + XSynchronize(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), True); + } +} diff --git a/toolkit/xre/nsGDKErrorHandler.h b/toolkit/xre/nsGDKErrorHandler.h new file mode 100644 index 000000000000..dc745961643e --- /dev/null +++ b/toolkit/xre/nsGDKErrorHandler.h @@ -0,0 +1,8 @@ +/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#if (MOZ_WIDGET_GTK == 3) +void InstallGdkErrorHandler(); +#endif diff --git a/toolkit/xre/nsX11ErrorHandler.cpp b/toolkit/xre/nsX11ErrorHandler.cpp index 12c8accf4a74..c34d33cb7622 100644 --- a/toolkit/xre/nsX11ErrorHandler.cpp +++ b/toolkit/xre/nsX11ErrorHandler.cpp @@ -16,7 +16,7 @@ #define BUFSIZE 2048 // What Xlib uses with XGetErrorDatabaseText extern "C" { -static int +int X11Error(Display *display, XErrorEvent *event) { // Get an indication of how long ago the request that caused the error was // made. @@ -159,6 +159,7 @@ X11Error(Display *display, XErrorEvent *event) { } } +#if (MOZ_WIDGET_GTK == 2) void InstallX11ErrorHandler() { @@ -170,3 +171,4 @@ InstallX11ErrorHandler() XSynchronize(display, True); } } +#endif diff --git a/toolkit/xre/nsX11ErrorHandler.h b/toolkit/xre/nsX11ErrorHandler.h index c602156e9f98..7abe2051a98f 100644 --- a/toolkit/xre/nsX11ErrorHandler.h +++ b/toolkit/xre/nsX11ErrorHandler.h @@ -4,5 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef MOZ_X11 +#include +#if (MOZ_WIDGET_GTK == 2) void InstallX11ErrorHandler(); #endif +extern "C" int X11Error(Display *display, XErrorEvent *event); +#endif From 2a1c77e607fbb493a8e9e1d1fec78e949f89254b Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Fri, 13 Jun 2014 08:04:00 -0400 Subject: [PATCH 22/64] Bug 1023004 - Fixes arrow angle rendering. r=karlt --- widget/gtk/gtk3drawing.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/widget/gtk/gtk3drawing.c b/widget/gtk/gtk3drawing.c index e213639324cb..14d77e091e51 100644 --- a/widget/gtk/gtk3drawing.c +++ b/widget/gtk/gtk3drawing.c @@ -1723,7 +1723,7 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRectangle* rect, GtkStyleContext* style; GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); GdkRectangle arrow_rect; - gdouble arrow_angle = ARROW_UP; + gdouble arrow_angle; ensure_button_arrow_widget(); style = gtk_widget_get_style_context(gButtonArrowWidget); @@ -1735,12 +1735,22 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRectangle* rect, direction); if (direction == GTK_TEXT_DIR_RTL) { - if (arrow_type == GTK_ARROW_LEFT) - arrow_angle = ARROW_RIGHT; - else if (arrow_type == GTK_ARROW_RIGHT) - arrow_angle = ARROW_LEFT; - } else if (arrow_type == GTK_ARROW_DOWN) { + arrow_type = (arrow_type == GTK_ARROW_LEFT) ? + GTK_ARROW_RIGHT : GTK_ARROW_LEFT; + } + switch (arrow_type) { + case GTK_ARROW_LEFT: + arrow_angle = ARROW_LEFT; + break; + case GTK_ARROW_RIGHT: + arrow_angle = ARROW_RIGHT; + break; + case GTK_ARROW_DOWN: arrow_angle = ARROW_DOWN; + break; + default: + arrow_angle = ARROW_UP; + break; } if (arrow_type != GTK_ARROW_NONE) gtk_render_arrow(style, cr, arrow_angle, From b5f59a72093fd45b30224c16ce1eacfad001d301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20L=C3=B3pez?= Date: Mon, 16 Jun 2014 00:24:05 +0200 Subject: [PATCH 23/64] Bug 1024579 - Create a sync getNetworkInformation and make getNetworkStatus use it. r=nsm --- dom/push/src/PushService.jsm | 60 ++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/dom/push/src/PushService.jsm b/dom/push/src/PushService.jsm index ab7a5576b67c..3b3d90dae125 100644 --- a/dom/push/src/PushService.jsm +++ b/dom/push/src/PushService.jsm @@ -1502,15 +1502,11 @@ this.PushService = { }, /** - * Get mobile network information to decide if the client is capable of being - * woken up by UDP (which currently just means having an mcc and mnc along - * with an IP). + * Returns information about MCC-MNC and the IP of the current connection. */ - _getNetworkState: function(callback) { - if (typeof callback !== 'function') { - throw new Error("No callback method. Aborting push agent !"); - } - debug("getNetworkState()"); + _getNetworkInformation: function() { + debug("getNetworkInformation()"); + try { if (!prefs.get("udp.wakeupEnabled")) { debug("UDP support disabled, we do not send any carrier info"); @@ -1534,16 +1530,11 @@ this.PushService = { let prefixLengths = {}; nm.active.getAddresses(ips, prefixLengths); - this._getMobileNetworkId(function(netid) { - debug("Recovered netID = " + netid); - callback({ - mcc: iccInfo.mcc, - mnc: iccInfo.mnc, - ip: ips.value[0], - netid: netid - }); - }); - return; + return { + mcc: iccInfo.mcc, + mnc: iccInfo.mnc, + ip: ips.value[0] + } } } } catch (e) { @@ -1551,11 +1542,40 @@ this.PushService = { } debug("Running on wifi"); - callback({ + return { mcc: 0, mnc: 0, ip: undefined - }); + }; + }, + + /** + * Get mobile network information to decide if the client is capable of being + * woken up by UDP (which currently just means having an mcc and mnc along + * with an IP, and optionally a netid). + */ + _getNetworkState: function(callback) { + debug("getNetworkState()"); + + if (typeof callback !== 'function') { + throw new Error("No callback method. Aborting push agent !"); + } + + var networkInfo = this._getNetworkInformation(); + + if (networkInfo.ip) { + this._getMobileNetworkId(function(netid) { + debug("Recovered netID = " + netid); + callback({ + mcc: networkInfo.mcc, + mnc: networkInfo.mnc, + ip: networkInfo.ip, + netid: netid + }); + }); + } else { + callback(networkInfo); + } }, // utility function used to add/remove observers in init() and shutdown() From 29acbb866c7e8570e9b93c379182282d38ae090d Mon Sep 17 00:00:00 2001 From: aceman Date: Fri, 13 Jun 2014 16:37:00 -0400 Subject: [PATCH 24/64] Bug 1025340 - Declare encType variable in toolkit/components/storage-mozStorage.js. r=MattN --- toolkit/components/passwordmgr/storage-mozStorage.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/toolkit/components/passwordmgr/storage-mozStorage.js b/toolkit/components/passwordmgr/storage-mozStorage.js index 1c63bf94afbf..4768857720e5 100644 --- a/toolkit/components/passwordmgr/storage-mozStorage.js +++ b/toolkit/components/passwordmgr/storage-mozStorage.js @@ -241,12 +241,10 @@ LoginManagerStorage_mozStorage.prototype = { * */ addLogin : function (login) { - let encUsername, encPassword; - // Throws if there are bogus values. LoginHelper.checkLoginValues(login); - [encUsername, encPassword, encType] = this._encryptLogin(login); + let [encUsername, encPassword, encType] = this._encryptLogin(login); // Clone the login, so we don't modify the caller's object. let loginClone = login.clone(); From 2697000e132b41cd78e857feca46da0f5b3e9de4 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Mon, 16 Jun 2014 15:51:45 -0400 Subject: [PATCH 25/64] Bug 1025176: Save AEC dumps in a specified directory depending on platform/pref r=pkerr --- .../src/common/browser_logging/WebRtcLog.cpp | 72 +++++++++++-------- .../WebrtcGlobalInformation.cpp | 1 + .../modules/audio_processing/aec/aec_core.c | 29 ++++++-- .../audio_processing/aec/echo_cancellation.c | 27 +++++-- .../webrtc/system_wrappers/interface/trace.h | 7 ++ .../system_wrappers/source/trace_impl.cc | 9 +++ modules/libpref/src/init/all.js | 5 +- 7 files changed, 108 insertions(+), 42 deletions(-) diff --git a/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp b/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp index d702d9ad1485..6569c563a5ed 100644 --- a/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp +++ b/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp @@ -52,11 +52,12 @@ public: static WebRtcTraceCallback gWebRtcCallback; #ifdef MOZILLA_INTERNAL_API -void GetWebRtcLogPrefs(uint32_t *aTraceMask, nsACString* aLogFile, bool *aMultiLog) +void GetWebRtcLogPrefs(uint32_t *aTraceMask, nsACString* aLogFile, nsACString *aAECLogDir, bool *aMultiLog) { *aMultiLog = mozilla::Preferences::GetBool("media.webrtc.debug.multi_log"); *aTraceMask = mozilla::Preferences::GetUint("media.webrtc.debug.trace_mask"); mozilla::Preferences::GetCString("media.webrtc.debug.log_file", aLogFile); + mozilla::Preferences::GetCString("media.webrtc.debug.aec_log_dir", aAECLogDir); webrtc::Trace::set_aec_debug_size(mozilla::Preferences::GetUint("media.webrtc.debug.aec_dump_max_size")); } #endif @@ -91,40 +92,52 @@ void CheckOverrides(uint32_t *aTraceMask, nsACString *aLogFile, bool *aMultiLog) } } -void ConfigWebRtcLog(uint32_t trace_mask, nsCString &aLogFile, bool multi_log) +void ConfigWebRtcLog(uint32_t trace_mask, nsCString &aLogFile, nsCString &aAECLogDir, bool multi_log) { - if (gWebRtcTraceLoggingOn || trace_mask == 0) { + if (gWebRtcTraceLoggingOn) { return; } - if (aLogFile.IsEmpty()) { + nsCString logFile; + nsCString aecLogDir; #if defined(XP_WIN) - // Use the Windows TEMP environment variable as part of the default location. - const char *temp_dir = PR_GetEnv("TEMP"); - if (!temp_dir) { - aLogFile.Assign(default_log); - } else { - aLogFile.Assign(temp_dir); - aLogFile.Append('/'); - aLogFile.Append(default_log); - } + // Use the Windows TEMP environment variable as part of the default location. + const char *temp_dir = PR_GetEnv("TEMP"); + if (!temp_dir) { + logFile.Assign(default_log); + } else { + logFile.Assign(temp_dir); + logFile.Append('/'); + aecLogDir = logFile; + logFile.Append(default_log); + } #elif defined(ANDROID) - // Special case: use callback to pipe to NSPR logging. - aLogFile.Assign("nspr"); + // Special case: use callback to pipe to NSPR logging. + logFile.Assign("nspr"); + // for AEC, force the user to specify a directory + aecLogDir.Assign("/dev/null"); #else - // UNIX-like place for the others - aLogFile.Assign("/tmp/"); - aLogFile.Append(default_log); + // UNIX-like place for the others + logFile.Assign("/tmp/"); + aecLogDir = logFile; + logFile.Append(default_log); #endif + if (aLogFile.IsEmpty()) { + aLogFile = logFile; + } + if (aAECLogDir.IsEmpty()) { + aAECLogDir = aecLogDir; } webrtc::Trace::set_level_filter(trace_mask); - if (aLogFile.EqualsLiteral("nspr")) { - webrtc::Trace::SetTraceCallback(&gWebRtcCallback); - } else { - webrtc::Trace::SetTraceFile(aLogFile.get(), multi_log); + webrtc::Trace::set_aec_debug_filename(aAECLogDir.get()); + if (trace_mask != 0) { + if (aLogFile.EqualsLiteral("nspr")) { + webrtc::Trace::SetTraceCallback(&gWebRtcCallback); + } else { + webrtc::Trace::SetTraceFile(aLogFile.get(), multi_log); + } } - return; } @@ -134,7 +147,7 @@ void StartWebRtcLog(uint32_t log_level) return; } - if (log_level == 0) { + if (log_level == 0) { if (gWebRtcTraceLoggingOn) { gWebRtcTraceLoggingOn = false; webrtc::Trace::set_level_filter(webrtc::kTraceNone); @@ -145,9 +158,10 @@ void StartWebRtcLog(uint32_t log_level) uint32_t trace_mask = 0; bool multi_log = false; nsAutoCString log_file; + nsAutoCString aec_log_dir; #ifdef MOZILLA_INTERNAL_API - GetWebRtcLogPrefs(&trace_mask, &log_file, &multi_log); + GetWebRtcLogPrefs(&trace_mask, &log_file, &aec_log_dir, &multi_log); #endif CheckOverrides(&trace_mask, &log_file, &multi_log); @@ -155,7 +169,7 @@ void StartWebRtcLog(uint32_t log_level) trace_mask = log_level; } - ConfigWebRtcLog(trace_mask, log_file, multi_log); + ConfigWebRtcLog(trace_mask, log_file, aec_log_dir, multi_log); return; } @@ -169,12 +183,12 @@ void EnableWebRtcLog() uint32_t trace_mask = 0; bool multi_log = false; nsAutoCString log_file; + nsAutoCString aec_log_dir; #ifdef MOZILLA_INTERNAL_API - GetWebRtcLogPrefs(&trace_mask, &log_file, &multi_log); + GetWebRtcLogPrefs(&trace_mask, &log_file, &aec_log_dir, &multi_log); #endif CheckOverrides(&trace_mask, &log_file, &multi_log); - ConfigWebRtcLog(trace_mask, log_file, multi_log); + ConfigWebRtcLog(trace_mask, log_file, aec_log_dir, multi_log); return; } - diff --git a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp index 089c95b657b7..bbc55b7b81f0 100644 --- a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp +++ b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp @@ -252,6 +252,7 @@ WebrtcGlobalInformation::DebugLevel(const GlobalObject& aGlobal) void WebrtcGlobalInformation::SetAecDebug(const GlobalObject& aGlobal, bool aEnable) { + StartWebRtcLog(sLastSetLevel); // to make it read the aec path webrtc::Trace::set_aec_debug(aEnable); sLastAECDebug = aEnable; } diff --git a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c index 222dcb96b3f3..cb3fc04aa285 100644 --- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c +++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c @@ -31,6 +31,7 @@ extern int AECDebug(); extern uint32_t AECDebugMaxSize(); extern void AECDebugEnable(uint32_t enable); +extern void AECDebugFilenameBase(char *buffer, size_t size); static void OpenCoreDebugFiles(AecCore* aec, int *instance_count); // Buffer size (samples) @@ -1730,16 +1731,34 @@ OpenCoreDebugFiles(AecCore* aec, // XXX If this impacts performance (opening files here), move file open // to Trace::set_aec_debug(), and just grab them here if (AECDebug() && !aec->farFile) { - char filename[128]; if (!aec->farFile) { + char path[1024]; + char *filename; + path[0] = '\0'; + AECDebugFilenameBase(path, sizeof(path)); + filename = path + strlen(path); + if (&path[sizeof(path)] - filename < 128) { + return; // avoid a lot of snprintf's and checks lower + } + if (filename > path) { +#ifdef XP_WIN + if (*(filename-1) != '\\') { + *filename++ = '\\'; + } +#else + if (*(filename-1) != '/') { + *filename++ = '/'; + } +#endif + } sprintf(filename, "aec_far%d.pcm", webrtc_aec_instance_count); - aec->farFile = fopen(filename, "wb"); + aec->farFile = fopen(path, "wb"); sprintf(filename, "aec_near%d.pcm", webrtc_aec_instance_count); - aec->nearFile = fopen(filename, "wb"); + aec->nearFile = fopen(path, "wb"); sprintf(filename, "aec_out%d.pcm", webrtc_aec_instance_count); - aec->outFile = fopen(filename, "wb"); + aec->outFile = fopen(path, "wb"); sprintf(filename, "aec_out_linear%d.pcm", webrtc_aec_instance_count); - aec->outLinearFile = fopen(filename, "wb"); + aec->outLinearFile = fopen(path, "wb"); aec->debugWritten = 0; if (!aec->outLinearFile || !aec->outFile || !aec->nearFile || !aec->farFile) { error = 1; diff --git a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c index 3b99154315ea..f657f1f7a69f 100644 --- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c +++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c @@ -30,6 +30,7 @@ extern int AECDebug(); extern uint32_t AECDebugMaxSize(); extern void AECDebugEnable(uint32_t enable); +extern void AECDebugFilenameBase(char *buffer, size_t size); static void OpenDebugFiles(aecpc_t* aecpc, int *instance_count); // Measured delays [ms] @@ -985,13 +986,31 @@ OpenDebugFiles(aecpc_t* aecpc, // XXX If this impacts performance (opening files here), move file open // to Trace::set_aec_debug(), and just grab them here if (AECDebug() && !aecpc->bufFile) { - char filename[128]; + char path[1024]; + char *filename; + path[0] = '\0'; + AECDebugFilenameBase(path, sizeof(path)); + filename = path + strlen(path); + if (&path[sizeof(path)] - filename < 128) { + return; // avoid a lot of snprintf's and checks lower + } + if (filename > path) { +#ifdef XP_WIN + if (*(filename-1) != '\\') { + *filename++ = '\\'; + } +#else + if (*(filename-1) != '/') { + *filename++ = '/'; + } +#endif + } sprintf(filename, "aec_buf%d.dat", *instance_count); - aecpc->bufFile = fopen(filename, "wb"); + aecpc->bufFile = fopen(path, "wb"); sprintf(filename, "aec_skew%d.dat", *instance_count); - aecpc->skewFile = fopen(filename, "wb"); + aecpc->skewFile = fopen(path, "wb"); sprintf(filename, "aec_delay%d.dat", *instance_count); - aecpc->delayFile = fopen(filename, "wb"); + aecpc->delayFile = fopen(path, "wb"); if (!aecpc->bufFile || !aecpc->skewFile || !aecpc->delayFile) { error = 1; diff --git a/media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h b/media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h index 9085680b537f..6844894a7157 100644 --- a/media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h +++ b/media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h @@ -18,6 +18,7 @@ #include "webrtc/common_types.h" #include "webrtc/typedefs.h" +#include namespace webrtc { @@ -59,6 +60,10 @@ class Trace { static void set_aec_debug_size(uint32_t size) { aec_debug_size_ = size; } static bool aec_debug() { return aec_debug_; } static uint32_t aec_debug_size() { return aec_debug_size_; } + static void aec_debug_filename(char *buffer, size_t size); + static void set_aec_debug_filename(const char* filename) { + aec_filename_base_ = filename; + } // Sets the file name. If add_file_counter is false the same file will be // reused when it fills up. If it's true a new file with incremented name @@ -93,6 +98,7 @@ class Trace { static uint32_t level_filter_; static bool aec_debug_; static uint32_t aec_debug_size_; + static std::string aec_filename_base_; }; } // namespace webrtc @@ -101,6 +107,7 @@ extern "C" { extern int AECDebug(); extern uint32_t AECDebugMaxSize(); extern void AECDebugEnable(uint32_t enable); + extern void AECDebugFilenameBase(char *buffer, size_t size); } #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ diff --git a/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc b/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc index f5b05ac4f5f4..c94e18c5277c 100644 --- a/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc +++ b/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc @@ -33,6 +33,9 @@ extern "C" { int AECDebug() { return (int) webrtc::Trace::aec_debug(); } uint32_t AECDebugMaxSize() { return webrtc::Trace::aec_debug_size(); } void AECDebugEnable(uint32_t enable) { webrtc::Trace::set_aec_debug(!!enable); } + void AECDebugFilenameBase(char *buffer, size_t size) { + webrtc::Trace::aec_debug_filename(buffer, size); + } } namespace webrtc { @@ -43,6 +46,12 @@ const int Trace::kTimestampLength = 12; uint32_t Trace::level_filter_ = kTraceDefault; bool Trace::aec_debug_ = false; uint32_t Trace::aec_debug_size_ = 4*1024*1024; +std::string Trace::aec_filename_base_; + +void Trace::aec_debug_filename(char *buffer, size_t size) { + strncpy(buffer, aec_filename_base_.c_str(), size-1); + buffer[size-1] = '\0'; +} // Construct On First Use idiom. Avoids "static initialization order fiasco". TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation, diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 15a45ab2ae11..e243543237fa 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -260,11 +260,8 @@ pref("media.navigator.video.default_minfps",10); pref("media.webrtc.debug.trace_mask", 0); pref("media.webrtc.debug.multi_log", false); -#if defined(ANDROID) || defined(XP_WIN) +pref("media.webrtc.debug.aec_log_dir", ""); pref("media.webrtc.debug.log_file", ""); -#else -pref("media.webrtc.debug.log_file", "/tmp/WebRTC.log"); -#endif pref("media.webrtc.debug.aec_dump_max_size", 4194304); // 4MB #ifdef MOZ_WIDGET_GONK From e14b1ad176068d182cca745c3e95e68df976acc5 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Mon, 16 Jun 2014 13:05:14 -0700 Subject: [PATCH 26/64] Bug 1025824 - Fix mHwcLayerMap handling r=sushil --- widget/gonk/HwcComposer2D.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index 7c99263afb49..b958c29ac1a6 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -683,7 +683,7 @@ HwcComposer2D::Commit() displays[HWC_DISPLAY_PRIMARY] = mList; for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { - if (!mHwcLayerMap[j] || + if (mHwcLayerMap.IsEmpty() || (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER)) { continue; } @@ -793,6 +793,7 @@ HwcComposer2D::TryRender(Layer* aRoot, gfxMatrix(), aGLWorldTransform)) { + mHwcLayerMap.Clear(); LOGD("Render aborted. Nothing was drawn to the screen"); return false; } From 96c7a686e5defd83ff42724cc0a6a7eeaba632e2 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 16 Jun 2014 13:34:01 -0700 Subject: [PATCH 27/64] Backed out changeset da73c6745a10 (bug 1023670) under suspicion of causing the android bustage CLOSED TREE --- testing/mozbase/mozdevice/mozdevice/devicemanager.py | 10 +--------- testing/mozbase/mozdevice/tests/sut_mkdir.py | 3 --- testing/mozbase/mozdevice/tests/sut_push.py | 1 - 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanager.py b/testing/mozbase/mozdevice/mozdevice/devicemanager.py index 7b5974a2fac3..8a79510599a5 100644 --- a/testing/mozbase/mozdevice/mozdevice/devicemanager.py +++ b/testing/mozbase/mozdevice/mozdevice/devicemanager.py @@ -6,7 +6,6 @@ import hashlib import mozlog import socket import os -import ntpath import posixpath import re import struct @@ -53,13 +52,6 @@ class DeviceManager(object): self._logger = mozlog.getLogger("DeviceManager") self._logLevel = logLevel self._logger.setLevel(logLevel) - self._remoteIsWin = None - - @property - def remoteIsWin(self): - if self._remoteIsWin is None: - self._remoteIsWin = self.getInfo("os")["os"][0] == "windows" - return self._remoteIsWin @property def logLevel(self): @@ -251,7 +243,7 @@ class DeviceManager(object): containing = posixpath.dirname(filename) if not self.dirExists(containing): parts = filename.split('/') - name = "/" if not self.remoteIsWin else parts.pop(0) + name = "/" for part in parts[:-1]: if part != "": name = posixpath.join(name, part) diff --git a/testing/mozbase/mozdevice/tests/sut_mkdir.py b/testing/mozbase/mozdevice/tests/sut_mkdir.py index 85752e9d1ff5..43ab0d251d8c 100644 --- a/testing/mozbase/mozdevice/tests/sut_mkdir.py +++ b/testing/mozbase/mozdevice/tests/sut_mkdir.py @@ -10,7 +10,6 @@ class MkDirsTest(unittest.TestCase): def test_mkdirs(self): subTests = [{'cmds': [('isdir /mnt/sdcard/baz/boop', 'FALSE'), - ('info os', 'android'), ('isdir /mnt', 'TRUE'), ('isdir /mnt/sdcard', 'TRUE'), ('isdir /mnt/sdcard/baz', 'FALSE'), @@ -21,7 +20,6 @@ class MkDirsTest(unittest.TestCase): '/mnt/sdcard/baz/boop successfully created')], 'expectException': False}, {'cmds': [('isdir /mnt/sdcard/baz/boop', 'FALSE'), - ('info os', 'android'), ('isdir /mnt', 'TRUE'), ('isdir /mnt/sdcard', 'TRUE'), ('isdir /mnt/sdcard/baz', 'FALSE'), @@ -50,7 +48,6 @@ class MkDirsTest(unittest.TestCase): """ cmds = [('isdir /mnt/sdcard/foo', 'FALSE'), - ('info os', 'android'), ('isdir /mnt', 'TRUE'), ('isdir /mnt/sdcard', 'TRUE'), ('isdir /mnt/sdcard/foo', 'FALSE'), diff --git a/testing/mozbase/mozdevice/tests/sut_push.py b/testing/mozbase/mozdevice/tests/sut_push.py index 558ed477b338..0eacc163383a 100644 --- a/testing/mozbase/mozdevice/tests/sut_push.py +++ b/testing/mozbase/mozdevice/tests/sut_push.py @@ -57,7 +57,6 @@ class PushTest(unittest.TestCase): "BADHASH") ], 'expectException': True }, { 'cmds': [ ("isdir /mnt/sdcard/baz", "FALSE"), - ('info os', 'android'), ("isdir /mnt", "FALSE"), ("mkdr /mnt", "##AGENT-WARNING## Could not create the directory /mnt") ], From abf9a453515c918cdf7eaa4a1de9cf26544b12b9 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 16 Jun 2014 13:34:50 -0700 Subject: [PATCH 28/64] Backed out 2 changesets (bug 727125) for reftest bustage on an otherwise CLOSED TREE Backed out changeset 443361e2724a (bug 727125) Backed out changeset 16c8d78df86e (bug 727125) --- layout/base/RestyleManager.cpp | 26 +----- layout/base/RestyleManager.h | 3 - layout/base/nsChangeHint.h | 21 ++--- layout/generic/nsLineLayout.cpp | 26 +++--- layout/generic/nsTextFrame.cpp | 90 +++---------------- layout/generic/nsTextFrame.h | 4 +- ...underline-vertical-align-quirks-1-ref.html | 21 ----- ...mic-underline-vertical-align-quirks-1.html | 26 ------ ...underline-vertical-align-quirks-2-ref.html | 21 ----- ...mic-underline-vertical-align-quirks-2.html | 26 ------ ...erline-vertical-align-standards-1-ref.html | 22 ----- ...-underline-vertical-align-standards-1.html | 27 ------ ...erline-vertical-align-standards-2-ref.html | 22 ----- ...-underline-vertical-align-standards-2.html | 27 ------ layout/reftests/text-decoration/reftest.list | 4 - layout/style/nsStyleStruct.h | 4 +- 16 files changed, 38 insertions(+), 332 deletions(-) delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html delete mode 100644 layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 7019d949ea81..883186dc348b 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -513,22 +513,6 @@ RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint) return; } -void -RestyleManager::AddSubtreeToOverflowTracker(nsIFrame* aFrame) -{ - mOverflowChangedTracker.AddFrame( - aFrame, - OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED); - nsIFrame::ChildListIterator lists(aFrame); - for (; !lists.IsDone(); lists.Next()) { - nsFrameList::Enumerator childFrames(lists.CurrentList()); - for (; !childFrames.AtEnd(); childFrames.Next()) { - nsIFrame* child = childFrames.get(); - AddSubtreeToOverflowTracker(child); - } - } -} - NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nullptr) /** @@ -732,7 +716,6 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) StyleChangeReflow(frame, hint); didReflowThisFrame = true; } - if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView | nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer | nsChangeHint_ChildrenOnlyTransform)) { @@ -750,11 +733,7 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) "nsChangeHint_UpdateOverflow should be passed too"); if (!didReflowThisFrame && (hint & (nsChangeHint_UpdateOverflow | - nsChangeHint_UpdatePostTransformOverflow | - nsChangeHint_UpdateSubtreeOverflow))) { - if (hint & nsChangeHint_UpdateSubtreeOverflow) { - AddSubtreeToOverflowTracker(frame); - } + nsChangeHint_UpdatePostTransformOverflow))) { OverflowChangedTracker::ChangeKind changeKind; if (hint & nsChangeHint_ChildrenOnlyTransform) { // The overflow areas of the child frames need to be updated: @@ -790,8 +769,7 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) // If we have both nsChangeHint_UpdateOverflow and // nsChangeHint_UpdatePostTransformOverflow, CHILDREN_AND_PARENT_CHANGED // is selected as it is stronger. - if (hint & (nsChangeHint_UpdateOverflow | - nsChangeHint_UpdateSubtreeOverflow)) { + if (hint & nsChangeHint_UpdateOverflow) { changeKind = OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED; } else { changeKind = OverflowChangedTracker::TRANSFORM_CHANGED; diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index f632e33bba90..027886fb00b1 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -245,9 +245,6 @@ private: void StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint); - // Recursively add all the given frame and all children to the tracker. - void AddSubtreeToOverflowTracker(nsIFrame* aFrame); - // Returns true if this function managed to successfully move a frame, and // false if it could not process the position change, and a reflow should // be performed instead. diff --git a/layout/base/nsChangeHint.h b/layout/base/nsChangeHint.h index 7acc5a2437c4..79d5632a620c 100644 --- a/layout/base/nsChangeHint.h +++ b/layout/base/nsChangeHint.h @@ -72,28 +72,23 @@ enum nsChangeHint { nsChangeHint_ReconstructFrame = 0x400, /** - * The frame's overflow area has changed. Does not update any descendant + * The frame's overflow area has changed, either through a change in its + * transform or a change in its position. Does not update any descendant * frames. */ nsChangeHint_UpdateOverflow = 0x800, - /** - * The overflow area of the frame and all of its descendants has changed. This - * can happen through a text-decoration change. - */ - nsChangeHint_UpdateSubtreeOverflow = 0x1000, - /** * The frame's overflow area has changed, through a change in its transform. * Does not update any descendant frames. */ - nsChangeHint_UpdatePostTransformOverflow = 0x2000, + nsChangeHint_UpdatePostTransformOverflow = 0x1000, /** * The children-only transform of an SVG frame changed, requiring the * overflow rects of the frame's immediate children to be updated. */ - nsChangeHint_ChildrenOnlyTransform = 0x4000, + nsChangeHint_ChildrenOnlyTransform = 0x2000, /** * The frame's offsets have changed, while its dimensions might have @@ -105,7 +100,7 @@ enum nsChangeHint { * nsChangeHint_UpdateOverflow in order to get the overflow areas of * the ancestors updated as well. */ - nsChangeHint_RecomputePosition = 0x8000, + nsChangeHint_RecomputePosition = 0x4000, /** * Behaves like ReconstructFrame, but only if the frame has descendants @@ -113,7 +108,7 @@ enum nsChangeHint { * has changed whether the frame is a container for fixed-pos or abs-pos * elements, but reframing is otherwise not needed. */ - nsChangeHint_AddOrRemoveTransform = 0x10000, + nsChangeHint_AddOrRemoveTransform = 0x8000, /** * This change hint has *no* change handling behavior. However, it @@ -121,13 +116,13 @@ enum nsChangeHint { * changes, and it's inherited by a child, that might require a reflow * due to the border-width change on the child. */ - nsChangeHint_BorderStyleNoneChange = 0x20000, + nsChangeHint_BorderStyleNoneChange = 0x10000, /** * SVG textPath needs to be recomputed because the path has changed. * This means that the glyph positions of the text need to be recomputed. */ - nsChangeHint_UpdateTextPath = 0x40000 + nsChangeHint_UpdateTextPath = 0x20000 // IMPORTANT NOTE: When adding new hints, consider whether you need to // add them to NS_HintsNotHandledForDescendantsIn() below. diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 4784b15895e9..605b164e7ada 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -731,16 +731,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, printf("\n"); #endif - if (mCurrentSpan == mRootSpan) { - pfd->mFrame->Properties().Remove(nsIFrame::LineBaselineOffset()); - } else { -#ifdef DEBUG - bool hasLineOffset; - pfd->mFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &hasLineOffset); - NS_ASSERTION(!hasLineOffset, "LineBaselineOffset was set but was not expected"); -#endif - } - mTextJustificationNumSpaces = 0; mTextJustificationNumLetters = 0; @@ -1462,6 +1452,22 @@ nsLineLayout::BlockDirAlignLine() } PlaceStartEndFrames(psd, -mBStartEdge, lineBSize); + // If the frame being reflowed has text decorations, we simulate the + // propagation of those decorations to a line-level element by storing the + // offset in a frame property on any child frames that are aligned in the + // block direction somewhere other than the baseline. This property is then + // used by nsTextFrame::GetTextDecorations when the same conditions are met. + if (rootPFD.mFrame->StyleContext()->HasTextDecorationLines()) { + for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) { + const nsIFrame *const f = pfd->mFrame; + if (f->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { + const nscoord offset = baselineBCoord - pfd->mBounds.BStart(lineWM); + f->Properties().Set(nsIFrame::LineBaselineOffset(), + NS_INT32_TO_PTR(offset)); + } + } + } + // Fill in returned line-box and max-element-width data mLineBox->SetBounds(lineWM, psd->mIStart, mBStartEdge, diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index aab6d8ba77aa..b692b6cd81c0 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -4620,40 +4620,6 @@ PaintSelectionBackground(gfxContext* aCtx, nsPresContext* aPresContext, } } -// Attempt to get the LineBaselineOffset property of aChildFrame -// If not set, calculate this value for all child frames of aBlockFrame -static nscoord -LazyGetLineBaselineOffset(nsIFrame* aChildFrame, nsBlockFrame* aBlockFrame) -{ - bool offsetFound; - nscoord offset = NS_PTR_TO_INT32( - aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound) - ); - - if (!offsetFound) { - for (nsBlockFrame::line_iterator line = aBlockFrame->begin_lines(), - line_end = aBlockFrame->end_lines(); - line != line_end; line++) { - if (line->IsInline()) { - int32_t n = line->GetChildCount(); - nscoord lineBaseline = line->BStart() + line->GetAscent(); - for (nsIFrame* lineFrame = line->mFirstChild; - n > 0; lineFrame = lineFrame->GetNextSibling(), --n) { - offset = lineBaseline - lineFrame->GetNormalPosition().y; - lineFrame->Properties().Set(nsIFrame::LineBaselineOffset(), - NS_INT32_TO_PTR(offset)); - } - } - } - return NS_PTR_TO_INT32( - aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound) - ); - - } else { - return offset; - } -} - void nsTextFrame::GetTextDecorations( nsPresContext* aPresContext, @@ -4697,8 +4663,7 @@ nsTextFrame::GetTextDecorations( nsLayoutUtils::GetColor(f, eCSSProperty_text_decoration_color); } - nsBlockFrame* fBlock = nsLayoutUtils::GetAsBlock(f); - const bool firstBlock = !nearestBlockFound && fBlock; + const bool firstBlock = !nearestBlockFound && nsLayoutUtils::GetAsBlock(f); // Not updating positions once we hit a parent block is equivalent to // the CSS 2.1 spec that blocks should propagate decorations down to their @@ -4709,15 +4674,13 @@ nsTextFrame::GetTextDecorations( if (firstBlock) { // At this point, fChild can't be null since TextFrames can't be blocks if (fChild->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { - // Since offset is the offset in the child's coordinate space, we have // to undo the accumulation to bring the transform out of the block's // coordinate space - const nscoord lineBaselineOffset = LazyGetLineBaselineOffset(fChild, - fBlock); - baselineOffset = - frameTopOffset - fChild->GetNormalPosition().y - lineBaselineOffset; + frameTopOffset - fChild->GetNormalPosition().y + - NS_PTR_TO_INT32( + fChild->Properties().Get(nsIFrame::LineBaselineOffset())); } } else if (!nearestBlockFound) { @@ -4801,7 +4764,7 @@ GetInflationForTextDecorations(nsIFrame* aFrame, nscoord aInflationMinFontSize) void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, - nsIFrame* aBlock, + const nsHTMLReflowState& aBlockReflowState, PropertyProvider& aProvider, nsRect* aVisualOverflowRect, bool aIncludeTextDecorations) @@ -4814,8 +4777,8 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, if (IsFloatingFirstLetterChild()) { // The underline/overline drawable area must be contained in the overflow // rect when this is in floating first letter frame at *both* modes. - // In this case, aBlock is the ::first-letter frame. - uint8_t decorationStyle = aBlock->StyleContext()-> + nsIFrame* firstLetterFrame = aBlockReflowState.frame; + uint8_t decorationStyle = firstLetterFrame->StyleContext()-> StyleTextReset()->GetDecorationStyle(); // If the style is none, let's include decoration line rect as solid style // since changing the style from none to solid/dotted/dashed doesn't cause @@ -4859,7 +4822,7 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, GetTextDecorations(aPresContext, eResolvedColors, textDecs); if (textDecs.HasDecorationLines()) { nscoord inflationMinFontSize = - nsLayoutUtils::InflationMinFontSizeFor(aBlock); + nsLayoutUtils::InflationMinFontSizeFor(aBlockReflowState.frame); const nscoord width = GetSize().width; const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(), @@ -8044,7 +8007,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, // When we have text decorations, we don't need to compute their overflow now // because we're guaranteed to do it later // (see nsLineLayout::RelativePositionFrames) - UnionAdditionalOverflow(presContext, aLineLayout.LineContainerRS()->frame, + UnionAdditionalOverflow(presContext, *aLineLayout.LineContainerRS(), provider, &aMetrics.VisualOverflow(), false); ///////////////////////////////////////////////////////////////////// @@ -8286,7 +8249,7 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) &provider); nsRect &vis = result.VisualOverflow(); vis.UnionRect(vis, RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent)); - UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider, + UnionAdditionalOverflow(PresContext(), aBlockReflowState, provider, &vis, true); return result; } @@ -8577,36 +8540,3 @@ nsTextFrame::HasAnyNoncollapsedCharacters() int32_t skippedOffsetEnd = iter.ConvertOriginalToSkipped(offsetEnd); return skippedOffset != skippedOffsetEnd; } - -bool -nsTextFrame::UpdateOverflow() -{ - nsRect rect(nsPoint(0, 0), GetSize()); - nsOverflowAreas overflowAreas(rect, rect); - - if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { - return false; - } - gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated); - if (!mTextRun) { - return false; - } - PropertyProvider provider(this, iter, nsTextFrame::eInflated); - provider.InitializeForDisplay(true); - - nsIFrame*decorationsBlock; - if (IsFloatingFirstLetterChild()) { - decorationsBlock = GetParent(); - } else { - for (nsIFrame* f = this; f; f = f->GetParent()) { - nsBlockFrame* fBlock = nsLayoutUtils::GetAsBlock(f); - if (fBlock) { - decorationsBlock = fBlock; - break; - } - } - } - UnionAdditionalOverflow(PresContext(), decorationsBlock, provider, - &overflowAreas.VisualOverflow(), true); - return FinishAndStoreOverflow(overflowAreas, GetSize()); -} diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 5b9575c19245..e7a28d1d981f 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -519,8 +519,6 @@ public: bool IsFloatingFirstLetterChild() const; - virtual bool UpdateOverflow() MOZ_OVERRIDE; - protected: virtual ~nsTextFrame(); @@ -554,7 +552,7 @@ protected: SelectionDetails* GetSelectionDetails(); void UnionAdditionalOverflow(nsPresContext* aPresContext, - nsIFrame* aBlock, + const nsHTMLReflowState& aBlockReflowState, PropertyProvider& aProvider, nsRect* aVisualOverflowRect, bool aIncludeTextDecorations); diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html deleted file mode 100644 index 915f3a7bb8f7..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1-ref.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - -

-This line has a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html deleted file mode 100644 index eccaa3eb17e3..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-1.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - -

-This line has a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html deleted file mode 100644 index 7a1ba472fe5c..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2-ref.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - -

-This line has only a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html deleted file mode 100644 index 52d5c5b62e05..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-quirks-2.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - -

-This line has only a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html deleted file mode 100644 index 01ba4d9b6c96..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1-ref.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -

-This line has a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html deleted file mode 100644 index c285c02466b9..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-1.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - -

-This line has a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html deleted file mode 100644 index fb465cce22b3..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2-ref.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -

-This line has only a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html b/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html deleted file mode 100644 index e48816365a85..000000000000 --- a/layout/reftests/text-decoration/dynamic-underline-vertical-align-standards-2.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - -

-This line has only a bottom vertical align span.
-This line has a top vertical align span. -

- - diff --git a/layout/reftests/text-decoration/reftest.list b/layout/reftests/text-decoration/reftest.list index a737269a2d70..d4d5cca48db3 100644 --- a/layout/reftests/text-decoration/reftest.list +++ b/layout/reftests/text-decoration/reftest.list @@ -4,10 +4,6 @@ skip-if(B2G) == complex-decoration-style-standards.html complex-decoration-style == decoration-color-standards.html decoration-color-standards-ref.html == decoration-style-quirks.html decoration-style-quirks-ref.html == decoration-style-standards.html decoration-style-standards-ref.html -fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-quirks-1.html dynamic-underline-vertical-align-quirks-1-ref.html -fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-1.html dynamic-underline-vertical-align-standards-1-ref.html -fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-quirks-2.html dynamic-underline-vertical-align-quirks-2-ref.html -fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-2.html dynamic-underline-vertical-align-standards-2-ref.html == line-through-style-block-solid-quirks.html line-through-style-block-quirks-ref.html != line-through-style-block-dotted-quirks.html line-through-style-block-quirks-ref.html != line-through-style-block-dashed-quirks.html line-through-style-block-quirks-ref.html diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index f4c4383d9d09..f162bf7a4ca2 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1480,9 +1480,7 @@ struct nsStyleTextReset { nsChangeHint CalcDifference(const nsStyleTextReset& aOther) const; static nsChangeHint MaxDifference() { - return nsChangeHint( - NS_STYLE_HINT_REFLOW | - nsChangeHint_UpdateSubtreeOverflow); + return NS_STYLE_HINT_REFLOW; } static nsChangeHint MaxDifferenceNeverInherited() { // CalcDifference never returns nsChangeHint_NeedReflow or From cea2702a6603a07532cb04b14607042209d93e5e Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 6 Jun 2014 09:51:26 -0400 Subject: [PATCH 29/64] Bug 774388 - Patch 5: Properly manage the lifetime of the compositor thread, by waiting for CrossProcessCompositorParents to die before destroying it - r=nical,mattwoodrow --- gfx/layers/ipc/CompositorParent.cpp | 271 +++++++++++++++++++--------- gfx/layers/ipc/CompositorParent.h | 43 +---- gfx/thebes/gfxPlatform.cpp | 4 +- xpcom/build/nsXPComInit.cpp | 8 +- 4 files changed, 203 insertions(+), 123 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 7657bff023b2..1c2d0abd49e6 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -53,6 +53,8 @@ #include "mozilla/unused.h" #include "mozilla/Hal.h" #include "mozilla/HalTypes.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/Monitor.h" namespace mozilla { namespace layers { @@ -73,64 +75,129 @@ CompositorParent::LayerTreeState::LayerTreeState() typedef map LayerTreeMap; static LayerTreeMap sIndirectLayerTrees; -// FIXME/bug 774386: we're assuming that there's only one -// CompositorParent, but that's not always true. This assumption only -// affects CrossProcessCompositorParent below. -static Thread* sCompositorThread = nullptr; -// manual reference count of the compositor thread. -static int sCompositorThreadRefCount = 0; -static MessageLoop* sMainLoop = nullptr; +/** + * A global map referencing each compositor by ID. + * + * This map is used by the ImageBridge protocol to trigger + * compositions without having to keep references to the + * compositor + */ +typedef map CompositorMap; +static CompositorMap* sCompositorMap; + +static void CreateCompositorMap() +{ + MOZ_ASSERT(!sCompositorMap); + sCompositorMap = new CompositorMap; +} + +static void DestroyCompositorMap() +{ + MOZ_ASSERT(sCompositorMap); + MOZ_ASSERT(sCompositorMap->empty()); + delete sCompositorMap; + sCompositorMap = nullptr; +} // See ImageBridgeChild.cpp void ReleaseImageBridgeParentSingleton(); -static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie) +/* + * CompositorThreadHolder is a singleton class that represents the lifetime + * of the compositor thread. Its constructor creates the compositor thread, + * and its destructor waits for CrossProcessCompositorParent's (CPCPs) to + * be destroyed and then destroys the compositor thread. + * + * The CompositorThreadHolder singleton must be created/destroyed on the main thread. + * CompositorParent's must hold a strong reference to it. + * CrossProcessCompositorParent's (CPCPs) must call + * AddCPCPReference/RemoveCPCPReference to ensure that the compositor thread + * destruction will wait for CPCPs to be destroyed first. + */ +class CompositorThreadHolder MOZ_FINAL { - aNowReadyToDie->Release(); -} + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorThreadHolder) -static void DeleteCompositorThread() -{ - if (NS_IsMainThread()){ - ReleaseImageBridgeParentSingleton(); - delete sCompositorThread; - sCompositorThread = nullptr; - } else { - sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread)); +public: + CompositorThreadHolder() + : mCompositorThread(CreateCompositorThread()) + , mCPCPReferencesMonitor("CompositorThreadHolder CPCP references monitor") + , mCPCPRefCnt(0) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_COUNT_CTOR(CompositorThreadHolder); } -} -static void ReleaseCompositorThread() -{ - if(--sCompositorThreadRefCount == 0) { - DeleteCompositorThread(); + ~CompositorThreadHolder() + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mCPCPRefCnt == 0, "You should have called WaitForCPCPs before!"); + + MOZ_COUNT_DTOR(CompositorThreadHolder); + + DestroyCompositorThread(mCompositorThread); } -} -static void SetThreadPriority() -{ - hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); -} + Thread* GetCompositorThread() const { + return mCompositorThread; + } -void CompositorParent::StartUp() + void WaitForCPCPs() + { + MOZ_ASSERT(NS_IsMainThread()); + MonitorAutoLock autoLock(mCPCPReferencesMonitor); + while(mCPCPRefCnt) { + mCPCPReferencesMonitor.Wait(); + } + } + + void AddCPCPReference() + { + MonitorAutoLock autoLock(mCPCPReferencesMonitor); + mCPCPRefCnt++; + } + + void ReleaseCPCPReference() + { + MOZ_ASSERT(!NS_IsMainThread()); + MonitorAutoLock autoLock(mCPCPReferencesMonitor); + MOZ_ASSERT(mCPCPRefCnt > 0, "dup release"); + mCPCPRefCnt--; + if (mCPCPRefCnt == 0) { + mCPCPReferencesMonitor.NotifyAll(); + } + } + +private: + + Thread* const mCompositorThread; + + /* Everywhere in this class, CPCP is short for CrossProcessCompositorParent. + * mCPCPRefCnt is the number of CPCPs referencing the compositor thread. + * It is not atomic because it is protected behind a monitor, mCPCPReferencesMonitor. + */ + Monitor mCPCPReferencesMonitor; + int mCPCPRefCnt; + + static Thread* CreateCompositorThread(); + static void DestroyCompositorThread(Thread* aCompositorThread); + + friend class CompositorParent; +}; + +static StaticRefPtr sCompositorThreadHolder; + +static MessageLoop* sMainLoop = nullptr; + +/* static */ Thread* +CompositorThreadHolder::CreateCompositorThread() { - CreateCompositorMap(); - CreateThread(); + MOZ_ASSERT(NS_IsMainThread()); sMainLoop = MessageLoop::current(); -} -void CompositorParent::ShutDown() -{ - DestroyThread(); - DestroyCompositorMap(); -} + MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); -bool CompositorParent::CreateThread() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); - MOZ_ASSERT(!sCompositorThread); - sCompositorThreadRefCount = 1; - sCompositorThread = new Thread("Compositor"); + Thread* compositorThread = new Thread("Compositor"); Thread::Options options; /* Timeout values are powers-of-two to enable us get better data. @@ -141,24 +208,64 @@ bool CompositorParent::CreateThread() than the default hang timeout on major platforms (about 5 seconds). */ options.permanent_hang_timeout = 8192; // milliseconds - if (!sCompositorThread->StartWithOptions(options)) { - delete sCompositorThread; - sCompositorThread = nullptr; - return false; + if (!compositorThread->StartWithOptions(options)) { + delete compositorThread; + return nullptr; } - return true; + CreateCompositorMap(); + + return compositorThread; } -void CompositorParent::DestroyThread() +/* static */ void +CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread) { - NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); - ReleaseCompositorThread(); + MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet."); + + if (NS_IsMainThread()) { + DestroyCompositorMap(); + ReleaseImageBridgeParentSingleton(); + delete aCompositorThread; + } else { + sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&CompositorThreadHolder::DestroyCompositorThread, aCompositorThread)); + } +} + +static Thread* CompositorThread() { + return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr; +} + +static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie) +{ + aNowReadyToDie->Release(); +} + +static void SetThreadPriority() +{ + hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); +} + +void CompositorParent::StartUpCompositorThread() +{ + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); + + sCompositorThreadHolder = new CompositorThreadHolder(); +} + +void CompositorParent::ShutDownCompositorThreadWhenCompositorParentsGone() +{ + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!"); + + sCompositorThreadHolder->WaitForCPCPs(); + sCompositorThreadHolder = nullptr; } MessageLoop* CompositorParent::CompositorLoop() { - return sCompositorThread ? sCompositorThread->message_loop() : nullptr; + return CompositorThread() ? CompositorThread()->message_loop() : nullptr; } CompositorParent::CompositorParent(nsIWidget* aWidget, @@ -175,9 +282,10 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, , mResumeCompositionMonitor("ResumeCompositionMonitor") , mOverrideComposeReadiness(false) , mForceCompositionTask(nullptr) + , mCompositorThreadHolder(sCompositorThreadHolder) { - MOZ_ASSERT(sCompositorThread != nullptr, - "The compositor thread must be Initialized before instanciating a CmpositorParent."); + MOZ_ASSERT(CompositorThread(), + "The compositor thread must be Initialized before instanciating a CompositorParent."); MOZ_COUNT_CTOR(CompositorParent); mCompositorID = 0; // FIXME: This holds on the the fact that right now the only thing that @@ -192,13 +300,12 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, sIndirectLayerTrees[mRootLayerTreeID].mParent = this; mApzcTreeManager = new APZCTreeManager(); - ++sCompositorThreadRefCount; } bool CompositorParent::IsInCompositorThread() { - return sCompositorThread && sCompositorThread->thread_id() == PlatformThread::CurrentId(); + return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId(); } uint64_t @@ -210,8 +317,6 @@ CompositorParent::RootLayerTreeId() CompositorParent::~CompositorParent() { MOZ_COUNT_DTOR(CompositorParent); - - ReleaseCompositorThread(); } void @@ -919,27 +1024,6 @@ CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor) return true; } - -typedef map CompositorMap; -static CompositorMap* sCompositorMap; - -void CompositorParent::CreateCompositorMap() -{ - if (sCompositorMap == nullptr) { - sCompositorMap = new CompositorMap; - } -} - -void CompositorParent::DestroyCompositorMap() -{ - if (sCompositorMap != nullptr) { - NS_ASSERTION(sCompositorMap->empty(), - "The Compositor map should be empty when destroyed>"); - delete sCompositorMap; - sCompositorMap = nullptr; - } -} - CompositorParent* CompositorParent::GetCompositor(uint64_t id) { CompositorMap::iterator it = sCompositorMap->find(id); @@ -1142,6 +1226,24 @@ private: Transport* mTransport; // Child side's process Id. base::ProcessId mChildProcessId; + + struct ScopedCompositorThreadReference + { + ScopedCompositorThreadReference() + { + MOZ_ASSERT(sCompositorThreadHolder); + sCompositorThreadHolder->AddCPCPReference(); + } + + ~ScopedCompositorThreadReference() + { + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(sCompositorThreadHolder); + sCompositorThreadHolder->ReleaseCPCPReference(); + } + }; + + ScopedCompositorThreadReference mCompositorThreadReference; }; void @@ -1173,6 +1275,8 @@ OpenCompositor(CrossProcessCompositorParent* aCompositor, /*static*/ PCompositorParent* CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess) { + gfxPlatform::InitLayersIPC(); + nsRefPtr cpcp = new CrossProcessCompositorParent(aTransport, aOtherProcess); ProcessHandle handle; @@ -1404,15 +1508,14 @@ CrossProcessCompositorParent::DeferredDestroy() CrossProcessCompositorParent* self; mSelfRef.forget(&self); - nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release); - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + MOZ_ASSERT(XRE_GetIOMessageLoop()); + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, + NewRunnableMethod(self, &CrossProcessCompositorParent::Release)); } CrossProcessCompositorParent::~CrossProcessCompositorParent() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(mTransport)); + delete mTransport; } IToplevelProtocol* diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index de41299ef887..c4189913edb9 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -63,6 +63,8 @@ private: uint64_t mLayersId; }; +class CompositorThreadHolder; + class CompositorParent : public PCompositorParent, public ShadowLayersManager { @@ -163,12 +165,15 @@ public: /** * Creates the compositor thread and the global compositor map. */ - static void StartUp(); + static void StartUpCompositorThread(); /** - * Destroys the compositor thread and the global compositor map. + * Drops the static reference to the compositor thread holder, + * and wait for CrossProcessCompositorParent's to be gone, + * allowing the compositor thread shutdown to occur + * as soon as CompositorParent's will be gone. */ - static void ShutDown(); + static void ShutDownCompositorThreadWhenCompositorParentsGone(); /** * Allocate an ID that can be used to refer to a layer tree and @@ -259,36 +264,6 @@ protected: void ForceComposition(); void CancelCurrentCompositeTask(); - /** - * Creates a global map referencing each compositor by ID. - * - * This map is used by the ImageBridge protocol to trigger - * compositions without having to keep references to the - * compositor - */ - static void CreateCompositorMap(); - static void DestroyCompositorMap(); - - /** - * Creates the compositor thread. - * - * All compositors live on the same thread. - * The thread is not lazily created on first access to avoid dealing with - * thread safety. Therefore it's best to create and destroy the thread when - * we know we areb't using it (So creating/destroying along with gfxPlatform - * looks like a good place). - */ - static bool CreateThread(); - - /** - * Destroys the compositor thread. - * - * It is safe to call this fucntion more than once, although the second call - * will have no effect. - * This function is not thread-safe. - */ - static void DestroyThread(); - /** * Add a compositor to the global compositor map. */ @@ -336,6 +311,8 @@ protected: nsRefPtr mApzcTreeManager; + const nsRefPtr mCompositorThreadHolder; + DISALLOW_EVIL_CONSTRUCTORS(CompositorParent); }; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 757e0390295c..3d1a24399c07 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -512,7 +512,7 @@ gfxPlatform::InitLayersIPC() if (UsesOffMainThreadCompositing() && XRE_GetProcessType() == GeckoProcessType_Default) { - mozilla::layers::CompositorParent::StartUp(); + mozilla::layers::CompositorParent::StartUpCompositorThread(); if (gfxPrefs::AsyncVideoEnabled()) { mozilla::layers::ImageBridgeChild::StartUp(); } @@ -540,7 +540,7 @@ gfxPlatform::ShutdownLayersIPC() layers::SharedBufferManagerChild::ShutDown(); #endif - layers::CompositorParent::ShutDown(); + layers::CompositorParent::ShutDownCompositorThreadWhenCompositorParentsGone(); } } diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 5e7f997e0ebe..05f6647a41bb 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -799,17 +799,17 @@ ShutdownXPCOM(nsIServiceManager* servMgr) } } + // This must happen after the shutdown of media and widgets, which + // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. NS_ProcessPendingEvents(thread); + gfxPlatform::ShutdownLayersIPC(); + mozilla::scache::StartupCache::DeleteSingleton(); if (observerService) (void) observerService-> NotifyObservers(nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, nullptr); - // This must happen after the shutdown of media and widgets, which - // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. - gfxPlatform::ShutdownLayersIPC(); - gXPCOMThreadsShutDown = true; NS_ProcessPendingEvents(thread); From 5ccfab68a1abc667ce6a1130d56b8e530770619e Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 17 Jun 2014 07:15:16 +0900 Subject: [PATCH 30/64] Bug 1025469 - Bump NSS version configure checks for. r=bsmith --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 1ab79d050e8c..c7c400411247 100644 --- a/configure.in +++ b/configure.in @@ -3589,7 +3589,7 @@ MOZ_ARG_WITH_BOOL(system-nss, _USE_SYSTEM_NSS=1 ) if test -n "$_USE_SYSTEM_NSS"; then - AM_PATH_NSS(3.16, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])]) + AM_PATH_NSS(3.16.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])]) fi if test -n "$MOZ_NATIVE_NSS"; then From 2ccaed991adaa01b4338dd682ff2fd4fc2ddcb5a Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 17 Jun 2014 07:15:36 +0900 Subject: [PATCH 31/64] Bug 1025576 - Fix crash in TSymbolTableLevel::~TSymbolTableLevel with GCC 4.9. r=bjacob --- gfx/angle/README.mozilla | 3 +++ gfx/angle/angle-fix-issue-651.patch | 27 ++++++++++++++++++++++++++ gfx/angle/src/compiler/SymbolTable.cpp | 3 ++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 gfx/angle/angle-fix-issue-651.patch diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla index acb2338c19d6..717430bd692a 100644 --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -60,6 +60,9 @@ In this order: angle-d3dcc47.patch: Tell ANGLE about d3dcompiler_47.dll from WinSDK 8.1. + angle-fix-issue-651.patch: + Fixes crash in TSymbolTableLevel::~TSymbolTableLevel with GCC 4.9 + In addition to these patches, the Makefile.in and moz.build build files are ours, they're not present in upsteam ANGLE. Therefore, changes made to the build files should not be stored in the local .patch files. diff --git a/gfx/angle/angle-fix-issue-651.patch b/gfx/angle/angle-fix-issue-651.patch new file mode 100644 index 000000000000..efd37adf663a --- /dev/null +++ b/gfx/angle/angle-fix-issue-651.patch @@ -0,0 +1,27 @@ +Fix for https://code.google.com/p/angleproject/issues/detail?id=651 + +See https://bugzilla.mozilla.org/show_bug.cgi?id=1025576 for details. + +diff --git a/gfx/angle/src/compiler/SymbolTable.cpp b/gfx/angle/src/compiler/SymbolTable.cpp +--- a/gfx/angle/src/compiler/SymbolTable.cpp ++++ b/gfx/angle/src/compiler/SymbolTable.cpp +@@ -166,17 +166,18 @@ TFunction::~TFunction() + } + + // + // Symbol table levels are a map of pointers to symbols that have to be deleted. + // + TSymbolTableLevel::~TSymbolTableLevel() + { + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) +- delete (*it).second; ++ if ((*it).first == (*it).second->getMangledName()) ++ delete (*it).second; + } + + // + // Change all function entries in the table with the non-mangled name + // to be related to the provided built-in operation. This is a low + // performance operation, and only intended for symbol tables that + // live across a large number of compiles. + // diff --git a/gfx/angle/src/compiler/SymbolTable.cpp b/gfx/angle/src/compiler/SymbolTable.cpp index 51180aff663d..42e8998c5ee3 100644 --- a/gfx/angle/src/compiler/SymbolTable.cpp +++ b/gfx/angle/src/compiler/SymbolTable.cpp @@ -171,7 +171,8 @@ TFunction::~TFunction() TSymbolTableLevel::~TSymbolTableLevel() { for (tLevel::iterator it = level.begin(); it != level.end(); ++it) - delete (*it).second; + if ((*it).first == (*it).second->getMangledName()) + delete (*it).second; } // From 6d4f99fdba3052780de509d1ab5baf1b882c8f95 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 6 Jun 2014 09:51:27 -0400 Subject: [PATCH 32/64] Bug 774388 - Patch 6: fix a silly double negation - r=nical --- gfx/layers/ipc/CompositorParent.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 1c2d0abd49e6..e23113ed9aec 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -789,7 +789,9 @@ CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const nsIntRect* aRe bool CompositorParent::CanComposite() { - return !(mPaused || !mLayerManager || !mLayerManager->GetRoot()); + return mLayerManager && + mLayerManager->GetRoot() && + !mPaused; } // Go down the composite layer tree, setting properties to match their From d84b1105f445d576220be34621aadb147b628949 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 16 Jun 2014 15:18:57 -0700 Subject: [PATCH 33/64] Bug 960786: SpiderMonkey should provide an introspection API for memory heap analysis (ubi::Node) r=sfink --- js/public/UbiNode.h | 462 ++++++++++++++++++ js/public/UbiNodeTraverse.h | 208 ++++++++ js/src/builtin/TestingFunctions.cpp | 230 +++++++++ .../jit-test/tests/heap-analysis/findPath.js | 44 ++ js/src/jsapi-tests/testIntTypesABI.cpp | 1 + js/src/moz.build | 3 + js/src/tests/js1_8_5/extensions/shell.js | 16 + js/src/vm/UbiNode.cpp | 226 +++++++++ 8 files changed, 1190 insertions(+) create mode 100644 js/public/UbiNode.h create mode 100644 js/public/UbiNodeTraverse.h create mode 100644 js/src/jit-test/tests/heap-analysis/findPath.js create mode 100644 js/src/vm/UbiNode.cpp diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h new file mode 100644 index 000000000000..d2acc2e24289 --- /dev/null +++ b/js/public/UbiNode.h @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 js_UbiNode_h +#define js_UbiNode_h + +#include "mozilla/Alignment.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" + +#include "jspubtd.h" + +#include "js/GCAPI.h" +#include "js/HashTable.h" +#include "js/TypeDecls.h" + +// JS::ubi::Node +// +// JS::ubi::Node is a pointer-like type designed for internal use by heap +// analysis tools. A ubi::Node can refer to: +// +// - a JS value, like a string or object; +// - an internal SpiderMonkey structure, like a shape or a scope chain object +// - an instance of some embedding-provided type: in Firefox, an XPCOM +// object, or an internal DOM node class instance +// +// A ubi::Node instance provides metadata about its referent, and can +// enumerate its referent's outgoing edges, so you can implement heap analysis +// algorithms that walk the graph - finding paths between objects, or +// computing heap dominator trees, say - using ubi::Node, while remaining +// ignorant of the details of the types you're operating on. +// +// Of course, when it comes to presenting the results in a developer-facing +// tool, you'll need to stop being ignorant of those details, because you have +// to discuss the ubi::Nodes' referents with the developer. Here, ubi::Node +// can hand you dynamically checked, properly typed pointers to the original +// objects via the as method, or generate descriptions of the referent +// itself. +// +// ubi::Node instances are lightweight (two-word) value types. Instances: +// - compare equal if and only if they refer to the same object; +// - have hash values that respect their equality relation; and +// - have serializations that are only equal if the ubi::Nodes are equal. +// +// A ubi::Node is only valid for as long as its referent is alive; if its +// referent goes away, the ubi::Node becomes a dangling pointer. A ubi::Node +// that refers to a GC-managed object is not automatically a GC root; if the +// GC frees or relocates its referent, the ubi::Node becomes invalid. A +// ubi::Node that refers to a reference-counted object does not bump the +// reference count. +// +// ubi::Node values require no supporting data structures, making them +// feasible for use in memory-constrained devices --- ideally, the memory +// requirements of the algorithm which uses them will be the limiting factor, +// not the demands of ubi::Node itself. +// +// One can construct a ubi::Node value given a pointer to a type that ubi::Node +// supports. In the other direction, one can convert a ubi::Node back to a +// pointer; these downcasts are checked dynamically. In particular, one can +// convert a 'JSRuntime *' to a ubi::Node, yielding a node with an outgoing edge +// for every root registered with the runtime; starting from this, one can walk +// the entire heap. (Of course, one could also start traversal at any other kind +// of type to which one has a pointer.) +// +// +// Extending ubi::Node To Handle Your Embedding's Types +// +// To add support for a new ubi::Node referent type R, you must define a +// specialization of the ubi::Concrete template, ubi::Concrete, which +// inherits from ubi::Base. ubi::Node itself uses the specialization for +// compile-time information (i.e. the checked conversions between R * and +// ubi::Node), and the inheritance for run-time dispatching. +// +// +// ubi::Node Exposes Implementation Details +// +// In many cases, a JavaScript developer's view of their data differs +// substantially from its actual implementation. For example, while the +// ECMAScript specification describes objects as maps from property names to +// sets of attributes (like ECMAScript's [[Value]]), in practice many objects +// have only a pointer to a shape, shared with other similar objects, and +// indexed slots that contain the [[Value]] attributes. As another example, a +// string produced by concatenating two other strings may sometimes be +// represented by a "rope", a structure that points to the two original +// strings. +// + +// We intend to use ubi::Node to write tools that report memory usage, so it's +// important that ubi::Node accurately portray how much memory nodes consume. +// Thus, for example, when data that apparently belongs to multiple nodes is +// in fact shared in a common structure, ubi::Node's graph uses a separate +// node for that shared structure, and presents edges to it from the data's +// apparent owners. For example, ubi::Node exposes SpiderMonkey objects' +// shapes and base shapes, and exposes rope string and substring structure, +// because these optimizations become visible when a tool reports how much +// memory a structure consumes. +// +// However, fine granularity is not a goal. When a particular object is the +// exclusive owner of a separate block of memory, ubi::Node may present the +// object and its block as a single node, and add their sizes together when +// reporting the node's size, as there is no meaningful loss of data in this +// case. Thus, for example, a ubi::Node referring to a JavaScript object, when +// asked for the object's size in bytes, includes the object's slot and +// element arrays' sizes in the total. There is no separate ubi::Node value +// representing the slot and element arrays, since they are owned exclusively +// by the object. +// +// +// Presenting Analysis Results To JavaScript Developers +// +// If an analysis provides its results in terms of ubi::Node values, a user +// interface presenting those results will generally need to clean them up +// before they can be understood by JavaScript developers. For example, +// JavaScript developers should not need to understand shapes, only JavaScript +// objects. Similarly, they should not need to understand the distinction +// between DOM nodes and the JavaScript shadow objects that represent them. +// +// +// Rooting Restrictions +// +// At present there is no way to root ubi::Node instances, so instances can't be +// live across any operation that might GC. Analyses using ubi::Node must either +// run to completion and convert their results to some other rootable type, or +// save their intermediate state in some rooted structure if they must GC before +// they complete. (For algorithms like path-finding and dominator tree +// computation, we implement the algorithm avoiding any operation that could +// cause a GC --- and use AutoCheckCannotGC to verify this.) +// +// If this restriction prevents us from implementing interesting tools, we may +// teach the GC how to root ubi::Nodes, fix up hash tables that use them as +// keys, etc. + + +// Forward declarations of SpiderMonkey's ubi::Node reference types. +namespace js { +class LazyScript; +class Shape; +class BaseShape; +namespace jit { +class JitCode; +} +namespace types { +struct TypeObject; +} +} + + +namespace JS { +namespace ubi { + +class Edge; +class EdgeRange; + +// The base class implemented by each ubi::Node referent type. Subclasses must +// not add data members to this class. +class Base { + friend class Node; + + // For performance's sake, we'd prefer to avoid a virtual destructor; and + // an empty constructor seems consistent with the 'lightweight value type' + // visible behavior we're trying to achieve. But if the destructor isn't + // virtual, and a subclass overrides it, the subclass's destructor will be + // ignored. Is there a way to make the compiler catch that error? + + protected: + // Space for the actual pointer. Concrete subclasses should define a + // properly typed 'get' member function to access this. + void *ptr; + + Base(void *ptr) : ptr(ptr) { } + + public: + bool operator==(const Base &rhs) const { + // Some compilers will indeed place objects of different types at + // the same address, so technically, we should include the vtable + // in this comparison. But it seems unlikely to cause problems in + // practice. + return ptr == rhs.ptr; + } + bool operator!=(const Base &rhs) const { return !(*this == rhs); } + + // Return a human-readable name for the referent's type. The result should + // be statically allocated. (You can use MOZ_UTF16("strings") for this.) + // + // This must always return Concrete::concreteTypeName; we use that + // pointer as a tag for this particular referent type. + virtual const jschar *typeName() const = 0; + + // Return the size of this node, in bytes. Include any structures that this + // node owns exclusively that are not exposed as their own ubi::Nodes. + virtual size_t size() const = 0; + + // Return an EdgeRange that initially contains all the referent's outgoing + // edges. The EdgeRange should be freed with 'js_delete'. (You could use + // ScopedDJSeletePtr to manage it.) On OOM, report an exception + // on |cx| and return nullptr. + virtual EdgeRange *edges(JSContext *cx) const = 0; + + private: + Base(const Base &rhs) MOZ_DELETE; + Base &operator=(const Base &rhs) MOZ_DELETE; +}; + +// A traits template with a specialization for each referent type that +// ubi::Node supports. The specialization must be the concrete subclass of +// Base that represents a pointer to the referent type. It must also +// include the members described here. +template +struct Concrete { + // The specific jschar array returned by Concrete::typeName. + static const jschar concreteTypeName[]; + + // Construct an instance of this concrete class in |storage| referring + // to |referent|. Implementations typically use a placement 'new'. + // + // In some cases, |referent| will contain dynamic type information that + // identifies it a some more specific subclass of |Referent|. For example, + // when |Referent| is |JSObject|, then |referent->getClass()| could tell us + // that it's actually a JSFunction. Similarly, if |Referent| is + // |nsISupports|, we would like a ubi::Node that knows its final + // implementation type. + // + // So, we delegate the actual construction to this specialization, which + // knows Referent's details. + static void construct(void *storage, Referent *referent); +}; + +// A container for a Base instance; all members simply forward to the contained instance. +// This container allows us to pass ubi::Node instances by value. +class Node { + // Storage in which we allocate Base subclasses. + mozilla::AlignedStorage2 storage; + Base *base() { return storage.addr(); } + const Base *base() const { return storage.addr(); } + + template + void construct(T *ptr) { + static_assert(sizeof(Concrete) == sizeof(*base()), + "ubi::Base specializations must be the same size as ubi::Base"); + Concrete::construct(base(), ptr); + } + + typedef void (Node::* ConvertibleToBool)(); + void nonNull() {} + + public: + Node() { construct(nullptr); } + + template + Node(T *ptr) { + construct(ptr); + } + template + Node &operator=(T *ptr) { + construct(ptr); + return *this; + } + + // We can construct and assign from rooted forms of pointers. + template + Node(const Rooted &root) { + construct(root.get()); + } + template + Node &operator=(const Rooted &root) { + construct(root.get()); + return *this; + } + + // Constructors accepting SpiderMonkey's other generic-pointer-ish types. + Node(JS::Value value); + Node(JSGCTraceKind kind, void *ptr); + + // copy construction and copy assignment just use memcpy, since we know + // instances contain nothing but a vtable pointer and a data pointer. + // + // To be completely correct, concrete classes could provide a virtual + // 'construct' member function, which we could invoke on rhs to construct an + // instance in our storage. But this is good enough; there's no need to jump + // through vtables for copying and assignment that are just going to move + // two words around. The compiler knows how to optimize memcpy. + Node(const Node &rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + } + + Node &operator=(const Node &rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + return *this; + } + + bool operator==(const Node &rhs) const { return *base() == *rhs.base(); } + bool operator!=(const Node &rhs) const { return *base() != *rhs.base(); } + + operator ConvertibleToBool() const { + return base()->ptr ? &Node::nonNull : 0; + } + + template + bool is() const { + return base()->typeName() == Concrete::concreteTypeName; + } + + template + T *as() const { + MOZ_ASSERT(is()); + return static_cast(base()->ptr); + } + + template + T *asOrNull() const { + return is() ? static_cast(base()->ptr) : nullptr; + } + + // If this node refers to something that can be represented as a + // JavaScript value that is safe to expose to JavaScript code, return that + // value. Otherwise return UndefinedValue(). JSStrings and some (but not + // all!) JSObjects can be exposed. + JS::Value exposeToJS() const; + + const jschar *typeName() const { return base()->typeName(); } + size_t size() const { return base()->size(); } + EdgeRange *edges(JSContext *cx) const { return base()->edges(cx); } + + // A hash policy for ubi::Nodes. + // This simply uses the stock PointerHasher on the ubi::Node's pointer. + // We specialize DefaultHasher below to make this the default. + class HashPolicy { + typedef js::PointerHasher::value> PtrHash; + + public: + typedef Node Lookup; + + static js::HashNumber hash(const Lookup &l) { return PtrHash::hash(l.base()->ptr); } + static bool match(const Node &k, const Lookup &l) { return k == l; } + static void rekey(Node &k, const Node &newKey) { k = newKey; } + }; +}; + + +// Edge is the abstract base class representing an outgoing edge of a node. +// Edges are owned by EdgeRanges, and need not have assignment operators or copy +// constructors. +// +// Each Edge class should inherit from this base class, overriding as +// appropriate. +class Edge { + protected: + Edge() : name(nullptr), referent() { } + virtual ~Edge() { } + + public: + // This edge's name. + // + // The storage is owned by this Edge, and will be freed when this Edge is + // destructed. + // + // (In real life we'll want a better representation for names, to avoid + // creating tons of strings when the names follow a pattern; and we'll need + // to think about lifetimes carefully to ensure traversal stays cheap.) + const jschar *name; + + // This edge's referent. + Node referent; + + private: + Edge(const Edge &) MOZ_DELETE; + Edge &operator=(const Edge &) MOZ_DELETE; +}; + + +// EdgeRange is an abstract base class for iterating over a node's outgoing +// edges. (This is modeled after js::HashTable::Range.) +// +// Concrete instances of this class need not be as lightweight as Node itself, +// since they're usually only instantiated while iterating over a particular +// object's edges. For example, a dumb implementation for JS Cells might use +// JS_TraceChildren to to get the outgoing edges, and then store them in an +// array internal to the EdgeRange. +class EdgeRange { + protected: + // The current front edge of this range, or nullptr if this range is empty. + Edge *front_; + + EdgeRange() : front_(nullptr) { } + + public: + virtual ~EdgeRange() { }; + + // True if there are no more edges in this range. + bool empty() const { return !front_; } + + // The front edge of this range. This is owned by the EdgeRange, and is + // only guaranteed to live until the next call to popFront, or until + // the EdgeRange is destructed. + const Edge &front() { return *front_; } + + // Remove the front edge from this range. This should only be called if + // !empty(). + virtual void popFront() = 0; + + private: + EdgeRange(const EdgeRange &) MOZ_DELETE; + EdgeRange &operator=(const EdgeRange &) MOZ_DELETE; +}; + + +// Concrete classes for ubi::Node referent types. + +// A reusable ubi::Concrete specialization base class for types supported by +// JS_TraceChildren. +template +class TracerConcrete : public Base { + const jschar *typeName() const MOZ_OVERRIDE { return concreteTypeName; } + size_t size() const MOZ_OVERRIDE { return 0; } // not implemented yet; bug 1011300 + EdgeRange *edges(JSContext *) const MOZ_OVERRIDE; + + TracerConcrete(Referent *ptr) : Base(ptr) { } + + public: + static const jschar concreteTypeName[]; + static void construct(void *storage, Referent *ptr) { new (storage) TracerConcrete(ptr); }; +}; + +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; + +// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts. +template<> +class Concrete : public Base { + const jschar *typeName() const MOZ_OVERRIDE; + size_t size() const MOZ_OVERRIDE; + EdgeRange *edges(JSContext *cx) const MOZ_OVERRIDE; + + Concrete(void *ptr) : Base(ptr) { } + + public: + static void construct(void *storage, void *ptr) { new (storage) Concrete(ptr); } + static const jschar concreteTypeName[]; +}; + + +} // namespace ubi +} // namespace JS + +namespace js { + +// Make ubi::Node::HashPolicy the default hash policy for ubi::Node. +template<> struct DefaultHasher : JS::ubi::Node::HashPolicy { }; + +} // namespace js + +#endif // js_UbiNode_h diff --git a/js/public/UbiNodeTraverse.h b/js/public/UbiNodeTraverse.h new file mode 100644 index 000000000000..6072cbc489c2 --- /dev/null +++ b/js/public/UbiNodeTraverse.h @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 js_UbiNodeTraverse_h +#define js_UbiNodeTraverse_h + +#include "js/UbiNode.h" +#include "js/Utility.h" +#include "js/Vector.h" + +namespace JS { +namespace ubi { + +// A breadth-first traversal template for graphs of ubi::Nodes. +// +// No GC may occur while an instance of this template is live. +// +// The provided Handler type should have two members: +// +// typename NodeData; +// +// The value type of |BreadthFirst::visited|, the HashMap of +// ubi::Nodes that have been visited so far. Since the algorithm needs a +// hash table like this for its own use anyway, it is simple to let +// Handler store its own metadata about each node in the same table. +// +// For example, if you want to find a shortest path to each node from any +// traversal starting point, your |NodeData| type could record the first +// edge to reach each node, and the node from which it originates. Then, +// when the traversal is complete, you can walk backwards from any node +// to some starting point, and the path recorded will be a shortest path. +// +// This type must have a default constructor. If this type owns any other +// resources, move constructors and assignment operators are probably a +// good idea, too. +// +// bool operator() (BreadthFirst &traversal, +// Node origin, const Edge &edge, +// Handler::NodeData *referentData, bool first); +// +// The visitor function, called to report that we have traversed +// |edge| from |origin|. This is called once for each edge we traverse. +// As this is a breadth-first search, any prior calls to the visitor function +// were for origin nodes not further from the start nodes than |origin|. +// +// |traversal| is this traversal object, passed along for convenience. +// +// |referentData| is a pointer to the value of the entry in +// |traversal.visited| for |edge.referent|; the visitor function can +// store whatever metadata it likes about |edge.referent| there. +// +// |first| is true if this is the first time we have visited an edge +// leading to |edge.referent|. This could be stored in NodeData, but +// the algorithm knows whether it has just created the entry in +// |traversal.visited|, so it passes it along for convenience. +// +// The visitor function may call |traversal.stop()| if it doesn't want +// to visit any more nodes. +// +// The visitor function may consult |traversal.visited| for information +// about other nodes, but it should not add or remove entries. +// +// The visitor function should return true on success, or false if an +// error occurs. A false return value terminates the traversal +// immediately, and causes BreadthFirst::traverse to return +// false. +template +struct BreadthFirst { + + // Construct a breadth-first traversal object that reports the nodes it + // reaches to |handler|. The traversal object reports OOM on |cx|, and + // asserts that no GC happens in |cx|'s runtime during its lifetime. + // + // We do nothing with noGC, other than require it to exist, with a lifetime + // that encloses our own. + BreadthFirst(JSContext *cx, Handler &handler, const JS::AutoCheckCannotGC &noGC) + : cx(cx), visited(cx), handler(handler), pending(cx), + traversalBegun(false), stopRequested(false) + { } + + // Initialize this traversal object. Return false on OOM. + bool init() { return visited.init(); } + + // Add |node| as a starting point for the traversal. You may add + // as many starting points as you like. Return false on OOM. + bool addStart(Node node) { return pending.append(node); } + + // Traverse the graph in breadth-first order, starting at the given + // start nodes, applying |handler::operator()| for each edge traversed + // as described above. + // + // This should be called only once per instance of this class. + // + // Return false on OOM or error return from |handler::operator()|. + bool traverse() + { + MOZ_ASSERT(!traversalBegun); + traversalBegun = true; + + // While there are pending nodes, visit them, until we've found a path to the target. + while (!pending.empty()) { + Node origin = pending.front(); + pending.popFront(); + + // Get a range containing all origin's outgoing edges. + js::ScopedJSDeletePtr range(origin.edges(cx)); + if (!range) + return false; + + // Traverse each edge. + for (; !range->empty(); range->popFront()) { + MOZ_ASSERT(!stopRequested); + + const Edge &edge = range->front(); + typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); + bool first = !a; + + if (first) { + // This is the first time we've reached |edge.referent|. + // Create an entry for it in |visited|, and arrange to + // traverse its outgoing edges later. + if (!visited.add(a, edge.referent, typename Handler::NodeData()) || + !pending.append(edge.referent)) { + return false; + } + } + + MOZ_ASSERT(a); + + // Report this edge to the visitor function. + if (!handler(*this, origin, edge, &a->value(), first)) + return false; + + if (stopRequested) + return true; + } + } + + return true; + } + + // Stop traversal, and return true from |traverse| without visiting any + // more nodes. Only |handler::operator()| should call this function; it + // may do so to stop the traversal early, without returning false and + // then making |traverse|'s caller disambiguate that result from a real + // error. + void stop() { stopRequested = true; } + + // The context with which we were constructed. + JSContext *cx; + + // A map associating each node N that we have reached with a + // Handler::NodeData, for |handler|'s use. This is public, so that + // |handler| can access it to see the traversal thus far. + typedef js::HashMap NodeMap; + NodeMap visited; + + private: + // Our handler object. + Handler &handler; + + // A queue template. Appending and popping the front are constant time. + // Wasted space is never more than some recent actual population plus the + // current population. + template + class Queue { + js::Vector head, tail; + size_t frontIndex; + public: + Queue(JSContext *cx) : head(cx), tail(cx), frontIndex(0) { } + bool empty() { return frontIndex >= head.length(); } + T &front() { + MOZ_ASSERT(!empty()); + return head[frontIndex]; + } + void popFront() { + MOZ_ASSERT(!empty()); + frontIndex++; + if (frontIndex >= head.length()) { + head.clearAndFree(); + head.swap(tail); + frontIndex = 0; + } + } + bool append(const T &elt) { + return frontIndex == 0 ? head.append(elt) : tail.append(elt); + } + }; + + // A queue of nodes that we have reached, but whose outgoing edges we + // have not yet traversed. Nodes reachable in fewer edges are enqueued + // earlier. + Queue pending; + + // True if our traverse function has been called. + bool traversalBegun; + + // True if we've been asked to stop the traversal. + bool stopRequested; +}; + +} // namespace ubi +} // namespace JS + +#endif // js_UbiNodeTraverse.h diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index e61f83e49c8d..e3c8866e58c4 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -6,6 +6,9 @@ #include "builtin/TestingFunctions.h" +#include "mozilla/Move.h" +#include "mozilla/Scoped.h" + #include "jsapi.h" #include "jscntxt.h" #include "jsfriendapi.h" @@ -18,7 +21,11 @@ #include "jit/AsmJS.h" #include "jit/AsmJSLink.h" +#include "js/HashTable.h" #include "js/StructuredClone.h" +#include "js/UbiNode.h" +#include "js/UbiNodeTraverse.h" +#include "js/Vector.h" #include "vm/ForkJoin.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" @@ -33,6 +40,8 @@ using namespace js; using namespace JS; using mozilla::ArrayLength; +using mozilla::Move; +using mozilla::ScopedFreePtr; // If fuzzingSafe is set, remove functionality that could cause problems with // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE. @@ -1651,6 +1660,214 @@ ReportLargeAllocationFailure(JSContext *cx, unsigned argc, jsval *vp) return true; } +namespace heaptools { + +// An edge to a node from its predecessor in a path through the graph. +class BackEdge { + // The node from which this edge starts. + JS::ubi::Node predecessor_; + + // The name of this edge. We own this storage. + ScopedFreePtr name_; + + public: + BackEdge() : name_(nullptr) { } + // Construct an initialized back edge. Take ownership of |name|. + BackEdge(JS::ubi::Node predecessor, jschar *name) + : predecessor_(predecessor), name_(name) { } + BackEdge(BackEdge &&rhs) : predecessor_(rhs.predecessor_), name_(rhs.name_.forget()) { } + BackEdge &operator=(BackEdge &&rhs) { + MOZ_ASSERT(&rhs != this); + this->~BackEdge(); + new(this) BackEdge(Move(rhs)); + return *this; + } + + jschar *forgetName() { return name_.forget(); } + JS::ubi::Node predecessor() const { return predecessor_; } + + private: + // No copy constructor or copying assignment. + BackEdge(const BackEdge &) MOZ_DELETE; + BackEdge &operator=(const BackEdge &) MOZ_DELETE; +}; + +// A path-finding handler class for use with JS::ubi::BreadthFirst. +struct FindPathHandler { + typedef BackEdge NodeData; + typedef JS::ubi::BreadthFirst Traversal; + + FindPathHandler(JS::ubi::Node start, JS::ubi::Node target, + AutoValueVector &nodes, Vector > &edges) + : start(start), target(target), foundPath(false), + nodes(nodes), edges(edges) { } + + bool + operator()(Traversal &traversal, JS::ubi::Node origin, const JS::ubi::Edge &edge, + BackEdge *backEdge, bool first) + { + // We take care of each node the first time we visit it, so there's + // nothing to be done on subsequent visits. + if (!first) + return true; + + // Record how we reached this node. This is the last edge on a + // shortest path to this node. + jschar *edgeName = js_strdup(traversal.cx, edge.name); + if (!edgeName) + return false; + *backEdge = mozilla::Move(BackEdge(origin, edgeName)); + + // Have we reached our final target node? + if (edge.referent == target) { + // Record the path that got us here, which must be a shortest path. + if (!recordPath(traversal)) + return false; + foundPath = true; + traversal.stop(); + } + + return true; + } + + // We've found a path to our target. Walk the backlinks to produce the + // (reversed) path, saving the path in |nodes| and |edges|. |nodes| is + // rooted, so it can hold the path's nodes as we leave the scope of + // the AutoCheckCannotGC. + bool recordPath(Traversal &traversal) { + JS::ubi::Node here = target; + + do { + Traversal::NodeMap::Ptr p = traversal.visited.lookup(here); + MOZ_ASSERT(p); + JS::ubi::Node predecessor = p->value().predecessor(); + if (!nodes.append(predecessor.exposeToJS()) || + !edges.append(p->value().forgetName())) + return false; + here = predecessor; + } while (here != start); + + return true; + } + + // The node we're starting from. + JS::ubi::Node start; + + // The node we're looking for. + JS::ubi::Node target; + + // True if we found a path to target, false if we didn't. + bool foundPath; + + // The nodes and edges of the path --- should we find one. The path is + // stored in reverse order, because that's how it's easiest for us to + // construct it: + // - edges[i] is the name of the edge from nodes[i] to nodes[i-1]. + // - edges[0] is the name of the edge from nodes[0] to the target. + // - The last node, nodes[n-1], is the start node. + AutoValueVector &nodes; + Vector > &edges; +}; + +} // namespace heaptools + +static bool +FindPath(JSContext *cx, unsigned argc, jsval *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (argc < 2) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, + "findPath", "1", ""); + return false; + } + + // We don't ToString non-objects given as 'start' or 'target'. We can't + // see edges to non-string primitive values, and it doesn't make much + // sense to ask for paths to or from a freshly allocated string, so + // if a non-string primitive appears here it's probably a mistake. + if (!args[0].isObject() && !args[0].isString()) { + js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, + JSDVG_SEARCH_STACK, args[0], JS::NullPtr(), + "neither an object nor a string", NULL); + return false; + } + + if (!args[1].isObject() && !args[1].isString()) { + js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, + JSDVG_SEARCH_STACK, args[0], JS::NullPtr(), + "neither an object nor a string", NULL); + return false; + } + + AutoValueVector nodes(cx); + Vector > edges(cx); + + { + // We can't tolerate the GC moving things around while we're searching + // the heap. Check that nothing we do causes a GC. + JS::AutoCheckCannotGC autoCannotGC; + + JS::ubi::Node start(args[0]), target(args[1]); + + heaptools::FindPathHandler handler(start, target, nodes, edges); + heaptools::FindPathHandler::Traversal traversal(cx, handler, autoCannotGC); + if (!traversal.init() || !traversal.addStart(start)) + return false; + + if (!traversal.traverse()) + return false; + + if (!handler.foundPath) { + // We didn't find any paths from the start to the target. + args.rval().setUndefined(); + return true; + } + } + + // |nodes| and |edges| contain the path from |start| to |target|, reversed. + // Construct a JavaScript array describing the path from the start to the + // target. Each element has the form: + // + // { node: , edge: } + // + // or, if the node is some internal thing, that isn't a proper + // JavaScript value: + // + // { node: undefined, edge: } + size_t length = nodes.length(); + RootedObject result(cx, NewDenseAllocatedArray(cx, length)); + if (!result) + return false; + result->ensureDenseInitializedLength(cx, 0, length); + + // Walk |nodes| and |edges| in the stored order, and construct the result + // array in start-to-target order. + for (size_t i = 0; i < length; i++) { + // Build an object describing the node and edge. + RootedObject obj(cx, NewBuiltinClassInstance(cx)); + if (!obj) + return false; + + if (!JS_DefineProperty(cx, obj, "node", nodes[i], + JSPROP_ENUMERATE, nullptr, nullptr)) + return false; + + RootedString edge(cx, js_NewString(cx, edges[i].get(), js_strlen(edges[i]))); + if (!edge) + return false; + edges[i].forget(); + RootedValue edgeString(cx, StringValue(edge)); + if (!JS_DefineProperty(cx, obj, "edge", edgeString, + JSPROP_ENUMERATE, nullptr, nullptr)) + return false; + + result->setDenseElement(length - i - 1, ObjectValue(*obj)); + } + + args.rval().setObject(*result); + return true; +} + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'compartment')", @@ -1931,6 +2148,19 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " then return undefined. In Gecko, this sends a memory pressure notification, which\n" " can free up some memory."), + JS_FN_HELP("findPath", FindPath, 2, 0, +"findPath(start, target)", +" Return an array describing one of the shortest paths of GC heap edges from\n" +" |start| to |target|, or |undefined| if |target| is unreachable from |start|.\n" +" Each element of the array is either of the form:\n" +" { node: , edge: }\n" +" if the node is a JavaScript object or value; or of the form:\n" +" { type: , edge: }\n" +" if the node is some internal thing that is not a proper JavaScript value\n" +" (like a shape or a scope chain element). The destination of the i'th array\n" +" element's edge is the node of the i+1'th array element; the destination of\n" +" the last array element is implicitly |target|.\n"), + #ifdef DEBUG JS_FN_HELP("dumpObject", DumpObject, 1, 0, "dumpObject()", diff --git a/js/src/jit-test/tests/heap-analysis/findPath.js b/js/src/jit-test/tests/heap-analysis/findPath.js new file mode 100644 index 000000000000..ede2363e8d58 --- /dev/null +++ b/js/src/jit-test/tests/heap-analysis/findPath.js @@ -0,0 +1,44 @@ +load(libdir + "match.js") + +// At the moment, findPath just returns the names as provided by ubi::Node, +// which just uses JS_TraceChildren for now. However, we have various plans +// to improve the quality of ubi::Node's metadata, to improve the precision +// and clarity of the results here. + +var o = { w: { x: { y: { z: {} } } } }; +Match.Pattern([{node: {}, edge: "w"}, + {node: {}, edge: "x"}, + {node: {}, edge: "y"}, + {node: {}, edge: "z"}]) + .assert(findPath(o, o.w.x.y.z)); +print(uneval(findPath(o, o.w.x.y.z))); + +var a = [ , o ]; +Match.Pattern([{node: {}, edge: "objectElements[1]"}]) + .assert(findPath(a, o)); +print(uneval(findPath(a, o))); + +function C() {} +C.prototype.obj = {}; +var c = new C; +Match.Pattern([{node: {}, edge: "type"}, + {node: Match.Pattern.ANY, edge: "type_proto"}, + {node: { constructor: Match.Pattern.ANY }, edge: "obj"}]) + .assert(findPath(c, c.obj)); +print(uneval(findPath(c, c.obj))); + +function f(x) { return function g(y) { return x+y; }; } +var o = {} +var gc = f(o); +Match.Pattern([{node: gc, edge: "fun_callscope"}, + {node: Match.Pattern.ANY, edge: "x"}]) + .assert(findPath(gc, o)); +print(uneval(findPath(gc, o))); + +Match.Pattern([{node: {}, edge: "shape"}, + {node: Match.Pattern.ANY, edge: "base"}, + {node: Match.Pattern.ANY, edge: "parent"}, + {node: {}, edge: "o"}]) + .assert(findPath(o, o)); +print(findPath(o, o).map((e) => e.edge).toString()); + diff --git a/js/src/jsapi-tests/testIntTypesABI.cpp b/js/src/jsapi-tests/testIntTypesABI.cpp index f1cf3d87468b..f63de81b1fd2 100644 --- a/js/src/jsapi-tests/testIntTypesABI.cpp +++ b/js/src/jsapi-tests/testIntTypesABI.cpp @@ -34,6 +34,7 @@ #include "js/StructuredClone.h" #include "js/TracingAPI.h" #include "js/TypeDecls.h" +#include "js/UbiNode.h" #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" diff --git a/js/src/moz.build b/js/src/moz.build index 3e055b02c620..bedb6c75d6d1 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -86,6 +86,8 @@ EXPORTS.js += [ '../public/StructuredClone.h', '../public/TracingAPI.h', '../public/TypeDecls.h', + '../public/UbiNode.h', + '../public/UbiNodeTraverse.h', '../public/Utility.h', '../public/Value.h', '../public/Vector.h', @@ -191,6 +193,7 @@ UNIFIED_SOURCES += [ 'vm/StructuredClone.cpp', 'vm/ThreadPool.cpp', 'vm/TypedArrayObject.cpp', + 'vm/UbiNode.cpp', 'vm/Unicode.cpp', 'vm/Value.cpp', 'vm/WeakMapPtr.cpp', diff --git a/js/src/tests/js1_8_5/extensions/shell.js b/js/src/tests/js1_8_5/extensions/shell.js index c4312881a195..56a78dae5931 100644 --- a/js/src/tests/js1_8_5/extensions/shell.js +++ b/js/src/tests/js1_8_5/extensions/shell.js @@ -83,6 +83,10 @@ var Match = return (x !== null) && (typeof x === "object"); } + function isFunction(x) { + return typeof x === "function"; + } + function isArrayLike(x) { return isObject(x) && ("length" in x); } @@ -134,6 +138,15 @@ var Match = return true; } + function matchFunction(act, exp) { + if (!isFunction(act)) + throw new MatchError("expected function, got " + quote(act)); + + if (act !== exp) + throw new MatchError("expected function: " + exp + + "\nbut got different function: " + act); + } + function matchArray(act, exp) { if (!isObject(act) || !("length" in act)) throw new MatchError("expected array-like object, got " + quote(act)); @@ -166,6 +179,9 @@ var Match = if (isArrayLike(exp)) return matchArray(act, exp); + if (isFunction(exp)) + return matchFunction(act, exp); + return matchObject(act, exp); } diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp new file mode 100644 index 000000000000..95a79ae91fcc --- /dev/null +++ b/js/src/vm/UbiNode.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 "js/UbiNode.h" + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Scoped.h" + +#include "jscntxt.h" + +#include "js/TracingAPI.h" +#include "js/TypeDecls.h" +#include "js/Utility.h" +#include "js/Vector.h" +#include "vm/ScopeObject.h" + +#include "jsobjinlines.h" + +using JS::Value; +using JS::ubi::Concrete; +using JS::ubi::Edge; +using JS::ubi::EdgeRange; +using JS::ubi::Node; +using JS::ubi::TracerConcrete; + +// All operations on null ubi::Nodes assert. +const jschar *Concrete::typeName() const { MOZ_ASSUME_UNREACHABLE("null ubi::Node"); } +size_t Concrete::size() const { MOZ_ASSUME_UNREACHABLE("null ubi::Node"); } +EdgeRange *Concrete::edges(JSContext *) const { MOZ_ASSUME_UNREACHABLE("null ubi::Node"); } + + +Node::Node(JSGCTraceKind kind, void *ptr) +{ + switch (kind) { + case JSTRACE_OBJECT: construct(static_cast(ptr)); break; + case JSTRACE_STRING: construct(static_cast(ptr)); break; + case JSTRACE_SCRIPT: construct(static_cast(ptr)); break; + case JSTRACE_LAZY_SCRIPT: construct(static_cast(ptr)); break; + case JSTRACE_JITCODE: construct(static_cast(ptr)); break; + case JSTRACE_SHAPE: construct(static_cast(ptr)); break; + case JSTRACE_BASE_SHAPE: construct(static_cast(ptr)); break; + case JSTRACE_TYPE_OBJECT: construct(static_cast(ptr)); break; + + default: + MOZ_ASSUME_UNREACHABLE("bad JSGCTraceKind passed to JS::ubi::Node::Node"); + } +} + + +Node::Node(Value value) +{ + if (value.isObject()) + construct(&value.toObject()); + else if (value.isString()) + construct(value.toString()); + else + construct(nullptr); +} + +Value +Node::exposeToJS() const +{ + Value v; + + if (is()) { + JSObject &obj = *as(); + if (obj.is()) { + v.setUndefined(); + } else if (obj.is() && IsInternalFunctionObject(&obj)) { + v.setUndefined(); + } else { + v.setObject(obj); + } + } else if (is()) { + v.setString(as()); + } else { + v.setUndefined(); + } + + return v; +} + +// A dumb Edge concrete class. All but the most essential members have the +// default behavior. +class SimpleEdge : public Edge { + SimpleEdge(SimpleEdge &) MOZ_DELETE; + SimpleEdge &operator=(const SimpleEdge &) MOZ_DELETE; + + public: + SimpleEdge() : Edge() { } + + // Construct an initialized SimpleEdge, taking ownership of |name|. + SimpleEdge(jschar *name, const Node &referent) { + this->name = name; + this->referent = referent; + } + ~SimpleEdge() { + js_free(const_cast(name)); + } + + // Move construction and assignment. + SimpleEdge(SimpleEdge &&rhs) { + name = rhs.name; + referent = rhs.referent; + + rhs.name = nullptr; + } + SimpleEdge &operator=(SimpleEdge &&rhs) { + MOZ_ASSERT(&rhs != this); + this->~SimpleEdge(); + new(this) SimpleEdge(mozilla::Move(rhs)); + return *this; + } +}; + + +typedef mozilla::Vector SimpleEdgeVector; + + +// A JSTracer subclass that adds a SimpleEdge to a Vector for each edge on +// which it is invoked. +class SimpleEdgeVectorTracer : public JSTracer { + // The vector to which we add SimpleEdges. + SimpleEdgeVector *vec; + + static void staticCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) { + static_cast(trc)->callback(thingp, kind); + } + + void callback(void **thingp, JSGCTraceKind kind) { + if (!okay) + return; + + // Ask the tracer to compute an edge name for us. + char buffer[1024]; + const char *name = getTracingEdgeName(buffer, sizeof(buffer)); + + // Convert the name to jschars. + jschar *jsname = js_pod_malloc(strlen(name) + 1); + if (!jsname) { + okay = false; + return; + } + + size_t i; + for (i = 0; name[i]; i++) + jsname[i] = name[i]; + jsname[i] = '\0'; + + // The simplest code is correct! The temporary SimpleEdge takes + // ownership of name; if the append succeeds, the vector element + // then takes ownership; if the append fails, then the temporary + // retains it, and its destructor will free it. + if (!vec->append(mozilla::Move(SimpleEdge(jsname, Node(kind, *thingp))))) { + okay = false; + return; + } + } + + public: + // True if no errors (OOM, say) have yet occurred. + bool okay; + + SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec) + : JSTracer(JS_GetRuntime(cx), staticCallback), vec(vec), okay(true) { + } +}; + + +// An EdgeRange concrete class that simply holds a vector of SimpleEdges, +// populated by the init method. +class SimpleEdgeRange : public EdgeRange { + SimpleEdgeVector edges; + size_t i; + + void settle() { + front_ = i < edges.length() ? &edges[i] : nullptr; + } + + public: + SimpleEdgeRange(JSContext *cx) : edges(cx), i(0) { } + + bool init(JSContext *cx, void *thing, JSGCTraceKind kind) { + SimpleEdgeVectorTracer tracer(cx, &edges); + JS_TraceChildren(&tracer, thing, kind); + settle(); + return tracer.okay; + } + + void popFront() MOZ_OVERRIDE { i++; settle(); } +}; + + +template +EdgeRange * +TracerConcrete::edges(JSContext *cx) const { + js::ScopedJSDeletePtr r(js_new(cx)); + if (!r) + return nullptr; + + if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind::kind)) + return nullptr; + + return r.forget(); +} + +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("JSObject"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("JSString"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("JSScript"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("js::LazyScript"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("js::jit::JitCode"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("js::Shape"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("js::BaseShape"); +template<> const jschar TracerConcrete::concreteTypeName[] = + MOZ_UTF16("js::types::TypeObject"); From 8d64d57e4f2aa86c20756abfd4b56577c8d76a4c Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 16 Jun 2014 18:17:47 -0400 Subject: [PATCH 34/64] Bug 1025393 - Enable building webrtc with clang-cl; r=jesup --HG-- extra : rebase_source : 16c3846d3a31b71e4ba3f9e4214c1ef8ff6a03e4 --- media/webrtc/trunk/webrtc/common_audio/common_audio.gyp | 6 +++++- .../webrtc/modules/audio_processing/audio_processing.gypi | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp b/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp index af0391817865..9c09be288e8b 100644 --- a/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp +++ b/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp @@ -155,7 +155,11 @@ 'resampler/sinc_resampler_sse.cc', ], 'cflags': ['-msse2',], - 'cflags_mozilla': ['-msse2',], + 'conditions': [ + [ 'os_posix == 1', { + 'cflags_mozilla': ['-msse2',], + }], + ], 'xcode_settings': { 'OTHER_CFLAGS': ['-msse2',], }, diff --git a/media/webrtc/trunk/webrtc/modules/audio_processing/audio_processing.gypi b/media/webrtc/trunk/webrtc/modules/audio_processing/audio_processing.gypi index 0eff063dd954..d22687544d24 100644 --- a/media/webrtc/trunk/webrtc/modules/audio_processing/audio_processing.gypi +++ b/media/webrtc/trunk/webrtc/modules/audio_processing/audio_processing.gypi @@ -174,7 +174,11 @@ 'aec/aec_rdft_sse2.c', ], 'cflags': ['-msse2',], - 'cflags_mozilla': [ '-msse2', ], + 'conditions': [ + [ 'os_posix == 1', { + 'cflags_mozilla': ['-msse2',], + }], + ], 'xcode_settings': { 'OTHER_CFLAGS': ['-msse2',], }, From c2cbd699a1df78c3b2e636acb4f920382ff5ffba Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 16 Jun 2014 18:19:49 -0400 Subject: [PATCH 35/64] Bug 1025900 - #include intrin.h directly in Atomics.h instead of declaring functions manually from it; r=froydnj This is basically more of bug 1022049. --HG-- extra : rebase_source : 39cf2745d47d90ba1684c2c26a38f9781a4d179e --- mfbt/Atomics.h | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/mfbt/Atomics.h b/mfbt/Atomics.h index fcf86a63fe53..d2b571885c8a 100644 --- a/mfbt/Atomics.h +++ b/mfbt/Atomics.h @@ -514,19 +514,9 @@ struct AtomicIntrinsics : public IntrinsicMemoryOps, * version of Windows we support. Therefore, we only provide operations * on 32-bit datatypes for 32-bit Windows versions; for 64-bit Windows * versions, we support 64-bit datatypes as well. - * - * To avoid namespace pollution issues, we declare whatever functions we - * need ourselves. */ -extern "C" { -long __cdecl _InterlockedExchangeAdd(long volatile* aDst, long aVal); -long __cdecl _InterlockedOr(long volatile* aDst, long aVal); -long __cdecl _InterlockedXor(long volatile* aDst, long aVal); -long __cdecl _InterlockedAnd(long volatile* aDst, long aVal); -long __cdecl _InterlockedExchange(long volatile *aDst, long aVal); -long __cdecl _InterlockedCompareExchange(long volatile *aDst, long aNewVal, long aOldVal); -} +# include # pragma intrinsic(_InterlockedExchangeAdd) # pragma intrinsic(_InterlockedOr) @@ -639,22 +629,6 @@ struct PrimitiveIntrinsics<4> # if defined(_M_X64) -extern "C" { -long long __cdecl _InterlockedExchangeAdd64(long long volatile* aDst, - long long aVal); -long long __cdecl _InterlockedOr64(long long volatile* aDst, - long long aVal); -long long __cdecl _InterlockedXor64(long long volatile* aDst, - long long aVal); -long long __cdecl _InterlockedAnd64(long long volatile* aDst, - long long aVal); -long long __cdecl _InterlockedExchange64(long long volatile* aDst, - long long aVal); -long long __cdecl _InterlockedCompareExchange64(long long volatile* aDst, - long long aNewVal, - long long aOldVal); -} - # pragma intrinsic(_InterlockedExchangeAdd64) # pragma intrinsic(_InterlockedOr64) # pragma intrinsic(_InterlockedXor64) @@ -713,8 +687,6 @@ struct PrimitiveIntrinsics<8> # endif -extern "C" { void _ReadWriteBarrier(); } - # pragma intrinsic(_ReadWriteBarrier) template struct Barrier; From ced60d7954ccda947dfbfbf2e1bb8bd30dcb1f63 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 16 Jun 2014 18:25:43 -0400 Subject: [PATCH 36/64] Bug 1024166 - Misc header/namespace cleanups in imglib, r=seth --- gfx/gl/GLTextureImage.cpp | 1 + gfx/layers/Layers.cpp | 1 + image/public/imgIContainer.idl | 8 +------- image/src/RasterImage.cpp | 12 ++++++------ image/src/RasterImage.h | 14 +++++++------- image/src/SurfaceCache.cpp | 1 - image/src/imgFrame.cpp | 1 - image/src/imgFrame.h | 4 ++-- widget/cocoa/nsDragService.mm | 1 + 9 files changed, 19 insertions(+), 24 deletions(-) diff --git a/gfx/gl/GLTextureImage.cpp b/gfx/gl/GLTextureImage.cpp index 721781c2e35c..368969b758b2 100644 --- a/gfx/gl/GLTextureImage.cpp +++ b/gfx/gl/GLTextureImage.cpp @@ -9,6 +9,7 @@ #include "gfxPlatform.h" #include "gfxUtils.h" #include "gfx2DGlue.h" +#include "gfxImageSurface.h" #include "ScopedGLHelpers.h" #include "GLUploadHelpers.h" diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 0182999d4248..265212d6f6b1 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -17,6 +17,7 @@ #include "gfxPlatform.h" // for gfxPlatform #include "gfxUtils.h" // for gfxUtils, etc #include "gfx2DGlue.h" +#include "gfxImageSurface.h" #include "mozilla/DebugOnly.h" // for DebugOnly #include "mozilla/Telemetry.h" // for Accumulate #include "mozilla/gfx/2D.h" // for DrawTarget diff --git a/image/public/imgIContainer.idl b/image/public/imgIContainer.idl index 2ee0ce4a4aae..f8b7b4be9712 100644 --- a/image/public/imgIContainer.idl +++ b/image/public/imgIContainer.idl @@ -7,12 +7,10 @@ #include "nsISupports.idl" %{C++ -#include "gfxImageSurface.h" #include "gfxContext.h" #include "gfxMatrix.h" #include "gfxRect.h" #include "GraphicsFilter.h" -#include "gfxASurface.h" #include "mozilla/gfx/2D.h" #include "mozilla/RefPtr.h" #include "nsRect.h" @@ -41,9 +39,6 @@ class Orientation; %} -[ptr] native gfxImageSurface(gfxImageSurface); -[ptr] native gfxASurface(gfxASurface); -native gfxImageFormat(gfxASurface::gfxImageFormat); [ptr] native gfxContext(gfxContext); [ref] native gfxMatrix(gfxMatrix); [ref] native gfxRect(gfxRect); @@ -176,8 +171,7 @@ interface imgIContainer : nsISupports /** * Get a surface for the given frame. This may be a platform-native, * optimized surface, so you cannot inspect its pixel data. If you - * need that, use gfxASurface::GetAsReadableARGB32ImageSurface or - * gfxASurface::CopyToARGB32ImageSurface. + * need that, use SourceSurface::GetDataSurface. * * @param aWhichFrame Frame specifier of the FRAME_* variety. * @param aFlags Flags of the FLAG_* variety diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index fb91a677e649..d2ebf5c03cd7 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -346,9 +346,9 @@ public: ScaleRequest* request = mScaleRequest; if (!request->stopped) { - request->done = mozilla::gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride, - request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride, - request->srcFormat); + request->done = gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride, + request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride, + request->srcFormat); } else { request->done = false; } @@ -535,7 +535,7 @@ RasterImage::Init(const char* aMimeType, //****************************************************************************** // [notxpcom] void requestRefresh ([const] in TimeStamp aTime); NS_IMETHODIMP_(void) -RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime) +RasterImage::RequestRefresh(const TimeStamp& aTime) { if (HadRecentRefresh(aTime)) { return; @@ -1568,7 +1568,7 @@ RasterImage::ResetAnimation() //****************************************************************************** // [notxpcom] void setAnimationStartTime ([const] in TimeStamp aTime); NS_IMETHODIMP_(void) -RasterImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime) +RasterImage::SetAnimationStartTime(const TimeStamp& aTime) { if (mError || mAnimationMode == kDontAnimMode || mAnimating || !mAnim) return; @@ -3232,7 +3232,7 @@ RasterImage::DecodePool::DecodePool() } #endif - nsCOMPtr obsSvc = mozilla::services::GetObserverService(); + nsCOMPtr obsSvc = services::GetObserverService(); if (obsSvc) { obsSvc->AddObserver(this, "xpcom-shutdown-threads", false); } diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index a96d4b2ea620..bfbc8c94b947 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -176,8 +176,8 @@ public: /* The total number of frames in this image. */ uint32_t GetNumFrames() const; - virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const; - virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const; + virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const; + virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const; virtual size_t NonHeapSizeOfDecoded() const; virtual size_t OutOfProcessSizeOfDecoded() const; @@ -497,7 +497,7 @@ private: // mThreadPoolMutex protects mThreadPool. For all RasterImages R, // R::mDecodingMonitor must be acquired before mThreadPoolMutex // if both are acquired; the other order may cause deadlock. - mozilla::Mutex mThreadPoolMutex; + Mutex mThreadPoolMutex; nsCOMPtr mThreadPool; }; @@ -577,7 +577,7 @@ private: uint32_t GetCurrentImgFrameIndex() const; size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, - mozilla::MallocSizeOf aMallocSizeOf) const; + MallocSizeOf aMallocSizeOf) const; void EnsureAnimExists(); @@ -660,10 +660,10 @@ private: // data int mRequestedSampleSize; // Cached value for GetImageContainer. - nsRefPtr mImageContainer; + nsRefPtr mImageContainer; // If not cached in mImageContainer, this might have our image container - WeakPtr mImageContainerCache; + WeakPtr mImageContainerCache; #ifdef DEBUG uint32_t mFramesNotified; @@ -673,7 +673,7 @@ private: // data // at once, and hence need to be locked by mDecodingMonitor. // BEGIN LOCKED MEMBER VARIABLES - mozilla::ReentrantMonitor mDecodingMonitor; + ReentrantMonitor mDecodingMonitor; FallibleTArray mSourceData; diff --git a/image/src/SurfaceCache.cpp b/image/src/SurfaceCache.cpp index 93aa8eea2449..d89925b66779 100644 --- a/image/src/SurfaceCache.cpp +++ b/image/src/SurfaceCache.cpp @@ -17,7 +17,6 @@ #include "mozilla/StaticPtr.h" #include "nsIMemoryReporter.h" #include "gfx2DGlue.h" -#include "gfxASurface.h" #include "gfxPattern.h" // Workaround for flaw in bug 921753 part 2. #include "gfxDrawable.h" #include "gfxPlatform.h" diff --git a/image/src/imgFrame.cpp b/image/src/imgFrame.cpp index 19e1745cc73b..72c786b358f3 100644 --- a/image/src/imgFrame.cpp +++ b/image/src/imgFrame.cpp @@ -16,7 +16,6 @@ static bool gDisableOptimize = false; -#include "cairo.h" #include "GeckoProfiler.h" #include "mozilla/Likely.h" #include "mozilla/MemoryReporting.h" diff --git a/image/src/imgFrame.h b/image/src/imgFrame.h index cd8a96cff0ee..cd88d69b6b28 100644 --- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -25,7 +25,7 @@ public: imgFrame(); ~imgFrame(); - nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, mozilla::gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth = 0); + nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, SurfaceFormat aFormat, uint8_t aPaletteDepth = 0); nsresult Optimize(); bool Draw(gfxContext *aContext, GraphicsFilter aFilter, @@ -36,7 +36,7 @@ public: nsresult ImageUpdated(const nsIntRect &aUpdateRect); nsIntRect GetRect() const; - mozilla::gfx::SurfaceFormat GetFormat() const; + SurfaceFormat GetFormat() const; bool GetNeedsBackground() const; uint32_t GetImageBytesPerRow() const; uint32_t GetImageDataLength() const; diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm index 5b669e472685..fcb93112a25f 100644 --- a/widget/cocoa/nsDragService.mm +++ b/widget/cocoa/nsDragService.mm @@ -31,6 +31,7 @@ #include "nsCocoaUtils.h" #include "mozilla/gfx/2D.h" #include "gfxPlatform.h" +#include "gfxImageSurface.h" using namespace mozilla; using namespace mozilla::gfx; From 57bf9f52dde5d129ab363264f55c39ebe7a9a664 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 12 Jun 2014 11:34:35 -0400 Subject: [PATCH 37/64] Bug 1024148 - Part 1: Merge nsDisplayOpacity items together. r=mattwoodrow --HG-- extra : rebase_source : f461cb97357c854db22122b40777358a17f736ec --- layout/base/nsDisplayList.cpp | 28 +++++++++++++++++++++------- layout/base/nsDisplayList.h | 6 ++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 5c0e7ca35cbc..38850444d661 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3274,7 +3274,8 @@ nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder, nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) - : nsDisplayWrapList(aBuilder, aFrame, aList) { + : nsDisplayWrapList(aBuilder, aFrame, aList) + , mOpacity(aFrame->StyleDisplay()->mOpacity) { MOZ_COUNT_CTOR(nsDisplayOpacity); } @@ -3287,8 +3288,9 @@ nsDisplayOpacity::~nsDisplayOpacity() { nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) { *aSnap = false; - // We are never opaque, if our opacity was < 1 then we wouldn't have - // been created. + // The only time where mOpacity == 1.0 should be when we have will-change. + // We could report this as opaque then but when the will-change value starts + // animating the element would become non opaque and could cause repaints. return nsRegion(); } @@ -3297,7 +3299,7 @@ already_AddRefed nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) { - if (mFrame->StyleDisplay()->mOpacity == 0 && mFrame->GetContent() && + if (mOpacity == 0 && mFrame->GetContent() && !nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) { return nullptr; } @@ -3307,7 +3309,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, if (!container) return nullptr; - container->SetOpacity(mFrame->StyleDisplay()->mOpacity); + container->SetOpacity(mOpacity); nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder, this, mFrame, eCSSProperty_opacity); @@ -3344,6 +3346,18 @@ nsDisplayOpacity::NeedsActiveLayer() return false; } +bool +nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) +{ + mOpacity = mOpacity * aOpacity; + if (aClip) { + IntersectClip(aBuilder, *aClip); + } + return true; +} + bool nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) { @@ -3358,7 +3372,7 @@ nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) return false; } - return child->ApplyOpacity(aBuilder, mFrame->StyleDisplay()->mOpacity, mClip); + return child->ApplyOpacity(aBuilder, mOpacity, mClip); } nsDisplayItem::LayerState @@ -3408,7 +3422,7 @@ bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* a void nsDisplayOpacity::WriteDebugInfo(nsACString& aTo) { - aTo += nsPrintfCString(" (opacity %f)", mFrame->StyleDisplay()->mOpacity); + aTo += nsPrintfCString(" (opacity %f)", mOpacity); } #endif diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 844c70e61858..90303394067e 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2747,6 +2747,9 @@ public: { // We don't need to compute an invalidation region since we have LayerTreeInvalidation } + virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) MOZ_OVERRIDE; virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; bool NeedsActiveLayer(); NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY) @@ -2755,6 +2758,9 @@ public: #endif bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; + +private: + float mOpacity; }; class nsDisplayMixBlendMode : public nsDisplayWrapList { From 99cc55b9f2209280e75147d3d54796cc1c524ec5 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Sat, 14 Jun 2014 11:10:45 -0400 Subject: [PATCH 38/64] Bug 1024148 - Part 2: Merge nsDisplayOpacity into nsDisplayBackgroundColor. r=mattwoodrow --HG-- extra : rebase_source : c48cc799414ff83b74caff8df5503a743dbf74b1 --- gfx/src/nsColor.h | 4 ++++ layout/base/nsCSSRendering.cpp | 20 +++++++++-------- layout/base/nsCSSRendering.h | 8 ++++--- layout/base/nsDisplayList.cpp | 30 ++++++++++++++++++-------- layout/base/nsDisplayList.h | 20 ++++++++++++----- layout/reftests/bugs/759036-1-ref.html | 2 +- layout/reftests/bugs/759036-1.html | 2 +- layout/reftests/bugs/reftest.list | 4 ++-- 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/gfx/src/nsColor.h b/gfx/src/nsColor.h index a93fabcba0be..ca6603fc32fa 100644 --- a/gfx/src/nsColor.h +++ b/gfx/src/nsColor.h @@ -29,6 +29,10 @@ typedef uint32_t nscolor; #define NS_RGBA(_r,_g,_b,_a) \ ((nscolor) (((_a) << 24) | ((_b)<<16) | ((_g)<<8) | (_r))) +// Make a color out of a gfxRGBA. +#define NS_RGBA_FROM_GFXRGBA(gfxColor) \ + ((nscolor) (gfxColor.Packed())) + // Extract color components from nscolor #define NS_GET_R(_rgba) ((uint8_t) ((_rgba) & 0xff)) #define NS_GET_G(_rgba) ((uint8_t) (((_rgba) >> 8) & 0xff)) diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 8fb055ce99af..1f0524beef2e 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -1602,7 +1602,8 @@ nsCSSRendering::PaintBackground(nsPresContext* aPresContext, } void -nsCSSRendering::PaintBackgroundColor(nsPresContext* aPresContext, +nsCSSRendering::PaintBackgroundColor(gfxRGBA aColor, + nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aDirtyRect, @@ -1634,7 +1635,7 @@ nsCSSRendering::PaintBackgroundColor(nsPresContext* aPresContext, sc = aForFrame->StyleContext(); } - PaintBackgroundColorWithSC(aPresContext, aRenderingContext, aForFrame, + PaintBackgroundColorWithSC(aColor, aPresContext, aRenderingContext, aForFrame, aDirtyRect, aBorderArea, sc, *aForFrame->StyleBorder(), aFlags); } @@ -2873,7 +2874,8 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext, } void -nsCSSRendering::PaintBackgroundColorWithSC(nsPresContext* aPresContext, +nsCSSRendering::PaintBackgroundColorWithSC(gfxRGBA aColor, + nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aDirtyRect, @@ -2903,11 +2905,11 @@ nsCSSRendering::PaintBackgroundColorWithSC(nsPresContext* aPresContext, // background colors. bool drawBackgroundImage; bool drawBackgroundColor; - nscolor bgColor = DetermineBackgroundColor(aPresContext, - aBackgroundSC, - aForFrame, - drawBackgroundImage, - drawBackgroundColor); + DetermineBackgroundColor(aPresContext, + aBackgroundSC, + aForFrame, + drawBackgroundImage, + drawBackgroundColor); NS_ASSERTION(drawBackgroundImage || drawBackgroundColor, "Should not be trying to paint a background if we don't have one"); @@ -2951,7 +2953,7 @@ nsCSSRendering::PaintBackgroundColorWithSC(nsPresContext* aPresContext, aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel, &clipState); - ctx->SetColor(gfxRGBA(bgColor)); + ctx->SetColor(aColor); gfxContextAutoSaveRestore autoSR; DrawBackgroundColor(clipState, ctx, haveRoundedCorners, appUnitsPerPixel); diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index f6e668f38576..132958491caf 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -495,8 +495,9 @@ struct nsCSSRendering { uint32_t aFlags, nsRect* aBGClipRect = nullptr, int32_t aLayer = -1); - - static void PaintBackgroundColor(nsPresContext* aPresContext, + + static void PaintBackgroundColor(gfxRGBA aColor, + nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aDirtyRect, @@ -523,7 +524,8 @@ struct nsCSSRendering { nsRect* aBGClipRect = nullptr, int32_t aLayer = -1); - static void PaintBackgroundColorWithSC(nsPresContext* aPresContext, + static void PaintBackgroundColorWithSC(gfxRGBA aColor, + nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aDirtyRect, diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 38850444d661..5cf1d3d376a4 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2593,9 +2593,21 @@ nsDisplayThemedBackground::GetBoundsInternal() { return r + ToReferenceFrame(); } +bool +nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) +{ + mColor.a = mColor.a * aOpacity; + if (aClip) { + IntersectClip(aBuilder, *aClip); + } + return true; +} + void nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) + nsRenderingContext* aCtx) { if (mColor == NS_RGBA(0, 0, 0, 0)) { return; @@ -2604,7 +2616,7 @@ nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, nsPoint offset = ToReferenceFrame(); uint32_t flags = aBuilder->GetBackgroundPaintFlags(); CheckForBorderItem(this, flags); - nsCSSRendering::PaintBackgroundColor(mFrame->PresContext(), *aCtx, mFrame, + nsCSSRendering::PaintBackgroundColor(mColor, mFrame->PresContext(), *aCtx, mFrame, mVisibleRect, nsRect(offset, mFrame->GetSize()), flags); @@ -2612,9 +2624,9 @@ nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, nsRegion nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, - bool* aSnap) + bool* aSnap) { - if (NS_GET_A(mColor) != 255) { + if (mColor.a != 1) { return nsRegion(); } @@ -2630,9 +2642,9 @@ nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, } bool -nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) +nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { - *aColor = mColor; + *aColor = NS_RGBA_FROM_GFXRGBA(mColor); if (!mBackgroundStyle) return true; @@ -2659,9 +2671,9 @@ nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder, void nsDisplayBackgroundColor::WriteDebugInfo(nsACString& aTo) { - aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)", - NS_GET_R(mColor), NS_GET_G(mColor), - NS_GET_B(mColor), NS_GET_A(mColor)); + aTo += nsPrintfCString(" (rgba %f,%f,%f,%f)", + mColor.r, mColor.g, + mColor.b, mColor.a); } #endif diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 90303394067e..0aceef8da4e4 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2325,17 +2325,21 @@ public: nscolor aColor) : nsDisplayItem(aBuilder, aFrame) , mBackgroundStyle(aBackgroundStyle) - , mColor(aColor) + , mColor(gfxRGBA(aColor)) { } virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; - + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; + virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) MOZ_OVERRIDE; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE { *aSnap = true; @@ -2344,14 +2348,20 @@ public: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - return new nsDisplayItemBoundsGeometry(this, aBuilder); + return new nsDisplaySolidColorGeometry(this, aBuilder, + NS_RGBA_FROM_GFXRGBA(mColor)); } virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, nsRegion* aInvalidRegion) MOZ_OVERRIDE { - const nsDisplayItemBoundsGeometry* geometry = static_cast(aGeometry); + const nsDisplaySolidColorGeometry* geometry = static_cast(aGeometry); + if (NS_RGBA_FROM_GFXRGBA(mColor) != geometry->mColor) { + bool dummy; + aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy)); + return; + } ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); } @@ -2362,7 +2372,7 @@ public: protected: const nsStyleBackground* mBackgroundStyle; - nscolor mColor; + gfxRGBA mColor; }; /** diff --git a/layout/reftests/bugs/759036-1-ref.html b/layout/reftests/bugs/759036-1-ref.html index 092df596e629..8c6bbe68ec8a 100644 --- a/layout/reftests/bugs/759036-1-ref.html +++ b/layout/reftests/bugs/759036-1-ref.html @@ -11,7 +11,7 @@ #inner { width: 380px; height: 260px; - background-color: #7fff7f; + background-color: #66ff66; } diff --git a/layout/reftests/bugs/759036-1.html b/layout/reftests/bugs/759036-1.html index e965213ebe81..851f9c767058 100644 --- a/layout/reftests/bugs/759036-1.html +++ b/layout/reftests/bugs/759036-1.html @@ -7,7 +7,7 @@ width: 300px; overflow:hidden; border-radius:30px; - opacity: 0.5; + opacity: 0.6; } #inner { width: 380px; diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 722e14fda170..09fb0127fda7 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1719,7 +1719,7 @@ skip-if(B2G) == 751012-1a.html 751012-1-ref.html skip-if(B2G) == 751012-1b.html 751012-1-ref.html random-if(Android||(B2G&&browserIsRemote)) == 753329-1.html about:blank == 758561-1.html 758561-1-ref.html -fuzzy-if(true,1,19) fails-if(d2d) random-if(Android&&AndroidVersion<15) == 759036-1.html 759036-1-ref.html +fuzzy-if(true,1,90) random-if(Android&&AndroidVersion<15) == 759036-1.html 759036-1-ref.html fuzzy-if(true,17,5879) random-if(Android&&AndroidVersion<15) == 759036-2.html 759036-2-ref.html random-if(Android&&AndroidVersion<15) == 776265-1a.html 776265-1-ref.html == 776265-1b.html 776265-1-ref.html @@ -1778,7 +1778,7 @@ skip-if(B2G&&browserIsRemote) == 858803-1.html 858803-1-ref.html # bug 974780 random-if(B2G&&browserIsRemote) == 894931-1.html 894931-1-ref.html == 897491-1.html 897491-1-ref.html == 897491-2.html 897491-2-ref.html -fuzzy(1,10000) fuzzy-if(Android&&AndroidVersion>=15,5,10000) == 902330-1.html 902330-1-ref.html +fuzzy(2,10000) fuzzy-if(Android&&AndroidVersion>=15,5,10000) == 902330-1.html 902330-1-ref.html fuzzy-if(Android,8,400) == 906199-1.html 906199-1-ref.html == 921716-1.html 921716-1-ref.html test-pref(layout.css.sticky.enabled,true) random-if(B2G&&browserIsRemote) == 926155-1.html 926155-1-ref.html From 1387c9241d3f202e9bc039364f5716ae19171b9d Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Mon, 16 Jun 2014 18:32:42 -0400 Subject: [PATCH 39/64] Bug 1025704 - Add --video flag to merge-profiles.py. r=ehsan --- tools/profiler/merge-profiles.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/profiler/merge-profiles.py b/tools/profiler/merge-profiles.py index 04e3efe604de..399cdce27a7d 100755 --- a/tools/profiler/merge-profiles.py +++ b/tools/profiler/merge-profiles.py @@ -15,9 +15,14 @@ def MergeProfiles(files): symTable = dict() meta = None libs = None + videoUrl = None minStartTime = None for fname in files: + if fname.startswith("--video="): + videoUrl = fname[8:] + continue + match = re.match('profile_([0-9]+)_(.+)\.sym', fname) if match is None: raise Exception("Filename '" + fname + "' doesn't match expected pattern") @@ -76,6 +81,8 @@ def MergeProfiles(files): result['profileJSON']['threads'] = threads result['symbolicationTable'] = symTable result['format'] = "profileJSONWithSymbolicationTable,1" + if videoUrl: + result['profileJSON']['meta']['videoCapture'] = {"src": videoUrl} json.dump(result, sys.stdout) From 5385dceeca610de66ed3925532afff7d1327b563 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 16 Jun 2014 15:37:53 -0700 Subject: [PATCH 40/64] Bug 1024038 - Remove YARR, r=jandem. --- js/public/MemoryMetrics.h | 1 - js/src/builtin/RegExp.cpp | 68 +- js/src/builtin/RegExp.h | 4 +- js/src/configure.in | 14 - js/src/jit/JitCommon.h | 24 - js/src/jsstr.cpp | 32 - js/src/moz.build | 41 +- js/src/vm/MatchPairs.h | 22 - js/src/vm/RegExpObject.cpp | 271 +-- js/src/vm/RegExpObject.h | 87 +- js/src/vm/Runtime.cpp | 31 - js/src/vm/Runtime.h | 19 - js/src/vm/TraceLogging.cpp | 6 - js/src/vm/TraceLogging.h | 3 - js/src/yarr/ASCIICType.h | 183 -- js/src/yarr/BumpPointerAllocator.h | 276 --- js/src/yarr/CheckedArithmetic.h | 715 ------- js/src/yarr/MatchResult.h | 78 - js/src/yarr/OSAllocator.h | 103 - js/src/yarr/OSAllocatorPosix.cpp | 129 -- js/src/yarr/OSAllocatorWin.cpp | 89 - js/src/yarr/PageAllocation.h | 131 -- js/src/yarr/PageBlock.cpp | 92 - js/src/yarr/PageBlock.h | 90 - js/src/yarr/RegExpJitTables.h | 2718 ------------------------- js/src/yarr/VMTags.h | 92 - js/src/yarr/Yarr.h | 72 - js/src/yarr/YarrCanonicalizeUCS2.cpp | 464 ----- js/src/yarr/YarrCanonicalizeUCS2.h | 141 -- js/src/yarr/YarrCanonicalizeUCS2.js | 218 -- js/src/yarr/YarrInterpreter.cpp | 1997 ------------------ js/src/yarr/YarrInterpreter.h | 395 ---- js/src/yarr/YarrJIT.cpp | 2804 -------------------------- js/src/yarr/YarrJIT.h | 172 -- js/src/yarr/YarrParser.h | 849 -------- js/src/yarr/YarrPattern.cpp | 933 --------- js/src/yarr/YarrPattern.h | 463 ----- js/src/yarr/YarrSyntaxChecker.cpp | 60 - js/src/yarr/YarrSyntaxChecker.h | 40 - js/src/yarr/wtfbridge.h | 386 ---- js/xpconnect/src/XPCJSRuntime.cpp | 6 - 41 files changed, 35 insertions(+), 14284 deletions(-) delete mode 100644 js/src/yarr/ASCIICType.h delete mode 100644 js/src/yarr/BumpPointerAllocator.h delete mode 100644 js/src/yarr/CheckedArithmetic.h delete mode 100644 js/src/yarr/MatchResult.h delete mode 100644 js/src/yarr/OSAllocator.h delete mode 100644 js/src/yarr/OSAllocatorPosix.cpp delete mode 100644 js/src/yarr/OSAllocatorWin.cpp delete mode 100644 js/src/yarr/PageAllocation.h delete mode 100644 js/src/yarr/PageBlock.cpp delete mode 100644 js/src/yarr/PageBlock.h delete mode 100644 js/src/yarr/RegExpJitTables.h delete mode 100644 js/src/yarr/VMTags.h delete mode 100644 js/src/yarr/Yarr.h delete mode 100644 js/src/yarr/YarrCanonicalizeUCS2.cpp delete mode 100644 js/src/yarr/YarrCanonicalizeUCS2.h delete mode 100644 js/src/yarr/YarrCanonicalizeUCS2.js delete mode 100644 js/src/yarr/YarrInterpreter.cpp delete mode 100644 js/src/yarr/YarrInterpreter.h delete mode 100644 js/src/yarr/YarrJIT.cpp delete mode 100644 js/src/yarr/YarrJIT.h delete mode 100644 js/src/yarr/YarrParser.h delete mode 100644 js/src/yarr/YarrPattern.cpp delete mode 100644 js/src/yarr/YarrPattern.h delete mode 100644 js/src/yarr/YarrSyntaxChecker.cpp delete mode 100644 js/src/yarr/YarrSyntaxChecker.h delete mode 100644 js/src/yarr/wtfbridge.h diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 383e4e790f63..e2f5977f6b81 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -349,7 +349,6 @@ struct RuntimeSizes macro(_, _, contexts) \ macro(_, _, dtoa) \ macro(_, _, temporary) \ - macro(_, _, regexpData) \ macro(_, _, interpreterStack) \ macro(_, _, mathCache) \ macro(_, _, sourceDataCache) \ diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 021d43a2b700..1b7296c02daa 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -10,10 +10,7 @@ #include "jscntxt.h" -#ifndef JS_YARR #include "irregexp/RegExpParser.h" -#endif - #include "vm/RegExpStatics.h" #include "vm/StringBuffer.h" @@ -94,28 +91,12 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs static RegExpRunStatus ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, HandleLinearString input, const jschar *chars, size_t length, - size_t *lastIndex, MatchConduit &matches) + size_t *lastIndex, MatchPairs &matches) { - RegExpRunStatus status; - - /* Switch between MatchOnly and IncludeSubpatterns modes. */ - if (matches.isPair) { -#ifdef JS_YARR - size_t lastIndex_orig = *lastIndex; - /* Only one MatchPair slot provided: execute short-circuiting regexp. */ - status = re.executeMatchOnly(cx, chars, length, lastIndex, *matches.u.pair); - if (status == RegExpRunStatus_Success && res) - res->updateLazily(cx, input, &re, lastIndex_orig); -#else - MOZ_CRASH(); -#endif - } else { - /* Vector of MatchPairs provided: execute full regexp. */ - status = re.execute(cx, chars, length, lastIndex, *matches.u.pairs); - if (status == RegExpRunStatus_Success && res) { - if (!res->updateFromMatchPairs(cx, input, *matches.u.pairs)) - return RegExpRunStatus_Error; - } + RegExpRunStatus status = re.execute(cx, chars, length, lastIndex, matches); + if (status == RegExpRunStatus_Success && res) { + if (!res->updateFromMatchPairs(cx, input, matches)) + return RegExpRunStatus_Error; } return status; } @@ -131,10 +112,9 @@ js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj, return false; ScopedMatchPairs matches(&cx->tempLifoAlloc()); - MatchConduit conduit(&matches); RegExpRunStatus status = - ExecuteRegExpImpl(cx, res, *shared, input_, chars, length, lastIndex, conduit); + ExecuteRegExpImpl(cx, res, *shared, input_, chars, length, lastIndex, matches); if (status == RegExpRunStatus_Error) return false; @@ -308,16 +288,11 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args) if (!escapedSourceStr) return false; -#ifdef JS_YARR - if (!RegExpShared::checkSyntax(cx, nullptr, escapedSourceStr)) - return false; -#else // JS_YARR CompileOptions options(cx); frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr); if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), escapedSourceStr)) return false; -#endif // JS_YARR RegExpStatics *res = cx->global()->getRegExpStatics(cx); if (!res) @@ -557,7 +532,7 @@ js_InitRegExpClass(JSContext *cx, HandleObject obj) RegExpRunStatus js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, - MatchConduit &matches, RegExpStaticsUpdate staticsUpdate) + MatchPairs &matches, RegExpStaticsUpdate staticsUpdate) { /* Step 1 (b) was performed by CallNonGenericMethod. */ Rooted reobj(cx, ®exp->as()); @@ -633,7 +608,7 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, /* ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). */ static RegExpRunStatus -ExecuteRegExp(JSContext *cx, CallArgs args, MatchConduit &matches) +ExecuteRegExp(JSContext *cx, CallArgs args, MatchPairs &matches) { /* Step 1 (a) was performed by CallNonGenericMethod. */ RootedObject regexp(cx, &args.thisv().toObject()); @@ -653,9 +628,8 @@ regexp_exec_impl(JSContext *cx, HandleObject regexp, HandleString string, { /* Execute regular expression and gather matches. */ ScopedMatchPairs matches(&cx->tempLifoAlloc()); - MatchConduit conduit(&matches); - RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, staticsUpdate); + RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, matches, staticsUpdate); if (status == RegExpRunStatus_Error) return false; @@ -711,14 +685,8 @@ js::regexp_exec_no_statics(JSContext *cx, unsigned argc, Value *vp) static bool regexp_test_impl(JSContext *cx, CallArgs args) { -#ifdef JS_YARR - MatchPair match; - MatchConduit conduit(&match); -#else ScopedMatchPairs matches(&cx->tempLifoAlloc()); - MatchConduit conduit(&matches); -#endif - RegExpRunStatus status = ExecuteRegExp(cx, args, conduit); + RegExpRunStatus status = ExecuteRegExp(cx, args, matches); args.rval().setBoolean(status == RegExpRunStatus_Success); return status != RegExpRunStatus_Error; } @@ -727,14 +695,8 @@ regexp_test_impl(JSContext *cx, CallArgs args) bool js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result) { -#ifdef JS_YARR - MatchPair match; - MatchConduit conduit(&match); -#else ScopedMatchPairs matches(&cx->tempLifoAlloc()); - MatchConduit conduit(&matches); -#endif - RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit, UpdateRegExpStatics); + RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, matches, UpdateRegExpStatics); *result = (status == RegExpRunStatus_Success); return status != RegExpRunStatus_Error; } @@ -757,14 +719,8 @@ js::regexp_test_no_statics(JSContext *cx, unsigned argc, Value *vp) RootedObject regexp(cx, &args[0].toObject()); RootedString string(cx, args[1].toString()); -#ifdef JS_YARR - MatchPair match; - MatchConduit conduit(&match); -#else ScopedMatchPairs matches(&cx->tempLifoAlloc()); - MatchConduit conduit(&matches); -#endif - RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, DontUpdateRegExpStatics); + RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, matches, DontUpdateRegExpStatics); args.rval().setBoolean(status == RegExpRunStatus_Success); return status != RegExpRunStatus_Error; } diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 6d2cbac9ab09..fe194b9a1045 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -19,15 +19,13 @@ js_InitRegExpClass(JSContext *cx, js::HandleObject obj); namespace js { -class MatchConduit; - // Whether RegExp statics should be updated with the input and results of a // regular expression execution. enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics }; RegExpRunStatus ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, - MatchConduit &matches, RegExpStaticsUpdate staticsUpdate); + MatchPairs &matches, RegExpStaticsUpdate staticsUpdate); /* * Legacy behavior of ExecuteRegExp(), which is baked into the JSAPI. diff --git a/js/src/configure.in b/js/src/configure.in index ca0b358c25db..98595d1e3444 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -3004,20 +3004,6 @@ if test "$ENABLE_TRACE_LOGGING"; then AC_DEFINE(JS_TRACE_LOGGING) fi -dnl ======================================================== -dnl = Enable yarr regexp engine -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(yarr, -[ --enable-yarr Enable yarr regexp engine], - ENABLE_YARR=1, - ENABLE_YARR= ) - -AC_SUBST(ENABLE_YARR) - -if test "$ENABLE_YARR"; then - AC_DEFINE(JS_YARR) -fi - dnl ======================================================== dnl = Enable any treating of compile warnings as errors dnl ======================================================== diff --git a/js/src/jit/JitCommon.h b/js/src/jit/JitCommon.h index 0236dc457eca..1e5f28178f63 100644 --- a/js/src/jit/JitCommon.h +++ b/js/src/jit/JitCommon.h @@ -21,21 +21,9 @@ (js::jit::Simulator::Current()->call( \ JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 8, p0, p1, p2, p3, p4, p5, p6, p7) & 0xffffffff) -#ifdef JS_YARR - -#define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2) \ - js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 3, p0, p1, p2) - -#define CALL_GENERATED_YARR_CODE4(entry, p0, p1, p2, p3) \ - js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 4, p0, p1, p2, p3) - -#else // JS_YARR - #define CALL_GENERATED_REGEXP(entry, p0) \ js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 1, p0) -#endif // JS_YARR - #define CALL_GENERATED_ASMJS(entry, p0, p1) \ (Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 2, p0, p1) & 0xffffffff) @@ -45,21 +33,9 @@ #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ entry(p0, p1, p2, p3, p4, p5, p6, p7) -#ifdef JS_YARR - -#define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2) \ - entry(p0, p1, p2) - -#define CALL_GENERATED_YARR_CODE4(entry, p0, p1, p2, p3) \ - entry(p0, p1, p2, p3) - -#else // JS_YARR - #define CALL_GENERATED_REGEXP(entry, p0) \ entry(p0) -#endif // JS_YARR - #define CALL_GENERATED_ASMJS(entry, p0, p1) \ entry(p0, p1) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 0cbde406424a..fb11db597928 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2254,11 +2254,7 @@ DoMatchGlobal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleLinearStri // techniques from the spec to implement step 8f's loop. // Step 8f. -#ifdef JS_YARR - MatchPair match; -#else ScopedMatchPairs matches(&cx->tempLifoAlloc()); -#endif size_t charsLen = input->length(); const jschar *chars = input->chars(); RegExpShared &re = g.regExp(); @@ -2268,11 +2264,7 @@ DoMatchGlobal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleLinearStri // Steps 8f(i-ii), minus "lastIndex" updates (see above). size_t nextSearchIndex = searchIndex; -#ifdef JS_YARR - RegExpRunStatus status = re.executeMatchOnly(cx, chars, charsLen, &nextSearchIndex, match); -#else RegExpRunStatus status = re.execute(cx, chars, charsLen, &nextSearchIndex, matches); -#endif if (status == RegExpRunStatus_Error) return false; @@ -2281,10 +2273,7 @@ DoMatchGlobal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleLinearStri break; lastSuccessfulStart = searchIndex; - -#ifndef JS_YARR MatchPair &match = matches[0]; -#endif // Steps 8f(iii)(1-3). searchIndex = match.isEmpty() ? nextSearchIndex + 1 : nextSearchIndex; @@ -2423,25 +2412,15 @@ js::str_search(JSContext *cx, unsigned argc, Value *vp) /* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */ size_t i = 0; -#ifdef JS_YARR - MatchPair match; - RegExpRunStatus status = g.regExp().executeMatchOnly(cx, chars, length, &i, match); -#else ScopedMatchPairs matches(&cx->tempLifoAlloc()); RegExpRunStatus status = g.regExp().execute(cx, chars, length, &i, matches); -#endif if (status == RegExpRunStatus_Error) return false; if (status == RegExpRunStatus_Success) res->updateLazily(cx, linearStr, &g.regExp(), 0); -#ifdef JS_YARR - JS_ASSERT_IF(status == RegExpRunStatus_Success_NotFound, match.start == -1); - args.rval().setInt32(match.start); -#else args.rval().setInt32(status == RegExpRunStatus_Success_NotFound ? -1 : matches[0].start); -#endif return true; } @@ -3100,11 +3079,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl size_t charsLen = flatStr->length(); -#ifdef JS_YARR - MatchPair match; -#else ScopedMatchPairs matches(&cx->tempLifoAlloc()); -#endif size_t startIndex = 0; /* Index used for iterating through the string. */ size_t lastIndex = 0; /* Index after last successful match. */ size_t lazyIndex = 0; /* Index before last successful match. */ @@ -3114,19 +3089,12 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl if (!CheckForInterrupt(cx)) return false; -#ifdef JS_YARR - RegExpRunStatus status = re.executeMatchOnly(cx, flatStr->chars(), charsLen, &startIndex, match); -#else RegExpRunStatus status = re.execute(cx, flatStr->chars(), charsLen, &startIndex, matches); -#endif if (status == RegExpRunStatus_Error) return false; if (status == RegExpRunStatus_Success_NotFound) break; - -#ifndef JS_YARR MatchPair &match = matches[0]; -#endif /* Include the latest unmatched substring. */ if (size_t(match.start) > lastIndex) { diff --git a/js/src/moz.build b/js/src/moz.build index bedb6c75d6d1..34276afce396 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -125,6 +125,12 @@ UNIFIED_SOURCES += [ 'gc/Tracer.cpp', 'gc/Verifier.cpp', 'gc/Zone.cpp', + 'irregexp/RegExpAST.cpp', + 'irregexp/RegExpEngine.cpp', + 'irregexp/RegExpInterpreter.cpp', + 'irregexp/RegExpMacroAssembler.cpp', + 'irregexp/RegExpParser.cpp', + 'irregexp/RegExpStack.cpp', 'jsalloc.cpp', 'jsapi.cpp', 'jsbool.cpp', @@ -234,42 +240,9 @@ if CONFIG['ENABLE_TRACE_LOGGING']: 'vm/TraceLogging.cpp', ] -if CONFIG['ENABLE_YARR']: - UNIFIED_SOURCES += [ - 'yarr/PageBlock.cpp', - 'yarr/YarrCanonicalizeUCS2.cpp', - 'yarr/YarrInterpreter.cpp', - 'yarr/YarrPattern.cpp', - 'yarr/YarrSyntaxChecker.cpp', - ] - if CONFIG['OS_ARCH'] == 'WINNT': - SOURCES += [ - 'yarr/OSAllocatorWin.cpp', - ] - else: - SOURCES += [ - 'yarr/OSAllocatorPosix.cpp', - ] - if CONFIG['ENABLE_ION']: - SOURCES += [ - 'yarr/YarrJIT.cpp' - ] -else: - UNIFIED_SOURCES += [ - 'irregexp/RegExpAST.cpp', - 'irregexp/RegExpEngine.cpp', - 'irregexp/RegExpInterpreter.cpp', - 'irregexp/RegExpMacroAssembler.cpp', - 'irregexp/RegExpParser.cpp', - 'irregexp/RegExpStack.cpp', - ] - if CONFIG['ENABLE_ION']: - UNIFIED_SOURCES += [ - 'irregexp/NativeRegExpMacroAssembler.cpp', - ] - if CONFIG['ENABLE_ION']: UNIFIED_SOURCES += [ + 'irregexp/NativeRegExpMacroAssembler.cpp', 'jit/AliasAnalysis.cpp', 'jit/AsmJS.cpp', 'jit/AsmJSLink.cpp', diff --git a/js/src/vm/MatchPairs.h b/js/src/vm/MatchPairs.h index 7ee3bc840062..47eb03bdd52a 100644 --- a/js/src/vm/MatchPairs.h +++ b/js/src/vm/MatchPairs.h @@ -150,28 +150,6 @@ class VectorMatchPairs : public MatchPairs bool allocOrExpandArray(size_t pairCount); }; -/* - * Passes either MatchPair or MatchPairs through ExecuteRegExp() - * to avoid duplication of generic code. - */ -struct MatchConduit -{ - union { - MatchPair *pair; - MatchPairs *pairs; - } u; - bool isPair; - - explicit MatchConduit(MatchPair *pair) { - isPair = true; - u.pair = pair; - } - explicit MatchConduit(MatchPairs *pairs) { - isPair = false; - u.pairs = pairs; - } -}; - } /* namespace js */ #endif /* vm_MatchPairs_h */ diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index d8930ef45a3a..b5033a996d2a 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -11,17 +11,12 @@ #include "jsstr.h" #include "frontend/TokenStream.h" -#ifndef JS_YARR #include "irregexp/RegExpParser.h" -#endif #include "vm/MatchPairs.h" #include "vm/RegExpStatics.h" #include "vm/StringBuffer.h" #include "vm/TraceLogging.h" #include "vm/Xdr.h" -#ifdef JS_YARR -#include "yarr/YarrSyntaxChecker.h" -#endif #include "jsobjinlines.h" @@ -306,10 +301,6 @@ RegExpObject * RegExpObject::createNoStatics(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags, TokenStream *tokenStream, LifoAlloc &alloc) { -#ifdef JS_YARR - if (!RegExpShared::checkSyntax(cx, tokenStream, source)) - return nullptr; -#else // JS_YARR Maybe dummyOptions; Maybe dummyTokenStream; if (!tokenStream) { @@ -322,7 +313,6 @@ RegExpObject::createNoStatics(ExclusiveContext *cx, HandleAtom source, RegExpFla if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source)) return nullptr; -#endif RegExpObjectBuilder builder(cx); return builder.build(source, flags); @@ -437,25 +427,13 @@ RegExpObject::toString(JSContext *cx) const /* RegExpShared */ RegExpShared::RegExpShared(JSAtom *source, RegExpFlag flags) - : source(source), flags(flags), parenCount(0), canStringMatch(false), marked_(false) -{ -#ifdef JS_YARR - bytecode = nullptr; -#else - byteCode = nullptr; -#endif -} + : source(source), flags(flags), parenCount(0), canStringMatch(false), marked_(false), + byteCode(nullptr) +{} RegExpShared::~RegExpShared() { -#ifdef JS_YARR -#ifdef JS_ION - codeBlock.release(); -#endif - js_delete(bytecode); -#else // JS_YARR js_free(byteCode); -#endif // JS_YARR for (size_t i = 0; i < tables.length(); i++) js_delete(tables[i]); @@ -470,68 +448,21 @@ RegExpShared::trace(JSTracer *trc) if (source) MarkString(trc, &source, "RegExpShared source"); -#if !defined(JS_YARR) && defined(JS_ION) +#ifdef JS_ION if (jitCode) MarkJitCode(trc, &jitCode, "RegExpShared code"); #endif } -#ifdef JS_YARR - -void -RegExpShared::reportYarrError(ExclusiveContext *cx, TokenStream *ts, ErrorCode error) -{ - switch (error) { - case JSC::Yarr::NoError: - MOZ_ASSUME_UNREACHABLE("Called reportYarrError with value for no error"); -#define COMPILE_EMSG(__code, __msg) \ - case JSC::Yarr::__code: \ - if (ts) \ - ts->reportError(__msg); \ - else \ - JS_ReportErrorFlagsAndNumberUC(cx->asJSContext(), \ - JSREPORT_ERROR, js_GetErrorMessage, nullptr, __msg); \ - return - COMPILE_EMSG(PatternTooLarge, JSMSG_REGEXP_TOO_COMPLEX); - COMPILE_EMSG(QuantifierOutOfOrder, JSMSG_BAD_QUANTIFIER); - COMPILE_EMSG(QuantifierWithoutAtom, JSMSG_BAD_QUANTIFIER); - COMPILE_EMSG(MissingParentheses, JSMSG_MISSING_PAREN); - COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN); - COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */ - COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE); - COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE); - COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE); - COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER); - COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH); - COMPILE_EMSG(RuntimeError, JSMSG_REGEXP_RUNTIME_ERROR); -#undef COMPILE_EMSG - default: - MOZ_ASSUME_UNREACHABLE("Unknown Yarr error code"); - } -} - bool -RegExpShared::checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLinearString *source) -{ - ErrorCode error = JSC::Yarr::checkSyntax(*source); - if (error == JSC::Yarr::NoError) - return true; - - reportYarrError(cx, tokenStream, error); - return false; -} - -#endif // JS_YARR - -bool -RegExpShared::compile(JSContext *cx, bool matchOnly, const jschar *sampleChars, size_t sampleLength) +RegExpShared::compile(JSContext *cx, const jschar *sampleChars, size_t sampleLength) { TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); AutoTraceLog logCompile(logger, TraceLogger::IrregexpCompile); if (!sticky()) { RootedAtom pattern(cx, source); - return compile(cx, pattern, matchOnly, sampleChars, sampleLength); + return compile(cx, pattern, sampleChars, sampleLength); } /* @@ -554,11 +485,11 @@ RegExpShared::compile(JSContext *cx, bool matchOnly, const jschar *sampleChars, if (!fakeySource) return false; - return compile(cx, fakeySource, matchOnly, sampleChars, sampleLength); + return compile(cx, fakeySource, sampleChars, sampleLength); } bool -RegExpShared::compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const jschar *sampleChars, size_t sampleLength) +RegExpShared::compile(JSContext *cx, HandleAtom pattern, const jschar *sampleChars, size_t sampleLength) { if (!ignoreCase() && !StringHasRegExpMetaChars(pattern->chars(), pattern->length())) { canStringMatch = true; @@ -566,47 +497,6 @@ RegExpShared::compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const j return true; } -#ifdef JS_YARR - - ErrorCode yarrError; - YarrPattern yarrPattern(*pattern, ignoreCase(), multiline(), &yarrError); - if (yarrError) { - reportYarrError(cx, nullptr, yarrError); - return false; - } - this->parenCount = yarrPattern.m_numSubpatterns; - -#ifdef JS_ION - if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) { - JSC::ExecutableAllocator *execAlloc = cx->runtime()->getExecAlloc(cx); - if (!execAlloc) - return false; - - JSGlobalData globalData(execAlloc); - YarrJITCompileMode compileMode = matchOnly ? JSC::Yarr::MatchOnly - : JSC::Yarr::IncludeSubpatterns; - - jitCompile(yarrPattern, JSC::Yarr::Char16, &globalData, codeBlock, compileMode); - - /* Unset iff the Yarr JIT compilation was successful. */ - if (!codeBlock.isFallBack()) - return true; - } - codeBlock.setFallBack(true); -#endif - - WTF::BumpPointerAllocator *bumpAlloc = cx->runtime()->getBumpPointerAllocator(cx); - if (!bumpAlloc) { - js_ReportOutOfMemory(cx); - return false; - } - - bytecode = byteCompile(yarrPattern, bumpAlloc).get(); - -#else // JS_YARR - - JS_ASSERT(!matchOnly); - CompileOptions options(cx); TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr); @@ -632,29 +522,17 @@ RegExpShared::compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const j byteCode = code.byteCode; -#endif // JS_YARR - return true; } bool RegExpShared::compileIfNecessary(JSContext *cx, const jschar *sampleChars, size_t sampleLength) { - if (isCompiled(false) || canStringMatch) + if (isCompiled() || canStringMatch) return true; - return compile(cx, false, sampleChars, sampleLength); + return compile(cx, sampleChars, sampleLength); } -#ifdef JS_YARR -bool -RegExpShared::compileMatchOnlyIfNecessary(JSContext *cx) -{ - if (isCompiled(true) || canStringMatch) - return true; - return compile(cx, true, nullptr, 0); -} -#endif // JS_YARR - RegExpRunStatus RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex, MatchPairs &matches) @@ -684,10 +562,8 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, start = 0; } -#ifndef JS_YARR // Reset the Irregexp backtrack stack if it grows during execution. irregexp::RegExpStackScope stackScope(cx->runtime()); -#endif if (canStringMatch) { int res = StringFindPattern(chars+start, length-start, source->chars(), source->length()); @@ -703,39 +579,6 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, return RegExpRunStatus_Success; } -#ifdef JS_YARR - - unsigned result; - - // Yarr wants plain integers for its output buffer (whatever). - JS_STATIC_ASSERT(sizeof(int32_t) == sizeof(int)); - JS_STATIC_ASSERT(sizeof(int32_t) == sizeof(unsigned)); - -#ifdef JS_ION - if (codeBlock.isFallBack()) { - AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret); - result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw()); - } else { - AutoTraceLog logJIT(logger, TraceLogger::YarrJIT); - result = codeBlock.execute(chars, start, length, (int *) matches.pairsRaw()).start; - } -#else // JS_ION - { - AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret); - result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw()); - } -#endif // JS_ION - - if (result == JSC::Yarr::offsetError) { - reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError); - return RegExpRunStatus_Error; - } - - if (result == JSC::Yarr::offsetNoMatch) - return RegExpRunStatus_Success_NotFound; - -#else // JS_YARR - if (hasByteCode()) { AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute); RegExpRunStatus result = @@ -786,111 +629,19 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, MOZ_CRASH(); #endif // JS_ION -#endif // JS_YARR - matches.displace(displacement); matches.checkAgainst(origLength); *lastIndex = matches[0].limit; return RegExpRunStatus_Success; } -#ifdef JS_YARR - -RegExpRunStatus -RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length, - size_t *lastIndex, MatchPair &match) -{ - TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime()); - - /* Compile the code at point-of-use. */ - if (!compileMatchOnlyIfNecessary(cx)) - return RegExpRunStatus_Error; - -#ifdef DEBUG - const size_t origLength = length; -#endif - size_t start = *lastIndex; - size_t displacement = 0; - - if (sticky()) { - displacement = start; - chars += displacement; - length -= displacement; - start = 0; - } - - if (canStringMatch) { - int res = StringFindPattern(chars+start, length-start, source->chars(), source->length()); - if (res == -1) - return RegExpRunStatus_Success_NotFound; - - match = MatchPair(res + start, res + start + source->length()); - match.displace(displacement); - *lastIndex = match.limit; - return RegExpRunStatus_Success; - } - -#ifdef JS_ION - if (!codeBlock.isFallBack()) { - AutoTraceLog logJIT(logger, TraceLogger::YarrJIT); - MatchResult result = codeBlock.execute(chars, start, length); - if (!result) - return RegExpRunStatus_Success_NotFound; - - match = MatchPair(result.start, result.end); - match.displace(displacement); - *lastIndex = match.limit; - return RegExpRunStatus_Success; - } -#endif - - /* - * The JIT could not be used, so fall back to the Yarr interpreter. - * Unfortunately, the interpreter does not have a MatchOnly mode, so a - * temporary output vector must be provided. - */ - JS_ASSERT(hasBytecode()); - ScopedMatchPairs matches(&cx->tempLifoAlloc()); - if (!matches.initArray(pairCount())) - return RegExpRunStatus_Error; - - unsigned result; - { - AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret); - result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw()); - } - - if (result == JSC::Yarr::offsetError) { - reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError); - return RegExpRunStatus_Error; - } - - if (result == JSC::Yarr::offsetNoMatch) - return RegExpRunStatus_Success_NotFound; - - match = MatchPair(result, matches[0].limit); - match.displace(displacement); - -#ifdef DEBUG - matches.displace(displacement); - matches.checkAgainst(origLength); -#endif - - *lastIndex = match.limit; - return RegExpRunStatus_Success; -} - -#endif // JS_YARR - size_t RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { size_t n = mallocSizeOf(this); -#ifndef JS_YARR if (byteCode) n += mallocSizeOf(byteCode); -#endif n += tables.sizeOfExcludingThis(mallocSizeOf); for (size_t i = 0; i < tables.length(); i++) @@ -979,7 +730,7 @@ RegExpCompartment::sweep(JSRuntime *rt) // the RegExpShared if it was accidentally marked earlier but wasn't // marked by the current trace. bool keep = shared->marked() && !IsStringAboutToBeFinalized(shared->source.unsafeGet()); -#if !defined(JS_YARR) && defined(JS_ION) +#ifdef JS_ION if (keep && shared->jitCode) keep = !IsJitCodeAboutToBeFinalized(shared->jitCode.unsafeGet()); #endif diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index 045fa04dda4f..72faa642d6b7 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -17,13 +17,6 @@ #include "gc/Zone.h" #include "vm/Shape.h" -#ifdef JS_YARR -#ifdef JS_ION -#include "yarr/YarrJIT.h" -#endif -#include "yarr/YarrInterpreter.h" -#endif // JS_YARR - /* * JavaScript Regular Expressions * @@ -111,17 +104,6 @@ class RegExpShared typedef frontend::TokenStream TokenStream; -#ifdef JS_YARR - typedef JSC::Yarr::BytecodePattern BytecodePattern; - typedef JSC::Yarr::ErrorCode ErrorCode; - typedef JSC::Yarr::YarrPattern YarrPattern; -#ifdef JS_ION - typedef JSC::Yarr::JSGlobalData JSGlobalData; - typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock; - typedef JSC::Yarr::YarrJITCompileMode YarrJITCompileMode; -#endif -#endif - /* Source to the RegExp, for lazy compilation. */ HeapPtrAtom source; @@ -130,69 +112,28 @@ class RegExpShared bool canStringMatch; bool marked_; -#ifdef JS_YARR - -#ifdef JS_ION - /* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */ - YarrCodeBlock codeBlock; -#endif - BytecodePattern *bytecode; - -#else // JS_YARR - #ifdef JS_ION HeapPtrJitCode jitCode; #endif uint8_t *byteCode; -#endif // JS_YARR - // Tables referenced by JIT code. Vector tables; /* Internal functions. */ - bool compile(JSContext *cx, bool matchOnly, const jschar *sampleChars, size_t sampleLength); - bool compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const jschar *sampleChars, size_t sampleLength); + bool compile(JSContext *cx, const jschar *sampleChars, size_t sampleLength); + bool compile(JSContext *cx, HandleAtom pattern, const jschar *sampleChars, size_t sampleLength); bool compileIfNecessary(JSContext *cx, const jschar *sampleChars, size_t sampleLength); -#ifdef JS_YARR - bool compileMatchOnlyIfNecessary(JSContext *cx); -#endif - public: RegExpShared(JSAtom *source, RegExpFlag flags); ~RegExpShared(); -#ifdef JS_YARR - /* Static functions to expose some Yarr logic. */ - - // This function should be deleted once bad Android platforms phase out. See bug 604774. - static bool isJITRuntimeEnabled(JSContext *cx) { - #ifdef JS_ION - # if defined(ANDROID) - return !cx->jitIsBroken; - # else - return true; - # endif - #else - return false; - #endif - } - static void reportYarrError(ExclusiveContext *cx, TokenStream *ts, ErrorCode error); - static bool checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLinearString *source); -#endif // JS_YARR - /* Primary interface: run this regular expression on the given string. */ RegExpRunStatus execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex, MatchPairs &matches); -#ifdef JS_YARR - /* Run the regular expression without collecting matches, for test(). */ - RegExpRunStatus executeMatchOnly(JSContext *cx, const jschar *chars, size_t length, - size_t *lastIndex, MatchPair &match); -#endif - // Register a table with this RegExpShared, and take ownership. bool addTable(uint8_t *table) { return tables.append(table); @@ -201,7 +142,7 @@ class RegExpShared /* Accessors */ size_t getParenCount() const { - JS_ASSERT(isCompiled(true) || isCompiled(false) || canStringMatch); + JS_ASSERT(isCompiled() || canStringMatch); return parenCount; } @@ -215,24 +156,6 @@ class RegExpShared bool multiline() const { return flags & MultilineFlag; } bool sticky() const { return flags & StickyFlag; } -#ifdef JS_YARR - - bool hasCode(bool matchOnly) const { -#ifdef JS_ION - return matchOnly ? codeBlock.has16BitCodeMatchOnly() : codeBlock.has16BitCode(); -#else - return false; -#endif - } - bool hasBytecode() const { - return bytecode != nullptr; - } - bool isCompiled(bool matchOnly) const { - return hasBytecode() || hasCode(matchOnly); - } - -#else // JS_YARR - bool hasJitCode() const { #ifdef JS_ION return jitCode != nullptr; @@ -244,12 +167,10 @@ class RegExpShared return byteCode != nullptr; } - bool isCompiled(bool matchOnly) const { + bool isCompiled() const { return hasJitCode() || hasByteCode(); } -#endif // JS_YARR - void trace(JSTracer *trc); bool marked() const { return marked_; } diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index a7b61449b76e..4806ee61c344 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -39,9 +39,6 @@ #include "jit/PcScriptCache.h" #include "js/MemoryMetrics.h" #include "js/SliceBudget.h" -#ifdef JS_YARR -#include "yarr/BumpPointerAllocator.h" -#endif #include "jscntxtinlines.h" #include "jsgcinlines.h" @@ -110,10 +107,8 @@ PerThreadData::init() if (!dtoaState) return false; -#ifndef JS_YARR if (!regexpStack.init()) return false; -#endif return true; } @@ -157,9 +152,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), execAlloc_(nullptr), -#ifdef JS_YARR - bumpAlloc_(nullptr), -#endif jitRuntime_(nullptr), selfHostingGlobal_(nullptr), nativeStackBase(0), @@ -439,9 +431,6 @@ JSRuntime::~JSRuntime() atomsCompartment_ = nullptr; js_free(defaultLocale); -#ifdef JS_YARR - js_delete(bumpAlloc_); -#endif js_delete(mathCache_); #ifdef JS_ION js_delete(jitRuntime_); @@ -518,10 +507,6 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf); -#ifdef JS_YARR - rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0; -#endif - rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf); rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0; @@ -604,22 +589,6 @@ JSRuntime::createExecutableAllocator(JSContext *cx) return execAlloc_; } -#ifdef JS_YARR - -WTF::BumpPointerAllocator * -JSRuntime::createBumpPointerAllocator(JSContext *cx) -{ - JS_ASSERT(!bumpAlloc_); - JS_ASSERT(cx->runtime() == this); - - bumpAlloc_ = js_new(); - if (!bumpAlloc_) - js_ReportOutOfMemory(cx); - return bumpAlloc_; -} - -#endif // JS_YARR - MathCache * JSRuntime::createMathCache(JSContext *cx) { diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 4407d0c14fa6..d57322d4c6f9 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -28,9 +28,7 @@ #include "frontend/ParseMaps.h" #include "gc/GCRuntime.h" #include "gc/Tracer.h" -#ifndef JS_YARR #include "irregexp/RegExpStack.h" -#endif #ifdef XP_MACOSX # include "jit/AsmJSSignalHandlers.h" #endif @@ -75,10 +73,6 @@ js_ReportOverRecursed(js::ThreadSafeContext *cx); namespace JSC { class ExecutableAllocator; } -#ifdef JS_YARR -namespace WTF { class BumpPointerAllocator; } -#endif - namespace js { class Activation; @@ -499,10 +493,8 @@ class PerThreadData : public PerThreadDataFriendFields inline void setJitStackLimit(uintptr_t limit); -#ifndef JS_YARR // Information about the heap allocated backtrack stack used by RegExp JIT code. irregexp::RegExpStack regexpStack; -#endif #ifdef JS_TRACE_LOGGING TraceLogger *traceLogger; @@ -809,9 +801,6 @@ struct JSRuntime : public JS::shadow::Runtime, * thread-data level. */ JSC::ExecutableAllocator *execAlloc_; -#ifdef JS_YARR - WTF::BumpPointerAllocator *bumpAlloc_; -#endif js::jit::JitRuntime *jitRuntime_; /* @@ -824,9 +813,6 @@ struct JSRuntime : public JS::shadow::Runtime, js::InterpreterStack interpreterStack_; JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx); -#ifdef JS_YARR - WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx); -#endif js::jit::JitRuntime *createJitRuntime(JSContext *cx); public: @@ -840,11 +826,6 @@ struct JSRuntime : public JS::shadow::Runtime, JSC::ExecutableAllocator *maybeExecAlloc() { return execAlloc_; } -#ifdef JS_YARR - WTF::BumpPointerAllocator *getBumpPointerAllocator(JSContext *cx) { - return bumpAlloc_ ? bumpAlloc_ : createBumpPointerAllocator(cx); - } -#endif js::jit::JitRuntime *getJitRuntime(JSContext *cx) { return jitRuntime_ ? jitRuntime_ : createJitRuntime(cx); } diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp index 48b4f0497aaa..d2fe5b145490 100644 --- a/js/src/vm/TraceLogging.cpp +++ b/js/src/vm/TraceLogging.cpp @@ -832,14 +832,8 @@ TraceLogging::lazyInit() enabledTextIds[TraceLogger::ParserCompileFunction] = true; enabledTextIds[TraceLogger::ParserCompileLazy] = true; enabledTextIds[TraceLogger::ParserCompileScript] = true; -#ifdef JS_YARR - enabledTextIds[TraceLogger::YarrCompile] = true; - enabledTextIds[TraceLogger::YarrInterpret] = true; - enabledTextIds[TraceLogger::YarrJIT] = true; -#else enabledTextIds[TraceLogger::IrregexpCompile] = true; enabledTextIds[TraceLogger::IrregexpExecute] = true; -#endif } if (ContainsFlag(env, "IonCompiler") || strlen(env) == 0) { diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h index 3818b3ac3a28..3fe3b17298f0 100644 --- a/js/src/vm/TraceLogging.h +++ b/js/src/vm/TraceLogging.h @@ -125,9 +125,6 @@ namespace jit { _(ParserCompileLazy) \ _(ParserCompileScript) \ _(TL) \ - _(YarrCompile) \ - _(YarrInterpret) \ - _(YarrJIT) \ _(IrregexpCompile) \ _(IrregexpExecute) \ _(VM) \ diff --git a/js/src/yarr/ASCIICType.h b/js/src/yarr/ASCIICType.h deleted file mode 100644 index aab8d3e5bfbf..000000000000 --- a/js/src/yarr/ASCIICType.h +++ /dev/null @@ -1,183 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef yarr_ASCIICType_h -#define yarr_ASCIICType_h - -#include "assembler/wtf/Assertions.h" - -// The behavior of many of the functions in the header is dependent -// on the current locale. But in the WebKit project, all uses of those functions -// are in code processing something that's not locale-specific. These equivalents -// for some of the functions are named more explicitly, not dependent -// on the C library locale, and we should also optimize them as needed. - -// All functions return false or leave the character unchanged if passed a character -// that is outside the range 0-7F. So they can be used on Unicode strings or -// characters if the intent is to do processing only if the character is ASCII. - -namespace WTF { - - inline bool isASCII(char c) { return !(c & ~0x7F); } - inline bool isASCII(unsigned short c) { return !(c & ~0x7F); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCII(wchar_t c) { return !(c & ~0x7F); } -#endif - inline bool isASCII(int c) { return !(c & ~0x7F); } - inline bool isASCII(unsigned c) { return !(c & ~0x7F); } - - inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } - inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } -#endif - inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } - inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } - - inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } - inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } -#endif - inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } - inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } - - inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); } - inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); } -#endif - inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); } - inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); } - - inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } - inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } -#endif - inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } - inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } - - inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); } - inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); } -#endif - inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); } - inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); } - - inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; } - inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; } -#endif - inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; } - inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; } - - inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; } - inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; } -#endif - inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; } - inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; } - - /* - Statistics from a run of Apple's page load test for callers of isASCIISpace: - - character count - --------- ----- - non-spaces 689383 - 20 space 294720 - 0A \n 89059 - 09 \t 28320 - 0D \r 0 - 0C \f 0 - 0B \v 0 - */ - inline bool isASCIISpace(char c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } - inline bool isASCIISpace(unsigned short c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } -#endif - inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } - inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } - - inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); } -#endif - inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - - // FIXME: Why do these need static_cast? - inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } -#endif - inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - - inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } -#endif - inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - - inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; } - inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; } -#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; } -#endif - inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; } - inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; } -} - -using WTF::isASCII; -using WTF::isASCIIAlpha; -using WTF::isASCIIAlphanumeric; -using WTF::isASCIIDigit; -using WTF::isASCIIHexDigit; -using WTF::isASCIILower; -using WTF::isASCIIOctalDigit; -using WTF::isASCIIPrintable; -using WTF::isASCIISpace; -using WTF::isASCIIUpper; -using WTF::toASCIIHexValue; -using WTF::toASCIILower; -using WTF::toASCIIUpper; - -#endif /* yarr_ASCIICType_h */ diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h deleted file mode 100644 index e41e18c11ff6..000000000000 --- a/js/src/yarr/BumpPointerAllocator.h +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef yarr_BumpPointerAllocator_h -#define yarr_BumpPointerAllocator_h - -#include "yarr/PageAllocation.h" - -namespace WTF { - -#if WTF_CPU_SPARC -#define MINIMUM_BUMP_POOL_SIZE 0x2000 -#elif WTF_CPU_IA64 -#define MINIMUM_BUMP_POOL_SIZE 0x4000 -#else -#define MINIMUM_BUMP_POOL_SIZE 0x1000 -#endif - -class BumpPointerPool { -public: - // ensureCapacity will check whether the current pool has capacity to - // allocate 'size' bytes of memory If it does not, it will attempt to - // allocate a new pool (which will be added to this one in a chain). - // - // If allocation fails (out of memory) this method will return null. - // If the return value is non-null, then callers should update any - // references they have to this current (possibly full) BumpPointerPool - // to instead point to the newly returned BumpPointerPool. - BumpPointerPool* ensureCapacity(size_t size) - { - void* allocationEnd = static_cast(m_current) + size; - ASSERT(allocationEnd > m_current); // check for overflow - if (allocationEnd <= static_cast(this)) - return this; - return ensureCapacityCrossPool(this, size); - } - - // alloc should only be called after calling ensureCapacity; as such - // alloc will never fail. - void* alloc(size_t size) - { - void* current = m_current; - void* allocationEnd = static_cast(current) + size; - ASSERT(allocationEnd > current); // check for overflow - ASSERT(allocationEnd <= static_cast(this)); - m_current = allocationEnd; - return current; - } - - // The dealloc method releases memory allocated using alloc. Memory - // must be released in a LIFO fashion, e.g. if the client calls alloc - // four times, returning pointer A, B, C, D, then the only valid order - // in which these may be deallocaed is D, C, B, A. - // - // The client may optionally skip some deallocations. In the example - // above, it would be valid to only explicitly dealloc C, A (D being - // dealloced along with C, B along with A). - // - // If pointer was not allocated from this pool (or pools) then dealloc - // will CRASH(). Callers should update any references they have to - // this current BumpPointerPool to instead point to the returned - // BumpPointerPool. - BumpPointerPool* dealloc(void* position) - { - if ((position >= m_start) && (position <= static_cast(this))) { - ASSERT(position <= m_current); - m_current = position; - return this; - } - return deallocCrossPool(this, position); - } - - size_t sizeOfNonHeapData() const - { - ASSERT(!m_previous); - size_t n = 0; - const BumpPointerPool *curr = this; - while (curr) { - n += m_allocation.size(); - curr = curr->m_next; - } - return n; - } - -private: - // Placement operator new, returns the last 'size' bytes of allocation for use as this. - void* operator new(size_t size, const PageAllocation& allocation) - { - ASSERT(size < allocation.size()); - return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size; - } - - BumpPointerPool(const PageAllocation& allocation) - : m_current(allocation.base()) - , m_start(allocation.base()) - , m_next(0) - , m_previous(0) - , m_allocation(allocation) - { - } - - static BumpPointerPool* create(size_t minimumCapacity = 0) - { - // Add size of BumpPointerPool object, check for overflow. - minimumCapacity += sizeof(BumpPointerPool); - if (minimumCapacity < sizeof(BumpPointerPool)) - return 0; - - size_t poolSize = MINIMUM_BUMP_POOL_SIZE; - while (poolSize < minimumCapacity) { - poolSize <<= 1; - // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2! - ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1))); - if (!poolSize) - return 0; - } - - PageAllocation allocation = PageAllocation::allocate(poolSize); - if (!!allocation) - return new(allocation) BumpPointerPool(allocation); - return 0; - } - - void shrink() - { - ASSERT(!m_previous); - m_current = m_start; - while (m_next) { - BumpPointerPool* nextNext = m_next->m_next; - m_next->destroy(); - m_next = nextNext; - } - } - - void destroy() - { - m_allocation.deallocate(); - } - - static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size) - { - // The pool passed should not have capacity, so we'll start with the next one. - ASSERT(previousPool); - ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow - ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool)); - BumpPointerPool* pool = previousPool->m_next; - - while (true) { - if (!pool) { - // We've run to the end; allocate a new pool. - pool = BumpPointerPool::create(size); - previousPool->m_next = pool; - pool->m_previous = previousPool; - return pool; - } - - void* current = pool->m_current; - void* allocationEnd = static_cast(current) + size; - ASSERT(allocationEnd > current); // check for overflow - if (allocationEnd <= static_cast(pool)) - return pool; - } - } - - static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position) - { - // Should only be called if position is not in the current pool. - ASSERT((position < pool->m_start) || (position > static_cast(pool))); - - while (true) { - // Unwind the current pool to the start, move back in the chain to the previous pool. - pool->m_current = pool->m_start; - pool = pool->m_previous; - - // position was nowhere in the chain! - if (!pool) - CRASH(); - - if ((position >= pool->m_start) && (position <= static_cast(pool))) { - ASSERT(position <= pool->m_current); - pool->m_current = position; - return pool; - } - } - } - - void* m_current; - void* m_start; - BumpPointerPool* m_next; - BumpPointerPool* m_previous; - PageAllocation m_allocation; - - friend class BumpPointerAllocator; -}; - -// A BumpPointerAllocator manages a set of BumpPointerPool objects, which -// can be used for LIFO (stack like) allocation. -// -// To begin allocating using this class call startAllocator(). The result -// of this method will be null if the initial pool allocation fails, or a -// pointer to a BumpPointerPool object that can be used to perform -// allocations. Whilst running no memory will be released until -// stopAllocator() is called. At this point all allocations made through -// this allocator will be reaped, and underlying memory may be freed. -// -// (In practice we will still hold on to the initial pool to allow allocation -// to be quickly restared, but aditional pools will be freed). -// -// This allocator is non-renetrant, it is encumbant on the clients to ensure -// startAllocator() is not called again until stopAllocator() has been called. -class BumpPointerAllocator { -public: - BumpPointerAllocator() - : m_head(0) - { - } - - ~BumpPointerAllocator() - { - if (m_head) - m_head->destroy(); - } - - BumpPointerPool* startAllocator() - { - if (!m_head) - m_head = BumpPointerPool::create(); - return m_head; - } - - void stopAllocator() - { - if (m_head) - m_head->shrink(); - } - - size_t sizeOfNonHeapData() const - { - return m_head ? m_head->sizeOfNonHeapData() : 0; - } - -private: - BumpPointerPool* m_head; -}; - -} - -using WTF::BumpPointerAllocator; - -#endif /* yarr_BumpPointerAllocator_h */ diff --git a/js/src/yarr/CheckedArithmetic.h b/js/src/yarr/CheckedArithmetic.h deleted file mode 100644 index 20fb23013115..000000000000 --- a/js/src/yarr/CheckedArithmetic.h +++ /dev/null @@ -1,715 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_CheckedArithmetic_h -#define yarr_CheckedArithmetic_h - -#include "assembler/wtf/Assertions.h" - -#include -#include -#include "mozilla/TypeTraits.h" - -#ifdef _MSC_VER -# undef min -# undef max -#endif - -/* Checked - * - * This class provides a mechanism to perform overflow-safe integer arithmetic - * without having to manually ensure that you have all the required bounds checks - * directly in your code. - * - * There are two modes of operation: - * - The default is Checked, and crashes at the point - * and overflow has occurred. - * - The alternative is Checked, which uses an additional - * byte of storage to track whether an overflow has occurred, subsequent - * unchecked operations will crash if an overflow has occured - * - * It is possible to provide a custom overflow handler, in which case you need - * to support these functions: - * - void overflowed(); - * This function is called when an operation has produced an overflow. - * - bool hasOverflowed(); - * This function must return true if overflowed() has been called on an - * instance and false if it has not. - * - void clearOverflow(); - * Used to reset overflow tracking when a value is being overwritten with - * a new value. - * - * Checked works for all integer types, with the following caveats: - * - Mixing signedness of operands is only supported for types narrower than - * 64bits. - * - It does have a performance impact, so tight loops may want to be careful - * when using it. - * - */ - -namespace WTF { - -class CrashOnOverflow { -protected: - void overflowed() - { - CRASH(); - } - - void clearOverflow() { } - -public: - bool hasOverflowed() const { return false; } -}; - -class RecordOverflow { -protected: - RecordOverflow() - : m_overflowed(false) - { - } - - void overflowed() - { - m_overflowed = true; - } - - void clearOverflow() - { - m_overflowed = false; - } - -public: - bool hasOverflowed() const { return m_overflowed; } - -private: - unsigned char m_overflowed; -}; - -template class Checked; -template struct RemoveChecked; -template struct RemoveChecked >; - -template ::is_signed, bool sourceSigned = ::std::numeric_limits::is_signed> struct BoundsChecker; -template struct BoundsChecker { - static bool inBounds(Source value) - { - // Same signedness so implicit type conversion will always increase precision - // to widest type - return value <= ::std::numeric_limits::max(); - } -}; - -template struct BoundsChecker { - static bool inBounds(Source value) - { - // Same signedness so implicit type conversion will always increase precision - // to widest type - return ::std::numeric_limits::min() <= value && value <= ::std::numeric_limits::max(); - } -}; - -template struct BoundsChecker { - static bool inBounds(Source value) - { - // Target is unsigned so any value less than zero is clearly unsafe - if (value < 0) - return false; - // If our (unsigned) Target is the same or greater width we can - // convert value to type Target without losing precision - if (sizeof(Target) >= sizeof(Source)) - return static_cast(value) <= ::std::numeric_limits::max(); - // The signed Source type has greater precision than the target so - // max(Target) -> Source will widen. - return value <= static_cast(::std::numeric_limits::max()); - } -}; - -template struct BoundsChecker { - static bool inBounds(Source value) - { - // Signed target with an unsigned source - if (sizeof(Target) <= sizeof(Source)) - return value <= static_cast(::std::numeric_limits::max()); - // Target is Wider than Source so we're guaranteed to fit any value in - // unsigned Source - return true; - } -}; - -template ::value> struct BoundsCheckElider; -template struct BoundsCheckElider { - static bool inBounds(Source) { return true; } -}; -template struct BoundsCheckElider : public BoundsChecker { -}; - -template static inline bool isInBounds(Source value) -{ - return BoundsCheckElider::inBounds(value); -} - -template struct RemoveChecked { - typedef T CleanType; - static const CleanType DefaultValue = 0; -}; - -template struct RemoveChecked > { - typedef typename RemoveChecked::CleanType CleanType; - static const CleanType DefaultValue = 0; -}; - -template struct RemoveChecked > { - typedef typename RemoveChecked::CleanType CleanType; - static const CleanType DefaultValue = 0; -}; - -// The ResultBase and SignednessSelector are used to workaround typeof not being -// available in MSVC -template sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase; -template struct ResultBase { - typedef U ResultType; -}; - -template struct ResultBase { - typedef V ResultType; -}; - -template struct ResultBase { - typedef U ResultType; -}; - -template ::is_signed, bool vIsSigned = ::std::numeric_limits::is_signed> struct SignednessSelector; -template struct SignednessSelector { - typedef U ResultType; -}; - -template struct SignednessSelector { - typedef U ResultType; -}; - -template struct SignednessSelector { - typedef V ResultType; -}; - -template struct SignednessSelector { - typedef U ResultType; -}; - -template struct ResultBase { - typedef typename SignednessSelector::ResultType ResultType; -}; - -template struct Result : ResultBase::CleanType, typename RemoveChecked::CleanType> { -}; - -template ::ResultType, - bool lhsSigned = ::std::numeric_limits::is_signed, bool rhsSigned = ::std::numeric_limits::is_signed> struct ArithmeticOperations; - -template struct ArithmeticOperations { - // LHS and RHS are signed types - - // Helper function - static inline bool signsMatch(LHS lhs, RHS rhs) - { - return (lhs ^ rhs) >= 0; - } - - static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN - { - if (signsMatch(lhs, rhs)) { - if (lhs >= 0) { - if ((::std::numeric_limits::max() - rhs) < lhs) - return false; - } else { - ResultType temp = lhs - ::std::numeric_limits::min(); - if (rhs < -temp) - return false; - } - } // if the signs do not match this operation can't overflow - result = lhs + rhs; - return true; - } - - static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN - { - if (!signsMatch(lhs, rhs)) { - if (lhs >= 0) { - if (lhs > ::std::numeric_limits::max() + rhs) - return false; - } else { - if (rhs > ::std::numeric_limits::max() + lhs) - return false; - } - } // if the signs match this operation can't overflow - result = lhs - rhs; - return true; - } - - static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN - { - if (signsMatch(lhs, rhs)) { - if (lhs >= 0) { - if (lhs && (::std::numeric_limits::max() / lhs) < rhs) - return false; - } else { - if (lhs == ::std::numeric_limits::min() || rhs == ::std::numeric_limits::min()) - return false; - if ((::std::numeric_limits::max() / -lhs) < -rhs) - return false; - } - } else { - if (lhs < 0) { - if (rhs && lhs < (::std::numeric_limits::min() / rhs)) - return false; - } else { - if (lhs && rhs < (::std::numeric_limits::min() / lhs)) - return false; - } - } - result = lhs * rhs; - return true; - } - - static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } - -}; - -template struct ArithmeticOperations { - // LHS and RHS are unsigned types so bounds checks are nice and easy - static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN - { - ResultType temp = lhs + rhs; - if (temp < lhs) - return false; - result = temp; - return true; - } - - static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN - { - ResultType temp = lhs - rhs; - if (temp > lhs) - return false; - result = temp; - return true; - } - - static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN - { - ResultType temp = lhs * rhs; - if (temp < lhs) - return false; - result = temp; - return true; - } - - static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } - -}; - -template struct ArithmeticOperations { - static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) - { - int64_t temp = lhs + rhs; - if (temp < ::std::numeric_limits::min()) - return false; - if (temp > ::std::numeric_limits::max()) - return false; - result = static_cast(temp); - return true; - } - - static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) - { - int64_t temp = lhs - rhs; - if (temp < ::std::numeric_limits::min()) - return false; - if (temp > ::std::numeric_limits::max()) - return false; - result = static_cast(temp); - return true; - } - - static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) - { - int64_t temp = lhs * rhs; - if (temp < ::std::numeric_limits::min()) - return false; - if (temp > ::std::numeric_limits::max()) - return false; - result = static_cast(temp); - return true; - } - - static inline bool equals(int lhs, unsigned rhs) - { - return static_cast(lhs) == static_cast(rhs); - } -}; - -template struct ArithmeticOperations { - static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) - { - return ArithmeticOperations::add(rhs, lhs, result); - } - - static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) - { - return ArithmeticOperations::sub(lhs, rhs, result); - } - - static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) - { - return ArithmeticOperations::multiply(rhs, lhs, result); - } - - static inline bool equals(unsigned lhs, int rhs) - { - return ArithmeticOperations::equals(rhs, lhs); - } -}; - -template static inline bool safeAdd(U lhs, V rhs, R& result) -{ - return ArithmeticOperations::add(lhs, rhs, result); -} - -template static inline bool safeSub(U lhs, V rhs, R& result) -{ - return ArithmeticOperations::sub(lhs, rhs, result); -} - -template static inline bool safeMultiply(U lhs, V rhs, R& result) -{ - return ArithmeticOperations::multiply(lhs, rhs, result); -} - -template static inline bool safeEquals(U lhs, V rhs) -{ - return ArithmeticOperations::equals(lhs, rhs); -} - -enum ResultOverflowedTag { ResultOverflowed }; - -// FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801 -static inline bool workAroundClangBug() { return true; } - -template class Checked : public OverflowHandler { -public: - template friend class Checked; - Checked() - : m_value(0) - { - } - - Checked(ResultOverflowedTag) - : m_value(0) - { - // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801 - if (workAroundClangBug()) - this->overflowed(); - } - - template Checked(U value) - { - if (!isInBounds(value)) - this->overflowed(); - m_value = static_cast(value); - } - - template Checked(const Checked& rhs) - : m_value(rhs.m_value) - { - if (rhs.hasOverflowed()) - this->overflowed(); - } - - template Checked(const Checked& rhs) - : OverflowHandler(rhs) - { - if (!isInBounds(rhs.m_value)) - this->overflowed(); - m_value = static_cast(rhs.m_value); - } - - template Checked(const Checked& rhs) - { - if (rhs.hasOverflowed()) - this->overflowed(); - if (!isInBounds(rhs.m_value)) - this->overflowed(); - m_value = static_cast(rhs.m_value); - } - - const Checked& operator=(Checked rhs) - { - this->clearOverflow(); - if (rhs.hasOverflowed()) - this->overflowed(); - m_value = static_cast(rhs.m_value); - return *this; - } - - template const Checked& operator=(U value) - { - return *this = Checked(value); - } - - template const Checked& operator=(const Checked& rhs) - { - return *this = Checked(rhs); - } - - // prefix - const Checked& operator++() - { - if (m_value == ::std::numeric_limits::max()) - this->overflowed(); - m_value++; - return *this; - } - - const Checked& operator--() - { - if (m_value == ::std::numeric_limits::min()) - this->overflowed(); - m_value--; - return *this; - } - - // postfix operators - const Checked operator++(int) - { - if (m_value == ::std::numeric_limits::max()) - this->overflowed(); - return Checked(m_value++); - } - - const Checked operator--(int) - { - if (m_value == ::std::numeric_limits::min()) - this->overflowed(); - return Checked(m_value--); - } - - // Boolean operators - bool operator!() const - { - if (this->hasOverflowed()) - CRASH(); - return !m_value; - } - - typedef void* (Checked::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const - { - if (this->hasOverflowed()) - CRASH(); - return (m_value) ? reinterpret_cast(1) : 0; - } - - // Value accessors. unsafeGet() will crash if there's been an overflow. - T unsafeGet() const - { - if (this->hasOverflowed()) - CRASH(); - return m_value; - } - - bool safeGet(T& value) const WARN_UNUSED_RETURN - { - value = m_value; - return this->hasOverflowed(); - } - - // Mutating assignment - template const Checked operator+=(U rhs) - { - if (!safeAdd(m_value, rhs, m_value)) - this->overflowed(); - return *this; - } - - template const Checked operator-=(U rhs) - { - if (!safeSub(m_value, rhs, m_value)) - this->overflowed(); - return *this; - } - - template const Checked operator*=(U rhs) - { - if (!safeMultiply(m_value, rhs, m_value)) - this->overflowed(); - return *this; - } - - const Checked operator*=(double rhs) - { - double result = rhs * m_value; - // Handle +/- infinity and NaN - if (!(::std::numeric_limits::min() <= result && ::std::numeric_limits::max() >= result)) - this->overflowed(); - m_value = (T)result; - return *this; - } - - const Checked operator*=(float rhs) - { - return *this *= (double)rhs; - } - - template const Checked operator+=(Checked rhs) - { - if (rhs.hasOverflowed()) - this->overflowed(); - return *this += rhs.m_value; - } - - template const Checked operator-=(Checked rhs) - { - if (rhs.hasOverflowed()) - this->overflowed(); - return *this -= rhs.m_value; - } - - template const Checked operator*=(Checked rhs) - { - if (rhs.hasOverflowed()) - this->overflowed(); - return *this *= rhs.m_value; - } - - // Equality comparisons - template bool operator==(Checked rhs) - { - return unsafeGet() == rhs.unsafeGet(); - } - - template bool operator==(U rhs) - { - if (this->hasOverflowed()) - this->overflowed(); - return safeEquals(m_value, rhs); - } - - template const Checked operator==(Checked rhs) - { - return unsafeGet() == Checked(rhs.unsafeGet()); - } - - template bool operator!=(U rhs) - { - return !(*this == rhs); - } - -private: - // Disallow implicit conversion of floating point to integer types - Checked(float); - Checked(double); - void operator=(float); - void operator=(double); - void operator+=(float); - void operator+=(double); - void operator-=(float); - void operator-=(double); - T m_value; -}; - -template static inline Checked::ResultType, OverflowHandler> operator+(Checked lhs, Checked rhs) -{ - U x = 0; - V y = 0; - bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); - typename Result::ResultType result = 0; - overflowed |= !safeAdd(x, y, result); - if (overflowed) - return ResultOverflowed; - return result; -} - -template static inline Checked::ResultType, OverflowHandler> operator-(Checked lhs, Checked rhs) -{ - U x = 0; - V y = 0; - bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); - typename Result::ResultType result = 0; - overflowed |= !safeSub(x, y, result); - if (overflowed) - return ResultOverflowed; - return result; -} - -template static inline Checked::ResultType, OverflowHandler> operator*(Checked lhs, Checked rhs) -{ - U x = 0; - V y = 0; - bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); - typename Result::ResultType result = 0; - overflowed |= !safeMultiply(x, y, result); - if (overflowed) - return ResultOverflowed; - return result; -} - -template static inline Checked::ResultType, OverflowHandler> operator+(Checked lhs, V rhs) -{ - return lhs + Checked(rhs); -} - -template static inline Checked::ResultType, OverflowHandler> operator-(Checked lhs, V rhs) -{ - return lhs - Checked(rhs); -} - -template static inline Checked::ResultType, OverflowHandler> operator*(Checked lhs, V rhs) -{ - return lhs * Checked(rhs); -} - -template static inline Checked::ResultType, OverflowHandler> operator+(U lhs, Checked rhs) -{ - return Checked(lhs) + rhs; -} - -template static inline Checked::ResultType, OverflowHandler> operator-(U lhs, Checked rhs) -{ - return Checked(lhs) - rhs; -} - -template static inline Checked::ResultType, OverflowHandler> operator*(U lhs, Checked rhs) -{ - return Checked(lhs) * rhs; -} - -} - -using WTF::Checked; -using WTF::RecordOverflow; - -#endif /* yarr_CheckedArithmetic_h */ diff --git a/js/src/yarr/MatchResult.h b/js/src/yarr/MatchResult.h deleted file mode 100644 index 62f7cbdb6b71..000000000000 --- a/js/src/yarr/MatchResult.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_MatchResult_h -#define yarr_MatchResult_h - -#include "yarr/wtfbridge.h" - -typedef uint64_t EncodedMatchResult; - -struct MatchResult { - MatchResult(int start, int end) - : start(start) - , end(end) - { - } - -#if !WTF_CPU_X86_64 || WTF_PLATFORM_WIN - explicit MatchResult(EncodedMatchResult encoded) - { - union u { - uint64_t encoded; - struct s { - int start; - int end; - } split; - } value; - value.encoded = encoded; - start = value.split.start; - end = value.split.end; - } -#endif - - static MatchResult failed() - { - return MatchResult(int(WTF::notFound), 0); - } - - operator bool() - { - return start != int(WTF::notFound); - } - - bool empty() - { - return start == end; - } - - // strings are limited to a length of 2^28. So this is safe - int start; - int end; -}; - -#endif /* yarr_MatchResult_h */ diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h deleted file mode 100644 index 5ad0fb437395..000000000000 --- a/js/src/yarr/OSAllocator.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef yarr_OSAllocator_h -#define yarr_OSAllocator_h - -#include -#include "yarr/wtfbridge.h" -#include "assembler/wtf/VMTags.h" -#include "assembler/wtf/Assertions.h" - -namespace WTF { - -class OSAllocator { -public: - enum Usage { - UnknownUsage = -1, - FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY, - JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY, - JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY, - JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY - }; - - // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state, - // releaseDecommitted should be called on a region of VM allocated by a single reservation, - // the memory must all currently be in a decommitted state. - static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false); - static void releaseDecommitted(void*, size_t); - - // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should - // never be accessed, since the OS may not have attached physical memory for these regions). - // Clients should only call commit on uncommitted regions and decommit on committed regions. - static void commit(void*, size_t, bool writable, bool executable); - static void decommit(void*, size_t); - - // These methods are symmetric; reserveAndCommit allocates VM in an committed state, - // decommitAndRelease should be called on a region of VM allocated by a single reservation, - // the memory must all currently be in a committed state. - static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false); - static void decommitAndRelease(void* base, size_t size); - - // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than - // committing/decommitting the entire region additional parameters allow a subregion to be - // specified. - static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false); - static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize); -}; - -inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable) -{ - void* base = reserveUncommitted(reserveSize, usage, writable, executable); - commit(base, commitSize, writable, executable); - return base; -} - -inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize) -{ - ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize)); -#if WTF_OS_WINCE || WTF_OS_SYMBIAN - // On most platforms we can actually skip this final decommit; releasing the VM will - // implicitly decommit any physical memory in the region. This is not true on WINCE. - // On Symbian, this makes implementation simpler and better aligned with the RChunk API - decommit(decommitBase, decommitSize); -#endif - releaseDecommitted(releaseBase, releaseSize); -} - -inline void OSAllocator::decommitAndRelease(void* base, size_t size) -{ - decommitAndRelease(base, size, base, size); -} - -} // namespace WTF - -using WTF::OSAllocator; - -#endif /* yarr_OSAllocator_h */ diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp deleted file mode 100644 index 2c8ee2593479..000000000000 --- a/js/src/yarr/OSAllocatorPosix.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#include "assembler/wtf/Platform.h" - -#if WTF_OS_UNIX && !WTF_OS_SYMBIAN - -#include "yarr/OSAllocator.h" - -#include -#include -#include "assembler/wtf/Assertions.h" - -namespace WTF { - -void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable) -{ - void* result = reserveAndCommit(bytes, usage, writable, executable); -#if HAVE_MADV_FREE_REUSE - // To support the "reserve then commit" model, we have to initially decommit. - while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } -#endif - return result; -} - -void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable) -{ - // All POSIX reservations start out logically committed. - int protection = PROT_READ; - if (writable) - protection |= PROT_WRITE; - if (executable) - protection |= PROT_EXEC; - - int flags = MAP_PRIVATE | MAP_ANON; - -#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) - int fd = usage; -#else - int fd = -1; -#endif - - void* result = 0; -#if (WTF_OS_DARWIN && WTF_CPU_X86_64) - if (executable) { - // Cook up an address to allocate at, using the following recipe: - // 17 bits of zero, stay in userspace kids. - // 26 bits of randomness for ASLR. - // 21 bits of zero, at least stay aligned within one level of the pagetables. - // - // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854), - // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus - // 2^24, which should put up somewhere in the middle of userspace (in the address range - // 0x200000000000 .. 0x5fffffffffff). - intptr_t randomLocation = 0; - randomLocation = arc4random() & ((1 << 25) - 1); - randomLocation += (1 << 24); - randomLocation <<= 21; - result = reinterpret_cast(randomLocation); - } -#endif - - result = mmap(result, bytes, protection, flags, fd, 0); - if (result == MAP_FAILED) - CRASH(); - return result; -} - -void OSAllocator::commit(void* address, size_t bytes, bool, bool) -{ -#if HAVE_MADV_FREE_REUSE - while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { } -#else - // Non-MADV_FREE_REUSE reservations automatically commit on demand. - UNUSED_PARAM(address); - UNUSED_PARAM(bytes); -#endif -} - -void OSAllocator::decommit(void* address, size_t bytes) -{ -#if HAVE_MADV_FREE_REUSE - while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } -#elif HAVE_MADV_FREE - while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { } -#elif HAVE_MADV_DONTNEED - while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { } -#else - UNUSED_PARAM(address); - UNUSED_PARAM(bytes); -#endif -} - -void OSAllocator::releaseDecommitted(void* address, size_t bytes) -{ - int result = munmap(address, bytes); - if (result == -1) - CRASH(); -} - -} // namespace WTF - -#endif diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp deleted file mode 100644 index 0ff75a3fdd70..000000000000 --- a/js/src/yarr/OSAllocatorWin.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#include "assembler/wtf/Platform.h" - -#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS - -#include -#include "assembler/wtf/Assertions.h" - -#include "yarr/OSAllocator.h" - -namespace WTF { - -static inline DWORD protection(bool writable, bool executable) -{ - return executable ? - (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) : - (writable ? PAGE_READWRITE : PAGE_READONLY); -} - -void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable) -{ - void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable)); - if (!result) - CRASH(); - return result; -} - -void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable) -{ - void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable)); - if (!result) - CRASH(); - return result; -} - -void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable) -{ - void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable)); - if (!result) - CRASH(); -} - -void OSAllocator::decommit(void* address, size_t bytes) -{ - bool result = VirtualFree(address, bytes, MEM_DECOMMIT); - if (!result) - CRASH(); -} - -void OSAllocator::releaseDecommitted(void* address, size_t bytes) -{ - // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx, - // dwSize must be 0 if dwFreeType is MEM_RELEASE. - bool result = VirtualFree(address, 0, MEM_RELEASE); - if (!result) - CRASH(); -} - -} // namespace WTF - -#endif diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h deleted file mode 100644 index 1ea6abf00f8c..000000000000 --- a/js/src/yarr/PageAllocation.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef yarr_PageAllocation_h -#define yarr_PageAllocation_h - -#include "yarr/wtfbridge.h" -#include "yarr/OSAllocator.h" -#include "yarr/PageBlock.h" -#include "assembler/wtf/VMTags.h" - -#if WTF_OS_DARWIN -#include -#include -#endif - -#if WTF_OS_HAIKU -#include -#endif - -#if WTF_OS_WINDOWS -#include -#include -#endif - -#if WTF_OS_SYMBIAN -#include -#include -#endif - -#if WTF_HAVE_ERRNO_H -#include -#endif - -#if WTF_HAVE_MMAP -#include -#include -#endif - -namespace WTF { - -/* - PageAllocation - - The PageAllocation class provides a cross-platform memory allocation interface - with similar capabilities to posix mmap/munmap. Memory is allocated by calling - PageAllocation::allocate, and deallocated by calling deallocate on the - PageAllocation object. The PageAllocation holds the allocation's base pointer - and size. - - The allocate method is passed the size required (which must be a multiple of - the system page size, which can be accessed using PageAllocation::pageSize). - Callers may also optinally provide a flag indicating the usage (for use by - system memory usage tracking tools, where implemented), and boolean values - specifying the required protection (defaulting to writable, non-executable). -*/ - -class PageAllocation : private PageBlock { -public: - PageAllocation() - { - } - - using PageBlock::size; - using PageBlock::base; - -#ifndef __clang__ - using PageBlock::operator bool; -#else - // FIXME: This is a workaround for , wherein Clang incorrectly emits an access - // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool". - operator bool() const { return PageBlock::operator bool(); } -#endif - - static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false) - { - ASSERT(isPageAligned(size)); - return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size); - } - - void deallocate() - { - // Clear base & size before calling release; if this is *inside* allocation - // then we won't be able to clear then after deallocating the memory. - PageAllocation tmp; - JSC::std::swap(tmp, *this); - - ASSERT(tmp); - ASSERT(!*this); - - OSAllocator::decommitAndRelease(tmp.base(), tmp.size()); - } - -private: - PageAllocation(void* base, size_t size) - : PageBlock(base, size) - { - } -}; - -} // namespace WTF - -using WTF::PageAllocation; - -#endif /* yarr_PageAllocation_h */ diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp deleted file mode 100644 index e297fedd2e40..000000000000 --- a/js/src/yarr/PageBlock.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#include "yarr/PageBlock.h" -#include "assembler/wtf/Assertions.h" - -#if WTF_OS_UNIX && !WTF_OS_SYMBIAN -#include -#endif - -#if WTF_OS_WINDOWS -#include -#include -#endif - -#if WTF_OS_SYMBIAN -#include -#include -#endif - -#if WTF_OS_OS2 -#include -#endif - -namespace WTF { - -static size_t s_pageSize; - -#if (WTF_OS_UNIX && !WTF_OS_SYMBIAN) || WTF_OS_OS2 - -inline size_t systemPageSize() -{ - return getpagesize(); -} - -#elif WTF_OS_WINDOWS - -inline size_t systemPageSize() -{ - static size_t size = 0; - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - size = system_info.dwPageSize; - return size; -} - -#elif WTF_OS_SYMBIAN - -inline size_t systemPageSize() -{ - static TInt page_size = 0; - UserHal::PageSizeInBytes(page_size); - return page_size; -} - -#endif - -size_t pageSize() -{ - if (!s_pageSize) - s_pageSize = systemPageSize(); - ASSERT(isPowerOfTwo(s_pageSize)); - return s_pageSize; -} - -} // namespace WTF diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h deleted file mode 100644 index 0c7b51d33053..000000000000 --- a/js/src/yarr/PageBlock.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef yarr_PageBlock_h -#define yarr_PageBlock_h - -#include -#include - -namespace WTF { - -size_t pageSize(); -inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); } -inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); } -inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); } - -class PageBlock { -public: - PageBlock(); - PageBlock(const PageBlock&); - PageBlock(void*, size_t); - - void* base() const { return m_base; } - size_t size() const { return m_size; } - - operator bool() const { return !!m_base; } - - bool contains(void* containedBase, size_t containedSize) - { - return containedBase >= m_base - && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size); - } - -private: - void* m_base; - size_t m_size; -}; - -inline PageBlock::PageBlock() - : m_base(0) - , m_size(0) -{ -} - -inline PageBlock::PageBlock(const PageBlock& other) - : m_base(other.m_base) - , m_size(other.m_size) -{ -} - -inline PageBlock::PageBlock(void* base, size_t size) - : m_base(base) - , m_size(size) -{ -} - -} // namespace WTF - -using WTF::pageSize; -using WTF::isPageAligned; -using WTF::isPageAligned; -using WTF::isPowerOfTwo; - -#endif /* yarr_PageBlock_h */ diff --git a/js/src/yarr/RegExpJitTables.h b/js/src/yarr/RegExpJitTables.h deleted file mode 100644 index 2dd91b1d8f6e..000000000000 --- a/js/src/yarr/RegExpJitTables.h +++ /dev/null @@ -1,2718 +0,0 @@ -#ifndef yarr_RegExpJitTables_h -#define yarr_RegExpJitTables_h - -static const char _spacesData[65536] = { -0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, -1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; - -static const char _wordcharData[65536] = { -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, -1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; - - -CharacterClass* digitsCreate() -{ - CharacterClass* characterClass = newOrCrash(); - characterClass->m_ranges.append(CharacterRange(0x30, 0x39)); - return characterClass; -} - -CharacterClass* nondigitsCreate() -{ - CharacterClass* characterClass = newOrCrash(); - characterClass->m_ranges.append(CharacterRange(0x00, 0x2f)); - characterClass->m_ranges.append(CharacterRange(0x3a, 0x7f)); - characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0xffff)); - return characterClass; -} - -CharacterClass* newlineCreate() -{ - CharacterClass* characterClass = newOrCrash(); - characterClass->m_matches.append(0x0a); - characterClass->m_matches.append(0x0d); - characterClass->m_matchesUnicode.append(0x2028); - characterClass->m_matchesUnicode.append(0x2029); - return characterClass; -} - -CharacterClass* spacesCreate() -{ - CharacterClass* characterClass = newOrCrash(_spacesData, false); - characterClass->m_ranges.append(CharacterRange(0x09, 0x0d)); - characterClass->m_matches.append(0x20); - characterClass->m_matchesUnicode.append(0x00a0); - characterClass->m_matchesUnicode.append(0x1680); - characterClass->m_matchesUnicode.append(0x180e); - characterClass->m_rangesUnicode.append(CharacterRange(0x2000, 0x200a)); - characterClass->m_matchesUnicode.append(0x2028); - characterClass->m_matchesUnicode.append(0x2029); - characterClass->m_matchesUnicode.append(0x202f); - characterClass->m_matchesUnicode.append(0x205f); - characterClass->m_matchesUnicode.append(0x3000); - characterClass->m_matchesUnicode.append(0xfeff); - return characterClass; -} - -CharacterClass* nonspacesCreate() -{ - CharacterClass* characterClass = newOrCrash(_spacesData, true); - characterClass->m_ranges.append(CharacterRange(0x00, 0x08)); - characterClass->m_ranges.append(CharacterRange(0x0e, 0x1f)); - characterClass->m_ranges.append(CharacterRange(0x21, 0x7f)); - characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0x009f)); - characterClass->m_rangesUnicode.append(CharacterRange(0x00a1, 0x167f)); - characterClass->m_rangesUnicode.append(CharacterRange(0x1681, 0x180d)); - characterClass->m_rangesUnicode.append(CharacterRange(0x180f, 0x1fff)); - characterClass->m_rangesUnicode.append(CharacterRange(0x200b, 0x2027)); - characterClass->m_rangesUnicode.append(CharacterRange(0x202a, 0x202e)); - characterClass->m_rangesUnicode.append(CharacterRange(0x2030, 0x205e)); - characterClass->m_rangesUnicode.append(CharacterRange(0x2060, 0x2fff)); - characterClass->m_rangesUnicode.append(CharacterRange(0x3001, 0xfefe)); - characterClass->m_rangesUnicode.append(CharacterRange(0xff00, 0xffff)); - return characterClass; -} - -CharacterClass* nonwordcharCreate() -{ - CharacterClass* characterClass = newOrCrash(_wordcharData, true); - characterClass->m_ranges.append(CharacterRange(0x00, 0x2f)); - characterClass->m_ranges.append(CharacterRange(0x3a, 0x40)); - characterClass->m_ranges.append(CharacterRange(0x5b, 0x5e)); - characterClass->m_matches.append(0x60); - characterClass->m_ranges.append(CharacterRange(0x7b, 0x7f)); - characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0xffff)); - return characterClass; -} - -CharacterClass* wordcharCreate() -{ - CharacterClass* characterClass = newOrCrash(_wordcharData, false); - characterClass->m_ranges.append(CharacterRange(0x30, 0x39)); - characterClass->m_ranges.append(CharacterRange(0x41, 0x5a)); - characterClass->m_matches.append(0x5f); - characterClass->m_ranges.append(CharacterRange(0x61, 0x7a)); - return characterClass; -} - -#endif /* yarr_RegExpJitTables_h */ diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h deleted file mode 100644 index 9b00c2ce7595..000000000000 --- a/js/src/yarr/VMTags.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_VMTags_h -#define yarr_VMTags_h - -// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map -// in order to aid tools that inspect system memory use. -#if WTF_OS_DARWIN - -#include - -#if !defined(TARGETING_TIGER) - -#if defined(VM_MEMORY_TCMALLOC) -#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC) -#else -#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53) -#endif // defined(VM_MEMORY_TCMALLOC) - -#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) -#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) -#else -#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64) -#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) - -#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) -#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) -#else -#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65) -#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) - -#else // !defined(TARGETING_TIGER) - -// mmap on Tiger fails with tags that work on Leopard, so fall -// back to Tiger-compatible tags (that also work on Leopard) -// when targeting Tiger. -#define VM_TAG_FOR_TCMALLOC_MEMORY -1 -#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 -#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 - -#endif // !defined(TARGETING_TIGER) - -// Tags for vm_map and vm_allocate work on both Tiger and Leopard. - -#if defined(VM_MEMORY_JAVASCRIPT_CORE) -#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE) -#else -#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63) -#endif // defined(VM_MEMORY_JAVASCRIPT_CORE) - -#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) -#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) -#else -#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69) -#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) - -#else // OS(DARWIN) - -#define VM_TAG_FOR_TCMALLOC_MEMORY -1 -#define VM_TAG_FOR_COLLECTOR_MEMORY -1 -#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 -#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 -#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1 - -#endif // OS(DARWIN) - -#endif /* yarr_VMTags_h */ diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h deleted file mode 100644 index 910c3c54b77b..000000000000 --- a/js/src/yarr/Yarr.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_Yarr_h -#define yarr_Yarr_h - -#include -#include "yarr/YarrInterpreter.h" -#include "yarr/YarrPattern.h" - -namespace JSC { namespace Yarr { - -#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers. -#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers. -#define YarrStackSpaceForBackTrackInfoBackReference 2 -#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative. -#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1 -#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers. -#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1 -#define YarrStackSpaceForBackTrackInfoParentheses 2 - -static const unsigned quantifyInfinite = UINT_MAX; -static const unsigned offsetNoMatch = (unsigned)-1; -static const unsigned offsetError = (unsigned)-2; - -// The below limit restricts the number of "recursive" match calls in order to -// avoid spending exponential time on complex regular expressions. -static const unsigned matchLimit = 2500000; - -enum JSRegExpResult { - JSRegExpMatch = 1, - JSRegExpNoMatch = 0, - JSRegExpErrorNoMatch = -1, - JSRegExpErrorHitLimit = -2, - JSRegExpErrorNoMemory = -3, - JSRegExpErrorInternal = -4 -}; - -enum YarrCharSize { - Char8, - Char16 -}; - -} } // namespace JSC::Yarr - -#endif /* yarr_Yarr_h */ diff --git a/js/src/yarr/YarrCanonicalizeUCS2.cpp b/js/src/yarr/YarrCanonicalizeUCS2.cpp deleted file mode 100644 index 75c170f1af1a..000000000000 --- a/js/src/yarr/YarrCanonicalizeUCS2.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// DO NOT EDIT! - this file autogenerated by YarrCanonicalizeUCS2.js - -#include "yarr/YarrCanonicalizeUCS2.h" - -#include - -namespace JSC { namespace Yarr { - -const uint16_t ucs2CharacterSet0[] = { 0x01c4u, 0x01c5u, 0x01c6u, 0 }; -const uint16_t ucs2CharacterSet1[] = { 0x01c7u, 0x01c8u, 0x01c9u, 0 }; -const uint16_t ucs2CharacterSet2[] = { 0x01cau, 0x01cbu, 0x01ccu, 0 }; -const uint16_t ucs2CharacterSet3[] = { 0x01f1u, 0x01f2u, 0x01f3u, 0 }; -const uint16_t ucs2CharacterSet4[] = { 0x0392u, 0x03b2u, 0x03d0u, 0 }; -const uint16_t ucs2CharacterSet5[] = { 0x0395u, 0x03b5u, 0x03f5u, 0 }; -const uint16_t ucs2CharacterSet6[] = { 0x0398u, 0x03b8u, 0x03d1u, 0 }; -const uint16_t ucs2CharacterSet7[] = { 0x0345u, 0x0399u, 0x03b9u, 0x1fbeu, 0 }; -const uint16_t ucs2CharacterSet8[] = { 0x039au, 0x03bau, 0x03f0u, 0 }; -const uint16_t ucs2CharacterSet9[] = { 0x00b5u, 0x039cu, 0x03bcu, 0 }; -const uint16_t ucs2CharacterSet10[] = { 0x03a0u, 0x03c0u, 0x03d6u, 0 }; -const uint16_t ucs2CharacterSet11[] = { 0x03a1u, 0x03c1u, 0x03f1u, 0 }; -const uint16_t ucs2CharacterSet12[] = { 0x03a3u, 0x03c2u, 0x03c3u, 0 }; -const uint16_t ucs2CharacterSet13[] = { 0x03a6u, 0x03c6u, 0x03d5u, 0 }; -const uint16_t ucs2CharacterSet14[] = { 0x1e60u, 0x1e61u, 0x1e9bu, 0 }; - -static const size_t UCS2_CANONICALIZATION_SETS = 15; -const uint16_t* const characterSetInfo[UCS2_CANONICALIZATION_SETS] = { - ucs2CharacterSet0, - ucs2CharacterSet1, - ucs2CharacterSet2, - ucs2CharacterSet3, - ucs2CharacterSet4, - ucs2CharacterSet5, - ucs2CharacterSet6, - ucs2CharacterSet7, - ucs2CharacterSet8, - ucs2CharacterSet9, - ucs2CharacterSet10, - ucs2CharacterSet11, - ucs2CharacterSet12, - ucs2CharacterSet13, - ucs2CharacterSet14, -}; - -const size_t UCS2_CANONICALIZATION_RANGES = 364; -const UCS2CanonicalizationRange rangeInfo[UCS2_CANONICALIZATION_RANGES] = { - { 0x0000u, 0x0040u, 0x0000u, CanonicalizeUnique }, - { 0x0041u, 0x005au, 0x0020u, CanonicalizeRangeLo }, - { 0x005bu, 0x0060u, 0x0000u, CanonicalizeUnique }, - { 0x0061u, 0x007au, 0x0020u, CanonicalizeRangeHi }, - { 0x007bu, 0x00b4u, 0x0000u, CanonicalizeUnique }, - { 0x00b5u, 0x00b5u, 0x0009u, CanonicalizeSet }, - { 0x00b6u, 0x00bfu, 0x0000u, CanonicalizeUnique }, - { 0x00c0u, 0x00d6u, 0x0020u, CanonicalizeRangeLo }, - { 0x00d7u, 0x00d7u, 0x0000u, CanonicalizeUnique }, - { 0x00d8u, 0x00deu, 0x0020u, CanonicalizeRangeLo }, - { 0x00dfu, 0x00dfu, 0x0000u, CanonicalizeUnique }, - { 0x00e0u, 0x00f6u, 0x0020u, CanonicalizeRangeHi }, - { 0x00f7u, 0x00f7u, 0x0000u, CanonicalizeUnique }, - { 0x00f8u, 0x00feu, 0x0020u, CanonicalizeRangeHi }, - { 0x00ffu, 0x00ffu, 0x0079u, CanonicalizeRangeLo }, - { 0x0100u, 0x012fu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0130u, 0x0131u, 0x0000u, CanonicalizeUnique }, - { 0x0132u, 0x0137u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0138u, 0x0138u, 0x0000u, CanonicalizeUnique }, - { 0x0139u, 0x0148u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x0149u, 0x0149u, 0x0000u, CanonicalizeUnique }, - { 0x014au, 0x0177u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0178u, 0x0178u, 0x0079u, CanonicalizeRangeHi }, - { 0x0179u, 0x017eu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x017fu, 0x017fu, 0x0000u, CanonicalizeUnique }, - { 0x0180u, 0x0180u, 0x00c3u, CanonicalizeRangeLo }, - { 0x0181u, 0x0181u, 0x00d2u, CanonicalizeRangeLo }, - { 0x0182u, 0x0185u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0186u, 0x0186u, 0x00ceu, CanonicalizeRangeLo }, - { 0x0187u, 0x0188u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x0189u, 0x018au, 0x00cdu, CanonicalizeRangeLo }, - { 0x018bu, 0x018cu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x018du, 0x018du, 0x0000u, CanonicalizeUnique }, - { 0x018eu, 0x018eu, 0x004fu, CanonicalizeRangeLo }, - { 0x018fu, 0x018fu, 0x00cau, CanonicalizeRangeLo }, - { 0x0190u, 0x0190u, 0x00cbu, CanonicalizeRangeLo }, - { 0x0191u, 0x0192u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x0193u, 0x0193u, 0x00cdu, CanonicalizeRangeLo }, - { 0x0194u, 0x0194u, 0x00cfu, CanonicalizeRangeLo }, - { 0x0195u, 0x0195u, 0x0061u, CanonicalizeRangeLo }, - { 0x0196u, 0x0196u, 0x00d3u, CanonicalizeRangeLo }, - { 0x0197u, 0x0197u, 0x00d1u, CanonicalizeRangeLo }, - { 0x0198u, 0x0199u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x019au, 0x019au, 0x00a3u, CanonicalizeRangeLo }, - { 0x019bu, 0x019bu, 0x0000u, CanonicalizeUnique }, - { 0x019cu, 0x019cu, 0x00d3u, CanonicalizeRangeLo }, - { 0x019du, 0x019du, 0x00d5u, CanonicalizeRangeLo }, - { 0x019eu, 0x019eu, 0x0082u, CanonicalizeRangeLo }, - { 0x019fu, 0x019fu, 0x00d6u, CanonicalizeRangeLo }, - { 0x01a0u, 0x01a5u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x01a6u, 0x01a6u, 0x00dau, CanonicalizeRangeLo }, - { 0x01a7u, 0x01a8u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x01a9u, 0x01a9u, 0x00dau, CanonicalizeRangeLo }, - { 0x01aau, 0x01abu, 0x0000u, CanonicalizeUnique }, - { 0x01acu, 0x01adu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x01aeu, 0x01aeu, 0x00dau, CanonicalizeRangeLo }, - { 0x01afu, 0x01b0u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x01b1u, 0x01b2u, 0x00d9u, CanonicalizeRangeLo }, - { 0x01b3u, 0x01b6u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x01b7u, 0x01b7u, 0x00dbu, CanonicalizeRangeLo }, - { 0x01b8u, 0x01b9u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x01bau, 0x01bbu, 0x0000u, CanonicalizeUnique }, - { 0x01bcu, 0x01bdu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x01beu, 0x01beu, 0x0000u, CanonicalizeUnique }, - { 0x01bfu, 0x01bfu, 0x0038u, CanonicalizeRangeLo }, - { 0x01c0u, 0x01c3u, 0x0000u, CanonicalizeUnique }, - { 0x01c4u, 0x01c6u, 0x0000u, CanonicalizeSet }, - { 0x01c7u, 0x01c9u, 0x0001u, CanonicalizeSet }, - { 0x01cau, 0x01ccu, 0x0002u, CanonicalizeSet }, - { 0x01cdu, 0x01dcu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x01ddu, 0x01ddu, 0x004fu, CanonicalizeRangeHi }, - { 0x01deu, 0x01efu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x01f0u, 0x01f0u, 0x0000u, CanonicalizeUnique }, - { 0x01f1u, 0x01f3u, 0x0003u, CanonicalizeSet }, - { 0x01f4u, 0x01f5u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x01f6u, 0x01f6u, 0x0061u, CanonicalizeRangeHi }, - { 0x01f7u, 0x01f7u, 0x0038u, CanonicalizeRangeHi }, - { 0x01f8u, 0x021fu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0220u, 0x0220u, 0x0082u, CanonicalizeRangeHi }, - { 0x0221u, 0x0221u, 0x0000u, CanonicalizeUnique }, - { 0x0222u, 0x0233u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0234u, 0x0239u, 0x0000u, CanonicalizeUnique }, - { 0x023au, 0x023au, 0x2a2bu, CanonicalizeRangeLo }, - { 0x023bu, 0x023cu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x023du, 0x023du, 0x00a3u, CanonicalizeRangeHi }, - { 0x023eu, 0x023eu, 0x2a28u, CanonicalizeRangeLo }, - { 0x023fu, 0x0240u, 0x2a3fu, CanonicalizeRangeLo }, - { 0x0241u, 0x0242u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x0243u, 0x0243u, 0x00c3u, CanonicalizeRangeHi }, - { 0x0244u, 0x0244u, 0x0045u, CanonicalizeRangeLo }, - { 0x0245u, 0x0245u, 0x0047u, CanonicalizeRangeLo }, - { 0x0246u, 0x024fu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0250u, 0x0250u, 0x2a1fu, CanonicalizeRangeLo }, - { 0x0251u, 0x0251u, 0x2a1cu, CanonicalizeRangeLo }, - { 0x0252u, 0x0252u, 0x2a1eu, CanonicalizeRangeLo }, - { 0x0253u, 0x0253u, 0x00d2u, CanonicalizeRangeHi }, - { 0x0254u, 0x0254u, 0x00ceu, CanonicalizeRangeHi }, - { 0x0255u, 0x0255u, 0x0000u, CanonicalizeUnique }, - { 0x0256u, 0x0257u, 0x00cdu, CanonicalizeRangeHi }, - { 0x0258u, 0x0258u, 0x0000u, CanonicalizeUnique }, - { 0x0259u, 0x0259u, 0x00cau, CanonicalizeRangeHi }, - { 0x025au, 0x025au, 0x0000u, CanonicalizeUnique }, - { 0x025bu, 0x025bu, 0x00cbu, CanonicalizeRangeHi }, - { 0x025cu, 0x025fu, 0x0000u, CanonicalizeUnique }, - { 0x0260u, 0x0260u, 0x00cdu, CanonicalizeRangeHi }, - { 0x0261u, 0x0262u, 0x0000u, CanonicalizeUnique }, - { 0x0263u, 0x0263u, 0x00cfu, CanonicalizeRangeHi }, - { 0x0264u, 0x0264u, 0x0000u, CanonicalizeUnique }, - { 0x0265u, 0x0265u, 0xa528u, CanonicalizeRangeLo }, - { 0x0266u, 0x0267u, 0x0000u, CanonicalizeUnique }, - { 0x0268u, 0x0268u, 0x00d1u, CanonicalizeRangeHi }, - { 0x0269u, 0x0269u, 0x00d3u, CanonicalizeRangeHi }, - { 0x026au, 0x026au, 0x0000u, CanonicalizeUnique }, - { 0x026bu, 0x026bu, 0x29f7u, CanonicalizeRangeLo }, - { 0x026cu, 0x026eu, 0x0000u, CanonicalizeUnique }, - { 0x026fu, 0x026fu, 0x00d3u, CanonicalizeRangeHi }, - { 0x0270u, 0x0270u, 0x0000u, CanonicalizeUnique }, - { 0x0271u, 0x0271u, 0x29fdu, CanonicalizeRangeLo }, - { 0x0272u, 0x0272u, 0x00d5u, CanonicalizeRangeHi }, - { 0x0273u, 0x0274u, 0x0000u, CanonicalizeUnique }, - { 0x0275u, 0x0275u, 0x00d6u, CanonicalizeRangeHi }, - { 0x0276u, 0x027cu, 0x0000u, CanonicalizeUnique }, - { 0x027du, 0x027du, 0x29e7u, CanonicalizeRangeLo }, - { 0x027eu, 0x027fu, 0x0000u, CanonicalizeUnique }, - { 0x0280u, 0x0280u, 0x00dau, CanonicalizeRangeHi }, - { 0x0281u, 0x0282u, 0x0000u, CanonicalizeUnique }, - { 0x0283u, 0x0283u, 0x00dau, CanonicalizeRangeHi }, - { 0x0284u, 0x0287u, 0x0000u, CanonicalizeUnique }, - { 0x0288u, 0x0288u, 0x00dau, CanonicalizeRangeHi }, - { 0x0289u, 0x0289u, 0x0045u, CanonicalizeRangeHi }, - { 0x028au, 0x028bu, 0x00d9u, CanonicalizeRangeHi }, - { 0x028cu, 0x028cu, 0x0047u, CanonicalizeRangeHi }, - { 0x028du, 0x0291u, 0x0000u, CanonicalizeUnique }, - { 0x0292u, 0x0292u, 0x00dbu, CanonicalizeRangeHi }, - { 0x0293u, 0x0344u, 0x0000u, CanonicalizeUnique }, - { 0x0345u, 0x0345u, 0x0007u, CanonicalizeSet }, - { 0x0346u, 0x036fu, 0x0000u, CanonicalizeUnique }, - { 0x0370u, 0x0373u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0374u, 0x0375u, 0x0000u, CanonicalizeUnique }, - { 0x0376u, 0x0377u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0378u, 0x037au, 0x0000u, CanonicalizeUnique }, - { 0x037bu, 0x037du, 0x0082u, CanonicalizeRangeLo }, - { 0x037eu, 0x0385u, 0x0000u, CanonicalizeUnique }, - { 0x0386u, 0x0386u, 0x0026u, CanonicalizeRangeLo }, - { 0x0387u, 0x0387u, 0x0000u, CanonicalizeUnique }, - { 0x0388u, 0x038au, 0x0025u, CanonicalizeRangeLo }, - { 0x038bu, 0x038bu, 0x0000u, CanonicalizeUnique }, - { 0x038cu, 0x038cu, 0x0040u, CanonicalizeRangeLo }, - { 0x038du, 0x038du, 0x0000u, CanonicalizeUnique }, - { 0x038eu, 0x038fu, 0x003fu, CanonicalizeRangeLo }, - { 0x0390u, 0x0390u, 0x0000u, CanonicalizeUnique }, - { 0x0391u, 0x0391u, 0x0020u, CanonicalizeRangeLo }, - { 0x0392u, 0x0392u, 0x0004u, CanonicalizeSet }, - { 0x0393u, 0x0394u, 0x0020u, CanonicalizeRangeLo }, - { 0x0395u, 0x0395u, 0x0005u, CanonicalizeSet }, - { 0x0396u, 0x0397u, 0x0020u, CanonicalizeRangeLo }, - { 0x0398u, 0x0398u, 0x0006u, CanonicalizeSet }, - { 0x0399u, 0x0399u, 0x0007u, CanonicalizeSet }, - { 0x039au, 0x039au, 0x0008u, CanonicalizeSet }, - { 0x039bu, 0x039bu, 0x0020u, CanonicalizeRangeLo }, - { 0x039cu, 0x039cu, 0x0009u, CanonicalizeSet }, - { 0x039du, 0x039fu, 0x0020u, CanonicalizeRangeLo }, - { 0x03a0u, 0x03a0u, 0x000au, CanonicalizeSet }, - { 0x03a1u, 0x03a1u, 0x000bu, CanonicalizeSet }, - { 0x03a2u, 0x03a2u, 0x0000u, CanonicalizeUnique }, - { 0x03a3u, 0x03a3u, 0x000cu, CanonicalizeSet }, - { 0x03a4u, 0x03a5u, 0x0020u, CanonicalizeRangeLo }, - { 0x03a6u, 0x03a6u, 0x000du, CanonicalizeSet }, - { 0x03a7u, 0x03abu, 0x0020u, CanonicalizeRangeLo }, - { 0x03acu, 0x03acu, 0x0026u, CanonicalizeRangeHi }, - { 0x03adu, 0x03afu, 0x0025u, CanonicalizeRangeHi }, - { 0x03b0u, 0x03b0u, 0x0000u, CanonicalizeUnique }, - { 0x03b1u, 0x03b1u, 0x0020u, CanonicalizeRangeHi }, - { 0x03b2u, 0x03b2u, 0x0004u, CanonicalizeSet }, - { 0x03b3u, 0x03b4u, 0x0020u, CanonicalizeRangeHi }, - { 0x03b5u, 0x03b5u, 0x0005u, CanonicalizeSet }, - { 0x03b6u, 0x03b7u, 0x0020u, CanonicalizeRangeHi }, - { 0x03b8u, 0x03b8u, 0x0006u, CanonicalizeSet }, - { 0x03b9u, 0x03b9u, 0x0007u, CanonicalizeSet }, - { 0x03bau, 0x03bau, 0x0008u, CanonicalizeSet }, - { 0x03bbu, 0x03bbu, 0x0020u, CanonicalizeRangeHi }, - { 0x03bcu, 0x03bcu, 0x0009u, CanonicalizeSet }, - { 0x03bdu, 0x03bfu, 0x0020u, CanonicalizeRangeHi }, - { 0x03c0u, 0x03c0u, 0x000au, CanonicalizeSet }, - { 0x03c1u, 0x03c1u, 0x000bu, CanonicalizeSet }, - { 0x03c2u, 0x03c3u, 0x000cu, CanonicalizeSet }, - { 0x03c4u, 0x03c5u, 0x0020u, CanonicalizeRangeHi }, - { 0x03c6u, 0x03c6u, 0x000du, CanonicalizeSet }, - { 0x03c7u, 0x03cbu, 0x0020u, CanonicalizeRangeHi }, - { 0x03ccu, 0x03ccu, 0x0040u, CanonicalizeRangeHi }, - { 0x03cdu, 0x03ceu, 0x003fu, CanonicalizeRangeHi }, - { 0x03cfu, 0x03cfu, 0x0008u, CanonicalizeRangeLo }, - { 0x03d0u, 0x03d0u, 0x0004u, CanonicalizeSet }, - { 0x03d1u, 0x03d1u, 0x0006u, CanonicalizeSet }, - { 0x03d2u, 0x03d4u, 0x0000u, CanonicalizeUnique }, - { 0x03d5u, 0x03d5u, 0x000du, CanonicalizeSet }, - { 0x03d6u, 0x03d6u, 0x000au, CanonicalizeSet }, - { 0x03d7u, 0x03d7u, 0x0008u, CanonicalizeRangeHi }, - { 0x03d8u, 0x03efu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x03f0u, 0x03f0u, 0x0008u, CanonicalizeSet }, - { 0x03f1u, 0x03f1u, 0x000bu, CanonicalizeSet }, - { 0x03f2u, 0x03f2u, 0x0007u, CanonicalizeRangeLo }, - { 0x03f3u, 0x03f4u, 0x0000u, CanonicalizeUnique }, - { 0x03f5u, 0x03f5u, 0x0005u, CanonicalizeSet }, - { 0x03f6u, 0x03f6u, 0x0000u, CanonicalizeUnique }, - { 0x03f7u, 0x03f8u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x03f9u, 0x03f9u, 0x0007u, CanonicalizeRangeHi }, - { 0x03fau, 0x03fbu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x03fcu, 0x03fcu, 0x0000u, CanonicalizeUnique }, - { 0x03fdu, 0x03ffu, 0x0082u, CanonicalizeRangeHi }, - { 0x0400u, 0x040fu, 0x0050u, CanonicalizeRangeLo }, - { 0x0410u, 0x042fu, 0x0020u, CanonicalizeRangeLo }, - { 0x0430u, 0x044fu, 0x0020u, CanonicalizeRangeHi }, - { 0x0450u, 0x045fu, 0x0050u, CanonicalizeRangeHi }, - { 0x0460u, 0x0481u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0482u, 0x0489u, 0x0000u, CanonicalizeUnique }, - { 0x048au, 0x04bfu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x04c0u, 0x04c0u, 0x000fu, CanonicalizeRangeLo }, - { 0x04c1u, 0x04ceu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x04cfu, 0x04cfu, 0x000fu, CanonicalizeRangeHi }, - { 0x04d0u, 0x0527u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x0528u, 0x0530u, 0x0000u, CanonicalizeUnique }, - { 0x0531u, 0x0556u, 0x0030u, CanonicalizeRangeLo }, - { 0x0557u, 0x0560u, 0x0000u, CanonicalizeUnique }, - { 0x0561u, 0x0586u, 0x0030u, CanonicalizeRangeHi }, - { 0x0587u, 0x109fu, 0x0000u, CanonicalizeUnique }, - { 0x10a0u, 0x10c5u, 0x1c60u, CanonicalizeRangeLo }, - { 0x10c6u, 0x1d78u, 0x0000u, CanonicalizeUnique }, - { 0x1d79u, 0x1d79u, 0x8a04u, CanonicalizeRangeLo }, - { 0x1d7au, 0x1d7cu, 0x0000u, CanonicalizeUnique }, - { 0x1d7du, 0x1d7du, 0x0ee6u, CanonicalizeRangeLo }, - { 0x1d7eu, 0x1dffu, 0x0000u, CanonicalizeUnique }, - { 0x1e00u, 0x1e5fu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x1e60u, 0x1e61u, 0x000eu, CanonicalizeSet }, - { 0x1e62u, 0x1e95u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x1e96u, 0x1e9au, 0x0000u, CanonicalizeUnique }, - { 0x1e9bu, 0x1e9bu, 0x000eu, CanonicalizeSet }, - { 0x1e9cu, 0x1e9fu, 0x0000u, CanonicalizeUnique }, - { 0x1ea0u, 0x1effu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x1f00u, 0x1f07u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f08u, 0x1f0fu, 0x0008u, CanonicalizeRangeHi }, - { 0x1f10u, 0x1f15u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f16u, 0x1f17u, 0x0000u, CanonicalizeUnique }, - { 0x1f18u, 0x1f1du, 0x0008u, CanonicalizeRangeHi }, - { 0x1f1eu, 0x1f1fu, 0x0000u, CanonicalizeUnique }, - { 0x1f20u, 0x1f27u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f28u, 0x1f2fu, 0x0008u, CanonicalizeRangeHi }, - { 0x1f30u, 0x1f37u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f38u, 0x1f3fu, 0x0008u, CanonicalizeRangeHi }, - { 0x1f40u, 0x1f45u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f46u, 0x1f47u, 0x0000u, CanonicalizeUnique }, - { 0x1f48u, 0x1f4du, 0x0008u, CanonicalizeRangeHi }, - { 0x1f4eu, 0x1f50u, 0x0000u, CanonicalizeUnique }, - { 0x1f51u, 0x1f51u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f52u, 0x1f52u, 0x0000u, CanonicalizeUnique }, - { 0x1f53u, 0x1f53u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f54u, 0x1f54u, 0x0000u, CanonicalizeUnique }, - { 0x1f55u, 0x1f55u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f56u, 0x1f56u, 0x0000u, CanonicalizeUnique }, - { 0x1f57u, 0x1f57u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f58u, 0x1f58u, 0x0000u, CanonicalizeUnique }, - { 0x1f59u, 0x1f59u, 0x0008u, CanonicalizeRangeHi }, - { 0x1f5au, 0x1f5au, 0x0000u, CanonicalizeUnique }, - { 0x1f5bu, 0x1f5bu, 0x0008u, CanonicalizeRangeHi }, - { 0x1f5cu, 0x1f5cu, 0x0000u, CanonicalizeUnique }, - { 0x1f5du, 0x1f5du, 0x0008u, CanonicalizeRangeHi }, - { 0x1f5eu, 0x1f5eu, 0x0000u, CanonicalizeUnique }, - { 0x1f5fu, 0x1f5fu, 0x0008u, CanonicalizeRangeHi }, - { 0x1f60u, 0x1f67u, 0x0008u, CanonicalizeRangeLo }, - { 0x1f68u, 0x1f6fu, 0x0008u, CanonicalizeRangeHi }, - { 0x1f70u, 0x1f71u, 0x004au, CanonicalizeRangeLo }, - { 0x1f72u, 0x1f75u, 0x0056u, CanonicalizeRangeLo }, - { 0x1f76u, 0x1f77u, 0x0064u, CanonicalizeRangeLo }, - { 0x1f78u, 0x1f79u, 0x0080u, CanonicalizeRangeLo }, - { 0x1f7au, 0x1f7bu, 0x0070u, CanonicalizeRangeLo }, - { 0x1f7cu, 0x1f7du, 0x007eu, CanonicalizeRangeLo }, - { 0x1f7eu, 0x1fafu, 0x0000u, CanonicalizeUnique }, - { 0x1fb0u, 0x1fb1u, 0x0008u, CanonicalizeRangeLo }, - { 0x1fb2u, 0x1fb7u, 0x0000u, CanonicalizeUnique }, - { 0x1fb8u, 0x1fb9u, 0x0008u, CanonicalizeRangeHi }, - { 0x1fbau, 0x1fbbu, 0x004au, CanonicalizeRangeHi }, - { 0x1fbcu, 0x1fbdu, 0x0000u, CanonicalizeUnique }, - { 0x1fbeu, 0x1fbeu, 0x0007u, CanonicalizeSet }, - { 0x1fbfu, 0x1fc7u, 0x0000u, CanonicalizeUnique }, - { 0x1fc8u, 0x1fcbu, 0x0056u, CanonicalizeRangeHi }, - { 0x1fccu, 0x1fcfu, 0x0000u, CanonicalizeUnique }, - { 0x1fd0u, 0x1fd1u, 0x0008u, CanonicalizeRangeLo }, - { 0x1fd2u, 0x1fd7u, 0x0000u, CanonicalizeUnique }, - { 0x1fd8u, 0x1fd9u, 0x0008u, CanonicalizeRangeHi }, - { 0x1fdau, 0x1fdbu, 0x0064u, CanonicalizeRangeHi }, - { 0x1fdcu, 0x1fdfu, 0x0000u, CanonicalizeUnique }, - { 0x1fe0u, 0x1fe1u, 0x0008u, CanonicalizeRangeLo }, - { 0x1fe2u, 0x1fe4u, 0x0000u, CanonicalizeUnique }, - { 0x1fe5u, 0x1fe5u, 0x0007u, CanonicalizeRangeLo }, - { 0x1fe6u, 0x1fe7u, 0x0000u, CanonicalizeUnique }, - { 0x1fe8u, 0x1fe9u, 0x0008u, CanonicalizeRangeHi }, - { 0x1feau, 0x1febu, 0x0070u, CanonicalizeRangeHi }, - { 0x1fecu, 0x1fecu, 0x0007u, CanonicalizeRangeHi }, - { 0x1fedu, 0x1ff7u, 0x0000u, CanonicalizeUnique }, - { 0x1ff8u, 0x1ff9u, 0x0080u, CanonicalizeRangeHi }, - { 0x1ffau, 0x1ffbu, 0x007eu, CanonicalizeRangeHi }, - { 0x1ffcu, 0x2131u, 0x0000u, CanonicalizeUnique }, - { 0x2132u, 0x2132u, 0x001cu, CanonicalizeRangeLo }, - { 0x2133u, 0x214du, 0x0000u, CanonicalizeUnique }, - { 0x214eu, 0x214eu, 0x001cu, CanonicalizeRangeHi }, - { 0x214fu, 0x215fu, 0x0000u, CanonicalizeUnique }, - { 0x2160u, 0x216fu, 0x0010u, CanonicalizeRangeLo }, - { 0x2170u, 0x217fu, 0x0010u, CanonicalizeRangeHi }, - { 0x2180u, 0x2182u, 0x0000u, CanonicalizeUnique }, - { 0x2183u, 0x2184u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x2185u, 0x24b5u, 0x0000u, CanonicalizeUnique }, - { 0x24b6u, 0x24cfu, 0x001au, CanonicalizeRangeLo }, - { 0x24d0u, 0x24e9u, 0x001au, CanonicalizeRangeHi }, - { 0x24eau, 0x2bffu, 0x0000u, CanonicalizeUnique }, - { 0x2c00u, 0x2c2eu, 0x0030u, CanonicalizeRangeLo }, - { 0x2c2fu, 0x2c2fu, 0x0000u, CanonicalizeUnique }, - { 0x2c30u, 0x2c5eu, 0x0030u, CanonicalizeRangeHi }, - { 0x2c5fu, 0x2c5fu, 0x0000u, CanonicalizeUnique }, - { 0x2c60u, 0x2c61u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x2c62u, 0x2c62u, 0x29f7u, CanonicalizeRangeHi }, - { 0x2c63u, 0x2c63u, 0x0ee6u, CanonicalizeRangeHi }, - { 0x2c64u, 0x2c64u, 0x29e7u, CanonicalizeRangeHi }, - { 0x2c65u, 0x2c65u, 0x2a2bu, CanonicalizeRangeHi }, - { 0x2c66u, 0x2c66u, 0x2a28u, CanonicalizeRangeHi }, - { 0x2c67u, 0x2c6cu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x2c6du, 0x2c6du, 0x2a1cu, CanonicalizeRangeHi }, - { 0x2c6eu, 0x2c6eu, 0x29fdu, CanonicalizeRangeHi }, - { 0x2c6fu, 0x2c6fu, 0x2a1fu, CanonicalizeRangeHi }, - { 0x2c70u, 0x2c70u, 0x2a1eu, CanonicalizeRangeHi }, - { 0x2c71u, 0x2c71u, 0x0000u, CanonicalizeUnique }, - { 0x2c72u, 0x2c73u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x2c74u, 0x2c74u, 0x0000u, CanonicalizeUnique }, - { 0x2c75u, 0x2c76u, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x2c77u, 0x2c7du, 0x0000u, CanonicalizeUnique }, - { 0x2c7eu, 0x2c7fu, 0x2a3fu, CanonicalizeRangeHi }, - { 0x2c80u, 0x2ce3u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0x2ce4u, 0x2ceau, 0x0000u, CanonicalizeUnique }, - { 0x2cebu, 0x2ceeu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0x2cefu, 0x2cffu, 0x0000u, CanonicalizeUnique }, - { 0x2d00u, 0x2d25u, 0x1c60u, CanonicalizeRangeHi }, - { 0x2d26u, 0xa63fu, 0x0000u, CanonicalizeUnique }, - { 0xa640u, 0xa66du, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa66eu, 0xa67fu, 0x0000u, CanonicalizeUnique }, - { 0xa680u, 0xa697u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa698u, 0xa721u, 0x0000u, CanonicalizeUnique }, - { 0xa722u, 0xa72fu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa730u, 0xa731u, 0x0000u, CanonicalizeUnique }, - { 0xa732u, 0xa76fu, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa770u, 0xa778u, 0x0000u, CanonicalizeUnique }, - { 0xa779u, 0xa77cu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0xa77du, 0xa77du, 0x8a04u, CanonicalizeRangeHi }, - { 0xa77eu, 0xa787u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa788u, 0xa78au, 0x0000u, CanonicalizeUnique }, - { 0xa78bu, 0xa78cu, 0x0000u, CanonicalizeAlternatingUnaligned }, - { 0xa78du, 0xa78du, 0xa528u, CanonicalizeRangeHi }, - { 0xa78eu, 0xa78fu, 0x0000u, CanonicalizeUnique }, - { 0xa790u, 0xa791u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa792u, 0xa79fu, 0x0000u, CanonicalizeUnique }, - { 0xa7a0u, 0xa7a9u, 0x0000u, CanonicalizeAlternatingAligned }, - { 0xa7aau, 0xff20u, 0x0000u, CanonicalizeUnique }, - { 0xff21u, 0xff3au, 0x0020u, CanonicalizeRangeLo }, - { 0xff3bu, 0xff40u, 0x0000u, CanonicalizeUnique }, - { 0xff41u, 0xff5au, 0x0020u, CanonicalizeRangeHi }, - { 0xff5bu, 0xffffu, 0x0000u, CanonicalizeUnique }, -}; - -const size_t LATIN_CANONICALIZATION_RANGES = 20; -const LatinCanonicalizationRange latinRangeInfo[LATIN_CANONICALIZATION_RANGES] = { - { 0x0000u, 0x0040u, 0x0000u, CanonicalizeLatinSelf }, - { 0x0041u, 0x005au, 0x0000u, CanonicalizeLatinMask0x20 }, - { 0x005bu, 0x0060u, 0x0000u, CanonicalizeLatinSelf }, - { 0x0061u, 0x007au, 0x0000u, CanonicalizeLatinMask0x20 }, - { 0x007bu, 0x00bfu, 0x0000u, CanonicalizeLatinSelf }, - { 0x00c0u, 0x00d6u, 0x0000u, CanonicalizeLatinMask0x20 }, - { 0x00d7u, 0x00d7u, 0x0000u, CanonicalizeLatinSelf }, - { 0x00d8u, 0x00deu, 0x0000u, CanonicalizeLatinMask0x20 }, - { 0x00dfu, 0x00dfu, 0x0000u, CanonicalizeLatinSelf }, - { 0x00e0u, 0x00f6u, 0x0000u, CanonicalizeLatinMask0x20 }, - { 0x00f7u, 0x00f7u, 0x0000u, CanonicalizeLatinSelf }, - { 0x00f8u, 0x00feu, 0x0000u, CanonicalizeLatinMask0x20 }, - { 0x00ffu, 0x00ffu, 0x0000u, CanonicalizeLatinSelf }, - { 0x0100u, 0x0177u, 0x0000u, CanonicalizeLatinInvalid }, - { 0x0178u, 0x0178u, 0x00ffu, CanonicalizeLatinOther }, - { 0x0179u, 0x039bu, 0x0000u, CanonicalizeLatinInvalid }, - { 0x039cu, 0x039cu, 0x00b5u, CanonicalizeLatinOther }, - { 0x039du, 0x03bbu, 0x0000u, CanonicalizeLatinInvalid }, - { 0x03bcu, 0x03bcu, 0x00b5u, CanonicalizeLatinOther }, - { 0x03bdu, 0xffffu, 0x0000u, CanonicalizeLatinInvalid }, -}; - -} } // JSC::Yarr - diff --git a/js/src/yarr/YarrCanonicalizeUCS2.h b/js/src/yarr/YarrCanonicalizeUCS2.h deleted file mode 100644 index a6779ba60b48..000000000000 --- a/js/src/yarr/YarrCanonicalizeUCS2.h +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_YarrCanonicalizeUCS2_h -#define yarr_YarrCanonicalizeUCS2_h - -#include - -#include "yarr/wtfbridge.h" - -namespace JSC { namespace Yarr { - -// This set of data (autogenerated using YarrCanonicalizeUCS2.js into YarrCanonicalizeUCS2.cpp) -// provides information for each UCS2 code point as to the set of code points that it should -// match under the ES5.1 case insensitive RegExp matching rules, specified in 15.10.2.8. -enum UCS2CanonicalizationType { - CanonicalizeUnique, // No canonically equal values, e.g. 0x0. - CanonicalizeSet, // Value indicates a set in characterSetInfo. - CanonicalizeRangeLo, // Value is positive delta to pair, E.g. 0x41 has value 0x20, -> 0x61. - CanonicalizeRangeHi, // Value is positive delta to pair, E.g. 0x61 has value 0x20, -> 0x41. - CanonicalizeAlternatingAligned, // Aligned consequtive pair, e.g. 0x1f4,0x1f5. - CanonicalizeAlternatingUnaligned // Unaligned consequtive pair, e.g. 0x241,0x242. -}; -struct UCS2CanonicalizationRange { uint16_t begin, end, value, type; }; -extern const size_t UCS2_CANONICALIZATION_RANGES; -extern const uint16_t* const characterSetInfo[]; -extern const UCS2CanonicalizationRange rangeInfo[]; - -// This table is similar to the full rangeInfo table, however this maps from UCS2 codepoints to -// the set of Latin1 codepoints that could match. -enum LatinCanonicalizationType { - CanonicalizeLatinSelf, // This character is in the Latin1 range, but has no canonical equivalent in the range. - CanonicalizeLatinMask0x20, // One of a pair of characters, under the mask 0x20. - CanonicalizeLatinOther, // This character is not in the Latin1 range, but canonicalizes to another that is. - CanonicalizeLatinInvalid // Cannot match against Latin1 input. -}; -struct LatinCanonicalizationRange { uint16_t begin, end, value, type; }; -extern const size_t LATIN_CANONICALIZATION_RANGES; -extern const LatinCanonicalizationRange latinRangeInfo[]; - -// This searches in log2 time over ~364 entries, so should typically result in 8 compares. -inline const UCS2CanonicalizationRange* rangeInfoFor(UChar ch) -{ - const UCS2CanonicalizationRange* info = rangeInfo; - size_t entries = UCS2_CANONICALIZATION_RANGES; - - while (true) { - size_t candidate = entries >> 1; - const UCS2CanonicalizationRange* candidateInfo = info + candidate; - if (ch < candidateInfo->begin) - entries = candidate; - else if (ch <= candidateInfo->end) - return candidateInfo; - else { - info = candidateInfo + 1; - entries -= (candidate + 1); - } - } -} - -// Should only be called for characters that have one canonically matching value. -inline UChar getCanonicalPair(const UCS2CanonicalizationRange* info, UChar ch) -{ - ASSERT(ch >= info->begin && ch <= info->end); - switch (info->type) { - case CanonicalizeRangeLo: - return ch + info->value; - case CanonicalizeRangeHi: - return ch - info->value; - case CanonicalizeAlternatingAligned: - return ch ^ 1; - case CanonicalizeAlternatingUnaligned: - return ((ch - 1) ^ 1) + 1; - default: - ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return 0; -} - -// Returns true if no other UCS2 codepoint can match this value. -inline bool isCanonicallyUnique(UChar ch) -{ - return rangeInfoFor(ch)->type == CanonicalizeUnique; -} - -// Returns true if values are equal, under the canonicalization rules. -inline bool areCanonicallyEquivalent(UChar a, UChar b) -{ - const UCS2CanonicalizationRange* info = rangeInfoFor(a); - switch (info->type) { - case CanonicalizeUnique: - return a == b; - case CanonicalizeSet: { - for (const uint16_t* set = characterSetInfo[info->value]; (a = *set); ++set) { - if (a == b) - return true; - } - return false; - } - case CanonicalizeRangeLo: - return (a == b) || (a + info->value == b); - case CanonicalizeRangeHi: - return (a == b) || (a - info->value == b); - case CanonicalizeAlternatingAligned: - return (a | 1) == (b | 1); - case CanonicalizeAlternatingUnaligned: - return ((a - 1) | 1) == ((b - 1) | 1); - } - - ASSERT_NOT_REACHED(); - return false; -} - -} } // JSC::Yarr - -#endif /* yarr_YarrCanonicalizeUCS2_h */ diff --git a/js/src/yarr/YarrCanonicalizeUCS2.js b/js/src/yarr/YarrCanonicalizeUCS2.js deleted file mode 100644 index d2907fa75cf8..000000000000 --- a/js/src/yarr/YarrCanonicalizeUCS2.js +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// See ES 5.1, 15.10.2.8 -function canonicalize(ch) -{ - var u = String.fromCharCode(ch).toUpperCase(); - if (u.length > 1) - return ch; - var cu = u.charCodeAt(0); - if (ch >= 128 && cu < 128) - return ch; - return cu; -} - -var MAX_UCS2 = 0xFFFF; -var MAX_LATIN = 0xFF; - -var groupedCanonically = []; -// Pass 1: populate groupedCanonically - this is mapping from canonicalized -// values back to the set of character code that canonicalize to them. -for (var i = 0; i <= MAX_UCS2; ++i) { - var ch = canonicalize(i); - if (!groupedCanonically[ch]) - groupedCanonically[ch] = []; - groupedCanonically[ch].push(i); -} - -var typeInfo = []; -var latinTypeInfo = []; -var characterSetInfo = []; -// Pass 2: populate typeInfo & characterSetInfo. For every character calculate -// a typeInfo value, described by the types above, and a value payload. -for (cu in groupedCanonically) { - // The set of characters that canonicalize to cu - var characters = groupedCanonically[cu]; - - // If there is only one, it is unique. - if (characters.length == 1) { - typeInfo[characters[0]] = "CanonicalizeUnique:0"; - latinTypeInfo[characters[0]] = characters[0] <= MAX_LATIN ? "CanonicalizeLatinSelf:0" : "CanonicalizeLatinInvalid:0"; - continue; - } - - // Sort the array. - characters.sort(function(x,y){return x-y;}); - - // If there are more than two characters, create an entry in characterSetInfo. - if (characters.length > 2) { - for (i in characters) - typeInfo[characters[i]] = "CanonicalizeSet:" + characterSetInfo.length; - characterSetInfo.push(characters); - - if (characters[1] <= MAX_LATIN) - throw new Error("sets with more than one latin character not supported!"); - if (characters[0] <= MAX_LATIN) { - for (i in characters) - latinTypeInfo[characters[i]] = "CanonicalizeLatinOther:" + characters[0]; - latinTypeInfo[characters[0]] = "CanonicalizeLatinSelf:0"; - } else { - for (i in characters) - latinTypeInfo[characters[i]] = "CanonicalizeLatinInvalid:0"; - } - - continue; - } - - // We have a pair, mark alternating ranges, otherwise track whether this is the low or high partner. - var lo = characters[0]; - var hi = characters[1]; - var delta = hi - lo; - if (delta == 1) { - var type = lo & 1 ? "CanonicalizeAlternatingUnaligned:0" : "CanonicalizeAlternatingAligned:0"; - typeInfo[lo] = type; - typeInfo[hi] = type; - } else { - typeInfo[lo] = "CanonicalizeRangeLo:" + delta; - typeInfo[hi] = "CanonicalizeRangeHi:" + delta; - } - - if (lo > MAX_LATIN) { - latinTypeInfo[lo] = "CanonicalizeLatinInvalid:0"; - latinTypeInfo[hi] = "CanonicalizeLatinInvalid:0"; - } else if (hi > MAX_LATIN) { - latinTypeInfo[lo] = "CanonicalizeLatinSelf:0"; - latinTypeInfo[hi] = "CanonicalizeLatinOther:" + lo; - } else { - if (delta != 0x20 || lo & 0x20) - throw new Error("pairs of latin characters that don't mask with 0x20 not supported!"); - latinTypeInfo[lo] = "CanonicalizeLatinMask0x20:0"; - latinTypeInfo[hi] = "CanonicalizeLatinMask0x20:0"; - } -} - -var rangeInfo = []; -// Pass 3: coallesce types into ranges. -for (var end = 0; end <= MAX_UCS2; ++end) { - var begin = end; - var type = typeInfo[end]; - while (end < MAX_UCS2 && typeInfo[end + 1] == type) - ++end; - rangeInfo.push({begin:begin, end:end, type:type}); -} - -var latinRangeInfo = []; -// Pass 4: coallesce latin-1 types into ranges. -for (var end = 0; end <= MAX_UCS2; ++end) { - var begin = end; - var type = latinTypeInfo[end]; - while (end < MAX_UCS2 && latinTypeInfo[end + 1] == type) - ++end; - latinRangeInfo.push({begin:begin, end:end, type:type}); -} - - -// Helper function to convert a number to a fixed width hex representation of a C uint16_t. -function hex(x) -{ - var s = Number(x).toString(16); - while (s.length < 4) - s = 0 + s; - return "0x" + s + "u"; -} - -var copyright = ( - "/*" + "\n" + - " * Copyright (C) 2012 Apple Inc. All rights reserved." + "\n" + - " *" + "\n" + - " * Redistribution and use in source and binary forms, with or without" + "\n" + - " * modification, are permitted provided that the following conditions" + "\n" + - " * are met:" + "\n" + - " * 1. Redistributions of source code must retain the above copyright" + "\n" + - " * notice, this list of conditions and the following disclaimer." + "\n" + - " * 2. Redistributions in binary form must reproduce the above copyright" + "\n" + - " * notice, this list of conditions and the following disclaimer in the" + "\n" + - " * documentation and/or other materials provided with the distribution." + "\n" + - " *" + "\n" + - " * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY" + "\n" + - " * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + "\n" + - " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR" + "\n" + - " * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR" + "\n" + - " * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL," + "\n" + - " * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO," + "\n" + - " * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR" + "\n" + - " * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY" + "\n" + - " * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT" + "\n" + - " * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + "\n" + - " * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. " + "\n" + - " */"); - -print(copyright); -print(); -print("// DO NOT EDIT! - this file autogenerated by YarrCanonicalizeUCS2.js"); -print(); -print('#include "yarr/YarrCanonicalizeUCS2.h"'); -print(); -print('#include '); -print(); -print("namespace JSC { namespace Yarr {"); -print(); - -for (i in characterSetInfo) { - var characters = "" - var set = characterSetInfo[i]; - for (var j in set) - characters += hex(set[j]) + ", "; - print("uint16_t ucs2CharacterSet" + i + "[] = { " + characters + "0 };"); -} -print(); -print("static const size_t UCS2_CANONICALIZATION_SETS = " + characterSetInfo.length + ";"); -print("uint16_t* characterSetInfo[UCS2_CANONICALIZATION_SETS] = {"); -for (i in characterSetInfo) -print(" ucs2CharacterSet" + i + ","); -print("};"); -print(); -print("const size_t UCS2_CANONICALIZATION_RANGES = " + rangeInfo.length + ";"); -print("UCS2CanonicalizationRange rangeInfo[UCS2_CANONICALIZATION_RANGES] = {"); -for (i in rangeInfo) { - var info = rangeInfo[i]; - var typeAndValue = info.type.split(':'); - print(" { " + hex(info.begin) + ", " + hex(info.end) + ", " + hex(typeAndValue[1]) + ", " + typeAndValue[0] + " },"); -} -print("};"); -print(); -print("const size_t LATIN_CANONICALIZATION_RANGES = " + latinRangeInfo.length + ";"); -print("LatinCanonicalizationRange latinRangeInfo[LATIN_CANONICALIZATION_RANGES] = {"); -for (i in latinRangeInfo) { - var info = latinRangeInfo[i]; - var typeAndValue = info.type.split(':'); - print(" { " + hex(info.begin) + ", " + hex(info.end) + ", " + hex(typeAndValue[1]) + ", " + typeAndValue[0] + " },"); -} -print("};"); -print(); -print("} } // JSC::Yarr"); -print(); - diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp deleted file mode 100644 index 4231fd3ff47a..000000000000 --- a/js/src/yarr/YarrInterpreter.cpp +++ /dev/null @@ -1,1997 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yarr/YarrInterpreter.h" - -#include "jscntxt.h" - -#include "yarr/Yarr.h" -#include "yarr/YarrCanonicalizeUCS2.h" -#include "yarr/BumpPointerAllocator.h" - -using namespace WTF; - -namespace JSC { namespace Yarr { - -template -class Interpreter { -public: - struct ParenthesesDisjunctionContext; - - struct BackTrackInfoPatternCharacter { - uintptr_t matchAmount; - }; - struct BackTrackInfoCharacterClass { - uintptr_t matchAmount; - }; - struct BackTrackInfoBackReference { - uintptr_t begin; // Not really needed for greedy quantifiers. - uintptr_t matchAmount; // Not really needed for fixed quantifiers. - }; - struct BackTrackInfoAlternative { - uintptr_t offset; - }; - struct BackTrackInfoParentheticalAssertion { - uintptr_t begin; - }; - struct BackTrackInfoParenthesesOnce { - uintptr_t begin; - }; - struct BackTrackInfoParenthesesTerminal { - uintptr_t begin; - }; - struct BackTrackInfoParentheses { - uintptr_t matchAmount; - ParenthesesDisjunctionContext* lastContext; - }; - - static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context) - { - context->next = backTrack->lastContext; - backTrack->lastContext = context; - ++backTrack->matchAmount; - } - - static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack) - { - ASSERT(backTrack->matchAmount); - ASSERT(backTrack->lastContext); - backTrack->lastContext = backTrack->lastContext->next; - --backTrack->matchAmount; - } - - struct DisjunctionContext - { - DisjunctionContext() - : term(0) - { - } - - void* operator new(size_t, void* where) - { - return where; - } - - int term; - unsigned matchBegin; - unsigned matchEnd; - uintptr_t frame[1]; - }; - - DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction) - { - size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t); - allocatorPool = allocatorPool->ensureCapacity(size); - if (!allocatorPool) - CRASH(); - return new (allocatorPool->alloc(size)) DisjunctionContext(); - } - - void freeDisjunctionContext(DisjunctionContext* context) - { - allocatorPool = allocatorPool->dealloc(context); - } - - struct ParenthesesDisjunctionContext - { - ParenthesesDisjunctionContext(unsigned* output, ByteTerm& term) - : next(0) - { - unsigned firstSubpatternId = term.atom.subpatternId; - unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns; - - for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) { - subpatternBackup[i] = output[(firstSubpatternId << 1) + i]; - output[(firstSubpatternId << 1) + i] = offsetNoMatch; - } - - new (getDisjunctionContext(term)) DisjunctionContext(); - } - - void* operator new(size_t, void* where) - { - return where; - } - - void restoreOutput(unsigned* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns) - { - for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) - output[(firstSubpatternId << 1) + i] = subpatternBackup[i]; - } - - DisjunctionContext* getDisjunctionContext(ByteTerm& term) - { - return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1])); - } - - ParenthesesDisjunctionContext* next; - unsigned subpatternBackup[1]; - }; - - ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, unsigned* output, ByteTerm& term) - { - size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(unsigned) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(unsigned) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t); - size = JS_ROUNDUP(size, JS_ALIGNMENT_OF(ParenthesesDisjunctionContext)); - allocatorPool = allocatorPool->ensureCapacity(size); - if (!allocatorPool) - CRASH(); - return new (allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term); - } - - void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context) - { - allocatorPool = allocatorPool->dealloc(context); - } - - class InputStream { - public: - InputStream(const CharType* input, unsigned start, unsigned length) - : input(input) - , pos(start) - , length(length) - { - } - - void next() - { - ++pos; - } - - void rewind(unsigned amount) - { - ASSERT(pos >= amount); - pos -= amount; - } - - int read() - { - ASSERT(pos < length); - if (pos < length) - return input[pos]; - return -1; - } - - int readPair() - { - ASSERT(pos + 1 < length); - return input[pos] | input[pos + 1] << 16; - } - - int readChecked(unsigned negativePositionOffest) - { - if (pos < negativePositionOffest) - CRASH(); - unsigned p = pos - negativePositionOffest; - ASSERT(p < length); - return input[p]; - } - - int reread(unsigned from) - { - ASSERT(from < length); - return input[from]; - } - - int prev() - { - ASSERT(!(pos > length)); - if (pos && length) - return input[pos - 1]; - return -1; - } - - unsigned getPos() - { - return pos; - } - - void setPos(unsigned p) - { - pos = p; - } - - bool atStart() - { - return pos == 0; - } - - bool atEnd() - { - return pos == length; - } - - unsigned end() - { - return length; - } - - bool checkInput(unsigned count) - { - if (((pos + count) <= length) && ((pos + count) >= pos)) { - pos += count; - return true; - } - return false; - } - - void uncheckInput(unsigned count) - { - if (pos < count) - CRASH(); - pos -= count; - } - - bool atStart(unsigned negativePositionOffest) - { - return pos == negativePositionOffest; - } - - bool atEnd(unsigned negativePositionOffest) - { - if (pos < negativePositionOffest) - CRASH(); - return (pos - negativePositionOffest) == length; - } - - bool isAvailableInput(unsigned offset) - { - return (((pos + offset) <= length) && ((pos + offset) >= pos)); - } - - private: - const CharType* input; - unsigned pos; - unsigned length; - }; - - bool testCharacterClass(CharacterClass* characterClass, int ch) - { - if (ch & 0xFF80) { - for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i) - if (ch == characterClass->m_matchesUnicode[i]) - return true; - for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i) - if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end)) - return true; - } else { - for (unsigned i = 0; i < characterClass->m_matches.size(); ++i) - if (ch == characterClass->m_matches[i]) - return true; - for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i) - if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end)) - return true; - } - - return false; - } - - bool checkCharacter(int testChar, unsigned negativeInputOffset) - { - return testChar == input.readChecked(negativeInputOffset); - } - - bool checkCasedCharacter(int loChar, int hiChar, unsigned negativeInputOffset) - { - int ch = input.readChecked(negativeInputOffset); - return (loChar == ch) || (hiChar == ch); - } - - bool checkCharacterClass(CharacterClass* characterClass, bool invert, unsigned negativeInputOffset) - { - bool match = testCharacterClass(characterClass, input.readChecked(negativeInputOffset)); - return invert ? !match : match; - } - - bool tryConsumeBackReference(int matchBegin, int matchEnd, unsigned negativeInputOffset) - { - unsigned matchSize = (unsigned)(matchEnd - matchBegin); - - if (!input.checkInput(matchSize)) - return false; - - if (pattern->m_ignoreCase) { - for (unsigned i = 0; i < matchSize; ++i) { - int oldCh = input.reread(matchBegin + i); - int ch = input.readChecked(negativeInputOffset + matchSize - i); - - if (oldCh == ch) - continue; - - // The definition for canonicalize (see ES 5.1, 15.10.2.8) means that - // unicode values are never allowed to match against ascii ones. - if (isASCII(oldCh) || isASCII(ch)) { - if (toASCIIUpper(oldCh) == toASCIIUpper(ch)) - continue; - } else if (areCanonicallyEquivalent(oldCh, ch)) - continue; - - input.uncheckInput(matchSize); - return false; - } - } else { - for (unsigned i = 0; i < matchSize; ++i) { - if (!checkCharacter(input.reread(matchBegin + i), negativeInputOffset + matchSize - i)) { - input.uncheckInput(matchSize); - return false; - } - } - } - - return true; - } - - bool matchAssertionBOL(ByteTerm& term) - { - return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition + 1))); - } - - bool matchAssertionEOL(ByteTerm& term) - { - if (term.inputPosition) - return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition))); - - return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read())); - } - - bool matchAssertionWordBoundary(ByteTerm& term) - { - bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition + 1)); - bool readIsWordchar; - if (term.inputPosition) - readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition)); - else - readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read()); - - bool wordBoundary = prevIsWordchar != readIsWordchar; - return term.invert() ? !wordBoundary : wordBoundary; - } - - bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context) - { - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - switch (term.atom.quantityType) { - case QuantifierFixedCount: - break; - - case QuantifierGreedy: - if (backTrack->matchAmount) { - --backTrack->matchAmount; - input.uncheckInput(1); - return true; - } - break; - - case QuantifierNonGreedy: - if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) { - ++backTrack->matchAmount; - if (checkCharacter(term.atom.patternCharacter, term.inputPosition + 1)) - return true; - } - input.uncheckInput(backTrack->matchAmount); - break; - } - - return false; - } - - bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context) - { - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - switch (term.atom.quantityType) { - case QuantifierFixedCount: - break; - - case QuantifierGreedy: - if (backTrack->matchAmount) { - --backTrack->matchAmount; - input.uncheckInput(1); - return true; - } - break; - - case QuantifierNonGreedy: - if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) { - ++backTrack->matchAmount; - if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition + 1)) - return true; - } - input.uncheckInput(backTrack->matchAmount); - break; - } - - return false; - } - - bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeCharacterClass); - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - switch (term.atom.quantityType) { - case QuantifierFixedCount: { - for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) { - if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - matchAmount)) - return false; - } - return true; - } - - case QuantifierGreedy: { - unsigned matchAmount = 0; - while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) { - if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + 1)) { - input.uncheckInput(1); - break; - } - ++matchAmount; - } - backTrack->matchAmount = matchAmount; - - return true; - } - - case QuantifierNonGreedy: - backTrack->matchAmount = 0; - return true; - } - - ASSERT_NOT_REACHED(); - return false; - } - - bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeCharacterClass); - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - switch (term.atom.quantityType) { - case QuantifierFixedCount: - break; - - case QuantifierGreedy: - if (backTrack->matchAmount) { - --backTrack->matchAmount; - input.uncheckInput(1); - return true; - } - break; - - case QuantifierNonGreedy: - if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) { - ++backTrack->matchAmount; - if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + 1)) - return true; - } - input.uncheckInput(backTrack->matchAmount); - break; - } - - return false; - } - - bool matchBackReference(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeBackReference); - BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - unsigned matchBegin = output[(term.atom.subpatternId << 1)]; - unsigned matchEnd = output[(term.atom.subpatternId << 1) + 1]; - - // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that. - // In this case the result of match is empty string like when it references to a parentheses with zero-width match. - // Eg.: /(a\1)/ - if (matchEnd == offsetNoMatch) - return true; - - if (matchBegin == offsetNoMatch) - return true; - - ASSERT(matchBegin <= matchEnd); - - if (matchBegin == matchEnd) - return true; - - switch (term.atom.quantityType) { - case QuantifierFixedCount: { - backTrack->begin = input.getPos(); - for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) { - if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) { - input.setPos(backTrack->begin); - return false; - } - } - return true; - } - - case QuantifierGreedy: { - unsigned matchAmount = 0; - while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) - ++matchAmount; - backTrack->matchAmount = matchAmount; - return true; - } - - case QuantifierNonGreedy: - backTrack->begin = input.getPos(); - backTrack->matchAmount = 0; - return true; - } - - ASSERT_NOT_REACHED(); - return false; - } - - bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeBackReference); - BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - unsigned matchBegin = output[(term.atom.subpatternId << 1)]; - unsigned matchEnd = output[(term.atom.subpatternId << 1) + 1]; - - if (matchBegin == offsetNoMatch) - return false; - - ASSERT(matchBegin <= matchEnd); - - if (matchBegin == matchEnd) - return false; - - switch (term.atom.quantityType) { - case QuantifierFixedCount: - // for quantityCount == 1, could rewind. - input.setPos(backTrack->begin); - break; - - case QuantifierGreedy: - if (backTrack->matchAmount) { - --backTrack->matchAmount; - input.rewind(matchEnd - matchBegin); - return true; - } - break; - - case QuantifierNonGreedy: - if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) { - ++backTrack->matchAmount; - return true; - } - input.setPos(backTrack->begin); - break; - } - - return false; - } - - void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context) - { - if (term.capture()) { - unsigned subpatternId = term.atom.subpatternId; - output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition; - output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition; - } - } - void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context) - { - unsigned firstSubpatternId = term.atom.subpatternId; - unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns; - context->restoreOutput(output, firstSubpatternId, count); - } - JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack) - { - while (backTrack->matchAmount) { - ParenthesesDisjunctionContext* context = backTrack->lastContext; - - JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true); - if (result == JSRegExpMatch) - return JSRegExpMatch; - - resetMatches(term, context); - popParenthesesDisjunctionContext(backTrack); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - } - - return JSRegExpNoMatch; - } - - bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin); - ASSERT(term.atom.quantityCount == 1); - - BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - switch (term.atom.quantityType) { - case QuantifierGreedy: { - // set this speculatively; if we get to the parens end this will be true. - backTrack->begin = input.getPos(); - break; - } - case QuantifierNonGreedy: { - backTrack->begin = notFound; - context->term += term.atom.parenthesesWidth; - return true; - } - case QuantifierFixedCount: - break; - } - - if (term.capture()) { - unsigned subpatternId = term.atom.subpatternId; - output[(subpatternId << 1)] = input.getPos() - term.inputPosition; - } - - return true; - } - - bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd); - ASSERT(term.atom.quantityCount == 1); - - if (term.capture()) { - unsigned subpatternId = term.atom.subpatternId; - output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition; - } - - if (term.atom.quantityType == QuantifierFixedCount) - return true; - - BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); - return backTrack->begin != input.getPos(); - } - - bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin); - ASSERT(term.atom.quantityCount == 1); - - BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - if (term.capture()) { - unsigned subpatternId = term.atom.subpatternId; - output[(subpatternId << 1)] = offsetNoMatch; - output[(subpatternId << 1) + 1] = offsetNoMatch; - } - - switch (term.atom.quantityType) { - case QuantifierGreedy: - // if we backtrack to this point, there is another chance - try matching nothing. - ASSERT(backTrack->begin != notFound); - backTrack->begin = notFound; - context->term += term.atom.parenthesesWidth; - return true; - case QuantifierNonGreedy: - ASSERT(backTrack->begin != notFound); - case QuantifierFixedCount: - break; - } - - return false; - } - - bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd); - ASSERT(term.atom.quantityCount == 1); - - BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - switch (term.atom.quantityType) { - case QuantifierGreedy: - if (backTrack->begin == notFound) { - context->term -= term.atom.parenthesesWidth; - return false; - } - case QuantifierNonGreedy: - if (backTrack->begin == notFound) { - backTrack->begin = input.getPos(); - if (term.capture()) { - // Technically this access to inputPosition should be accessing the begin term's - // inputPosition, but for repeats other than fixed these values should be - // the same anyway! (We don't pre-check for greedy or non-greedy matches.) - ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin); - - // Disabled, see bug 808478 -#if 0 - ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition); -#endif - unsigned subpatternId = term.atom.subpatternId; - output[subpatternId << 1] = input.getPos() + term.inputPosition; - } - context->term -= term.atom.parenthesesWidth; - return true; - } - case QuantifierFixedCount: - break; - } - - return false; - } - - bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin); - ASSERT(term.atom.quantityType == QuantifierGreedy); - ASSERT(term.atom.quantityCount == quantifyInfinite); - ASSERT(!term.capture()); - - BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation); - backTrack->begin = input.getPos(); - return true; - } - - bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd); - - BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation); - // Empty match is a failed match. - if (backTrack->begin == input.getPos()) - return false; - - // Successful match! Okay, what's next? - loop around and try to match moar! - context->term -= (term.atom.parenthesesWidth + 1); - return true; - } - - bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin); - ASSERT(term.atom.quantityType == QuantifierGreedy); - ASSERT(term.atom.quantityCount == quantifyInfinite); - ASSERT(!term.capture()); - - // If we backtrack to this point, we have failed to match this iteration of the parens. - // Since this is greedy / zero minimum a failed is also accepted as a match! - context->term += term.atom.parenthesesWidth; - return true; - } - - bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*) - { - // 'Terminal' parentheses are at the end of the regex, and as such a match past end - // should always be returned as a successful match - we should never backtrack to here. - ASSERT_NOT_REACHED(); - return false; - } - - bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin); - ASSERT(term.atom.quantityCount == 1); - - BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - backTrack->begin = input.getPos(); - return true; - } - - bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd); - ASSERT(term.atom.quantityCount == 1); - - BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - input.setPos(backTrack->begin); - - // We've reached the end of the parens; if they are inverted, this is failure. - if (term.invert()) { - context->term -= term.atom.parenthesesWidth; - return false; - } - - return true; - } - - bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin); - ASSERT(term.atom.quantityCount == 1); - - // We've failed to match parens; if they are inverted, this is win! - if (term.invert()) { - context->term += term.atom.parenthesesWidth; - return true; - } - - return false; - } - - bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd); - ASSERT(term.atom.quantityCount == 1); - - BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation); - - input.setPos(backTrack->begin); - - context->term -= term.atom.parenthesesWidth; - return false; - } - - JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern); - - BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation); - ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction; - - backTrack->matchAmount = 0; - backTrack->lastContext = 0; - - switch (term.atom.quantityType) { - case QuantifierFixedCount: { - // While we haven't yet reached our fixed limit, - while (backTrack->matchAmount < term.atom.quantityCount) { - // Try to do a match, and it it succeeds, add it to the list. - ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)); - if (result == JSRegExpMatch) - appendParenthesesDisjunctionContext(backTrack, context); - else { - // The match failed; try to find an alternate point to carry on from. - resetMatches(term, context); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack); - if (backtrackResult != JSRegExpMatch) - return backtrackResult; - } - } - - ASSERT(backTrack->matchAmount == term.atom.quantityCount); - ParenthesesDisjunctionContext* context = backTrack->lastContext; - recordParenthesesMatch(term, context); - return JSRegExpMatch; - } - - case QuantifierGreedy: { - while (backTrack->matchAmount < term.atom.quantityCount) { - ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); - if (result == JSRegExpMatch) - appendParenthesesDisjunctionContext(backTrack, context); - else { - resetMatches(term, context); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - - break; - } - } - - if (backTrack->matchAmount) { - ParenthesesDisjunctionContext* context = backTrack->lastContext; - recordParenthesesMatch(term, context); - } - return JSRegExpMatch; - } - - case QuantifierNonGreedy: - return JSRegExpMatch; - } - - ASSERT_NOT_REACHED(); - return JSRegExpErrorNoMatch; - } - - // Rules for backtracking differ depending on whether this is greedy or non-greedy. - // - // Greedy matches never should try just adding more - you should already have done - // the 'more' cases. Always backtrack, at least a leetle bit. However cases where - // you backtrack an item off the list needs checking, since we'll never have matched - // the one less case. Tracking forwards, still add as much as possible. - // - // Non-greedy, we've already done the one less case, so don't match on popping. - // We haven't done the one more case, so always try to add that. - // - JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context) - { - ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern); - - BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation); - ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction; - - switch (term.atom.quantityType) { - case QuantifierFixedCount: { - ASSERT(backTrack->matchAmount == term.atom.quantityCount); - - ParenthesesDisjunctionContext* context = 0; - JSRegExpResult result = parenthesesDoBacktrack(term, backTrack); - - if (result != JSRegExpMatch) - return result; - - // While we haven't yet reached our fixed limit, - while (backTrack->matchAmount < term.atom.quantityCount) { - // Try to do a match, and it it succeeds, add it to the list. - context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)); - - if (result == JSRegExpMatch) - appendParenthesesDisjunctionContext(backTrack, context); - else { - // The match failed; try to find an alternate point to carry on from. - resetMatches(term, context); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack); - if (backtrackResult != JSRegExpMatch) - return backtrackResult; - } - } - - ASSERT(backTrack->matchAmount == term.atom.quantityCount); - context = backTrack->lastContext; - recordParenthesesMatch(term, context); - return JSRegExpMatch; - } - - case QuantifierGreedy: { - if (!backTrack->matchAmount) - return JSRegExpNoMatch; - - ParenthesesDisjunctionContext* context = backTrack->lastContext; - JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true); - if (result == JSRegExpMatch) { - while (backTrack->matchAmount < term.atom.quantityCount) { - ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); - if (parenthesesResult == JSRegExpMatch) - appendParenthesesDisjunctionContext(backTrack, context); - else { - resetMatches(term, context); - freeParenthesesDisjunctionContext(context); - - if (parenthesesResult != JSRegExpNoMatch) - return parenthesesResult; - - break; - } - } - } else { - // Avoid a topcrash before it occurs. - if (!backTrack->lastContext) { - ASSERT(!"Tripped Bug 856796!"); - return JSRegExpErrorInternal; - } - - resetMatches(term, context); - popParenthesesDisjunctionContext(backTrack); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - } - - if (backTrack->matchAmount) { - ParenthesesDisjunctionContext* context = backTrack->lastContext; - recordParenthesesMatch(term, context); - } - return JSRegExpMatch; - } - - case QuantifierNonGreedy: { - // If we've not reached the limit, try to add one more match. - if (backTrack->matchAmount < term.atom.quantityCount) { - ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); - JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); - if (result == JSRegExpMatch) { - appendParenthesesDisjunctionContext(backTrack, context); - recordParenthesesMatch(term, context); - return JSRegExpMatch; - } - - resetMatches(term, context); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - } - - // Nope - okay backtrack looking for an alternative. - while (backTrack->matchAmount) { - ParenthesesDisjunctionContext* context = backTrack->lastContext; - JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true); - if (result == JSRegExpMatch) { - // successful backtrack! we're back in the game! - if (backTrack->matchAmount) { - context = backTrack->lastContext; - recordParenthesesMatch(term, context); - } - return JSRegExpMatch; - } - - // Avoid a topcrash before it occurs. - if (!backTrack->lastContext) { - ASSERT(!"Tripped Bug 856796!"); - return JSRegExpErrorInternal; - } - - // pop a match off the stack - resetMatches(term, context); - popParenthesesDisjunctionContext(backTrack); - freeParenthesesDisjunctionContext(context); - - if (result != JSRegExpNoMatch) - return result; - } - - return JSRegExpNoMatch; - } - } - - ASSERT_NOT_REACHED(); - return JSRegExpErrorNoMatch; - } - - bool matchDotStarEnclosure(ByteTerm& term, DisjunctionContext* context) - { - UNUSED_PARAM(term); - unsigned matchBegin = context->matchBegin; - - if (matchBegin) { - for (matchBegin--; true; matchBegin--) { - if (testCharacterClass(pattern->newlineCharacterClass, input.reread(matchBegin))) { - ++matchBegin; - break; - } - - if (!matchBegin) - break; - } - } - - unsigned matchEnd = input.getPos(); - - for (; (matchEnd != input.end()) - && (!testCharacterClass(pattern->newlineCharacterClass, input.reread(matchEnd))); matchEnd++) { } - - if (((matchBegin && term.anchors.m_bol) - || ((matchEnd != input.end()) && term.anchors.m_eol)) - && !pattern->m_multiline) - return false; - - context->matchBegin = matchBegin; - context->matchEnd = matchEnd; - return true; - } - -#define MATCH_NEXT() { ++context->term; goto matchAgain; } -#define BACKTRACK() { --context->term; goto backtrack; } -#define currentTerm() (disjunction->terms[context->term]) - JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false) - { - if (!--remainingMatchCount) - return JSRegExpErrorHitLimit; - - if (btrack) - BACKTRACK(); - - context->matchBegin = input.getPos(); - context->term = 0; - - matchAgain: - ASSERT(context->term < static_cast(disjunction->terms.size())); - - // Prevent jank resulting from getting stuck in Yarr for a long time. - if (!CheckForInterrupt(this->cx)) - return JSRegExpErrorInternal; - - switch (currentTerm().type) { - case ByteTerm::TypeSubpatternBegin: - MATCH_NEXT(); - case ByteTerm::TypeSubpatternEnd: - context->matchEnd = input.getPos(); - return JSRegExpMatch; - - case ByteTerm::TypeBodyAlternativeBegin: - MATCH_NEXT(); - case ByteTerm::TypeBodyAlternativeDisjunction: - case ByteTerm::TypeBodyAlternativeEnd: - context->matchEnd = input.getPos(); - return JSRegExpMatch; - - case ByteTerm::TypeAlternativeBegin: - MATCH_NEXT(); - case ByteTerm::TypeAlternativeDisjunction: - case ByteTerm::TypeAlternativeEnd: { - int offset = currentTerm().alternative.end; - BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); - backTrack->offset = offset; - context->term += offset; - MATCH_NEXT(); - } - - case ByteTerm::TypeAssertionBOL: - if (matchAssertionBOL(currentTerm())) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeAssertionEOL: - if (matchAssertionEOL(currentTerm())) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeAssertionWordBoundary: - if (matchAssertionWordBoundary(currentTerm())) - MATCH_NEXT(); - BACKTRACK(); - - case ByteTerm::TypePatternCharacterOnce: - case ByteTerm::TypePatternCharacterFixed: { - for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) { - if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - matchAmount)) - BACKTRACK(); - } - MATCH_NEXT(); - } - case ByteTerm::TypePatternCharacterGreedy: { - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); - unsigned matchAmount = 0; - while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) { - if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + 1)) { - input.uncheckInput(1); - break; - } - ++matchAmount; - } - backTrack->matchAmount = matchAmount; - - MATCH_NEXT(); - } - case ByteTerm::TypePatternCharacterNonGreedy: { - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); - backTrack->matchAmount = 0; - MATCH_NEXT(); - } - - case ByteTerm::TypePatternCasedCharacterOnce: - case ByteTerm::TypePatternCasedCharacterFixed: { - for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) { - if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - matchAmount)) - BACKTRACK(); - } - MATCH_NEXT(); - } - case ByteTerm::TypePatternCasedCharacterGreedy: { - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); - unsigned matchAmount = 0; - while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) { - if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + 1)) { - input.uncheckInput(1); - break; - } - ++matchAmount; - } - backTrack->matchAmount = matchAmount; - - MATCH_NEXT(); - } - case ByteTerm::TypePatternCasedCharacterNonGreedy: { - BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); - backTrack->matchAmount = 0; - MATCH_NEXT(); - } - - case ByteTerm::TypeCharacterClass: - if (matchCharacterClass(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeBackReference: - if (matchBackReference(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpattern: { - JSRegExpResult result = matchParentheses(currentTerm(), context); - - if (result == JSRegExpMatch) { - MATCH_NEXT(); - } else if (result != JSRegExpNoMatch) - return result; - - BACKTRACK(); - } - case ByteTerm::TypeParenthesesSubpatternOnceBegin: - if (matchParenthesesOnceBegin(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpatternOnceEnd: - if (matchParenthesesOnceEnd(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpatternTerminalBegin: - if (matchParenthesesTerminalBegin(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpatternTerminalEnd: - if (matchParenthesesTerminalEnd(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParentheticalAssertionBegin: - if (matchParentheticalAssertionBegin(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParentheticalAssertionEnd: - if (matchParentheticalAssertionEnd(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - - case ByteTerm::TypeCheckInput: - if (input.checkInput(currentTerm().checkInputCount)) - MATCH_NEXT(); - BACKTRACK(); - - case ByteTerm::TypeUncheckInput: - input.uncheckInput(currentTerm().checkInputCount); - MATCH_NEXT(); - - case ByteTerm::TypeDotStarEnclosure: - if (matchDotStarEnclosure(currentTerm(), context)) - return JSRegExpMatch; - BACKTRACK(); - } - - // We should never fall-through to here. - ASSERT_NOT_REACHED(); - - backtrack: - ASSERT(context->term < static_cast(disjunction->terms.size())); - - // Prevent jank resulting from getting stuck in Yarr for a long time. - if (!CheckForInterrupt(this->cx)) - return JSRegExpErrorInternal; - - switch (currentTerm().type) { - case ByteTerm::TypeSubpatternBegin: - return JSRegExpNoMatch; - case ByteTerm::TypeSubpatternEnd: - ASSERT_NOT_REACHED(); - - case ByteTerm::TypeBodyAlternativeBegin: - case ByteTerm::TypeBodyAlternativeDisjunction: { - int offset = currentTerm().alternative.next; - context->term += offset; - if (offset > 0) - MATCH_NEXT(); - - if (input.atEnd()) - return JSRegExpNoMatch; - - input.next(); - - context->matchBegin = input.getPos(); - - if (currentTerm().alternative.onceThrough) - context->term += currentTerm().alternative.next; - - MATCH_NEXT(); - } - case ByteTerm::TypeBodyAlternativeEnd: - ASSERT_NOT_REACHED(); - - case ByteTerm::TypeAlternativeBegin: - case ByteTerm::TypeAlternativeDisjunction: { - int offset = currentTerm().alternative.next; - context->term += offset; - if (offset > 0) - MATCH_NEXT(); - BACKTRACK(); - } - case ByteTerm::TypeAlternativeEnd: { - // We should never backtrack back into an alternative of the main body of the regex. - BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); - unsigned offset = backTrack->offset; - context->term -= offset; - BACKTRACK(); - } - - case ByteTerm::TypeAssertionBOL: - case ByteTerm::TypeAssertionEOL: - case ByteTerm::TypeAssertionWordBoundary: - BACKTRACK(); - - case ByteTerm::TypePatternCharacterOnce: - case ByteTerm::TypePatternCharacterFixed: - case ByteTerm::TypePatternCharacterGreedy: - case ByteTerm::TypePatternCharacterNonGreedy: - if (backtrackPatternCharacter(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypePatternCasedCharacterOnce: - case ByteTerm::TypePatternCasedCharacterFixed: - case ByteTerm::TypePatternCasedCharacterGreedy: - case ByteTerm::TypePatternCasedCharacterNonGreedy: - if (backtrackPatternCasedCharacter(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeCharacterClass: - if (backtrackCharacterClass(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeBackReference: - if (backtrackBackReference(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpattern: { - JSRegExpResult result = backtrackParentheses(currentTerm(), context); - - if (result == JSRegExpMatch) { - MATCH_NEXT(); - } else if (result != JSRegExpNoMatch) - return result; - - BACKTRACK(); - } - case ByteTerm::TypeParenthesesSubpatternOnceBegin: - if (backtrackParenthesesOnceBegin(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpatternOnceEnd: - if (backtrackParenthesesOnceEnd(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpatternTerminalBegin: - if (backtrackParenthesesTerminalBegin(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParenthesesSubpatternTerminalEnd: - if (backtrackParenthesesTerminalEnd(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParentheticalAssertionBegin: - if (backtrackParentheticalAssertionBegin(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - case ByteTerm::TypeParentheticalAssertionEnd: - if (backtrackParentheticalAssertionEnd(currentTerm(), context)) - MATCH_NEXT(); - BACKTRACK(); - - case ByteTerm::TypeCheckInput: - input.uncheckInput(currentTerm().checkInputCount); - BACKTRACK(); - - case ByteTerm::TypeUncheckInput: - input.checkInput(currentTerm().checkInputCount); - BACKTRACK(); - - case ByteTerm::TypeDotStarEnclosure: - ASSERT_NOT_REACHED(); - } - - ASSERT_NOT_REACHED(); - return JSRegExpErrorNoMatch; - } - - JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false) - { - JSRegExpResult result = matchDisjunction(disjunction, context, btrack); - - if (result == JSRegExpMatch) { - while (context->matchBegin == context->matchEnd) { - result = matchDisjunction(disjunction, context, true); - if (result != JSRegExpMatch) - return result; - } - return JSRegExpMatch; - } - - return result; - } - - unsigned interpret() - { - if (!input.isAvailableInput(0)) - return offsetNoMatch; - - for (unsigned i = 0; i < pattern->m_body->m_numSubpatterns + 1; ++i) - output[i << 1] = offsetNoMatch; - - allocatorPool = pattern->m_allocator->startAllocator(); - if (!allocatorPool) - CRASH(); - - DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get()); - - JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false); - if (result == JSRegExpMatch) { - output[0] = context->matchBegin; - output[1] = context->matchEnd; - } - - freeDisjunctionContext(context); - - pattern->m_allocator->stopAllocator(); - - if (result != JSRegExpMatch && result != JSRegExpNoMatch) - output[0] = offsetError; - else - ASSERT((result == JSRegExpMatch) == (output[0] != offsetNoMatch)); - return output[0]; - } - - Interpreter(JSContext *cx, BytecodePattern* pattern, unsigned* output, const CharType* input, unsigned length, unsigned start) - : cx(cx) - , pattern(pattern) - , output(output) - , input(input, start, length) - , allocatorPool(0) - , remainingMatchCount(matchLimit) - { - } - -private: - JSContext *cx; - BytecodePattern* pattern; - unsigned* output; - InputStream input; - BumpPointerPool* allocatorPool; - unsigned remainingMatchCount; -}; - - - -class ByteCompiler { - struct ParenthesesStackEntry { - unsigned beginTerm; - unsigned savedAlternativeIndex; - - // For js::Vector. Does not create a valid object. - ParenthesesStackEntry() { } - - ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/) - : beginTerm(beginTerm) - , savedAlternativeIndex(savedAlternativeIndex) - { - } - }; - -public: - ByteCompiler(YarrPattern& pattern) - : m_pattern(pattern) - { - m_currentAlternativeIndex = 0; - } - - PassOwnPtr compile(BumpPointerAllocator* allocator) - { - regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough()); - emitDisjunction(m_pattern.m_body); - regexEnd(); - - return adoptPtr(newOrCrash(m_bodyDisjunction.release(), m_allParenthesesInfo, Ref(m_pattern), allocator)); - } - - void checkInput(unsigned count) - { - m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count)); - } - - void uncheckInput(unsigned count) - { - m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count)); - } - - void assertionBOL(unsigned inputPosition) - { - m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition)); - } - - void assertionEOL(unsigned inputPosition) - { - m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition)); - } - - void assertionWordBoundary(bool invert, unsigned inputPosition) - { - m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition)); - } - - void atomPatternCharacter(UChar ch, unsigned inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - { - if (m_pattern.m_ignoreCase) { - UChar lo = Unicode::toLower(ch); - UChar hi = Unicode::toUpper(ch); - - if (lo != hi) { - m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType)); - return; - } - } - - m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType)); - } - - void atomCharacterClass(CharacterClass* characterClass, bool invert, unsigned inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - { - m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition)); - - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - } - - void atomBackReference(unsigned subpatternId, unsigned inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - { - ASSERT(subpatternId); - - m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition)); - - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - } - - void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, unsigned inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) - { - int beginTerm = m_bodyDisjunction->terms.size(); - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition)); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; - - m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); - m_currentAlternativeIndex = beginTerm + 1; - } - - void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, unsigned inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) - { - int beginTerm = m_bodyDisjunction->terms.size(); - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition)); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; - - m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); - m_currentAlternativeIndex = beginTerm + 1; - } - - void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, unsigned inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) - { - // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin, - // then fix this up at the end! - simplifying this should make it much clearer. - // https://bugs.webkit.org/show_bug.cgi?id=50136 - - int beginTerm = m_bodyDisjunction->terms.size(); - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition)); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; - - m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); - m_currentAlternativeIndex = beginTerm + 1; - } - - void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation) - { - int beginTerm = m_bodyDisjunction->terms.size(); - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0)); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); - m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; - - m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); - m_currentAlternativeIndex = beginTerm + 1; - } - - void atomParentheticalAssertionEnd(unsigned inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - { - unsigned beginTerm = popParenthesesStack(); - closeAlternative(beginTerm + 1); - unsigned endTerm = m_bodyDisjunction->terms.size(); - - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin); - - bool invert = m_bodyDisjunction->terms[beginTerm].invert(); - unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition)); - m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; - m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; - m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; - - m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; - m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; - } - - void assertionDotStarEnclosure(bool bolAnchored, bool eolAnchored) - { - m_bodyDisjunction->terms.append(ByteTerm::DotStarEnclosure(bolAnchored, eolAnchored)); - } - - unsigned popParenthesesStack() - { - ASSERT(m_parenthesesStack.size()); - int stackEnd = m_parenthesesStack.size() - 1; - unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm; - m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex; - m_parenthesesStack.shrink(stackEnd); - - ASSERT(beginTerm < m_bodyDisjunction->terms.size()); - ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size()); - - return beginTerm; - } - -#ifndef NDEBUG - void dumpDisjunction(ByteDisjunction* disjunction) - { - dataLogF("ByteDisjunction(%p):\n\t", (void *)disjunction); - for (unsigned i = 0; i < disjunction->terms.size(); ++i) - dataLogF("{ %d } ", disjunction->terms[i].type); - dataLogF("\n"); - } -#endif - - void closeAlternative(int beginTerm) - { - int origBeginTerm = beginTerm; - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin); - int endIndex = m_bodyDisjunction->terms.size(); - - unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation; - - if (!m_bodyDisjunction->terms[beginTerm].alternative.next) - m_bodyDisjunction->terms.remove(beginTerm); - else { - while (m_bodyDisjunction->terms[beginTerm].alternative.next) { - beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next; - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction); - m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; - m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; - } - - m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; - - m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd()); - m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation; - } - } - - void closeBodyAlternative() - { - int beginTerm = 0; - int origBeginTerm = 0; - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin); - int endIndex = m_bodyDisjunction->terms.size(); - - unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation; - - while (m_bodyDisjunction->terms[beginTerm].alternative.next) { - beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next; - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction); - m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; - m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; - } - - m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; - - m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd()); - m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation; - } - - void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0) - { - unsigned beginTerm = popParenthesesStack(); - closeAlternative(beginTerm + 1); - unsigned endTerm = m_bodyDisjunction->terms.size(); - - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin); - - ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm]; - - bool capture = parenthesesBegin.capture(); - unsigned subpatternId = parenthesesBegin.atom.subpatternId; - - unsigned numSubpatterns = lastSubpatternId - subpatternId + 1; - ByteDisjunction* parenthesesDisjunction = newOrCrash(numSubpatterns, callFrameSize); - - parenthesesDisjunction->terms.reserve(endTerm - beginTerm + 1); - parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin()); - for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses) - parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]); - parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd()); - - m_bodyDisjunction->terms.shrink(beginTerm); - - m_allParenthesesInfo.append(parenthesesDisjunction); - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition)); - - m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; - m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; - } - - void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - { - unsigned beginTerm = popParenthesesStack(); - closeAlternative(beginTerm + 1); - unsigned endTerm = m_bodyDisjunction->terms.size(); - - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin); - - bool capture = m_bodyDisjunction->terms[beginTerm].capture(); - unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition)); - m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; - m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; - m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; - - m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; - m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; - } - - void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - { - unsigned beginTerm = popParenthesesStack(); - closeAlternative(beginTerm + 1); - unsigned endTerm = m_bodyDisjunction->terms.size(); - - ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin); - - bool capture = m_bodyDisjunction->terms[beginTerm].capture(); - unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; - - m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition)); - m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; - m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; - m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; - - m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; - m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount.unsafeGet(); - m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; - } - - void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough) - { - m_bodyDisjunction = adoptPtr(newOrCrash(numSubpatterns, callFrameSize)); - m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough)); - m_bodyDisjunction->terms[0].frameLocation = 0; - m_currentAlternativeIndex = 0; - } - - void regexEnd() - { - closeBodyAlternative(); - } - - void alternativeBodyDisjunction(bool onceThrough) - { - int newAlternativeIndex = m_bodyDisjunction->terms.size(); - m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; - m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough)); - - m_currentAlternativeIndex = newAlternativeIndex; - } - - void alternativeDisjunction() - { - int newAlternativeIndex = m_bodyDisjunction->terms.size(); - m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; - m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction()); - - m_currentAlternativeIndex = newAlternativeIndex; - } - - void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0) - { - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { - unsigned currentCountAlreadyChecked = inputCountAlreadyChecked; - - PatternAlternative* alternative = disjunction->m_alternatives[alt]; - - if (alt) { - if (disjunction == m_pattern.m_body) - alternativeBodyDisjunction(alternative->onceThrough()); - else - alternativeDisjunction(); - } - - unsigned minimumSize = alternative->m_minimumSize; - ASSERT(minimumSize >= parenthesesInputCountAlreadyChecked); - unsigned countToCheck = minimumSize - parenthesesInputCountAlreadyChecked; - - if (countToCheck) { - checkInput(countToCheck); - currentCountAlreadyChecked += countToCheck; - } - - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { - PatternTerm& term = alternative->m_terms[i]; - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - assertionBOL(currentCountAlreadyChecked - term.inputPosition); - break; - - case PatternTerm::TypeAssertionEOL: - assertionEOL(currentCountAlreadyChecked - term.inputPosition); - break; - - case PatternTerm::TypeAssertionWordBoundary: - assertionWordBoundary(term.invert(), currentCountAlreadyChecked - term.inputPosition); - break; - - case PatternTerm::TypePatternCharacter: - atomPatternCharacter(term.patternCharacter, currentCountAlreadyChecked - term.inputPosition, term.frameLocation, term.quantityCount, term.quantityType); - break; - - case PatternTerm::TypeCharacterClass: - atomCharacterClass(term.characterClass, term.invert(), currentCountAlreadyChecked- term.inputPosition, term.frameLocation, term.quantityCount, term.quantityType); - break; - - case PatternTerm::TypeBackReference: - atomBackReference(term.backReferenceSubpatternId, currentCountAlreadyChecked - term.inputPosition, term.frameLocation, term.quantityCount, term.quantityType); - break; - - case PatternTerm::TypeForwardReference: - break; - - case PatternTerm::TypeParenthesesSubpattern: { - unsigned disjunctionAlreadyCheckedCount = 0; - if (term.quantityCount == 1 && !term.parentheses.isCopy) { - unsigned alternativeFrameLocation = term.frameLocation; - // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame. - if (term.quantityType == QuantifierFixedCount) - disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize; - else - alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; - unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked; - atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), disjunctionAlreadyCheckedCount - delegateEndInputOffset, term.frameLocation, alternativeFrameLocation); - emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount); - atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType); - } else if (term.parentheses.isTerminal) { - unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked; - atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), disjunctionAlreadyCheckedCount - delegateEndInputOffset, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce); - emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount); - atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType); - } else { - unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked; - atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), disjunctionAlreadyCheckedCount - delegateEndInputOffset, term.frameLocation, 0); - emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0); - atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize); - } - break; - } - - case PatternTerm::TypeParentheticalAssertion: { - unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion; - - ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition)); - unsigned positiveInputOffset = currentCountAlreadyChecked - static_cast(term.inputPosition); - unsigned uncheckAmount = 0; - if (positiveInputOffset > term.parentheses.disjunction->m_minimumSize) { - uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize; - uncheckInput(uncheckAmount); - currentCountAlreadyChecked -= uncheckAmount; - } - - atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation); - emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount); - atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType); - if (uncheckAmount) { - checkInput(uncheckAmount); - currentCountAlreadyChecked += uncheckAmount; - } - break; - } - - case PatternTerm::TypeDotStarEnclosure: - assertionDotStarEnclosure(term.anchors.bolAnchor, term.anchors.eolAnchor); - break; - } - } - } - } - -private: - YarrPattern& m_pattern; - OwnPtr m_bodyDisjunction; - unsigned m_currentAlternativeIndex; - Vector m_parenthesesStack; - Vector m_allParenthesesInfo; -}; - -PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator) -{ - return ByteCompiler(pattern).compile(allocator); -} - -unsigned interpret(JSContext *cx, BytecodePattern* bytecode, const String& input, unsigned start, unsigned* output) -{ -#if YARR_8BIT_CHAR_SUPPORT - if (input.is8Bit()) - return Interpreter(cx, bytecode, output, input.characters8(), input.length(), start).interpret(); -#endif - return Interpreter(cx, bytecode, output, input.chars(), input.length(), start).interpret(); -} - -unsigned interpret(JSContext *cx, BytecodePattern* bytecode, const LChar* input, unsigned length, unsigned start, unsigned* output) -{ - return Interpreter(cx, bytecode, output, input, length, start).interpret(); -} - -unsigned interpret(JSContext *cx, BytecodePattern* bytecode, const UChar* input, unsigned length, unsigned start, unsigned* output) -{ - return Interpreter(cx, bytecode, output, input, length, start).interpret(); -} - -// These should be the same for both UChar & LChar. -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter); -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass); -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference); -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative); -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion); -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce); -COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses); - - -} } diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h deleted file mode 100644 index 091ffc46d90b..000000000000 --- a/js/src/yarr/YarrInterpreter.h +++ /dev/null @@ -1,395 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_YarrInterpreter_h -#define yarr_YarrInterpreter_h - -#include "yarr/YarrPattern.h" - -namespace WTF { -class BumpPointerAllocator; -} -using WTF::BumpPointerAllocator; - -namespace JSC { namespace Yarr { - -class ByteDisjunction; - -struct ByteTerm { - enum Type { - TypeBodyAlternativeBegin, - TypeBodyAlternativeDisjunction, - TypeBodyAlternativeEnd, - TypeAlternativeBegin, - TypeAlternativeDisjunction, - TypeAlternativeEnd, - TypeSubpatternBegin, - TypeSubpatternEnd, - TypeAssertionBOL, - TypeAssertionEOL, - TypeAssertionWordBoundary, - TypePatternCharacterOnce, - TypePatternCharacterFixed, - TypePatternCharacterGreedy, - TypePatternCharacterNonGreedy, - TypePatternCasedCharacterOnce, - TypePatternCasedCharacterFixed, - TypePatternCasedCharacterGreedy, - TypePatternCasedCharacterNonGreedy, - TypeCharacterClass, - TypeBackReference, - TypeParenthesesSubpattern, - TypeParenthesesSubpatternOnceBegin, - TypeParenthesesSubpatternOnceEnd, - TypeParenthesesSubpatternTerminalBegin, - TypeParenthesesSubpatternTerminalEnd, - TypeParentheticalAssertionBegin, - TypeParentheticalAssertionEnd, - TypeCheckInput, - TypeUncheckInput, - TypeDotStarEnclosure - } type; - union { - struct { - union { - UChar patternCharacter; - struct { - UChar lo; - UChar hi; - } casedCharacter; - CharacterClass* characterClass; - unsigned subpatternId; - }; - union { - ByteDisjunction* parenthesesDisjunction; - unsigned parenthesesWidth; - }; - QuantifierType quantityType; - unsigned quantityCount; - } atom; - struct { - int next; - int end; - bool onceThrough; - } alternative; - struct { - bool m_bol : 1; - bool m_eol : 1; - } anchors; - unsigned checkInputCount; - }; - unsigned frameLocation; - bool m_capture : 1; - bool m_invert : 1; - unsigned inputPosition; - - ByteTerm(UChar ch, int inputPos, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - : frameLocation(frameLocation) - , m_capture(false) - , m_invert(false) - { - switch (quantityType) { - case QuantifierFixedCount: - type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed; - break; - case QuantifierGreedy: - type = ByteTerm::TypePatternCharacterGreedy; - break; - case QuantifierNonGreedy: - type = ByteTerm::TypePatternCharacterNonGreedy; - break; - } - - atom.patternCharacter = ch; - atom.quantityType = quantityType; - atom.quantityCount = quantityCount.unsafeGet(); - inputPosition = inputPos; - } - - ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, Checked quantityCount, QuantifierType quantityType) - : frameLocation(frameLocation) - , m_capture(false) - , m_invert(false) - { - switch (quantityType) { - case QuantifierFixedCount: - type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed; - break; - case QuantifierGreedy: - type = ByteTerm::TypePatternCasedCharacterGreedy; - break; - case QuantifierNonGreedy: - type = ByteTerm::TypePatternCasedCharacterNonGreedy; - break; - } - - atom.casedCharacter.lo = lo; - atom.casedCharacter.hi = hi; - atom.quantityType = quantityType; - atom.quantityCount = quantityCount.unsafeGet(); - inputPosition = inputPos; - } - - ByteTerm(CharacterClass* characterClass, bool invert, int inputPos) - : type(ByteTerm::TypeCharacterClass) - , m_capture(false) - , m_invert(invert) - { - atom.characterClass = characterClass; - atom.quantityType = QuantifierFixedCount; - atom.quantityCount = 1; - inputPosition = inputPos; - } - - ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos) - : type(type) - , m_capture(capture) - , m_invert(false) - { - atom.subpatternId = subpatternId; - atom.parenthesesDisjunction = parenthesesInfo; - atom.quantityType = QuantifierFixedCount; - atom.quantityCount = 1; - inputPosition = inputPos; - } - - ByteTerm(Type type, bool invert = false) - : type(type) - , m_capture(false) - , m_invert(invert) - { - atom.quantityType = QuantifierFixedCount; - atom.quantityCount = 1; - } - - ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos) - : type(type) - , m_capture(capture) - , m_invert(invert) - { - atom.subpatternId = subpatternId; - atom.quantityType = QuantifierFixedCount; - atom.quantityCount = 1; - inputPosition = inputPos; - } - - // For js::Vector. Does not create a valid object. - ByteTerm() - { - } - - static ByteTerm BOL(int inputPos) - { - ByteTerm term(TypeAssertionBOL); - term.inputPosition = inputPos; - return term; - } - - static ByteTerm CheckInput(Checked count) - { - ByteTerm term(TypeCheckInput); - term.checkInputCount = count.unsafeGet(); - return term; - } - - static ByteTerm UncheckInput(Checked count) - { - ByteTerm term(TypeUncheckInput); - term.checkInputCount = count.unsafeGet(); - return term; - } - - static ByteTerm EOL(int inputPos) - { - ByteTerm term(TypeAssertionEOL); - term.inputPosition = inputPos; - return term; - } - - static ByteTerm WordBoundary(bool invert, int inputPos) - { - ByteTerm term(TypeAssertionWordBoundary, invert); - term.inputPosition = inputPos; - return term; - } - - static ByteTerm BackReference(unsigned subpatternId, int inputPos) - { - return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos); - } - - static ByteTerm BodyAlternativeBegin(bool onceThrough) - { - ByteTerm term(TypeBodyAlternativeBegin); - term.alternative.next = 0; - term.alternative.end = 0; - term.alternative.onceThrough = onceThrough; - return term; - } - - static ByteTerm BodyAlternativeDisjunction(bool onceThrough) - { - ByteTerm term(TypeBodyAlternativeDisjunction); - term.alternative.next = 0; - term.alternative.end = 0; - term.alternative.onceThrough = onceThrough; - return term; - } - - static ByteTerm BodyAlternativeEnd() - { - ByteTerm term(TypeBodyAlternativeEnd); - term.alternative.next = 0; - term.alternative.end = 0; - term.alternative.onceThrough = false; - return term; - } - - static ByteTerm AlternativeBegin() - { - ByteTerm term(TypeAlternativeBegin); - term.alternative.next = 0; - term.alternative.end = 0; - term.alternative.onceThrough = false; - return term; - } - - static ByteTerm AlternativeDisjunction() - { - ByteTerm term(TypeAlternativeDisjunction); - term.alternative.next = 0; - term.alternative.end = 0; - term.alternative.onceThrough = false; - return term; - } - - static ByteTerm AlternativeEnd() - { - ByteTerm term(TypeAlternativeEnd); - term.alternative.next = 0; - term.alternative.end = 0; - term.alternative.onceThrough = false; - return term; - } - - static ByteTerm SubpatternBegin() - { - return ByteTerm(TypeSubpatternBegin); - } - - static ByteTerm SubpatternEnd() - { - return ByteTerm(TypeSubpatternEnd); - } - - static ByteTerm DotStarEnclosure(bool bolAnchor, bool eolAnchor) - { - ByteTerm term(TypeDotStarEnclosure); - term.anchors.m_bol = bolAnchor; - term.anchors.m_eol = eolAnchor; - return term; - } - - bool invert() - { - return m_invert; - } - - bool capture() - { - return m_capture; - } -}; - -class ByteDisjunction { - WTF_MAKE_FAST_ALLOCATED; -public: - ByteDisjunction(unsigned numSubpatterns, unsigned frameSize) - : m_numSubpatterns(numSubpatterns) - , m_frameSize(frameSize) - { - } - - Vector terms; - unsigned m_numSubpatterns; - unsigned m_frameSize; -}; - -struct BytecodePattern { - WTF_MAKE_FAST_ALLOCATED; -public: - BytecodePattern(PassOwnPtr body, Vector &allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator) - : m_body(body) - , m_ignoreCase(pattern.m_ignoreCase) - , m_multiline(pattern.m_multiline) - , m_allocator(allocator) - { - newlineCharacterClass = pattern.newlineCharacterClass(); - wordcharCharacterClass = pattern.wordcharCharacterClass(); - - // Trick: 'Steal' the YarrPattern's ParenthesesInfo! - // The input vector isn't used afterwards anymore, - // that way we don't have to copy the input. - JS_ASSERT(m_allParenthesesInfo.size() == 0); - m_allParenthesesInfo.swap(allParenthesesInfo); - - // Trick: 'Steal' the YarrPattern's CharacterClasses! - // The input vector isn't used afterwards anymore, - // that way we don't have to copy the input. - JS_ASSERT(m_userCharacterClasses.size() == 0); - m_userCharacterClasses.swap(pattern.m_userCharacterClasses); - } - - ~BytecodePattern() - { - deleteAllValues(m_allParenthesesInfo); - deleteAllValues(m_userCharacterClasses); - } - - OwnPtr m_body; - bool m_ignoreCase; - bool m_multiline; - // Each BytecodePattern is associated with a RegExp, each RegExp is associated - // with a JSGlobalData. Cache a pointer to out JSGlobalData's m_regExpAllocator. - BumpPointerAllocator* m_allocator; - - CharacterClass* newlineCharacterClass; - CharacterClass* wordcharCharacterClass; - -private: - Vector m_allParenthesesInfo; - Vector m_userCharacterClasses; -}; - -JS_EXPORT_PRIVATE PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*); -JS_EXPORT_PRIVATE unsigned interpret(JSContext *cx, BytecodePattern*, const String& input, unsigned start, unsigned* output); -unsigned interpret(JSContext *cx, BytecodePattern*, const LChar* input, unsigned length, unsigned start, unsigned* output); -unsigned interpret(JSContext *cx, BytecodePattern*, const UChar* input, unsigned length, unsigned start, unsigned* output); - -} } // namespace JSC::Yarr - -#endif /* yarr_YarrInterpreter_h */ diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp deleted file mode 100644 index 276eaf11396c..000000000000 --- a/js/src/yarr/YarrJIT.cpp +++ /dev/null @@ -1,2804 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yarr/YarrJIT.h" - -#include "assembler/assembler/LinkBuffer.h" -#include "yarr/Yarr.h" -#include "yarr/YarrCanonicalizeUCS2.h" - -#if JS_ION - -using namespace WTF; - -namespace JSC { namespace Yarr { - -template -class YarrGenerator : private MacroAssembler { - friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const String& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); - -#if WTF_CPU_ARM - static const RegisterID input = ARMRegisters::r0; - static const RegisterID index = ARMRegisters::r1; - static const RegisterID length = ARMRegisters::r2; - static const RegisterID output = ARMRegisters::r4; - - static const RegisterID regT0 = ARMRegisters::r5; - static const RegisterID regT1 = ARMRegisters::r6; - - static const RegisterID returnRegister = ARMRegisters::r0; - static const RegisterID returnRegister2 = ARMRegisters::r1; -#elif WTF_CPU_MIPS - static const RegisterID input = MIPSRegisters::a0; - static const RegisterID index = MIPSRegisters::a1; - static const RegisterID length = MIPSRegisters::a2; - static const RegisterID output = MIPSRegisters::a3; - - static const RegisterID regT0 = MIPSRegisters::t4; - static const RegisterID regT1 = MIPSRegisters::t5; - - static const RegisterID returnRegister = MIPSRegisters::v0; - static const RegisterID returnRegister2 = MIPSRegisters::v1; -#elif WTF_CPU_SH4 - static const RegisterID input = SH4Registers::r4; - static const RegisterID index = SH4Registers::r5; - static const RegisterID length = SH4Registers::r6; - static const RegisterID output = SH4Registers::r7; - - static const RegisterID regT0 = SH4Registers::r0; - static const RegisterID regT1 = SH4Registers::r1; - - static const RegisterID returnRegister = SH4Registers::r0; - static const RegisterID returnRegister2 = SH4Registers::r1; -#elif WTF_CPU_SPARC - static const RegisterID input = SparcRegisters::i0; - static const RegisterID index = SparcRegisters::i1; - static const RegisterID length = SparcRegisters::i2; - static const RegisterID output = SparcRegisters::i3; - - static const RegisterID regT0 = SparcRegisters::i4; - static const RegisterID regT1 = SparcRegisters::i5; - - static const RegisterID returnRegister = SparcRegisters::i0; -#elif WTF_CPU_X86 - static const RegisterID input = X86Registers::eax; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::ecx; - static const RegisterID output = X86Registers::edi; - - static const RegisterID regT0 = X86Registers::ebx; - static const RegisterID regT1 = X86Registers::esi; - - static const RegisterID returnRegister = X86Registers::eax; - static const RegisterID returnRegister2 = X86Registers::edx; -#elif WTF_CPU_X86_64 -# if WTF_PLATFORM_WIN - static const RegisterID input = X86Registers::ecx; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::r8; - static const RegisterID output = X86Registers::r9; -# else - static const RegisterID input = X86Registers::edi; - static const RegisterID index = X86Registers::esi; - static const RegisterID length = X86Registers::edx; - static const RegisterID output = X86Registers::ecx; -# endif - - static const RegisterID regT0 = X86Registers::eax; - static const RegisterID regT1 = X86Registers::ebx; - - static const RegisterID returnRegister = X86Registers::eax; - -# if !WTF_PLATFORM_WIN - // no way to use int128_t as return value on Win64 ABI - static const RegisterID returnRegister2 = X86Registers::edx; -# endif -#endif - - void optimizeAlternative(PatternAlternative* alternative) - { - if (!alternative->m_terms.size()) - return; - - for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) { - PatternTerm& term = alternative->m_terms[i]; - PatternTerm& nextTerm = alternative->m_terms[i + 1]; - - if ((term.type == PatternTerm::TypeCharacterClass) - && (term.quantityType == QuantifierFixedCount) - && (nextTerm.type == PatternTerm::TypePatternCharacter) - && (nextTerm.quantityType == QuantifierFixedCount)) { - PatternTerm termCopy = term; - alternative->m_terms[i] = nextTerm; - alternative->m_terms[i + 1] = termCopy; - } - } - } - - void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) - { - do { - // pick which range we're going to generate - int which = count >> 1; - char lo = ranges[which].begin; - char hi = ranges[which].end; - - // check if there are any ranges or matches below lo. If not, just jl to failure - - // if there is anything else to check, check that first, if it falls through jmp to failure. - if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - // generate code for all ranges before this one - if (which) - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); - ++*matchIndex; - } - failures.append(jump()); - - loOrAbove.link(this); - } else if (which) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - failures.append(jump()); - - loOrAbove.link(this); - } else - failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) - ++*matchIndex; - - matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); - // fall through to here, the value is above hi. - - // shuffle along & loop around if there are any more matches to handle. - unsigned next = which + 1; - ranges += next; - count -= next; - } while (count); - } - - void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) - { - if (charClass->m_table) { - ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table)); - matchDest.append(branchTest8(charClass->m_tableInverted ? Zero : NonZero, tableEntry)); - return; - } - Jump unicodeFail; - if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) { - Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f)); - - if (charClass->m_matchesUnicode.size()) { - for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) { - UChar ch = charClass->m_matchesUnicode[i]; - matchDest.append(branch32(Equal, character, Imm32(ch))); - } - } - - if (charClass->m_rangesUnicode.size()) { - for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) { - UChar lo = charClass->m_rangesUnicode[i].begin; - UChar hi = charClass->m_rangesUnicode[i].end; - - Jump below = branch32(LessThan, character, Imm32(lo)); - matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); - below.link(this); - } - } - - unicodeFail = jump(); - isAscii.link(this); - } - - if (charClass->m_ranges.size()) { - unsigned matchIndex = 0; - JumpList failures; - matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size()); - while (matchIndex < charClass->m_matches.size()) - matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); - - failures.link(this); - } else if (charClass->m_matches.size()) { - // optimization: gather 'a','A' etc back together, can mask & test once. - Vector matchesAZaz; - - for (unsigned i = 0; i < charClass->m_matches.size(); ++i) { - char ch = charClass->m_matches[i]; - if (m_pattern.m_ignoreCase) { - if (isASCIILower(ch)) { - matchesAZaz.append(ch); - continue; - } - if (isASCIIUpper(ch)) - continue; - } - matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); - } - - if (unsigned countAZaz = matchesAZaz.size()) { - or32(TrustedImm32(32), character); - for (unsigned i = 0; i < countAZaz; ++i) - matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i]))); - } - } - - if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) - unicodeFail.link(this); - } - - // Jumps if input not available; will have (incorrectly) incremented already! - Jump jumpIfNoAvailableInput(unsigned countToCheck = 0) - { - if (countToCheck) - add32(Imm32(countToCheck), index); - return branch32(Above, index, length); - } - - Jump jumpIfAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(BelowOrEqual, index, length); - } - - Jump checkInput() - { - return branch32(BelowOrEqual, index, length); - } - - Jump atEndOfInput() - { - return branch32(Equal, index, length); - } - - Jump notAtEndOfInput() - { - return branch32(NotEqual, index, length); - } - - Jump jumpIfCharNotEquals(UChar ch, int inputPosition, RegisterID character) - { - readCharacter(inputPosition, character); - - // For case-insesitive compares, non-ascii characters that have different - // upper & lower case representations are converted to a character class. - ASSERT(!m_pattern.m_ignoreCase || isASCIIAlpha(ch) || isCanonicallyUnique(ch)); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - or32(TrustedImm32(0x20), character); - ch |= 0x20; - } - - return branch32(NotEqual, character, Imm32(ch)); - } - - void readCharacter(int inputPosition, RegisterID reg) - { - if (m_charSize == Char8) - load8(BaseIndex(input, index, TimesOne, inputPosition * sizeof(char)), reg); - else - load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); - } - - void storeToFrame(RegisterID reg, unsigned frameLocation) - { - poke(reg, frameLocation); - } - - void storeToFrame(TrustedImm32 imm, unsigned frameLocation) - { - poke(imm, frameLocation); - } - - DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) - { - return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - void loadFromFrame(unsigned frameLocation, RegisterID reg) - { - peek(reg, frameLocation); - } - - void loadFromFrameAndJump(unsigned frameLocation) - { - jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - void initCallFrame() - { - unsigned callFrameSize = m_pattern.m_body->m_callFrameSize; - if (callFrameSize) - subPtr(Imm32(callFrameSize * sizeof(void*)), stackPointerRegister); - } - void removeCallFrame() - { - unsigned callFrameSize = m_pattern.m_body->m_callFrameSize; - if (callFrameSize) - addPtr(Imm32(callFrameSize * sizeof(void*)), stackPointerRegister); - } - - // Used to record subpatters, should only be called if compileMode is IncludeSubpatterns. - void setSubpatternStart(RegisterID reg, unsigned subpattern) - { - ASSERT(subpattern); - // FIXME: should be able to ASSERT(compileMode == IncludeSubpatterns), but then this function is conditionally NORETURN. :-( - store32(reg, Address(output, (subpattern << 1) * sizeof(int))); - } - void setSubpatternEnd(RegisterID reg, unsigned subpattern) - { - ASSERT(subpattern); - // FIXME: should be able to ASSERT(compileMode == IncludeSubpatterns), but then this function is conditionally NORETURN. :-( - store32(reg, Address(output, ((subpattern << 1) + 1) * sizeof(int))); - } - void clearSubpatternStart(unsigned subpattern) - { - ASSERT(subpattern); - // FIXME: should be able to ASSERT(compileMode == IncludeSubpatterns), but then this function is conditionally NORETURN. :-( - store32(TrustedImm32(-1), Address(output, (subpattern << 1) * sizeof(int))); - } - - // We use one of three different strategies to track the start of the current match, - // while matching. - // 1) If the pattern has a fixed size, do nothing! - we calculate the value lazily - // at the end of matching. This is irrespective of compileMode, and in this case - // these methods should never be called. - // 2) If we're compiling IncludeSubpatterns, 'output' contains a pointer to an output - // vector, store the match start in the output vector. - // 3) If we're compiling MatchOnly, 'output' is unused, store the match start directly - // in this register. - void setMatchStart(RegisterID reg) - { - ASSERT(!m_pattern.m_body->m_hasFixedSize); - if (compileMode == IncludeSubpatterns) - store32(reg, output); - else - move(reg, output); - } - void getMatchStart(RegisterID reg) - { - ASSERT(!m_pattern.m_body->m_hasFixedSize); - if (compileMode == IncludeSubpatterns) - load32(output, reg); - else - move(output, reg); - } - - enum YarrOpCode { - // These nodes wrap body alternatives - those in the main disjunction, - // rather than subpatterns or assertions. These are chained together in - // a doubly linked list, with a 'begin' node for the first alternative, - // a 'next' node for each subsequent alternative, and an 'end' node at - // the end. In the case of repeating alternatives, the 'end' node also - // has a reference back to 'begin'. - OpBodyAlternativeBegin, - OpBodyAlternativeNext, - OpBodyAlternativeEnd, - // Similar to the body alternatives, but used for subpatterns with two - // or more alternatives. - OpNestedAlternativeBegin, - OpNestedAlternativeNext, - OpNestedAlternativeEnd, - // Used for alternatives in subpatterns where there is only a single - // alternative (backtrackingis easier in these cases), or for alternatives - // which never need to be backtracked (those in parenthetical assertions, - // terminal subpatterns). - OpSimpleNestedAlternativeBegin, - OpSimpleNestedAlternativeNext, - OpSimpleNestedAlternativeEnd, - // Used to wrap 'Once' subpattern matches (quantityCount == 1). - OpParenthesesSubpatternOnceBegin, - OpParenthesesSubpatternOnceEnd, - // Used to wrap 'Terminal' subpattern matches (at the end of the regexp). - OpParenthesesSubpatternTerminalBegin, - OpParenthesesSubpatternTerminalEnd, - // Used to wrap parenthetical assertions. - OpParentheticalAssertionBegin, - OpParentheticalAssertionEnd, - // Wraps all simple terms (pattern characters, character classes). - OpTerm, - // Where an expression contains only 'once through' body alternatives - // and no repeating ones, this op is used to return match failure. - OpMatchFailed - }; - - // This structure is used to hold the compiled opcode information, - // including reference back to the original PatternTerm/PatternAlternatives, - // and JIT compilation data structures. - struct YarrOp { - explicit YarrOp(PatternTerm* term) - : m_op(OpTerm) - , m_term(term) - , m_isDeadCode(false) - { - } - - explicit YarrOp(YarrOpCode op) - : m_op(op) - , m_isDeadCode(false) - { - } - - // The operation, as a YarrOpCode, and also a reference to the PatternTerm. - YarrOpCode m_op; - PatternTerm* m_term; - - // For alternatives, this holds the PatternAlternative and doubly linked - // references to this alternative's siblings. In the case of the - // OpBodyAlternativeEnd node at the end of a section of repeating nodes, - // m_nextOp will reference the OpBodyAlternativeBegin node of the first - // repeating alternative. - PatternAlternative* m_alternative; - size_t m_previousOp; - size_t m_nextOp; - - // Used to record a set of Jumps out of the generated code, typically - // used for jumps out to backtracking code, and a single reentry back - // into the code for a node (likely where a backtrack will trigger - // rematching). - Label m_reentry; - JumpList m_jumps; - - // Used for backtracking when the prior alternative did not consume any - // characters but matched. - Jump m_zeroLengthMatch; - - // This flag is used to null out the second pattern character, when - // two are fused to match a pair together. - bool m_isDeadCode; - - // Currently used in the case of some of the more complex management of - // 'm_checked', to cache the offset used in this alternative, to avoid - // recalculating it. - int m_checkAdjust; - - // Used by OpNestedAlternativeNext/End to hold the pointer to the - // value that will be pushed into the pattern's frame to return to, - // upon backtracking back into the disjunction. - DataLabelPtr m_returnAddress; - }; - - // BacktrackingState - // This class encapsulates information about the state of code generation - // whilst generating the code for backtracking, when a term fails to match. - // Upon entry to code generation of the backtracking code for a given node, - // the Backtracking state will hold references to all control flow sources - // that are outputs in need of further backtracking from the prior node - // generated (which is the subsequent operation in the regular expression, - // and in the m_ops Vector, since we generated backtracking backwards). - // These references to control flow take the form of: - // - A jump list of jumps, to be linked to code that will backtrack them - // further. - // - A set of DataLabelPtr values, to be populated with values to be - // treated effectively as return addresses backtracking into complex - // subpatterns. - // - A flag indicating that the current sequence of generated code up to - // this point requires backtracking. - class BacktrackingState { - public: - BacktrackingState() - : m_pendingFallthrough(false) - { - } - - // Add a jump or jumps, a return address, or set the flag indicating - // that the current 'fallthrough' control flow requires backtracking. - void append(const Jump& jump) - { - m_laterFailures.append(jump); - } - void append(JumpList& jumpList) - { - m_laterFailures.append(jumpList); - } - void append(const DataLabelPtr& returnAddress) - { - m_pendingReturns.append(returnAddress); - } - void fallthrough() - { - ASSERT(!m_pendingFallthrough); - m_pendingFallthrough = true; - } - - // These methods clear the backtracking state, either linking to the - // current location, a provided label, or copying the backtracking out - // to a JumpList. All actions may require code generation to take place, - // and as such are passed a pointer to the assembler. - void link(MacroAssembler* assembler) - { - if (m_pendingReturns.size()) { - Label here(assembler); - for (unsigned i = 0; i < m_pendingReturns.size(); ++i) - m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here)); - m_pendingReturns.clear(); - } - m_laterFailures.link(assembler); - m_laterFailures.clear(); - m_pendingFallthrough = false; - } - void linkTo(Label label, MacroAssembler* assembler) - { - if (m_pendingReturns.size()) { - for (unsigned i = 0; i < m_pendingReturns.size(); ++i) - m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label)); - m_pendingReturns.clear(); - } - if (m_pendingFallthrough) - assembler->jump(label); - m_laterFailures.linkTo(label, assembler); - m_laterFailures.clear(); - m_pendingFallthrough = false; - } - void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler) - { - if (m_pendingReturns.size()) { - Label here(assembler); - for (unsigned i = 0; i < m_pendingReturns.size(); ++i) - m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here)); - m_pendingReturns.clear(); - m_pendingFallthrough = true; - } - if (m_pendingFallthrough) - jumpList.append(assembler->jump()); - jumpList.append(m_laterFailures); - m_laterFailures.clear(); - m_pendingFallthrough = false; - } - - bool isEmpty() - { - return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough; - } - - // Called at the end of code generation to link all return addresses. - void linkDataLabels(LinkBuffer& linkBuffer) - { - ASSERT(isEmpty()); - for (unsigned i = 0; i < m_backtrackRecords.size(); ++i) - linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation)); - } - - private: - struct ReturnAddressRecord { - ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation) - : m_dataLabel(dataLabel) - , m_backtrackLocation(backtrackLocation) - { - } - - DataLabelPtr m_dataLabel; - Label m_backtrackLocation; - }; - - JumpList m_laterFailures; - bool m_pendingFallthrough; - Vector m_pendingReturns; - Vector m_backtrackRecords; - }; - - // Generation methods: - // =================== - - // This method provides a default implementation of backtracking common - // to many terms; terms commonly jump out of the forwards matching path - // on any failed conditions, and add these jumps to the m_jumps list. If - // no special handling is required we can often just backtrack to m_jumps. - bool backtrackTermDefault(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - m_backtrackingState.append(op.m_jumps); - return true; - } - - bool generateAssertionBOL(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (!term->inputPosition) - matchDest.append(branch32(Equal, index, Imm32(m_checked))); - - readCharacter((term->inputPosition - m_checked) - 1, character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - op.m_jumps.append(jump()); - - matchDest.link(this); - } else { - // Erk, really should poison out these alternatives early. :-/ - if (term->inputPosition) - op.m_jumps.append(jump()); - else - op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked))); - } - return true; - } - bool backtrackAssertionBOL(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - bool generateAssertionEOL(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (term->inputPosition == m_checked) - matchDest.append(atEndOfInput()); - - readCharacter(term->inputPosition - m_checked, character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - op.m_jumps.append(jump()); - - matchDest.link(this); - } else { - if (term->inputPosition == m_checked) - op.m_jumps.append(notAtEndOfInput()); - // Erk, really should poison out these alternatives early. :-/ - else - op.m_jumps.append(jump()); - } - return true; - } - bool backtrackAssertionEOL(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - // Also falls though on nextIsNotWordChar. - void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - - if (term->inputPosition == m_checked) - nextIsNotWordChar.append(atEndOfInput()); - - readCharacter((term->inputPosition - m_checked), character); - matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); - } - - bool generateAssertionWordBoundary(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - - Jump atBegin; - JumpList matchDest; - if (!term->inputPosition) - atBegin = branch32(Equal, index, Imm32(m_checked)); - readCharacter((term->inputPosition - m_checked) - 1, character); - matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); - if (!term->inputPosition) - atBegin.link(this); - - // We fall through to here if the last character was not a wordchar. - JumpList nonWordCharThenWordChar; - JumpList nonWordCharThenNonWordChar; - if (term->invert()) { - matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar); - nonWordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar); - nonWordCharThenNonWordChar.append(jump()); - } - op.m_jumps.append(nonWordCharThenNonWordChar); - - // We jump here if the last character was a wordchar. - matchDest.link(this); - JumpList wordCharThenWordChar; - JumpList wordCharThenNonWordChar; - if (term->invert()) { - matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar); - wordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar); - // This can fall-though! - } - - op.m_jumps.append(wordCharThenWordChar); - - nonWordCharThenWordChar.link(this); - wordCharThenNonWordChar.link(this); - return true; - } - bool backtrackAssertionWordBoundary(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - bool generatePatternCharacterOnce(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - - if (op.m_isDeadCode) - return true; - - // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed - // node, so there must always be at least one more node. - ASSERT(opIndex + 1 < m_ops.size()); - YarrOp* nextOp = &m_ops[opIndex + 1]; - - PatternTerm* term = op.m_term; - UChar ch = term->patternCharacter; - - if ((ch > 0xff) && (m_charSize == Char8)) { - // Have a 16 bit pattern character and an 8 bit string - short circuit - op.m_jumps.append(jump()); - return true; - } - - const RegisterID character = regT0; - int maxCharactersAtOnce = m_charSize == Char8 ? 4 : 2; - unsigned ignoreCaseMask = 0; -#if CPU(BIG_ENDIAN) - int allCharacters = ch << (m_charSize == Char8 ? 24 : 16); -#else - int allCharacters = ch; -#endif - int numberCharacters; - int startTermPosition = term->inputPosition; - - // For case-insesitive compares, non-ascii characters that have different - // upper & lower case representations are converted to a character class. - ASSERT(!m_pattern.m_ignoreCase || isASCIIAlpha(ch) || isCanonicallyUnique(ch)); - - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) -#if CPU(BIG_ENDIAN) - ignoreCaseMask |= 32 << (m_charSize == Char8 ? 24 : 16); -#else - ignoreCaseMask |= 32; -#endif - - for (numberCharacters = 1; numberCharacters < maxCharactersAtOnce && nextOp->m_op == OpTerm; ++numberCharacters, nextOp = &m_ops[opIndex + numberCharacters]) { - PatternTerm* nextTerm = nextOp->m_term; - - if (nextTerm->type != PatternTerm::TypePatternCharacter - || nextTerm->quantityType != QuantifierFixedCount - || nextTerm->quantityCount != 1 - || nextTerm->inputPosition != (startTermPosition + numberCharacters)) - break; - - nextOp->m_isDeadCode = true; - -#if CPU(BIG_ENDIAN) - int shiftAmount = (m_charSize == Char8 ? 24 : 16) - ((m_charSize == Char8 ? 8 : 16) * numberCharacters); -#else - int shiftAmount = (m_charSize == Char8 ? 8 : 16) * numberCharacters; -#endif - - UChar currentCharacter = nextTerm->patternCharacter; - - if ((currentCharacter > 0xff) && (m_charSize == Char8)) { - // Have a 16 bit pattern character and an 8 bit string - short circuit - op.m_jumps.append(jump()); - return true; - } - - // For case-insesitive compares, non-ascii characters that have different - // upper & lower case representations are converted to a character class. - ASSERT(!m_pattern.m_ignoreCase || isASCIIAlpha(currentCharacter) || isCanonicallyUnique(currentCharacter)); - - allCharacters |= (currentCharacter << shiftAmount); - - if ((m_pattern.m_ignoreCase) && (isASCIIAlpha(currentCharacter))) - ignoreCaseMask |= 32 << shiftAmount; - } - - if (m_charSize == Char8) { - switch (numberCharacters) { - case 1: - op.m_jumps.append(jumpIfCharNotEquals(ch, startTermPosition - m_checked, character)); - return true; - case 2: { - BaseIndex address(input, index, TimesOne, (startTermPosition - m_checked) * sizeof(LChar)); - load16Unaligned(address, character); - break; - } - case 3: { - BaseIndex highAddress(input, index, TimesOne, (startTermPosition - m_checked) * sizeof(LChar)); - load16Unaligned(highAddress, character); - if (ignoreCaseMask) - or32(Imm32(ignoreCaseMask), character); - op.m_jumps.append(branch32(NotEqual, character, Imm32((allCharacters & 0xffff) | ignoreCaseMask))); - op.m_jumps.append(jumpIfCharNotEquals(allCharacters >> 16, startTermPosition + 2 - m_checked, character)); - return true; - } - case 4: { - BaseIndex address(input, index, TimesOne, (startTermPosition - m_checked) * sizeof(LChar)); - load32WithUnalignedHalfWords(address, character); - break; - } - } - } else { - switch (numberCharacters) { - case 1: - op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked, character)); - return true; - case 2: - BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar)); - load32WithUnalignedHalfWords(address, character); - break; - } - } - - if (ignoreCaseMask) - or32(Imm32(ignoreCaseMask), character); - op.m_jumps.append(branch32(NotEqual, character, Imm32(allCharacters | ignoreCaseMask))); - return true; - } - bool backtrackPatternCharacterOnce(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - bool generatePatternCharacterFixed(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - UChar ch = term->patternCharacter; - - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - - move(index, countRegister); - if (term->quantityCount.hasOverflowed()) - return false; - sub32(Imm32(term->quantityCount.unsafeGet()), countRegister); - - Label loop(this); - int offset; - if ((Checked(term->inputPosition - m_checked + Checked(term->quantityCount)) * static_cast(m_charSize == Char8 ? sizeof(char) : sizeof(UChar))).safeGet(offset)) - return false; - BaseIndex address(input, countRegister, m_charScale, offset); - - if (m_charSize == Char8) - load8(address, character); - else - load16(address, character); - - // For case-insesitive compares, non-ascii characters that have different - // upper & lower case representations are converted to a character class. - ASSERT(!m_pattern.m_ignoreCase || isASCIIAlpha(ch) || isCanonicallyUnique(ch)); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - or32(TrustedImm32(0x20), character); - ch |= 0x20; - } - - op.m_jumps.append(branch32(NotEqual, character, Imm32(ch))); - add32(TrustedImm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - - return true; - } - bool backtrackPatternCharacterFixed(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - bool generatePatternCharacterGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - UChar ch = term->patternCharacter; - - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - - move(TrustedImm32(0), countRegister); - - // Unless have a 16 bit pattern character and an 8 bit string - short circuit - if (!((ch > 0xff) && (m_charSize == Char8))) { - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked, character)); - - add32(TrustedImm32(1), countRegister); - add32(TrustedImm32(1), index); - if (term->quantityCount == quantifyInfinite) { - jump(loop); - } else { - if (term->quantityCount.hasOverflowed()) - return false; - branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this); - } - - failures.link(this); - } - op.m_reentry = label(); - - storeToFrame(countRegister, term->frameLocation); - return true; - } - bool backtrackPatternCharacterGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID countRegister = regT1; - - m_backtrackingState.link(this); - - loadFromFrame(term->frameLocation, countRegister); - m_backtrackingState.append(branchTest32(Zero, countRegister)); - sub32(TrustedImm32(1), countRegister); - sub32(TrustedImm32(1), index); - jump(op.m_reentry); - - return true; - } - - bool generatePatternCharacterNonGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID countRegister = regT1; - - move(TrustedImm32(0), countRegister); - op.m_reentry = label(); - storeToFrame(countRegister, term->frameLocation); - return true; - } - bool backtrackPatternCharacterNonGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - UChar ch = term->patternCharacter; - - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - - m_backtrackingState.link(this); - - loadFromFrame(term->frameLocation, countRegister); - - // Unless have a 16 bit pattern character and an 8 bit string - short circuit - if (!((ch > 0xff) && (m_charSize == Char8))) { - JumpList nonGreedyFailures; - nonGreedyFailures.append(atEndOfInput()); - if (term->quantityCount != quantifyInfinite) { - if (term->quantityCount.hasOverflowed()) - return false; - nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet()))); - } - nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked, character)); - - add32(TrustedImm32(1), countRegister); - add32(TrustedImm32(1), index); - - jump(op.m_reentry); - nonGreedyFailures.link(this); - } - - sub32(countRegister, index); - m_backtrackingState.fallthrough(); - - return true; - } - - bool generateCharacterClassOnce(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - - JumpList matchDest; - readCharacter(term->inputPosition - m_checked, character); - matchCharacterClass(character, matchDest, term->characterClass); - - if (term->invert()) - op.m_jumps.append(matchDest); - else { - op.m_jumps.append(jump()); - matchDest.link(this); - } - return true; - } - bool backtrackCharacterClassOnce(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - bool generateCharacterClassFixed(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - - move(index, countRegister); - if (term->quantityCount.hasOverflowed()) - return false; - sub32(Imm32(term->quantityCount.unsafeGet()), countRegister); - - Label loop(this); - JumpList matchDest; - - int offset; - Checked checkedOffset(term->inputPosition - m_checked + Checked(term->quantityCount)); - - if (m_charSize == Char8) { - if ((Checked(checkedOffset) * static_cast(sizeof(char))).safeGet(offset)) - return false; - load8(BaseIndex(input, countRegister, TimesOne, offset), character); - } else { - if ((Checked(checkedOffset) * static_cast(sizeof(UChar))).safeGet(offset)) - return false; - load16(BaseIndex(input, countRegister, TimesTwo, offset), character); - } - matchCharacterClass(character, matchDest, term->characterClass); - - if (term->invert()) - op.m_jumps.append(matchDest); - else { - op.m_jumps.append(jump()); - matchDest.link(this); - } - - add32(TrustedImm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - return true; - } - bool backtrackCharacterClassFixed(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - bool generateCharacterClassGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - - move(TrustedImm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - - if (term->invert()) { - readCharacter(term->inputPosition - m_checked, character); - matchCharacterClass(character, failures, term->characterClass); - } else { - JumpList matchDest; - readCharacter(term->inputPosition - m_checked, character); - matchCharacterClass(character, matchDest, term->characterClass); - failures.append(jump()); - matchDest.link(this); - } - - add32(TrustedImm32(1), countRegister); - add32(TrustedImm32(1), index); - if (term->quantityCount != quantifyInfinite) { - unsigned quantityCount; - if (term->quantityCount.safeGet(quantityCount)) - return false; - branch32(NotEqual, countRegister, Imm32(quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - failures.link(this); - op.m_reentry = label(); - - storeToFrame(countRegister, term->frameLocation); - return true; - } - bool backtrackCharacterClassGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID countRegister = regT1; - - m_backtrackingState.link(this); - - loadFromFrame(term->frameLocation, countRegister); - m_backtrackingState.append(branchTest32(Zero, countRegister)); - sub32(TrustedImm32(1), countRegister); - sub32(TrustedImm32(1), index); - jump(op.m_reentry); - - return true; - } - - bool generateCharacterClassNonGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID countRegister = regT1; - - move(TrustedImm32(0), countRegister); - op.m_reentry = label(); - storeToFrame(countRegister, term->frameLocation); - return true; - } - bool backtrackCharacterClassNonGreedy(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - - JumpList nonGreedyFailures; - - m_backtrackingState.link(this); - - loadFromFrame(term->frameLocation, countRegister); - - nonGreedyFailures.append(atEndOfInput()); - if (term->quantityCount.hasOverflowed()) - return false; - nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet()))); - - JumpList matchDest; - readCharacter(term->inputPosition - m_checked, character); - matchCharacterClass(character, matchDest, term->characterClass); - - if (term->invert()) - nonGreedyFailures.append(matchDest); - else { - nonGreedyFailures.append(jump()); - matchDest.link(this); - } - - add32(TrustedImm32(1), countRegister); - add32(TrustedImm32(1), index); - - jump(op.m_reentry); - - nonGreedyFailures.link(this); - sub32(countRegister, index); - m_backtrackingState.fallthrough(); - - return true; - } - - bool generateDotStarEnclosure(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - const RegisterID character = regT0; - const RegisterID matchPos = regT1; - - JumpList foundBeginningNewLine; - JumpList saveStartIndex; - JumpList foundEndingNewLine; - - ASSERT(!m_pattern.m_body->m_hasFixedSize); - getMatchStart(matchPos); - - saveStartIndex.append(branchTest32(Zero, matchPos)); - Label findBOLLoop(this); - sub32(TrustedImm32(1), matchPos); - if (m_charSize == Char8) - load8(BaseIndex(input, matchPos, TimesOne, 0), character); - else - load16(BaseIndex(input, matchPos, TimesTwo, 0), character); - matchCharacterClass(character, foundBeginningNewLine, m_pattern.newlineCharacterClass()); - branchTest32(NonZero, matchPos).linkTo(findBOLLoop, this); - saveStartIndex.append(jump()); - - foundBeginningNewLine.link(this); - add32(TrustedImm32(1), matchPos); // Advance past newline - saveStartIndex.link(this); - - if (!m_pattern.m_multiline && term->anchors.bolAnchor) - op.m_jumps.append(branchTest32(NonZero, matchPos)); - - ASSERT(!m_pattern.m_body->m_hasFixedSize); - setMatchStart(matchPos); - - move(index, matchPos); - - Label findEOLLoop(this); - foundEndingNewLine.append(branch32(Equal, matchPos, length)); - if (m_charSize == Char8) - load8(BaseIndex(input, matchPos, TimesOne, 0), character); - else - load16(BaseIndex(input, matchPos, TimesTwo, 0), character); - matchCharacterClass(character, foundEndingNewLine, m_pattern.newlineCharacterClass()); - add32(TrustedImm32(1), matchPos); - jump(findEOLLoop); - - foundEndingNewLine.link(this); - - if (!m_pattern.m_multiline && term->anchors.eolAnchor) - op.m_jumps.append(branch32(NotEqual, matchPos, length)); - - move(matchPos, index); - return true; - } - - bool backtrackDotStarEnclosure(size_t opIndex) - { - return backtrackTermDefault(opIndex); - } - - // Code generation/backtracking for simple terms - // (pattern characters, character classes, and assertions). - // These methods farm out work to the set of functions above. - bool generateTerm(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - switch (term->type) { - case PatternTerm::TypePatternCharacter: - switch (term->quantityType) { - case QuantifierFixedCount: - if (term->quantityCount == 1) - return generatePatternCharacterOnce(opIndex); - else - return generatePatternCharacterFixed(opIndex); - break; - case QuantifierGreedy: - return generatePatternCharacterGreedy(opIndex); - case QuantifierNonGreedy: - return generatePatternCharacterNonGreedy(opIndex); - } - break; - - case PatternTerm::TypeCharacterClass: - switch (term->quantityType) { - case QuantifierFixedCount: - if (term->quantityCount == 1) - return generateCharacterClassOnce(opIndex); - else - return generateCharacterClassFixed(opIndex); - break; - case QuantifierGreedy: - return generateCharacterClassGreedy(opIndex); - case QuantifierNonGreedy: - return generateCharacterClassNonGreedy(opIndex); - } - break; - - case PatternTerm::TypeAssertionBOL: - return generateAssertionBOL(opIndex); - - case PatternTerm::TypeAssertionEOL: - return generateAssertionEOL(opIndex); - - case PatternTerm::TypeAssertionWordBoundary: - return generateAssertionWordBoundary(opIndex); - - case PatternTerm::TypeForwardReference: - return true; - - case PatternTerm::TypeParenthesesSubpattern: - case PatternTerm::TypeParentheticalAssertion: - ASSERT_NOT_REACHED(); - return false; - case PatternTerm::TypeBackReference: - return false; - case PatternTerm::TypeDotStarEnclosure: - return generateDotStarEnclosure(opIndex); - } - - return false; - } - bool backtrackTerm(size_t opIndex) - { - YarrOp& op = m_ops[opIndex]; - PatternTerm* term = op.m_term; - - switch (term->type) { - case PatternTerm::TypePatternCharacter: - switch (term->quantityType) { - case QuantifierFixedCount: - if (term->quantityCount == 1) - return backtrackPatternCharacterOnce(opIndex); - else - return backtrackPatternCharacterFixed(opIndex); - case QuantifierGreedy: - return backtrackPatternCharacterGreedy(opIndex); - case QuantifierNonGreedy: - return backtrackPatternCharacterNonGreedy(opIndex); - } - break; - - case PatternTerm::TypeCharacterClass: - switch (term->quantityType) { - case QuantifierFixedCount: - if (term->quantityCount == 1) - return backtrackCharacterClassOnce(opIndex); - else - return backtrackCharacterClassFixed(opIndex); - case QuantifierGreedy: - return backtrackCharacterClassGreedy(opIndex); - case QuantifierNonGreedy: - return backtrackCharacterClassNonGreedy(opIndex); - } - break; - - case PatternTerm::TypeAssertionBOL: - return backtrackAssertionBOL(opIndex); - - case PatternTerm::TypeAssertionEOL: - return backtrackAssertionEOL(opIndex); - - case PatternTerm::TypeAssertionWordBoundary: - return backtrackAssertionWordBoundary(opIndex); - - case PatternTerm::TypeForwardReference: - return true; - - case PatternTerm::TypeParenthesesSubpattern: - case PatternTerm::TypeParentheticalAssertion: - ASSERT_NOT_REACHED(); - return false; - - case PatternTerm::TypeDotStarEnclosure: - return backtrackDotStarEnclosure(opIndex); - - case PatternTerm::TypeBackReference: - return false; - } - return true; - } - - bool generate() - { - // Forwards generate the matching code. - ASSERT(m_ops.size()); - size_t opIndex = 0; - - do { - YarrOp& op = m_ops[opIndex]; - switch (op.m_op) { - - case OpTerm: - if (!generateTerm(opIndex)) - return false; - break; - - // OpBodyAlternativeBegin/Next/End - // - // These nodes wrap the set of alternatives in the body of the regular expression. - // There may be either one or two chains of OpBodyAlternative nodes, one representing - // the 'once through' sequence of alternatives (if any exist), and one representing - // the repeating alternatives (again, if any exist). - // - // Upon normal entry to the Begin alternative, we will check that input is available. - // Reentry to the Begin alternative will take place after the check has taken place, - // and will assume that the input position has already been progressed as appropriate. - // - // Entry to subsequent Next/End alternatives occurs when the prior alternative has - // successfully completed a match - return a success state from JIT code. - // - // Next alternatives allow for reentry optimized to suit backtracking from its - // preceding alternative. It expects the input position to still be set to a position - // appropriate to its predecessor, and it will only perform an input check if the - // predecessor had a minimum size less than its own. - // - // In the case 'once through' expressions, the End node will also have a reentry - // point to jump to when the last alternative fails. Again, this expects the input - // position to still reflect that expected by the prior alternative. - case OpBodyAlternativeBegin: { - PatternAlternative* alternative = op.m_alternative; - - // Upon entry at the head of the set of alternatives, check if input is available - // to run the first alternative. (This progresses the input position). - op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize)); - // We will reenter after the check, and assume the input position to have been - // set as appropriate to this alternative. - op.m_reentry = label(); - - if (alternative->m_minimumSize > INT_MAX) - return false; - m_checked = alternative->m_minimumSize; - break; - } - case OpBodyAlternativeNext: - case OpBodyAlternativeEnd: { - PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative; - PatternAlternative* alternative = op.m_alternative; - - // If we get here, the prior alternative matched - return success. - - // Adjust the stack pointer to remove the pattern's frame. -#if !WTF_CPU_SPARC - removeCallFrame(); -#endif - - // Load appropriate values into the return register and the first output - // slot, and return. In the case of pattern with a fixed size, we will - // not have yet set the value in the first - ASSERT(index != returnRegister); - if (m_pattern.m_body->m_hasFixedSize) { - move(index, returnRegister); - if (priorAlternative->m_minimumSize) - sub32(Imm32(priorAlternative->m_minimumSize), returnRegister); - if (compileMode == IncludeSubpatterns) - store32(returnRegister, output); - } else - getMatchStart(returnRegister); - if (compileMode == IncludeSubpatterns) - store32(index, Address(output, 4)); -#if WTF_CPU_X86_64 - // upper 32bit to 0 - move32(returnRegister, returnRegister); - lshiftPtr(Imm32(32), index); - orPtr(index, returnRegister); -#else - move(index, returnRegister2); -#endif - - generateReturn(); - - // This is the divide between the tail of the prior alternative, above, and - // the head of the subsequent alternative, below. - - if (op.m_op == OpBodyAlternativeNext) { - // This is the reentry point for the Next alternative. We expect any code - // that jumps here to do so with the input position matching that of the - // PRIOR alteranative, and we will only check input availability if we - // need to progress it forwards. - op.m_reentry = label(); - if (alternative->m_minimumSize > priorAlternative->m_minimumSize) { - add32(Imm32(alternative->m_minimumSize - priorAlternative->m_minimumSize), index); - op.m_jumps.append(jumpIfNoAvailableInput()); - } else if (priorAlternative->m_minimumSize > alternative->m_minimumSize) - sub32(Imm32(priorAlternative->m_minimumSize - alternative->m_minimumSize), index); - } else if (op.m_nextOp == notFound) { - // This is the reentry point for the End of 'once through' alternatives, - // jumped to when the last alternative fails to match. - op.m_reentry = label(); - sub32(Imm32(priorAlternative->m_minimumSize), index); - } - - if (op.m_op == OpBodyAlternativeNext) - m_checked += alternative->m_minimumSize; - m_checked -= priorAlternative->m_minimumSize; - break; - } - - // OpSimpleNestedAlternativeBegin/Next/End - // OpNestedAlternativeBegin/Next/End - // - // These nodes are used to handle sets of alternatives that are nested within - // subpatterns and parenthetical assertions. The 'simple' forms are used where - // we do not need to be able to backtrack back into any alternative other than - // the last, the normal forms allow backtracking into any alternative. - // - // Each Begin/Next node is responsible for planting an input check to ensure - // sufficient input is available on entry. Next nodes additionally need to - // jump to the end - Next nodes use the End node's m_jumps list to hold this - // set of jumps. - // - // In the non-simple forms, successful alternative matches must store a - // 'return address' using a DataLabelPtr, used to store the address to jump - // to when backtracking, to get to the code for the appropriate alternative. - case OpSimpleNestedAlternativeBegin: - case OpNestedAlternativeBegin: { - PatternTerm* term = op.m_term; - PatternAlternative* alternative = op.m_alternative; - PatternDisjunction* disjunction = term->parentheses.disjunction; - - // Calculate how much input we need to check for, and if non-zero check. - op.m_checkAdjust = alternative->m_minimumSize; - if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion)) - op.m_checkAdjust -= disjunction->m_minimumSize; - if (op.m_checkAdjust) - op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust)); - - m_checked += op.m_checkAdjust; - break; - } - case OpSimpleNestedAlternativeNext: - case OpNestedAlternativeNext: { - PatternTerm* term = op.m_term; - PatternAlternative* alternative = op.m_alternative; - PatternDisjunction* disjunction = term->parentheses.disjunction; - - // In the non-simple case, store a 'return address' so we can backtrack correctly. - if (op.m_op == OpNestedAlternativeNext) { - unsigned parenthesesFrameLocation = term->frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation; - if (term->quantityType != QuantifierFixedCount) - alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; - op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation); - } - - if (term->quantityType != QuantifierFixedCount && !m_ops[op.m_previousOp].m_alternative->m_minimumSize) { - // If the previous alternative matched without consuming characters then - // backtrack to try to match while consumming some input. - op.m_zeroLengthMatch = branch32(Equal, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*))); - } - - // If we reach here then the last alternative has matched - jump to the - // End node, to skip over any further alternatives. - // - // FIXME: this is logically O(N^2) (though N can be expected to be very - // small). We could avoid this either by adding an extra jump to the JIT - // data structures, or by making backtracking code that jumps to Next - // alternatives are responsible for checking that input is available (if - // we didn't need to plant the input checks, then m_jumps would be free). - YarrOp* endOp = &m_ops[op.m_nextOp]; - while (endOp->m_nextOp != notFound) { - ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext); - endOp = &m_ops[endOp->m_nextOp]; - } - ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd); - endOp->m_jumps.append(jump()); - - // This is the entry point for the next alternative. - op.m_reentry = label(); - - // Calculate how much input we need to check for, and if non-zero check. - op.m_checkAdjust = alternative->m_minimumSize; - if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion)) - op.m_checkAdjust -= disjunction->m_minimumSize; - if (op.m_checkAdjust) - op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust)); - - YarrOp& lastOp = m_ops[op.m_previousOp]; - m_checked -= lastOp.m_checkAdjust; - m_checked += op.m_checkAdjust; - break; - } - case OpSimpleNestedAlternativeEnd: - case OpNestedAlternativeEnd: { - PatternTerm* term = op.m_term; - - // In the non-simple case, store a 'return address' so we can backtrack correctly. - if (op.m_op == OpNestedAlternativeEnd) { - unsigned parenthesesFrameLocation = term->frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation; - if (term->quantityType != QuantifierFixedCount) - alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; - op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation); - } - - if (term->quantityType != QuantifierFixedCount && !m_ops[op.m_previousOp].m_alternative->m_minimumSize) { - // If the previous alternative matched without consuming characters then - // backtrack to try to match while consumming some input. - op.m_zeroLengthMatch = branch32(Equal, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*))); - } - - // If this set of alternatives contains more than one alternative, - // then the Next nodes will have planted jumps to the End, and added - // them to this node's m_jumps list. - op.m_jumps.link(this); - op.m_jumps.clear(); - - YarrOp& lastOp = m_ops[op.m_previousOp]; - m_checked -= lastOp.m_checkAdjust; - break; - } - - // OpParenthesesSubpatternOnceBegin/End - // - // These nodes support (optionally) capturing subpatterns, that have a - // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). - case OpParenthesesSubpatternOnceBegin: { - PatternTerm* term = op.m_term; - unsigned parenthesesFrameLocation = term->frameLocation; - const RegisterID indexTemporary = regT0; - ASSERT(term->quantityCount == 1); - - // Upon entry to a Greedy quantified set of parenthese store the index. - // We'll use this for two purposes: - // - To indicate which iteration we are on of mathing the remainder of - // the expression after the parentheses - the first, including the - // match within the parentheses, or the second having skipped over them. - // - To check for empty matches, which must be rejected. - // - // At the head of a NonGreedy set of parentheses we'll immediately set the - // value on the stack to -1 (indicating a match skipping the subpattern), - // and plant a jump to the end. We'll also plant a label to backtrack to - // to reenter the subpattern later, with a store to set up index on the - // second iteration. - // - // FIXME: for capturing parens, could use the index in the capture array? - if (term->quantityType == QuantifierGreedy) - storeToFrame(index, parenthesesFrameLocation); - else if (term->quantityType == QuantifierNonGreedy) { - storeToFrame(TrustedImm32(-1), parenthesesFrameLocation); - op.m_jumps.append(jump()); - op.m_reentry = label(); - storeToFrame(index, parenthesesFrameLocation); - } - - // If the parenthese are capturing, store the starting index value to the - // captures array, offsetting as necessary. - // - // FIXME: could avoid offsetting this value in JIT code, apply - // offsets only afterwards, at the point the results array is - // being accessed. - if (term->capture() && compileMode == IncludeSubpatterns) { - int inputOffset = term->inputPosition - m_checked; - if (term->quantityType == QuantifierFixedCount) - inputOffset -= term->parentheses.disjunction->m_minimumSize; - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(inputOffset), indexTemporary); - setSubpatternStart(indexTemporary, term->parentheses.subpatternId); - } else - setSubpatternStart(index, term->parentheses.subpatternId); - } - break; - } - case OpParenthesesSubpatternOnceEnd: { - PatternTerm* term = op.m_term; - const RegisterID indexTemporary = regT0; - ASSERT(term->quantityCount == 1); - -#ifndef NDEBUG - // Runtime ASSERT to make sure that the nested alternative handled the - // "no input consumed" check. - if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize) { - Jump pastBreakpoint; - pastBreakpoint = branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*))); - breakpoint(); - pastBreakpoint.link(this); - } -#endif - - // If the parenthese are capturing, store the ending index value to the - // captures array, offsetting as necessary. - // - // FIXME: could avoid offsetting this value in JIT code, apply - // offsets only afterwards, at the point the results array is - // being accessed. - if (term->capture() && compileMode == IncludeSubpatterns) { - int inputOffset = term->inputPosition - m_checked; - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(inputOffset), indexTemporary); - setSubpatternEnd(indexTemporary, term->parentheses.subpatternId); - } else - setSubpatternEnd(index, term->parentheses.subpatternId); - } - - // If the parentheses are quantified Greedy then add a label to jump back - // to if get a failed match from after the parentheses. For NonGreedy - // parentheses, link the jump from before the subpattern to here. - if (term->quantityType == QuantifierGreedy) - op.m_reentry = label(); - else if (term->quantityType == QuantifierNonGreedy) { - YarrOp& beginOp = m_ops[op.m_previousOp]; - beginOp.m_jumps.link(this); - } - break; - } - - // OpParenthesesSubpatternTerminalBegin/End - case OpParenthesesSubpatternTerminalBegin: { - PatternTerm* term = op.m_term; - ASSERT(term->quantityType == QuantifierGreedy); - ASSERT(term->quantityCount == quantifyInfinite); - ASSERT(!term->capture()); - - // Upon entry set a label to loop back to. - op.m_reentry = label(); - - // Store the start index of the current match; we need to reject zero - // length matches. - storeToFrame(index, term->frameLocation); - break; - } - case OpParenthesesSubpatternTerminalEnd: { - YarrOp& beginOp = m_ops[op.m_previousOp]; -#ifndef NDEBUG - PatternTerm* term = op.m_term; - - // Runtime ASSERT to make sure that the nested alternative handled the - // "no input consumed" check. - Jump pastBreakpoint; - pastBreakpoint = branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*))); - breakpoint(); - pastBreakpoint.link(this); -#endif - - // We know that the match is non-zero, we can accept it and - // loop back up to the head of the subpattern. - jump(beginOp.m_reentry); - - // This is the entry point to jump to when we stop matching - we will - // do so once the subpattern cannot match any more. - op.m_reentry = label(); - break; - } - - // OpParentheticalAssertionBegin/End - case OpParentheticalAssertionBegin: { - PatternTerm* term = op.m_term; - - // Store the current index - assertions should not update index, so - // we will need to restore it upon a successful match. - unsigned parenthesesFrameLocation = term->frameLocation; - storeToFrame(index, parenthesesFrameLocation); - - // Check - op.m_checkAdjust = m_checked - term->inputPosition; - if (op.m_checkAdjust) - sub32(Imm32(op.m_checkAdjust), index); - - m_checked -= op.m_checkAdjust; - break; - } - case OpParentheticalAssertionEnd: { - PatternTerm* term = op.m_term; - - // Restore the input index value. - unsigned parenthesesFrameLocation = term->frameLocation; - loadFromFrame(parenthesesFrameLocation, index); - - // If inverted, a successful match of the assertion must be treated - // as a failure, so jump to backtracking. - if (term->invert()) { - op.m_jumps.append(jump()); - op.m_reentry = label(); - } - - YarrOp& lastOp = m_ops[op.m_previousOp]; - m_checked += lastOp.m_checkAdjust; - break; - } - - case OpMatchFailed: -#if !WTF_CPU_SPARC - removeCallFrame(); -#endif -#if WTF_CPU_X86_64 - move(TrustedImm32(int(WTF::notFound)), returnRegister); -#else - move(TrustedImmPtr((void*)WTF::notFound), returnRegister); - move(TrustedImm32(0), returnRegister2); -#endif - generateReturn(); - break; - } - - ++opIndex; - } while (opIndex < m_ops.size()); - - return true; - } - - bool backtrack() - { - // Backwards generate the backtracking code. - size_t opIndex = m_ops.size(); - ASSERT(opIndex); - - do { - --opIndex; - YarrOp& op = m_ops[opIndex]; - switch (op.m_op) { - - case OpTerm: - if (!backtrackTerm(opIndex)) - return false; - break; - - // OpBodyAlternativeBegin/Next/End - // - // For each Begin/Next node representing an alternative, we need to decide what to do - // in two circumstances: - // - If we backtrack back into this node, from within the alternative. - // - If the input check at the head of the alternative fails (if this exists). - // - // We treat these two cases differently since in the former case we have slightly - // more information - since we are backtracking out of a prior alternative we know - // that at least enough input was available to run it. For example, given the regular - // expression /a|b/, if we backtrack out of the first alternative (a failed pattern - // character match of 'a'), then we need not perform an additional input availability - // check before running the second alternative. - // - // Backtracking required differs for the last alternative, which in the case of the - // repeating set of alternatives must loop. The code generated for the last alternative - // will also be used to handle all input check failures from any prior alternatives - - // these require similar functionality, in seeking the next available alternative for - // which there is sufficient input. - // - // Since backtracking of all other alternatives simply requires us to link backtracks - // to the reentry point for the subsequent alternative, we will only be generating any - // code when backtracking the last alternative. - case OpBodyAlternativeBegin: - case OpBodyAlternativeNext: { - PatternAlternative* alternative = op.m_alternative; - - if (op.m_op == OpBodyAlternativeNext) { - PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative; - m_checked += priorAlternative->m_minimumSize; - } - m_checked -= alternative->m_minimumSize; - - // Is this the last alternative? If not, then if we backtrack to this point we just - // need to jump to try to match the next alternative. - if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) { - m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this); - break; - } - YarrOp& endOp = m_ops[op.m_nextOp]; - - YarrOp* beginOp = &op; - while (beginOp->m_op != OpBodyAlternativeBegin) { - ASSERT(beginOp->m_op == OpBodyAlternativeNext); - beginOp = &m_ops[beginOp->m_previousOp]; - } - - bool onceThrough = endOp.m_nextOp == notFound; - - // First, generate code to handle cases where we backtrack out of an attempted match - // of the last alternative. If this is a 'once through' set of alternatives then we - // have nothing to do - link this straight through to the End. - if (onceThrough) - m_backtrackingState.linkTo(endOp.m_reentry, this); - else { - // If we don't need to move the input poistion, and the pattern has a fixed size - // (in which case we omit the store of the start index until the pattern has matched) - // then we can just link the backtrack out of the last alternative straight to the - // head of the first alternative. - if (m_pattern.m_body->m_hasFixedSize - && (alternative->m_minimumSize > beginOp->m_alternative->m_minimumSize) - && (alternative->m_minimumSize - beginOp->m_alternative->m_minimumSize == 1)) - m_backtrackingState.linkTo(beginOp->m_reentry, this); - else { - // We need to generate a trampoline of code to execute before looping back - // around to the first alternative. - m_backtrackingState.link(this); - - // If the pattern size is not fixed, then store the start index, for use if we match. - if (!m_pattern.m_body->m_hasFixedSize) { - if (alternative->m_minimumSize == 1) - setMatchStart(index); - else { - move(index, regT0); - if (alternative->m_minimumSize) - sub32(Imm32(alternative->m_minimumSize - 1), regT0); - else - add32(TrustedImm32(1), regT0); - setMatchStart(regT0); - } - } - - // Generate code to loop. Check whether the last alternative is longer than the - // first (e.g. /a|xy/ or /a|xyz/). - if (alternative->m_minimumSize > beginOp->m_alternative->m_minimumSize) { - // We want to loop, and increment input position. If the delta is 1, it is - // already correctly incremented, if more than one then decrement as appropriate. - unsigned delta = alternative->m_minimumSize - beginOp->m_alternative->m_minimumSize; - ASSERT(delta); - if (delta != 1) - sub32(Imm32(delta - 1), index); - jump(beginOp->m_reentry); - } else { - // If the first alternative has minimum size 0xFFFFFFFFu, then there cannot - // be sufficent input available to handle this, so just fall through. - unsigned delta = beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize; - if (delta != 0xFFFFFFFFu) { - // We need to check input because we are incrementing the input. - add32(Imm32(delta + 1), index); - checkInput().linkTo(beginOp->m_reentry, this); - } - } - } - } - - // We can reach this point in the code in two ways: - // - Fallthrough from the code above (a repeating alternative backtracked out of its - // last alternative, and did not have sufficent input to run the first). - // - We will loop back up to the following label when a releating alternative loops, - // following a failed input check. - // - // Either way, we have just failed the input check for the first alternative. - Label firstInputCheckFailed(this); - - // Generate code to handle input check failures from alternatives except the last. - // prevOp is the alternative we're handling a bail out from (initially Begin), and - // nextOp is the alternative we will be attempting to reenter into. - // - // We will link input check failures from the forwards matching path back to the code - // that can handle them. - YarrOp* prevOp = beginOp; - YarrOp* nextOp = &m_ops[beginOp->m_nextOp]; - while (nextOp->m_op != OpBodyAlternativeEnd) { - prevOp->m_jumps.link(this); - - // We only get here if an input check fails, it is only worth checking again - // if the next alternative has a minimum size less than the last. - if (prevOp->m_alternative->m_minimumSize > nextOp->m_alternative->m_minimumSize) { - // FIXME: if we added an extra label to YarrOp, we could avoid needing to - // subtract delta back out, and reduce this code. Should performance test - // the benefit of this. - unsigned delta = prevOp->m_alternative->m_minimumSize - nextOp->m_alternative->m_minimumSize; - sub32(Imm32(delta), index); - Jump fail = jumpIfNoAvailableInput(); - add32(Imm32(delta), index); - jump(nextOp->m_reentry); - fail.link(this); - } else if (prevOp->m_alternative->m_minimumSize < nextOp->m_alternative->m_minimumSize) - add32(Imm32(nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize), index); - prevOp = nextOp; - nextOp = &m_ops[nextOp->m_nextOp]; - } - - // We fall through to here if there is insufficient input to run the last alternative. - - // If there is insufficient input to run the last alternative, then for 'once through' - // alternatives we are done - just jump back up into the forwards matching path at the End. - if (onceThrough) { - op.m_jumps.linkTo(endOp.m_reentry, this); - jump(endOp.m_reentry); - break; - } - - // For repeating alternatives, link any input check failure from the last alternative to - // this point. - op.m_jumps.link(this); - - bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize; - - // Check for cases where input position is already incremented by 1 for the last - // alternative (this is particularly useful where the minimum size of the body - // disjunction is 0, e.g. /a*|b/). - if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) { - // index is already incremented by 1, so just store it now! - setMatchStart(index); - needsToUpdateMatchStart = false; - } - - // Check whether there is sufficient input to loop. Increment the input position by - // one, and check. Also add in the minimum disjunction size before checking - there - // is no point in looping if we're just going to fail all the input checks around - // the next iteration. - ASSERT(alternative->m_minimumSize >= m_pattern.m_body->m_minimumSize); - if (alternative->m_minimumSize == m_pattern.m_body->m_minimumSize) { - // If the last alternative had the same minimum size as the disjunction, - // just simply increment input pos by 1, no adjustment based on minimum size. - add32(TrustedImm32(1), index); - } else { - // If the minumum for the last alternative was one greater than than that - // for the disjunction, we're already progressed by 1, nothing to do! - unsigned delta = (alternative->m_minimumSize - m_pattern.m_body->m_minimumSize) - 1; - if (delta) - sub32(Imm32(delta), index); - } - Jump matchFailed = jumpIfNoAvailableInput(); - - if (needsToUpdateMatchStart) { - if (!m_pattern.m_body->m_minimumSize) - setMatchStart(index); - else { - move(index, regT0); - sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0); - setMatchStart(regT0); - } - } - - // Calculate how much more input the first alternative requires than the minimum - // for the body as a whole. If no more is needed then we dont need an additional - // input check here - jump straight back up to the start of the first alternative. - if (beginOp->m_alternative->m_minimumSize == m_pattern.m_body->m_minimumSize) - jump(beginOp->m_reentry); - else { - if (beginOp->m_alternative->m_minimumSize > m_pattern.m_body->m_minimumSize) - add32(Imm32(beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize), index); - else - sub32(Imm32(m_pattern.m_body->m_minimumSize - beginOp->m_alternative->m_minimumSize), index); - checkInput().linkTo(beginOp->m_reentry, this); - jump(firstInputCheckFailed); - } - - // We jump to here if we iterate to the point that there is insufficient input to - // run any matches, and need to return a failure state from JIT code. - matchFailed.link(this); - -#if !WTF_CPU_SPARC - removeCallFrame(); -#endif -#if WTF_CPU_X86_64 - move(TrustedImm32(int(WTF::notFound)), returnRegister); -#else - move(TrustedImmPtr((void*)WTF::notFound), returnRegister); - move(TrustedImm32(0), returnRegister2); -#endif - generateReturn(); - break; - } - case OpBodyAlternativeEnd: { - // We should never backtrack back into a body disjunction. - ASSERT(m_backtrackingState.isEmpty()); - - PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative; - m_checked += priorAlternative->m_minimumSize; - break; - } - - // OpSimpleNestedAlternativeBegin/Next/End - // OpNestedAlternativeBegin/Next/End - // - // Generate code for when we backtrack back out of an alternative into - // a Begin or Next node, or when the entry input count check fails. If - // there are more alternatives we need to jump to the next alternative, - // if not we backtrack back out of the current set of parentheses. - // - // In the case of non-simple nested assertions we need to also link the - // 'return address' appropriately to backtrack back out into the correct - // alternative. - case OpSimpleNestedAlternativeBegin: - case OpSimpleNestedAlternativeNext: - case OpNestedAlternativeBegin: - case OpNestedAlternativeNext: { - YarrOp& nextOp = m_ops[op.m_nextOp]; - bool isBegin = op.m_previousOp == notFound; - bool isLastAlternative = nextOp.m_nextOp == notFound; - ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin)); - ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd)); - - // Treat an input check failure the same as a failed match. - m_backtrackingState.append(op.m_jumps); - - // Set the backtracks to jump to the appropriate place. We may need - // to link the backtracks in one of three different way depending on - // the type of alternative we are dealing with: - // - A single alternative, with no simplings. - // - The last alternative of a set of two or more. - // - An alternative other than the last of a set of two or more. - // - // In the case of a single alternative on its own, we don't need to - // jump anywhere - if the alternative fails to match we can just - // continue to backtrack out of the parentheses without jumping. - // - // In the case of the last alternative in a set of more than one, we - // need to jump to return back out to the beginning. We'll do so by - // adding a jump to the End node's m_jumps list, and linking this - // when we come to generate the Begin node. For alternatives other - // than the last, we need to jump to the next alternative. - // - // If the alternative had adjusted the input position we must link - // backtracking to here, correct, and then jump on. If not we can - // link the backtracks directly to their destination. - if (op.m_checkAdjust) { - // Handle the cases where we need to link the backtracks here. - m_backtrackingState.link(this); - sub32(Imm32(op.m_checkAdjust), index); - if (!isLastAlternative) { - // An alternative that is not the last should jump to its successor. - jump(nextOp.m_reentry); - } else if (!isBegin) { - // The last of more than one alternatives must jump back to the beginning. - nextOp.m_jumps.append(jump()); - } else { - // A single alternative on its own can fall through. - m_backtrackingState.fallthrough(); - } - } else { - // Handle the cases where we can link the backtracks directly to their destinations. - if (!isLastAlternative) { - // An alternative that is not the last should jump to its successor. - m_backtrackingState.linkTo(nextOp.m_reentry, this); - } else if (!isBegin) { - // The last of more than one alternatives must jump back to the beginning. - m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this); - } - // In the case of a single alternative on its own do nothing - it can fall through. - } - - // If there is a backtrack jump from a zero length match link it here. - if (op.m_zeroLengthMatch.isSet()) - m_backtrackingState.append(op.m_zeroLengthMatch); - - // At this point we've handled the backtracking back into this node. - // Now link any backtracks that need to jump to here. - - // For non-simple alternatives, link the alternative's 'return address' - // so that we backtrack back out into the previous alternative. - if (op.m_op == OpNestedAlternativeNext) - m_backtrackingState.append(op.m_returnAddress); - - // If there is more than one alternative, then the last alternative will - // have planted a jump to be linked to the end. This jump was added to the - // End node's m_jumps list. If we are back at the beginning, link it here. - if (isBegin) { - YarrOp* endOp = &m_ops[op.m_nextOp]; - while (endOp->m_nextOp != notFound) { - ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext); - endOp = &m_ops[endOp->m_nextOp]; - } - ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd); - m_backtrackingState.append(endOp->m_jumps); - } - - if (!isBegin) { - YarrOp& lastOp = m_ops[op.m_previousOp]; - m_checked += lastOp.m_checkAdjust; - } - m_checked -= op.m_checkAdjust; - break; - } - case OpSimpleNestedAlternativeEnd: - case OpNestedAlternativeEnd: { - PatternTerm* term = op.m_term; - - // If there is a backtrack jump from a zero length match link it here. - if (op.m_zeroLengthMatch.isSet()) - m_backtrackingState.append(op.m_zeroLengthMatch); - - // If we backtrack into the end of a simple subpattern do nothing; - // just continue through into the last alternative. If we backtrack - // into the end of a non-simple set of alterntives we need to jump - // to the backtracking return address set up during generation. - if (op.m_op == OpNestedAlternativeEnd) { - m_backtrackingState.link(this); - - // Plant a jump to the return address. - unsigned parenthesesFrameLocation = term->frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation; - if (term->quantityType != QuantifierFixedCount) - alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; - loadFromFrameAndJump(alternativeFrameLocation); - - // Link the DataLabelPtr associated with the end of the last - // alternative to this point. - m_backtrackingState.append(op.m_returnAddress); - } - - YarrOp& lastOp = m_ops[op.m_previousOp]; - m_checked += lastOp.m_checkAdjust; - break; - } - - // OpParenthesesSubpatternOnceBegin/End - // - // When we are backtracking back out of a capturing subpattern we need - // to clear the start index in the matches output array, to record that - // this subpattern has not been captured. - // - // When backtracking back out of a Greedy quantified subpattern we need - // to catch this, and try running the remainder of the alternative after - // the subpattern again, skipping the parentheses. - // - // Upon backtracking back into a quantified set of parentheses we need to - // check whether we were currently skipping the subpattern. If not, we - // can backtrack into them, if we were we need to either backtrack back - // out of the start of the parentheses, or jump back to the forwards - // matching start, depending of whether the match is Greedy or NonGreedy. - case OpParenthesesSubpatternOnceBegin: { - PatternTerm* term = op.m_term; - ASSERT(term->quantityCount == 1); - - // We only need to backtrack to thispoint if capturing or greedy. - if ((term->capture() && compileMode == IncludeSubpatterns) || term->quantityType == QuantifierGreedy) { - m_backtrackingState.link(this); - - // If capturing, clear the capture (we only need to reset start). - if (term->capture() && compileMode == IncludeSubpatterns) - clearSubpatternStart(term->parentheses.subpatternId); - - // If Greedy, jump to the end. - if (term->quantityType == QuantifierGreedy) { - // Clear the flag in the stackframe indicating we ran through the subpattern. - unsigned parenthesesFrameLocation = term->frameLocation; - storeToFrame(TrustedImm32(-1), parenthesesFrameLocation); - // Jump to after the parentheses, skipping the subpattern. - jump(m_ops[op.m_nextOp].m_reentry); - // A backtrack from after the parentheses, when skipping the subpattern, - // will jump back to here. - op.m_jumps.link(this); - } - - m_backtrackingState.fallthrough(); - } - break; - } - case OpParenthesesSubpatternOnceEnd: { - PatternTerm* term = op.m_term; - - if (term->quantityType != QuantifierFixedCount) { - m_backtrackingState.link(this); - - // Check whether we should backtrack back into the parentheses, or if we - // are currently in a state where we had skipped over the subpattern - // (in which case the flag value on the stack will be -1). - unsigned parenthesesFrameLocation = term->frameLocation; - Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1)); - - if (term->quantityType == QuantifierGreedy) { - // For Greedy parentheses, we skip after having already tried going - // through the subpattern, so if we get here we're done. - YarrOp& beginOp = m_ops[op.m_previousOp]; - beginOp.m_jumps.append(hadSkipped); - } else { - // For NonGreedy parentheses, we try skipping the subpattern first, - // so if we get here we need to try running through the subpattern - // next. Jump back to the start of the parentheses in the forwards - // matching path. - ASSERT(term->quantityType == QuantifierNonGreedy); - YarrOp& beginOp = m_ops[op.m_previousOp]; - hadSkipped.linkTo(beginOp.m_reentry, this); - } - - m_backtrackingState.fallthrough(); - } - - m_backtrackingState.append(op.m_jumps); - break; - } - - // OpParenthesesSubpatternTerminalBegin/End - // - // Terminal subpatterns will always match - there is nothing after them to - // force a backtrack, and they have a minimum count of 0, and as such will - // always produce an acceptable result. - case OpParenthesesSubpatternTerminalBegin: { - // We will backtrack to this point once the subpattern cannot match any - // more. Since no match is accepted as a successful match (we are Greedy - // quantified with a minimum of zero) jump back to the forwards matching - // path at the end. - YarrOp& endOp = m_ops[op.m_nextOp]; - m_backtrackingState.linkTo(endOp.m_reentry, this); - break; - } - case OpParenthesesSubpatternTerminalEnd: - // We should never be backtracking to here (hence the 'terminal' in the name). - ASSERT(m_backtrackingState.isEmpty()); - m_backtrackingState.append(op.m_jumps); - break; - - // OpParentheticalAssertionBegin/End - case OpParentheticalAssertionBegin: { - PatternTerm* term = op.m_term; - YarrOp& endOp = m_ops[op.m_nextOp]; - - // We need to handle the backtracks upon backtracking back out - // of a parenthetical assertion if either we need to correct - // the input index, or the assertion was inverted. - if (op.m_checkAdjust || term->invert()) { - m_backtrackingState.link(this); - - if (op.m_checkAdjust) - add32(Imm32(op.m_checkAdjust), index); - - // In an inverted assertion failure to match the subpattern - // is treated as a successful match - jump to the end of the - // subpattern. We already have adjusted the input position - // back to that before the assertion, which is correct. - if (term->invert()) - jump(endOp.m_reentry); - - m_backtrackingState.fallthrough(); - } - - // The End node's jump list will contain any backtracks into - // the end of the assertion. Also, if inverted, we will have - // added the failure caused by a successful match to this. - m_backtrackingState.append(endOp.m_jumps); - - m_checked += op.m_checkAdjust; - break; - } - case OpParentheticalAssertionEnd: { - // FIXME: We should really be clearing any nested subpattern - // matches on bailing out from after the pattern. Firefox has - // this bug too (presumably because they use YARR!) - - // Never backtrack into an assertion; later failures bail to before the begin. - m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this); - - YarrOp& lastOp = m_ops[op.m_previousOp]; - m_checked -= lastOp.m_checkAdjust; - break; - } - - case OpMatchFailed: - break; - } - - } while (opIndex); - - return true; - } - - // Compilation methods: - // ==================== - - // opCompileParenthesesSubpattern - // Emits ops for a subpattern (set of parentheses). These consist - // of a set of alternatives wrapped in an outer set of nodes for - // the parentheses. - // Supported types of parentheses are 'Once' (quantityCount == 1) - // and 'Terminal' (non-capturing parentheses quantified as greedy - // and infinite). - // Alternatives will use the 'Simple' set of ops if either the - // subpattern is terminal (in which case we will never need to - // backtrack), or if the subpattern only contains one alternative. - void opCompileParenthesesSubpattern(PatternTerm* term) - { - YarrOpCode parenthesesBeginOpCode; - YarrOpCode parenthesesEndOpCode; - YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin; - YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext; - YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd; - - // We can currently only compile quantity 1 subpatterns that are - // not copies. We generate a copy in the case of a range quantifier, - // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to - // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem - // comes where the subpattern is capturing, in which case we would - // need to restore the capture from the first subpattern upon a - // failure in the second. - if (term->quantityCount == 1 && !term->parentheses.isCopy) { - // Select the 'Once' nodes. - parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin; - parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd; - - // If there is more than one alternative we cannot use the 'simple' nodes. - if (term->parentheses.disjunction->m_alternatives.size() != 1) { - alternativeBeginOpCode = OpNestedAlternativeBegin; - alternativeNextOpCode = OpNestedAlternativeNext; - alternativeEndOpCode = OpNestedAlternativeEnd; - } - } else if (term->parentheses.isTerminal) { - // Terminal groups are optimized on the assumption that matching will never - // backtrack into the terminal group. But this is false if there is more - // than one alternative and one of the alternatives can match empty. In that - // case, the empty match is counted as a failure, so we would need to backtrack. - // The backtracking code doesn't handle this case correctly, so we fall back - // to the interpreter. - Vector& alternatives = term->parentheses.disjunction->m_alternatives; - if (alternatives.size() != 1) { - for (unsigned i = 0; i < alternatives.size(); ++i) { - if (alternatives[i]->m_minimumSize == 0) { - m_shouldFallBack = true; - return; - } - } - } - - // Select the 'Terminal' nodes. - parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin; - parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd; - } else { - // This subpattern is not supported by the JIT. - m_shouldFallBack = true; - return; - } - - size_t parenBegin = m_ops.size(); - m_ops.append(parenthesesBeginOpCode); - - m_ops.append(alternativeBeginOpCode); - m_ops.last().m_previousOp = notFound; - m_ops.last().m_term = term; - Vector& alternatives = term->parentheses.disjunction->m_alternatives; - for (unsigned i = 0; i < alternatives.size(); ++i) { - size_t lastOpIndex = m_ops.size() - 1; - - PatternAlternative* nestedAlternative = alternatives[i]; - opCompileAlternative(nestedAlternative); - - size_t thisOpIndex = m_ops.size(); - m_ops.append(YarrOp(alternativeNextOpCode)); - - YarrOp& lastOp = m_ops[lastOpIndex]; - YarrOp& thisOp = m_ops[thisOpIndex]; - - lastOp.m_alternative = nestedAlternative; - lastOp.m_nextOp = thisOpIndex; - thisOp.m_previousOp = lastOpIndex; - thisOp.m_term = term; - } - YarrOp& lastOp = m_ops.last(); - ASSERT(lastOp.m_op == alternativeNextOpCode); - lastOp.m_op = alternativeEndOpCode; - lastOp.m_alternative = 0; - lastOp.m_nextOp = notFound; - - size_t parenEnd = m_ops.size(); - m_ops.append(parenthesesEndOpCode); - - m_ops[parenBegin].m_term = term; - m_ops[parenBegin].m_previousOp = notFound; - m_ops[parenBegin].m_nextOp = parenEnd; - m_ops[parenEnd].m_term = term; - m_ops[parenEnd].m_previousOp = parenBegin; - m_ops[parenEnd].m_nextOp = notFound; - } - - // opCompileParentheticalAssertion - // Emits ops for a parenthetical assertion. These consist of an - // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping - // the alternatives, with these wrapped by an outer pair of - // OpParentheticalAssertionBegin/End nodes. - // We can always use the OpSimpleNestedAlternative nodes in the - // case of parenthetical assertions since these only ever match - // once, and will never backtrack back into the assertion. - void opCompileParentheticalAssertion(PatternTerm* term) - { - size_t parenBegin = m_ops.size(); - m_ops.append(OpParentheticalAssertionBegin); - - m_ops.append(OpSimpleNestedAlternativeBegin); - m_ops.last().m_previousOp = notFound; - m_ops.last().m_term = term; - Vector& alternatives = term->parentheses.disjunction->m_alternatives; - for (unsigned i = 0; i < alternatives.size(); ++i) { - size_t lastOpIndex = m_ops.size() - 1; - - PatternAlternative* nestedAlternative = alternatives[i]; - opCompileAlternative(nestedAlternative); - - size_t thisOpIndex = m_ops.size(); - m_ops.append(YarrOp(OpSimpleNestedAlternativeNext)); - - YarrOp& lastOp = m_ops[lastOpIndex]; - YarrOp& thisOp = m_ops[thisOpIndex]; - - lastOp.m_alternative = nestedAlternative; - lastOp.m_nextOp = thisOpIndex; - thisOp.m_previousOp = lastOpIndex; - thisOp.m_term = term; - } - YarrOp& lastOp = m_ops.last(); - ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext); - lastOp.m_op = OpSimpleNestedAlternativeEnd; - lastOp.m_alternative = 0; - lastOp.m_nextOp = notFound; - - size_t parenEnd = m_ops.size(); - m_ops.append(OpParentheticalAssertionEnd); - - m_ops[parenBegin].m_term = term; - m_ops[parenBegin].m_previousOp = notFound; - m_ops[parenBegin].m_nextOp = parenEnd; - m_ops[parenEnd].m_term = term; - m_ops[parenEnd].m_previousOp = parenBegin; - m_ops[parenEnd].m_nextOp = notFound; - } - - // opCompileAlternative - // Called to emit nodes for all terms in an alternative. - void opCompileAlternative(PatternAlternative* alternative) - { - optimizeAlternative(alternative); - - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { - PatternTerm* term = &alternative->m_terms[i]; - - switch (term->type) { - case PatternTerm::TypeParenthesesSubpattern: - opCompileParenthesesSubpattern(term); - break; - - case PatternTerm::TypeParentheticalAssertion: - opCompileParentheticalAssertion(term); - break; - - default: - m_ops.append(term); - } - } - } - - // opCompileBody - // This method compiles the body disjunction of the regular expression. - // The body consists of two sets of alternatives - zero or more 'once - // through' (BOL anchored) alternatives, followed by zero or more - // repeated alternatives. - // For each of these two sets of alteratives, if not empty they will be - // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the - // 'begin' node referencing the first alternative, and 'next' nodes - // referencing any further alternatives. The begin/next/end nodes are - // linked together in a doubly linked list. In the case of repeating - // alternatives, the end node is also linked back to the beginning. - // If no repeating alternatives exist, then a OpMatchFailed node exists - // to return the failing result. - void opCompileBody(PatternDisjunction* disjunction) - { - Vector& alternatives = disjunction->m_alternatives; - size_t currentAlternativeIndex = 0; - - // Emit the 'once through' alternatives. - if (alternatives.size() && alternatives[0]->onceThrough()) { - m_ops.append(YarrOp(OpBodyAlternativeBegin)); - m_ops.last().m_previousOp = notFound; - - do { - size_t lastOpIndex = m_ops.size() - 1; - PatternAlternative* alternative = alternatives[currentAlternativeIndex]; - opCompileAlternative(alternative); - - size_t thisOpIndex = m_ops.size(); - m_ops.append(YarrOp(OpBodyAlternativeNext)); - - YarrOp& lastOp = m_ops[lastOpIndex]; - YarrOp& thisOp = m_ops[thisOpIndex]; - - lastOp.m_alternative = alternative; - lastOp.m_nextOp = thisOpIndex; - thisOp.m_previousOp = lastOpIndex; - - ++currentAlternativeIndex; - } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough()); - - YarrOp& lastOp = m_ops.last(); - - ASSERT(lastOp.m_op == OpBodyAlternativeNext); - lastOp.m_op = OpBodyAlternativeEnd; - lastOp.m_alternative = 0; - lastOp.m_nextOp = notFound; - } - - if (currentAlternativeIndex == alternatives.size()) { - m_ops.append(YarrOp(OpMatchFailed)); - return; - } - - // Emit the repeated alternatives. - size_t repeatLoop = m_ops.size(); - m_ops.append(YarrOp(OpBodyAlternativeBegin)); - m_ops.last().m_previousOp = notFound; - do { - size_t lastOpIndex = m_ops.size() - 1; - PatternAlternative* alternative = alternatives[currentAlternativeIndex]; - ASSERT(!alternative->onceThrough()); - opCompileAlternative(alternative); - - size_t thisOpIndex = m_ops.size(); - m_ops.append(YarrOp(OpBodyAlternativeNext)); - - YarrOp& lastOp = m_ops[lastOpIndex]; - YarrOp& thisOp = m_ops[thisOpIndex]; - - lastOp.m_alternative = alternative; - lastOp.m_nextOp = thisOpIndex; - thisOp.m_previousOp = lastOpIndex; - - ++currentAlternativeIndex; - } while (currentAlternativeIndex < alternatives.size()); - YarrOp& lastOp = m_ops.last(); - ASSERT(lastOp.m_op == OpBodyAlternativeNext); - lastOp.m_op = OpBodyAlternativeEnd; - lastOp.m_alternative = 0; - lastOp.m_nextOp = repeatLoop; - } - - void generateEnter() - { -#if WTF_CPU_X86_64 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - push(X86Registers::ebx); - // The ABI doesn't guarantee the upper bits are zero on unsigned arguments, so clear them ourselves. - zeroExtend32ToPtr(index, index); - zeroExtend32ToPtr(length, length); -#elif WTF_CPU_X86 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - // TODO: do we need spill registers to fill the output pointer if there are no sub captures? - push(X86Registers::ebx); - push(X86Registers::edi); - push(X86Registers::esi); - // load output into edi (2 = saved ebp + return address). -# if WTF_COMPILER_MSVC || WTF_COMPILER_SUNCC - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); - loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); - loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); - if (compileMode == IncludeSubpatterns) - loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); -# else - if (compileMode == IncludeSubpatterns) - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); -# endif -#elif WTF_CPU_ARM - push(ARMRegisters::r4); - push(ARMRegisters::r5); - push(ARMRegisters::r6); -# if WTF_CPU_ARM_TRADITIONAL - push(ARMRegisters::r8); // scratch register -# endif - if (compileMode == IncludeSubpatterns) - move(ARMRegisters::r3, output); -#elif WTF_CPU_SH4 - push(SH4Registers::r11); - push(SH4Registers::r13); -#elif WTF_CPU_SPARC - save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); -#elif WTF_CPU_MIPS - // Do nothing. -#endif - } - - void generateReturn() - { -#if WTF_CPU_X86_64 - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_X86 - pop(X86Registers::esi); - pop(X86Registers::edi); - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_ARM -# if WTF_CPU_ARM_TRADITIONAL - pop(ARMRegisters::r8); // scratch register -# endif - pop(ARMRegisters::r6); - pop(ARMRegisters::r5); - pop(ARMRegisters::r4); -#elif WTF_CPU_SH4 - pop(SH4Registers::r13); - pop(SH4Registers::r11); -#elif WTF_CPU_SPARC - ret_and_restore(); - return; -#elif WTF_CPU_MIPS - // Do nothing -#endif - ret(); - } - -public: - YarrGenerator(YarrPattern& pattern, YarrCharSize charSize) - : m_pattern(pattern) - , m_charSize(charSize) - , m_charScale(m_charSize == Char8 ? TimesOne: TimesTwo) - , m_shouldFallBack(false) - , m_checked(0) - { - } - - void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject) - { - generateEnter(); - - Jump hasInput = checkInput(); -#if WTF_CPU_X86_64 - move(TrustedImm32(int(WTF::notFound)), returnRegister); -#else - move(TrustedImmPtr((void*)WTF::notFound), returnRegister); - move(TrustedImm32(0), returnRegister2); -#endif - generateReturn(); - hasInput.link(this); - - if (compileMode == IncludeSubpatterns) { - for (unsigned i = 0; i < m_pattern.m_numSubpatterns + 1; ++i) - store32(TrustedImm32(-1), Address(output, (i << 1) * sizeof(int))); - } - - if (!m_pattern.m_body->m_hasFixedSize) - setMatchStart(index); - - initCallFrame(); - - // Compile the pattern to the internal 'YarrOp' representation. - opCompileBody(m_pattern.m_body); - - // If we encountered anything we can't handle in the JIT code - // (e.g. backreferences) then return early. - if (m_shouldFallBack) { - jitObject.setFallBack(true); - return; - } - - if (!generate() || !backtrack()) { - jitObject.setFallBack(true); - return; - } - - // Link & finalize the code. - ExecutablePool *pool; - bool ok; - LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok, REGEXP_CODE); - - // Attempt to detect OOM during linkBuffer creation. - if (linkBuffer.unsafeCode() == nullptr) { - jitObject.setFallBack(true); - return; - } - - m_backtrackingState.linkDataLabels(linkBuffer); - - if (compileMode == MatchOnly) { -#if YARR_8BIT_CHAR_SUPPORT - if (m_charSize == Char8) - jitObject.set8BitCodeMatchOnly(linkBuffer.finalizeCode()); - else -#endif - jitObject.set16BitCodeMatchOnly(linkBuffer.finalizeCode()); - } else { -#if YARR_8BIT_CHAR_SUPPORT - if (m_charSize == Char8) - jitObject.set8BitCode(linkBuffer.finalizeCode()); - else -#endif - jitObject.set16BitCode(linkBuffer.finalizeCode()); - } - jitObject.setFallBack(m_shouldFallBack); - } - -private: - YarrPattern& m_pattern; - - YarrCharSize m_charSize; - - Scale m_charScale; - - // Used to detect regular expression constructs that are not currently - // supported in the JIT; fall back to the interpreter when this is detected. - bool m_shouldFallBack; - - // The regular expression expressed as a linear sequence of operations. - Vector m_ops; - - // This records the current input offset being applied due to the current - // set of alternatives we are nested within. E.g. when matching the - // character 'b' within the regular expression /abc/, we will know that - // the minimum size for the alternative is 3, checked upon entry to the - // alternative, and that 'b' is at offset 1 from the start, and as such - // when matching 'b' we need to apply an offset of -2 to the load. - // - // FIXME: This should go away. Rather than tracking this value throughout - // code generation, we should gather this information up front & store it - // on the YarrOp structure. - int m_checked; - - // This class records state whilst generating the backtracking path of code. - BacktrackingState m_backtrackingState; -}; - -void jitCompile(YarrPattern& pattern, YarrCharSize charSize, JSGlobalData* globalData, YarrCodeBlock& jitObject, YarrJITCompileMode mode) -{ - if (mode == MatchOnly) - YarrGenerator(pattern, charSize).compile(globalData, jitObject); - else - YarrGenerator(pattern, charSize).compile(globalData, jitObject); -} - -}} - -#endif diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h deleted file mode 100644 index 30613dd5099c..000000000000 --- a/js/src/yarr/YarrJIT.h +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_YarrJIT_h -#define yarr_YarrJIT_h - -#include "assembler/wtf/Platform.h" - -#if JS_ION - -#include "assembler/assembler/MacroAssemblerCodeRef.h" - -#include "yarr/MatchResult.h" -#include "yarr/Yarr.h" - -#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNCC -#define YARR_CALL __attribute__ ((regparm (3))) -#else -#define YARR_CALL -#endif - -#include "jit/JitCommon.h" - -namespace JSC { - -class JSGlobalData; -class ExecutablePool; - -namespace Yarr { - -class YarrCodeBlock { -#if defined(WTF_CPU_X86_64) && !defined(_WIN64) - typedef MatchResult JITMatchResult; -#else - typedef EncodedMatchResult JITMatchResult; -#endif - - typedef JITMatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output) YARR_CALL; - typedef JITMatchResult (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; - typedef JITMatchResult (*YarrJITCodeMatchOnly8)(const LChar* input, unsigned start, unsigned length) YARR_CALL; - typedef JITMatchResult (*YarrJITCodeMatchOnly16)(const UChar* input, unsigned start, unsigned length) YARR_CALL; - -public: - YarrCodeBlock() - : m_needFallBack(false) - { - } - - ~YarrCodeBlock() - { - } - - void setFallBack(bool fallback) { m_needFallBack = fallback; } - bool isFallBack() { return m_needFallBack; } - -#ifdef YARR_8BIT_CHAR_SUPPORT - bool has8BitCode() const { return m_ref8.allocSize(); } - void set8BitCode(MacroAssemblerCodeRef ref) { m_ref8 = ref; } - bool has8BitCodeMatchOnly() const { return m_matchOnly8.allocSize(); } - void set8BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly8 = matchOnly; } -#endif - - bool has16BitCode() const { return m_ref16.allocSize(); } - void set16BitCode(MacroAssemblerCodeRef ref) { m_ref16 = ref; } - - bool has16BitCodeMatchOnly() const { return m_matchOnly16.allocSize(); } - void set16BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly16 = matchOnly; } - -#if YARR_8BIT_CHAR_SUPPORT - MatchResult execute(const LChar* input, unsigned start, unsigned length, int* output) - { - ASSERT(has8BitCode()); - - return MatchResult(reinterpret_cast(m_ref8.code().executableAddress())(input, start, length, output)); - } - - MatchResult execute(const LChar* input, unsigned start, unsigned length) - { - ASSERT(has8BitCodeMatchOnly()); - - return MatchResult(reinterpret_cast(m_matchOnly8.code().executableAddress())(input, start, length)); - } -#endif - - MatchResult execute(const UChar* input, unsigned start, unsigned length, int* output) - { - ASSERT(has16BitCode()); - - YarrJITCode16 fn = JS_FUNC_TO_DATA_PTR(YarrJITCode16, m_ref16.code().executableAddress()); - return MatchResult(CALL_GENERATED_YARR_CODE4(fn, input, start, length, output)); - } - - MatchResult execute(const UChar* input, unsigned start, unsigned length) - { - ASSERT(has16BitCodeMatchOnly()); - - YarrJITCodeMatchOnly16 fn = JS_FUNC_TO_DATA_PTR(YarrJITCodeMatchOnly16, m_matchOnly16.code().executableAddress()); - return MatchResult(CALL_GENERATED_YARR_CODE3(fn, input, start, length)); - } - -#if ENABLE_REGEXP_TRACING - void *getAddr() { return m_ref.code().executableAddress(); } -#endif - - void clear() - { -#ifdef YARR_8BIT_CHAR_SUPPORT - m_ref8 = MacroAssemblerCodeRef(); - m_matchOnly8 = MacroAssemblerCodeRef(); -#endif - - m_ref16 = MacroAssemblerCodeRef(); - m_matchOnly16 = MacroAssemblerCodeRef(); - m_needFallBack = false; - } - - void release() { -#ifdef YARR_8BIT_CHAR_SUPPORT - m_ref8.release(); - m_matchOnly8.release(); -#endif - - m_ref16.release(); - m_matchOnly16.release(); - } - -private: -#ifdef YARR_8BIT_CHAR_SUPPORT - MacroAssemblerCodeRef m_ref8; - MacroAssemblerCodeRef m_matchOnly8; -#endif - - MacroAssemblerCodeRef m_ref16; - MacroAssemblerCodeRef m_matchOnly16; - bool m_needFallBack; -}; - -enum YarrJITCompileMode { - MatchOnly, - IncludeSubpatterns -}; -void jitCompile(YarrPattern&, YarrCharSize, JSGlobalData*, YarrCodeBlock& jitObject, YarrJITCompileMode = IncludeSubpatterns); - -} } // namespace JSC::Yarr - -#endif - -#endif /* yarr_YarrJIT_h */ diff --git a/js/src/yarr/YarrParser.h b/js/src/yarr/YarrParser.h deleted file mode 100644 index 8ff24b11fd4a..000000000000 --- a/js/src/yarr/YarrParser.h +++ /dev/null @@ -1,849 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_YarrParser_h -#define yarr_YarrParser_h - -#include "yarr/Yarr.h" - -namespace JSC { namespace Yarr { - -enum BuiltInCharacterClassID { - DigitClassID, - SpaceClassID, - WordClassID, - NewlineClassID -}; - -// The Parser class should not be used directly - only via the Yarr::parse() method. -template -class Parser { -private: - template - friend ErrorCode parse(FriendDelegate&, const String& pattern, unsigned backReferenceLimit); - - /* - * CharacterClassParserDelegate: - * - * The class CharacterClassParserDelegate is used in the parsing of character - * classes. This class handles detection of character ranges. This class - * implements enough of the delegate interface such that it can be passed to - * parseEscape() as an EscapeDelegate. This allows parseEscape() to be reused - * to perform the parsing of escape characters in character sets. - */ - class CharacterClassParserDelegate { - public: - CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err) - : m_delegate(delegate) - , m_err(err) - , m_state(Empty) - , m_character(0) - { - } - - /* - * begin(): - * - * Called at beginning of construction. - */ - void begin(bool invert) - { - m_delegate.atomCharacterClassBegin(invert); - } - - /* - * atomPatternCharacter(): - * - * This method is called either from parseCharacterClass() (for an unescaped - * character in a character class), or from parseEscape(). In the former case - * the value true will be passed for the argument 'hyphenIsRange', and in this - * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/ - * is different to /[a\-z]/). - */ - void atomPatternCharacter(UChar ch, bool hyphenIsRange = false) - { - switch (m_state) { - case AfterCharacterClass: - // Following a builtin character class we need look out for a hyphen. - // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/. - // If we see a hyphen following a charater class then unlike usual - // we'll report it to the delegate immediately, and put ourself into - // a poisoned state. Any following calls to add another character or - // character class will result in an error. (A hypen following a - // character-class is itself valid, but only at the end of a regex). - if (hyphenIsRange && ch == '-') { - m_delegate.atomCharacterClassAtom('-'); - m_state = AfterCharacterClassHyphen; - return; - } - // Otherwise just fall through - cached character so treat this as Empty. - - case Empty: - m_character = ch; - m_state = CachedCharacter; - return; - - case CachedCharacter: - if (hyphenIsRange && ch == '-') - m_state = CachedCharacterHyphen; - else { - m_delegate.atomCharacterClassAtom(m_character); - m_character = ch; - } - return; - - case CachedCharacterHyphen: - if (ch < m_character) { - m_err = CharacterClassOutOfOrder; - return; - } - m_delegate.atomCharacterClassRange(m_character, ch); - m_state = Empty; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassAtom(ch); - m_state = Empty; - return; - } - } - - /* - * atomBuiltInCharacterClass(): - * - * Adds a built-in character class, called by parseEscape(). - */ - void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert) - { - switch (m_state) { - case CachedCharacter: - // Flush the currently cached character, then fall through. - m_delegate.atomCharacterClassAtom(m_character); - - case Empty: - case AfterCharacterClass: - m_state = AfterCharacterClass; - m_delegate.atomCharacterClassBuiltIn(classID, invert); - return; - - case CachedCharacterHyphen: - // Error! We have a range that looks like [x-\d]. We require - // the end of the range to be a single character. - m_err = CharacterClassInvalidRange; - return; - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassBuiltIn(classID, invert); - m_state = Empty; - return; - } - } - - /* - * end(): - * - * Called at end of construction. - */ - void end() - { - if (m_state == CachedCharacter) - m_delegate.atomCharacterClassAtom(m_character); - else if (m_state == CachedCharacterHyphen) { - m_delegate.atomCharacterClassAtom(m_character); - m_delegate.atomCharacterClassAtom('-'); - } - m_delegate.atomCharacterClassEnd(); - } - - // parseEscape() should never call these delegate methods when - // invoked with inCharacterClass set. - NO_RETURN_DUE_TO_ASSERT void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); } - NO_RETURN_DUE_TO_ASSERT void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); } - - private: - Delegate& m_delegate; - ErrorCode& m_err; - enum CharacterClassConstructionState { - Empty, - CachedCharacter, - CachedCharacterHyphen, - AfterCharacterClass, - AfterCharacterClassHyphen - } m_state; - UChar m_character; - }; - - Parser(Delegate& delegate, const String& pattern, unsigned backReferenceLimit) - : m_delegate(delegate) - , m_backReferenceLimit(backReferenceLimit) - , m_err(NoError) - , m_data(pattern.chars()) - , m_size(pattern.length()) - , m_index(0) - , m_parenthesesNestingDepth(0) - { - } - - /* - * parseEscape(): - * - * Helper for parseTokens() AND parseCharacterClass(). - * Unlike the other parser methods, this function does not report tokens - * directly to the member delegate (m_delegate), instead tokens are - * emitted to the delegate provided as an argument. In the case of atom - * escapes, parseTokens() will call parseEscape() passing m_delegate as - * an argument, and as such the escape will be reported to the delegate. - * - * However this method may also be used by parseCharacterClass(), in which - * case a CharacterClassParserDelegate will be passed as the delegate that - * tokens should be added to. A boolean flag is also provided to indicate - * whether that an escape in a CharacterClass is being parsed (some parsing - * rules change in this context). - * - * The boolean value returned by this method indicates whether the token - * parsed was an atom (outside of a characted class \b and \B will be - * interpreted as assertions). - */ - template - bool parseEscape(EscapeDelegate& delegate) - { - ASSERT(!m_err); - ASSERT(peek() == '\\'); - consume(); - - if (atEndOfPattern()) { - m_err = EscapeUnterminated; - return false; - } - - switch (peek()) { - // Assertions - case 'b': - consume(); - if (inCharacterClass) - delegate.atomPatternCharacter('\b'); - else { - delegate.assertionWordBoundary(false); - return false; - } - break; - case 'B': - consume(); - if (inCharacterClass) - delegate.atomPatternCharacter('B'); - else { - delegate.assertionWordBoundary(true); - return false; - } - break; - - // CharacterClassEscape - case 'd': - consume(); - delegate.atomBuiltInCharacterClass(DigitClassID, false); - break; - case 's': - consume(); - delegate.atomBuiltInCharacterClass(SpaceClassID, false); - break; - case 'w': - consume(); - delegate.atomBuiltInCharacterClass(WordClassID, false); - break; - case 'D': - consume(); - delegate.atomBuiltInCharacterClass(DigitClassID, true); - break; - case 'S': - consume(); - delegate.atomBuiltInCharacterClass(SpaceClassID, true); - break; - case 'W': - consume(); - delegate.atomBuiltInCharacterClass(WordClassID, true); - break; - - // DecimalEscape - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - // To match Firefox, we parse an invalid backreference in the range [1-7] as an octal escape. - // First, try to parse this as backreference. - if (!inCharacterClass) { - ParseState state = saveState(); - - unsigned backReference; - if (!consumeNumber(backReference)) - break; - if (backReference <= m_backReferenceLimit) { - delegate.atomBackReference(backReference); - break; - } - - restoreState(state); - } - - // Not a backreference, and not octal. - if (peek() >= '8') { - delegate.atomPatternCharacter('\\'); - break; - } - - // Fall-through to handle this as an octal escape. - } - - // Octal escape - case '0': - delegate.atomPatternCharacter(consumeOctal()); - break; - - // ControlEscape - case 'f': - consume(); - delegate.atomPatternCharacter('\f'); - break; - case 'n': - consume(); - delegate.atomPatternCharacter('\n'); - break; - case 'r': - consume(); - delegate.atomPatternCharacter('\r'); - break; - case 't': - consume(); - delegate.atomPatternCharacter('\t'); - break; - case 'v': - consume(); - delegate.atomPatternCharacter('\v'); - break; - - // ControlLetter - case 'c': { - ParseState state = saveState(); - consume(); - if (!atEndOfPattern()) { - int control = consume(); - - // To match Firefox, inside a character class, we also accept numbers and '_' as control characters. - if (inCharacterClass ? WTF::isASCIIAlphanumeric(control) || (control == '_') : WTF::isASCIIAlpha(control)) { - delegate.atomPatternCharacter(control & 0x1f); - break; - } - } - restoreState(state); - delegate.atomPatternCharacter('\\'); - break; - } - - // HexEscape - case 'x': { - consume(); - int x = tryConsumeHex(2); - if (x == -1) - delegate.atomPatternCharacter('x'); - else - delegate.atomPatternCharacter(x); - break; - } - - // UnicodeEscape - case 'u': { - consume(); - int u = tryConsumeHex(4); - if (u == -1) - delegate.atomPatternCharacter('u'); - else - delegate.atomPatternCharacter(u); - break; - } - - // IdentityEscape - default: - delegate.atomPatternCharacter(consume()); - } - - return true; - } - - /* - * parseAtomEscape(), parseCharacterClassEscape(): - * - * These methods alias to parseEscape(). - */ - bool parseAtomEscape() - { - return parseEscape(m_delegate); - } - void parseCharacterClassEscape(CharacterClassParserDelegate& delegate) - { - parseEscape(delegate); - } - - /* - * parseCharacterClass(): - * - * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape) - * to an instance of CharacterClassParserDelegate, to describe the character class to the - * delegate. - */ - void parseCharacterClass() - { - ASSERT(!m_err); - ASSERT(peek() == '['); - consume(); - - CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err); - - characterClassConstructor.begin(tryConsume('^')); - - while (!atEndOfPattern()) { - switch (peek()) { - case ']': - consume(); - characterClassConstructor.end(); - return; - - case '\\': - parseCharacterClassEscape(characterClassConstructor); - break; - - default: - characterClassConstructor.atomPatternCharacter(consume(), true); - } - - if (m_err) - return; - } - - m_err = CharacterClassUnmatched; - } - - /* - * parseParenthesesBegin(): - * - * Helper for parseTokens(); checks for parentheses types other than regular capturing subpatterns. - */ - void parseParenthesesBegin() - { - ASSERT(!m_err); - ASSERT(peek() == '('); - consume(); - - if (tryConsume('?')) { - if (atEndOfPattern()) { - m_err = ParenthesesTypeInvalid; - return; - } - - switch (consume()) { - case ':': - m_delegate.atomParenthesesSubpatternBegin(false); - break; - - case '=': - m_delegate.atomParentheticalAssertionBegin(); - break; - - case '!': - m_delegate.atomParentheticalAssertionBegin(true); - break; - - default: - m_err = ParenthesesTypeInvalid; - } - } else - m_delegate.atomParenthesesSubpatternBegin(); - - ++m_parenthesesNestingDepth; - } - - /* - * parseParenthesesEnd(): - * - * Helper for parseTokens(); checks for parse errors (due to unmatched parentheses). - */ - void parseParenthesesEnd() - { - ASSERT(!m_err); - ASSERT(peek() == ')'); - consume(); - - if (m_parenthesesNestingDepth > 0) - m_delegate.atomParenthesesEnd(); - else - m_err = ParenthesesUnmatched; - - --m_parenthesesNestingDepth; - } - - /* - * parseQuantifier(): - * - * Helper for parseTokens(); checks for parse errors and non-greedy quantifiers. - */ - void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max) - { - ASSERT(!m_err); - ASSERT(min <= max); - - if (min == UINT_MAX) { - m_err = QuantifierTooLarge; - return; - } - - if (lastTokenWasAnAtom) - m_delegate.quantifyAtom(min, max, !tryConsume('?')); - else - m_err = QuantifierWithoutAtom; - } - - /* - * parseTokens(): - * - * This method loops over the input pattern reporting tokens to the delegate. - * The method returns when a parse error is detected, or the end of the pattern - * is reached. One piece of state is tracked around the loop, which is whether - * the last token passed to the delegate was an atom (this is necessary to detect - * a parse error when a quantifier provided without an atom to quantify). - */ - void parseTokens() - { - bool lastTokenWasAnAtom = false; - - while (!atEndOfPattern()) { - switch (peek()) { - case '|': - consume(); - m_delegate.disjunction(); - lastTokenWasAnAtom = false; - break; - - case '(': - parseParenthesesBegin(); - lastTokenWasAnAtom = false; - break; - - case ')': - parseParenthesesEnd(); - lastTokenWasAnAtom = true; - break; - - case '^': - consume(); - m_delegate.assertionBOL(); - lastTokenWasAnAtom = false; - break; - - case '$': - consume(); - m_delegate.assertionEOL(); - lastTokenWasAnAtom = false; - break; - - case '.': - consume(); - m_delegate.atomBuiltInCharacterClass(NewlineClassID, true); - lastTokenWasAnAtom = true; - break; - - case '[': - parseCharacterClass(); - lastTokenWasAnAtom = true; - break; - - case '\\': - lastTokenWasAnAtom = parseAtomEscape(); - break; - - case '*': - consume(); - parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite); - lastTokenWasAnAtom = false; - break; - - case '+': - consume(); - parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite); - lastTokenWasAnAtom = false; - break; - - case '?': - consume(); - parseQuantifier(lastTokenWasAnAtom, 0, 1); - lastTokenWasAnAtom = false; - break; - - case '{': { - ParseState state = saveState(); - - consume(); - if (peekIsDigit()) { - unsigned min; - if (!consumeNumber(min)) - break; - - unsigned max = min; - if (tryConsume(',')) { - if (peekIsDigit()) { - if (!consumeNumber(max)) - break; - } else { - max = quantifyInfinite; - } - } - - if (tryConsume('}')) { - if (min <= max) - parseQuantifier(lastTokenWasAnAtom, min, max); - else - m_err = QuantifierOutOfOrder; - lastTokenWasAnAtom = false; - break; - } - } - - restoreState(state); - } // if we did not find a complete quantifer, fall through to the default case. - - default: - m_delegate.atomPatternCharacter(consume()); - lastTokenWasAnAtom = true; - } - - if (m_err) - return; - } - - if (m_parenthesesNestingDepth > 0) - m_err = MissingParentheses; - } - - /* - * parse(): - * - * This method calls parseTokens() to parse over the input and converts any - * error code to a const char* for a result. - */ - ErrorCode parse() - { - if (m_size > MAX_PATTERN_SIZE) - m_err = PatternTooLarge; - else - parseTokens(); - ASSERT(atEndOfPattern() || m_err); - - return m_err; - } - - // Misc helper functions: - - typedef unsigned ParseState; - - ParseState saveState() - { - return m_index; - } - - void restoreState(ParseState state) - { - m_index = state; - } - - bool atEndOfPattern() - { - ASSERT(m_index <= m_size); - return m_index == m_size; - } - - int peek() - { - ASSERT(m_index < m_size); - return m_data[m_index]; - } - - bool peekIsDigit() - { - return !atEndOfPattern() && WTF::isASCIIDigit(peek()); - } - - unsigned peekDigit() - { - ASSERT(peekIsDigit()); - return peek() - '0'; - } - - int consume() - { - ASSERT(m_index < m_size); - return m_data[m_index++]; - } - - unsigned consumeDigit() - { - ASSERT(peekIsDigit()); - return consume() - '0'; - } - - bool consumeNumber(unsigned &accum) - { - accum = consumeDigit(); - while (peekIsDigit()) { - unsigned newValue = accum * 10 + peekDigit(); - if (newValue < accum) { /* Overflow check. */ - m_err = QuantifierTooLarge; - return false; - } - accum = newValue; - consume(); - } - return true; - } - - unsigned consumeOctal() - { - ASSERT(WTF::isASCIIOctalDigit(peek())); - - unsigned n = consumeDigit(); - while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek())) - n = n * 8 + consumeDigit(); - return n; - } - - bool tryConsume(UChar ch) - { - if (atEndOfPattern() || (m_data[m_index] != ch)) - return false; - ++m_index; - return true; - } - - int tryConsumeHex(int count) - { - ParseState state = saveState(); - - int n = 0; - while (count--) { - if (atEndOfPattern() || !WTF::isASCIIHexDigit(peek())) { - restoreState(state); - return -1; - } - n = (n << 4) | WTF::toASCIIHexValue(consume()); - } - return n; - } - - Delegate& m_delegate; - unsigned m_backReferenceLimit; - ErrorCode m_err; - const CharType* m_data; - unsigned m_size; - unsigned m_index; - unsigned m_parenthesesNestingDepth; - - // Derived by empirical testing of compile time in PCRE and WREC. - static const unsigned MAX_PATTERN_SIZE = 1024 * 1024; -}; - -/* - * Yarr::parse(): - * - * The parse method is passed a pattern to be parsed and a delegate upon which - * callbacks will be made to record the parsed tokens forming the regex. - * Yarr::parse() returns null on success, or a const C string providing an error - * message where a parse error occurs. - * - * The Delegate must implement the following interface: - * - * void assertionBOL(); - * void assertionEOL(); - * void assertionWordBoundary(bool invert); - * - * void atomPatternCharacter(UChar ch); - * void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert); - * void atomCharacterClassBegin(bool invert) - * void atomCharacterClassAtom(UChar ch) - * void atomCharacterClassRange(UChar begin, UChar end) - * void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert) - * void atomCharacterClassEnd() - * void atomParenthesesSubpatternBegin(bool capture = true); - * void atomParentheticalAssertionBegin(bool invert = false); - * void atomParenthesesEnd(); - * void atomBackReference(unsigned subpatternId); - * - * void quantifyAtom(unsigned min, unsigned max, bool greedy); - * - * void disjunction(); - * - * The regular expression is described by a sequence of assertion*() and atom*() - * callbacks to the delegate, describing the terms in the regular expression. - * Following an atom a quantifyAtom() call may occur to indicate that the previous - * atom should be quantified. In the case of atoms described across multiple - * calls (parentheses and character classes) the call to quantifyAtom() will come - * after the call to the atom*End() method, never after atom*Begin(). - * - * Character classes may either be described by a single call to - * atomBuiltInCharacterClass(), or by a sequence of atomCharacterClass*() calls. - * In the latter case, ...Begin() will be called, followed by a sequence of - * calls to ...Atom(), ...Range(), and ...BuiltIn(), followed by a call to ...End(). - * - * Sequences of atoms and assertions are broken into alternatives via calls to - * disjunction(). Assertions, atoms, and disjunctions emitted between calls to - * atomParenthesesBegin() and atomParenthesesEnd() form the body of a subpattern. - * atomParenthesesBegin() is passed a subpatternId. In the case of a regular - * capturing subpattern, this will be the subpatternId associated with these - * parentheses, and will also by definition be the lowest subpatternId of these - * parentheses and of any nested paretheses. The atomParenthesesEnd() method - * is passed the subpatternId of the last capturing subexpression nested within - * these paretheses. In the case of a capturing subpattern with no nested - * capturing subpatterns, the same subpatternId will be passed to the begin and - * end functions. In the case of non-capturing subpatterns the subpatternId - * passed to the begin method is also the first possible subpatternId that might - * be nested within these paretheses. If a set of non-capturing parentheses does - * not contain any capturing subpatterns, then the subpatternId passed to begin - * will be greater than the subpatternId passed to end. - */ - -template -ErrorCode parse(Delegate& delegate, const String& pattern, unsigned backReferenceLimit = quantifyInfinite) -{ -#ifdef YARR_8BIT_CHAR_SUPPORT - if (pattern.is8Bit()) - return Parser(delegate, pattern, backReferenceLimit).parse(); -#endif - return Parser(delegate, pattern, backReferenceLimit).parse(); -} - -} } // namespace JSC::Yarr - -#endif /* yarr_YarrParser_h */ diff --git a/js/src/yarr/YarrPattern.cpp b/js/src/yarr/YarrPattern.cpp deleted file mode 100644 index 380127d137e9..000000000000 --- a/js/src/yarr/YarrPattern.cpp +++ /dev/null @@ -1,933 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yarr/YarrPattern.h" - -#include "yarr/Yarr.h" -#include "yarr/YarrCanonicalizeUCS2.h" -#include "yarr/YarrParser.h" - -using namespace WTF; - -namespace JSC { namespace Yarr { - -#include "yarr/RegExpJitTables.h" - -#if WTF_CPU_SPARC -# define BASE_FRAME_SIZE 24 -#else -# define BASE_FRAME_SIZE 0 -#endif - -// Thanks, windows.h! -#undef min -#undef max - -class CharacterClassConstructor { -public: - CharacterClassConstructor(bool isCaseInsensitive = false) - : m_isCaseInsensitive(isCaseInsensitive) - { - } - - void reset() - { - m_matches.clear(); - m_ranges.clear(); - m_matchesUnicode.clear(); - m_rangesUnicode.clear(); - } - - void append(const CharacterClass* other) - { - for (size_t i = 0; i < other->m_matches.size(); ++i) - addSorted(m_matches, other->m_matches[i]); - for (size_t i = 0; i < other->m_ranges.size(); ++i) - addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end); - for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i) - addSorted(m_matchesUnicode, other->m_matchesUnicode[i]); - for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i) - addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end); - } - - void putChar(UChar ch) - { - // Handle ascii cases. - if (ch <= 0x7f) { - if (m_isCaseInsensitive && isASCIIAlpha(ch)) { - addSorted(m_matches, toASCIIUpper(ch)); - addSorted(m_matches, toASCIILower(ch)); - } else - addSorted(m_matches, ch); - return; - } - - // Simple case, not a case-insensitive match. - if (!m_isCaseInsensitive) { - addSorted(m_matchesUnicode, ch); - return; - } - - // Add multiple matches, if necessary. - const UCS2CanonicalizationRange* info = rangeInfoFor(ch); - if (info->type == CanonicalizeUnique) - addSorted(m_matchesUnicode, ch); - else - putUnicodeIgnoreCase(ch, info); - } - - void putUnicodeIgnoreCase(UChar ch, const UCS2CanonicalizationRange* info) - { - ASSERT(m_isCaseInsensitive); - ASSERT(ch > 0x7f); - ASSERT(ch >= info->begin && ch <= info->end); - ASSERT(info->type != CanonicalizeUnique); - if (info->type == CanonicalizeSet) { - for (const uint16_t* set = characterSetInfo[info->value]; (ch = *set); ++set) - addSorted(m_matchesUnicode, ch); - } else { - addSorted(m_matchesUnicode, ch); - addSorted(m_matchesUnicode, getCanonicalPair(info, ch)); - } - } - - void putRange(UChar lo, UChar hi) - { - if (lo <= 0x7f) { - char asciiLo = lo; - char asciiHi = std::min(hi, (UChar)0x7f); - addSortedRange(m_ranges, lo, asciiHi); - - if (m_isCaseInsensitive) { - if ((asciiLo <= 'Z') && (asciiHi >= 'A')) - addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A')); - if ((asciiLo <= 'z') && (asciiHi >= 'a')) - addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a')); - } - } - if (hi <= 0x7f) - return; - - lo = std::max(lo, (UChar)0x80); - addSortedRange(m_rangesUnicode, lo, hi); - - if (!m_isCaseInsensitive) - return; - - const UCS2CanonicalizationRange* info = rangeInfoFor(lo); - while (true) { - // Handle the range [lo .. end] - UChar end = std::min(info->end, hi); - - switch (info->type) { - case CanonicalizeUnique: - // Nothing to do - no canonical equivalents. - break; - case CanonicalizeSet: { - UChar ch; - for (const uint16_t* set = characterSetInfo[info->value]; (ch = *set); ++set) - addSorted(m_matchesUnicode, ch); - break; - } - case CanonicalizeRangeLo: - addSortedRange(m_rangesUnicode, lo + info->value, end + info->value); - break; - case CanonicalizeRangeHi: - addSortedRange(m_rangesUnicode, lo - info->value, end - info->value); - break; - case CanonicalizeAlternatingAligned: - // Use addSortedRange since there is likely an abutting range to combine with. - if (lo & 1) - addSortedRange(m_rangesUnicode, lo - 1, lo - 1); - if (!(end & 1)) - addSortedRange(m_rangesUnicode, end + 1, end + 1); - break; - case CanonicalizeAlternatingUnaligned: - // Use addSortedRange since there is likely an abutting range to combine with. - if (!(lo & 1)) - addSortedRange(m_rangesUnicode, lo - 1, lo - 1); - if (end & 1) - addSortedRange(m_rangesUnicode, end + 1, end + 1); - break; - } - - if (hi == end) - return; - - ++info; - lo = info->begin; - }; - - } - - CharacterClass* charClass() - { - CharacterClass* characterClass = newOrCrash(); - - characterClass->m_matches.swap(m_matches); - characterClass->m_ranges.swap(m_ranges); - characterClass->m_matchesUnicode.swap(m_matchesUnicode); - characterClass->m_rangesUnicode.swap(m_rangesUnicode); - - return characterClass; - } - -private: - void addSorted(Vector& matches, UChar ch) - { - unsigned pos = 0; - unsigned range = matches.size(); - - // binary chop, find position to insert char. - while (range) { - unsigned index = range >> 1; - - int val = matches[pos+index] - ch; - if (!val) - return; - else if (val > 0) - range = index; - else { - pos += (index+1); - range -= (index+1); - } - } - - if (pos == matches.size()) - matches.append(ch); - else - matches.insert(pos, ch); - } - - void addSortedRange(Vector& ranges, UChar lo, UChar hi) - { - unsigned end = ranges.size(); - - // Simple linear scan - I doubt there are that many ranges anyway... - // feel free to fix this with something faster (eg binary chop). - for (unsigned i = 0; i < end; ++i) { - // does the new range fall before the current position in the array - if (hi < ranges[i].begin) { - // optional optimization: concatenate appending ranges? - may not be worthwhile. - if (hi == (ranges[i].begin - 1)) { - ranges[i].begin = lo; - return; - } - ranges.insert(i, CharacterRange(lo, hi)); - return; - } - // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining - // If the new range start at or before the end of the last range, then the overlap (if it starts one after the - // end of the last range they concatenate, which is just as good. - if (lo <= (ranges[i].end + 1)) { - // found an intersect! we'll replace this entry in the array. - ranges[i].begin = std::min(ranges[i].begin, lo); - ranges[i].end = std::max(ranges[i].end, hi); - - // now check if the new range can subsume any subsequent ranges. - unsigned next = i+1; - // each iteration of the loop we will either remove something from the list, or break the loop. - while (next < ranges.size()) { - if (ranges[next].begin <= (ranges[i].end + 1)) { - // the next entry now overlaps / concatenates this one. - ranges[i].end = std::max(ranges[i].end, ranges[next].end); - ranges.remove(next); - } else - break; - } - - return; - } - } - - // CharacterRange comes after all existing ranges. - ranges.append(CharacterRange(lo, hi)); - } - - bool m_isCaseInsensitive; - - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; -}; - -class YarrPatternConstructor { -public: - YarrPatternConstructor(YarrPattern& pattern) - : m_pattern(pattern) - , m_stackBase(nullptr) - , m_characterClassConstructor(pattern.m_ignoreCase) - , m_invertParentheticalAssertion(false) - { - m_pattern.m_body = newOrCrash(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); - } - - ~YarrPatternConstructor() - { - } - - void reset() - { - m_pattern.reset(); - m_characterClassConstructor.reset(); - - m_pattern.m_body = newOrCrash(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); - } - - void assertionBOL() - { - if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) { - m_alternative->m_startsWithBOL = true; - m_alternative->m_containsBOL = true; - m_pattern.m_containsBOL = true; - } - m_alternative->m_terms.append(PatternTerm::BOL()); - } - void assertionEOL() - { - m_alternative->m_terms.append(PatternTerm::EOL()); - } - void assertionWordBoundary(bool invert) - { - m_alternative->m_terms.append(PatternTerm::WordBoundary(invert)); - } - - void atomPatternCharacter(UChar ch) - { - // We handle case-insensitive checking of unicode characters which do have both - // cases by handling them as if they were defined using a CharacterClass. - if (!m_pattern.m_ignoreCase || isASCII(ch)) { - m_alternative->m_terms.append(PatternTerm(ch)); - return; - } - - const UCS2CanonicalizationRange* info = rangeInfoFor(ch); - if (info->type == CanonicalizeUnique) { - m_alternative->m_terms.append(PatternTerm(ch)); - return; - } - - m_characterClassConstructor.putUnicodeIgnoreCase(ch, info); - CharacterClass* newCharacterClass = m_characterClassConstructor.charClass(); - m_pattern.m_userCharacterClasses.append(newCharacterClass); - m_alternative->m_terms.append(PatternTerm(newCharacterClass, false)); - } - - void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert) - { - switch (classID) { - case DigitClassID: - m_alternative->m_terms.append(PatternTerm(m_pattern.digitsCharacterClass(), invert)); - break; - case SpaceClassID: - m_alternative->m_terms.append(PatternTerm(m_pattern.spacesCharacterClass(), invert)); - break; - case WordClassID: - m_alternative->m_terms.append(PatternTerm(m_pattern.wordcharCharacterClass(), invert)); - break; - case NewlineClassID: - m_alternative->m_terms.append(PatternTerm(m_pattern.newlineCharacterClass(), invert)); - break; - } - } - - void atomCharacterClassBegin(bool invert = false) - { - m_invertCharacterClass = invert; - } - - void atomCharacterClassAtom(UChar ch) - { - m_characterClassConstructor.putChar(ch); - } - - void atomCharacterClassRange(UChar begin, UChar end) - { - m_characterClassConstructor.putRange(begin, end); - } - - void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert) - { - ASSERT(classID != NewlineClassID); - - switch (classID) { - case DigitClassID: - m_characterClassConstructor.append(invert ? m_pattern.nondigitsCharacterClass() : m_pattern.digitsCharacterClass()); - break; - - case SpaceClassID: - m_characterClassConstructor.append(invert ? m_pattern.nonspacesCharacterClass() : m_pattern.spacesCharacterClass()); - break; - - case WordClassID: - m_characterClassConstructor.append(invert ? m_pattern.nonwordcharCharacterClass() : m_pattern.wordcharCharacterClass()); - break; - - default: - ASSERT_NOT_REACHED(); - } - } - - void atomCharacterClassEnd() - { - CharacterClass* newCharacterClass = m_characterClassConstructor.charClass(); - m_pattern.m_userCharacterClasses.append(newCharacterClass); - m_alternative->m_terms.append(PatternTerm(newCharacterClass, m_invertCharacterClass)); - } - - void atomParenthesesSubpatternBegin(bool capture = true) - { - unsigned subpatternId = m_pattern.m_numSubpatterns + 1; - if (capture) - m_pattern.m_numSubpatterns++; - - PatternDisjunction* parenthesesDisjunction = newOrCrash(m_alternative); - m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false)); - m_alternative = parenthesesDisjunction->addNewAlternative(); - } - - void atomParentheticalAssertionBegin(bool invert = false) - { - PatternDisjunction* parenthesesDisjunction = newOrCrash(m_alternative); - m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert)); - m_alternative = parenthesesDisjunction->addNewAlternative(); - m_invertParentheticalAssertion = invert; - } - - void atomParenthesesEnd() - { - ASSERT(m_alternative->m_parent); - ASSERT(m_alternative->m_parent->m_parent); - - PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent; - m_alternative = m_alternative->m_parent->m_parent; - - PatternTerm& lastTerm = m_alternative->lastTerm(); - - unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size(); - unsigned numBOLAnchoredAlts = 0; - - for (unsigned i = 0; i < numParenAlternatives; i++) { - // Bubble up BOL flags - if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL) - numBOLAnchoredAlts++; - } - - if (numBOLAnchoredAlts) { - m_alternative->m_containsBOL = true; - // If all the alternatives in parens start with BOL, then so does this one - if (numBOLAnchoredAlts == numParenAlternatives) - m_alternative->m_startsWithBOL = true; - } - - lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; - m_invertParentheticalAssertion = false; - } - - void atomBackReference(unsigned subpatternId) - { - ASSERT(subpatternId); - m_pattern.m_containsBackreferences = true; - m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId); - - if (subpatternId > m_pattern.m_numSubpatterns) { - m_alternative->m_terms.append(PatternTerm::ForwardReference()); - return; - } - - PatternAlternative* currentAlternative = m_alternative; - ASSERT(currentAlternative); - - // Note to self: if we waited until the AST was baked, we could also remove forwards refs - while ((currentAlternative = currentAlternative->m_parent->m_parent)) { - PatternTerm& term = currentAlternative->lastTerm(); - ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); - - if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) { - m_alternative->m_terms.append(PatternTerm::ForwardReference()); - return; - } - } - - m_alternative->m_terms.append(PatternTerm(subpatternId)); - } - - // deep copy the argument disjunction. If filterStartsWithBOL is true, - // skip alternatives with m_startsWithBOL set true. - PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false) - { - PatternDisjunction* newDisjunction = 0; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { - PatternAlternative* alternative = disjunction->m_alternatives[alt]; - if (!filterStartsWithBOL || !alternative->m_startsWithBOL) { - if (!newDisjunction) { - newDisjunction = newOrCrash(); - newDisjunction->m_parent = disjunction->m_parent; - } - PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); - newAlternative->m_terms.reserve(alternative->m_terms.size()); - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) - newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL)); - } - } - - if (newDisjunction) - m_pattern.m_disjunctions.append(newDisjunction); - return newDisjunction; - } - - PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false) - { - if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion)) - return PatternTerm(term); - - PatternTerm termCopy = term; - termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL); - return termCopy; - } - - void quantifyAtom(unsigned min, unsigned max, bool greedy) - { - ASSERT(min <= max); - ASSERT(m_alternative->m_terms.size()); - - if (!max) { - m_alternative->removeLastTerm(); - return; - } - - PatternTerm& term = m_alternative->lastTerm(); - ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); - ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); - - if (term.type == PatternTerm::TypeParentheticalAssertion) { - // If an assertion is quantified with a minimum count of zero, it can simply be removed. - // This arises from the RepeatMatcher behaviour in the spec. Matching an assertion never - // results in any input being consumed, however the continuation passed to the assertion - // (called in steps, 8c and 9 of the RepeatMatcher definition, ES5.1 15.10.2.5) will - // reject all zero length matches (see step 2.1). A match from the continuation of the - // expression will still be accepted regardless (via steps 8a and 11) - the upshot of all - // this is that matches from the assertion are not required, and won't be accepted anyway, - // so no need to ever run it. - if (!min) - m_alternative->removeLastTerm(); - // We never need to run an assertion more than once. Subsequent interations will be run - // with the same start index (since assertions are non-capturing) and the same captures - // (per step 4 of RepeatMatcher in ES5.1 15.10.2.5), and as such will always produce the - // same result and captures. If the first match succeeds then the subsequent (min - 1) - // matches will too. Any additional optional matches will fail (on the same basis as the - // minimum zero quantified assertions, above), but this will still result in a match. - return; - } - - if (min == 0) - term.quantify(max, greedy ? QuantifierGreedy : QuantifierNonGreedy); - else if (min == max) - term.quantify(min, QuantifierFixedCount); - else { - term.quantify(min, QuantifierFixedCount); - m_alternative->m_terms.append(copyTerm(term)); - // NOTE: this term is interesting from an analysis perspective, in that it can be ignored..... - m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); - if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern) - m_alternative->lastTerm().parentheses.isCopy = true; - } - } - - void disjunction() - { - m_alternative = m_alternative->m_parent->addNewAlternative(); - } - - ErrorCode setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition, - unsigned *callFrameSizeOut) - { - /* - * Attempt detection of over-recursion: - * "1MB should be enough stack for anyone." - */ - uint8_t stackDummy_; - if (m_stackBase - &stackDummy_ > 1024*1024) - return PatternTooLarge; - - alternative->m_hasFixedSize = true; - Checked currentInputPosition = initialInputPosition; - - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { - PatternTerm& term = alternative->m_terms[i]; - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - case PatternTerm::TypeAssertionEOL: - case PatternTerm::TypeAssertionWordBoundary: - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - break; - - case PatternTerm::TypeBackReference: - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference; - alternative->m_hasFixedSize = false; - break; - - case PatternTerm::TypeForwardReference: - break; - - case PatternTerm::TypePatternCharacter: - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - if (term.quantityType != QuantifierFixedCount) { - term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter; - alternative->m_hasFixedSize = false; - } else - currentInputPosition += term.quantityCount; - break; - - case PatternTerm::TypeCharacterClass: - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - if (term.quantityType != QuantifierFixedCount) { - term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass; - alternative->m_hasFixedSize = false; - } else - currentInputPosition += term.quantityCount; - break; - - case PatternTerm::TypeParenthesesSubpattern: - // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own. - term.frameLocation = currentCallFrameSize; - unsigned position; - if (currentInputPosition.safeGet(position)) - return RuntimeError; - if (term.quantityCount == 1 && !term.parentheses.isCopy) { - if (term.quantityType != QuantifierFixedCount) - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, position, ¤tCallFrameSize)) - return error; - // If quantity is fixed, then pre-check its minimum size. - if (term.quantityType == QuantifierFixedCount) - currentInputPosition += term.parentheses.disjunction->m_minimumSize; - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - } else if (term.parentheses.isTerminal) { - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, position, ¤tCallFrameSize)) - return error; - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - } else { - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - unsigned dummy; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, BASE_FRAME_SIZE, position, &dummy)) - return error; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; - } - // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length. - alternative->m_hasFixedSize = false; - break; - - case PatternTerm::TypeParentheticalAssertion: - if (Checked(currentInputPosition).safeGet(term.inputPosition)) - return RuntimeError; - term.frameLocation = currentCallFrameSize; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, term.inputPosition, ¤tCallFrameSize)) - return error; - break; - - case PatternTerm::TypeDotStarEnclosure: - alternative->m_hasFixedSize = false; - term.inputPosition = initialInputPosition; - break; - } - } - - if ((currentInputPosition - initialInputPosition).safeGet(alternative->m_minimumSize)) - return RuntimeError; - *callFrameSizeOut = currentCallFrameSize; - return NoError; - } - - ErrorCode setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition, unsigned *maximumCallFrameSizeOut) - { - if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1)) - initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative; - - unsigned minimumInputSize = UINT_MAX; - unsigned maximumCallFrameSize = 0; - bool hasFixedSize = true; - - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { - PatternAlternative* alternative = disjunction->m_alternatives[alt]; - unsigned currentAlternativeCallFrameSize; - if (ErrorCode error = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition, ¤tAlternativeCallFrameSize)) - return error; - minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize); - maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize); - hasFixedSize &= alternative->m_hasFixedSize; - } - - ASSERT(minimumInputSize != UINT_MAX); - if (minimumInputSize == UINT_MAX) - return PatternTooLarge; - - ASSERT(minimumInputSize != UINT_MAX); - ASSERT(maximumCallFrameSize >= initialCallFrameSize); - - disjunction->m_hasFixedSize = hasFixedSize; - disjunction->m_minimumSize = minimumInputSize; - disjunction->m_callFrameSize = maximumCallFrameSize; - *maximumCallFrameSizeOut = maximumCallFrameSize; - return NoError; - } - - ErrorCode setupOffsets() - { - unsigned dummy; - return setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0, &dummy); - } - - // This optimization identifies sets of parentheses that we will never need to backtrack. - // In these cases we do not need to store state from prior iterations. - // We can presently avoid backtracking for: - // * where the parens are at the end of the regular expression (last term in any of the - // alternatives of the main body disjunction). - // * where the parens are non-capturing, and quantified unbounded greedy (*). - // * where the parens do not contain any capturing subpatterns. - void checkForTerminalParentheses() - { - // This check is much too crude; should be just checking whether the candidate - // node contains nested capturing subpatterns, not the whole expression! - if (m_pattern.m_numSubpatterns) - return; - - Vector& alternatives = m_pattern.m_body->m_alternatives; - for (size_t i = 0; i < alternatives.size(); ++i) { - Vector& terms = alternatives[i]->m_terms; - if (terms.size()) { - PatternTerm& term = terms.last(); - if (term.type == PatternTerm::TypeParenthesesSubpattern - && term.quantityType == QuantifierGreedy - && term.quantityCount == quantifyInfinite - && !term.capture()) - term.parentheses.isTerminal = true; - } - } - } - - void optimizeBOL() - { - // Look for expressions containing beginning of line (^) anchoring and unroll them. - // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops - // This code relies on the parsing code tagging alternatives with m_containsBOL and - // m_startsWithBOL and rolling those up to containing alternatives. - // At this point, this is only valid for non-multiline expressions. - PatternDisjunction* disjunction = m_pattern.m_body; - - if (!m_pattern.m_containsBOL || m_pattern.m_multiline) - return; - - PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true); - - // Set alternatives in disjunction to "onceThrough" - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives[alt]->setOnceThrough(); - - if (loopDisjunction) { - // Move alternatives from loopDisjunction to disjunction - for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]); - - loopDisjunction->m_alternatives.clear(); - } - } - - bool containsCapturingTerms(PatternAlternative* alternative, size_t firstTermIndex, size_t lastTermIndex) - { - Vector& terms = alternative->m_terms; - - for (size_t termIndex = firstTermIndex; termIndex <= lastTermIndex; ++termIndex) { - PatternTerm& term = terms[termIndex]; - - if (term.m_capture) - return true; - - if (term.type == PatternTerm::TypeParenthesesSubpattern) { - PatternDisjunction* nestedDisjunction = term.parentheses.disjunction; - for (unsigned alt = 0; alt < nestedDisjunction->m_alternatives.size(); ++alt) { - PatternAlternative *pattern = nestedDisjunction->m_alternatives[alt]; - if (pattern->m_terms.size() == 0) - continue; - if (containsCapturingTerms(pattern, 0, pattern->m_terms.size() - 1)) - return true; - } - } - } - - return false; - } - - // This optimization identifies alternatives in the form of - // [^].*[?].*[$] for expressions that don't have any - // capturing terms. The alternative is changed to - // followed by processing of the dot stars to find and adjust the - // beginning and the end of the match. - void optimizeDotStarWrappedExpressions() - { - Vector& alternatives = m_pattern.m_body->m_alternatives; - if (alternatives.size() != 1) - return; - - PatternAlternative* alternative = alternatives[0]; - Vector& terms = alternative->m_terms; - if (terms.size() >= 3) { - bool startsWithBOL = false; - bool endsWithEOL = false; - size_t termIndex, firstExpressionTerm, lastExpressionTerm; - - termIndex = 0; - if (terms[termIndex].type == PatternTerm::TypeAssertionBOL) { - startsWithBOL = true; - ++termIndex; - } - - PatternTerm& firstNonAnchorTerm = terms[termIndex]; - if ((firstNonAnchorTerm.type != PatternTerm::TypeCharacterClass) || (firstNonAnchorTerm.characterClass != m_pattern.newlineCharacterClass()) || !((firstNonAnchorTerm.quantityType == QuantifierGreedy) || (firstNonAnchorTerm.quantityType == QuantifierNonGreedy))) - return; - - firstExpressionTerm = termIndex + 1; - - termIndex = terms.size() - 1; - if (terms[termIndex].type == PatternTerm::TypeAssertionEOL) { - endsWithEOL = true; - --termIndex; - } - - PatternTerm& lastNonAnchorTerm = terms[termIndex]; - if ((lastNonAnchorTerm.type != PatternTerm::TypeCharacterClass) || (lastNonAnchorTerm.characterClass != m_pattern.newlineCharacterClass()) || (lastNonAnchorTerm.quantityType != QuantifierGreedy)) - return; - - lastExpressionTerm = termIndex - 1; - - if (firstExpressionTerm > lastExpressionTerm) - return; - - if (!containsCapturingTerms(alternative, firstExpressionTerm, lastExpressionTerm)) { - for (termIndex = terms.size() - 1; termIndex > lastExpressionTerm; --termIndex) - terms.remove(termIndex); - - for (termIndex = firstExpressionTerm; termIndex > 0; --termIndex) - terms.remove(termIndex - 1); - - terms.append(PatternTerm(startsWithBOL, endsWithEOL)); - - m_pattern.m_containsBOL = false; - } - } - } - - void setStackBase(uint8_t *stackBase) { - m_stackBase = stackBase; - } - -private: - YarrPattern& m_pattern; - uint8_t * m_stackBase; - PatternAlternative* m_alternative; - CharacterClassConstructor m_characterClassConstructor; - bool m_invertCharacterClass; - bool m_invertParentheticalAssertion; -}; - -ErrorCode YarrPattern::compile(const String& patternString) -{ - YarrPatternConstructor constructor(*this); - - if (ErrorCode error = parse(constructor, patternString)) - return error; - - // If the pattern contains illegal backreferences reset & reparse. - // Quoting Netscape's "What's new in JavaScript 1.2", - // "Note: if the number of left parentheses is less than the number specified - // in \#, the \# is taken as an octal escape as described in the next row." - if (containsIllegalBackReference()) { - unsigned numSubpatterns = m_numSubpatterns; - - constructor.reset(); -#if !ASSERT_DISABLED - ErrorCode error = -#endif - parse(constructor, patternString, numSubpatterns); - - ASSERT(!error); - ASSERT(numSubpatterns == m_numSubpatterns); - } - - uint8_t stackDummy_; - constructor.setStackBase(&stackDummy_); - - constructor.checkForTerminalParentheses(); - constructor.optimizeDotStarWrappedExpressions(); - constructor.optimizeBOL(); - - if (ErrorCode error = constructor.setupOffsets()) - return error; - - return NoError; -} - -YarrPattern::YarrPattern(const String& pattern, bool ignoreCase, bool multiline, ErrorCode* error) - : m_ignoreCase(ignoreCase) - , m_multiline(multiline) - , m_containsBackreferences(false) - , m_containsBOL(false) - , m_numSubpatterns(0) - , m_maxBackReference(0) - , newlineCached(0) - , digitsCached(0) - , spacesCached(0) - , wordcharCached(0) - , nondigitsCached(0) - , nonspacesCached(0) - , nonwordcharCached(0) -{ - *error = compile(pattern); -} - -} } diff --git a/js/src/yarr/YarrPattern.h b/js/src/yarr/YarrPattern.h deleted file mode 100644 index 599b2cb9c4c6..000000000000 --- a/js/src/yarr/YarrPattern.h +++ /dev/null @@ -1,463 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2009, 2013 Apple Inc. All rights reserved. - * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_YarrPattern_h -#define yarr_YarrPattern_h - -#include "yarr/wtfbridge.h" -#include "yarr/ASCIICType.h" - -namespace JSC { namespace Yarr { - -struct PatternDisjunction; - -enum ErrorCode { - NoError, - PatternTooLarge, - QuantifierOutOfOrder, - QuantifierWithoutAtom, - QuantifierTooLarge, - MissingParentheses, - ParenthesesUnmatched, - ParenthesesTypeInvalid, - CharacterClassUnmatched, - CharacterClassOutOfOrder, - CharacterClassInvalidRange, - EscapeUnterminated, - RuntimeError, - NumberOfErrorCodes -}; - -static inline const char* errorMessage(ErrorCode code) -{ - -#define REGEXP_ERROR_PREFIX "Invalid regular expression: " - // The order of this array must match the ErrorCode enum. - static const char* errorMessages[NumberOfErrorCodes] = { - 0, // NoError - REGEXP_ERROR_PREFIX "regular expression too large", - REGEXP_ERROR_PREFIX "numbers out of order in {} quantifier", - REGEXP_ERROR_PREFIX "nothing to repeat", - REGEXP_ERROR_PREFIX "number too large in {} quantifier", - REGEXP_ERROR_PREFIX "missing )", - REGEXP_ERROR_PREFIX "unmatched parentheses", - REGEXP_ERROR_PREFIX "unrecognized character after (?", - REGEXP_ERROR_PREFIX "missing terminating ] for character class", - REGEXP_ERROR_PREFIX "character class out of order" - REGEXP_ERROR_PREFIX "range out of order in character class", - REGEXP_ERROR_PREFIX "\\ at end of pattern" - }; -#undef REGEXP_ERROR_PREFIX - - return errorMessages[code]; -} - -struct CharacterRange { - UChar begin; - UChar end; - - CharacterRange(UChar begin, UChar end) - : begin(begin) - , end(end) - { - } -}; - -struct CharacterClass { - WTF_MAKE_FAST_ALLOCATED; -public: - // All CharacterClass instances have to have the full set of matches and ranges, - // they may have an optional m_table for faster lookups (which must match the - // specified matches and ranges) - CharacterClass() - : m_table(0) - { - } - CharacterClass(const char* table, bool inverted) - : m_table(table) - , m_tableInverted(inverted) - { - } - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; - - const char* m_table; - bool m_tableInverted; -}; - -enum QuantifierType { - QuantifierFixedCount, - QuantifierGreedy, - QuantifierNonGreedy -}; - -struct PatternTerm { - enum Type { - TypeAssertionBOL, - TypeAssertionEOL, - TypeAssertionWordBoundary, - TypePatternCharacter, - TypeCharacterClass, - TypeBackReference, - TypeForwardReference, - TypeParenthesesSubpattern, - TypeParentheticalAssertion, - TypeDotStarEnclosure - } type; - bool m_capture :1; - bool m_invert :1; - union { - UChar patternCharacter; - CharacterClass* characterClass; - unsigned backReferenceSubpatternId; - struct { - PatternDisjunction* disjunction; - unsigned subpatternId; - unsigned lastSubpatternId; - bool isCopy; - bool isTerminal; - } parentheses; - struct { - bool bolAnchor : 1; - bool eolAnchor : 1; - } anchors; - }; - QuantifierType quantityType; - Checked quantityCount; - int inputPosition; - unsigned frameLocation; - - PatternTerm(UChar ch) - : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) - { - patternCharacter = ch; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - PatternTerm(CharacterClass* charClass, bool invert) - : type(PatternTerm::TypeCharacterClass) - , m_capture(false) - , m_invert(invert) - { - characterClass = charClass; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false) - : type(type) - , m_capture(capture) - , m_invert(invert) - { - parentheses.disjunction = disjunction; - parentheses.subpatternId = subpatternId; - parentheses.isCopy = false; - parentheses.isTerminal = false; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - PatternTerm(Type type, bool invert = false) - : type(type) - , m_capture(false) - , m_invert(invert) - { - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - PatternTerm(unsigned spatternId) - : type(TypeBackReference) - , m_capture(false) - , m_invert(false) - { - backReferenceSubpatternId = spatternId; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - PatternTerm(bool bolAnchor, bool eolAnchor) - : type(TypeDotStarEnclosure) - , m_capture(false) - , m_invert(false) - { - anchors.bolAnchor = bolAnchor; - anchors.eolAnchor = eolAnchor; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - // No-argument constructor for js::Vector. - PatternTerm() - : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) - { - patternCharacter = 0; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - - static PatternTerm ForwardReference() - { - return PatternTerm(TypeForwardReference); - } - - static PatternTerm BOL() - { - return PatternTerm(TypeAssertionBOL); - } - - static PatternTerm EOL() - { - return PatternTerm(TypeAssertionEOL); - } - - static PatternTerm WordBoundary(bool invert) - { - return PatternTerm(TypeAssertionWordBoundary, invert); - } - - bool invert() - { - return m_invert; - } - - bool capture() - { - return m_capture; - } - - void quantify(unsigned count, QuantifierType type) - { - quantityCount = count; - quantityType = type; - } -}; - -struct PatternAlternative { - WTF_MAKE_FAST_ALLOCATED; -public: - PatternAlternative(PatternDisjunction* disjunction) - : m_parent(disjunction) - , m_onceThrough(false) - , m_hasFixedSize(false) - , m_startsWithBOL(false) - , m_containsBOL(false) - { - } - - PatternTerm& lastTerm() - { - ASSERT(m_terms.size()); - return m_terms[m_terms.size() - 1]; - } - - void removeLastTerm() - { - ASSERT(m_terms.size()); - m_terms.shrink(m_terms.size() - 1); - } - - void setOnceThrough() - { - m_onceThrough = true; - } - - bool onceThrough() - { - return m_onceThrough; - } - - Vector m_terms; - PatternDisjunction* m_parent; - unsigned m_minimumSize; - bool m_onceThrough : 1; - bool m_hasFixedSize : 1; - bool m_startsWithBOL : 1; - bool m_containsBOL : 1; -}; - -struct PatternDisjunction { - WTF_MAKE_FAST_ALLOCATED; -public: - PatternDisjunction(PatternAlternative* parent = 0) - : m_parent(parent) - , m_hasFixedSize(false) - { - } - - ~PatternDisjunction() - { - deleteAllValues(m_alternatives); - } - - PatternAlternative* addNewAlternative() - { - PatternAlternative* alternative = newOrCrash(this); - m_alternatives.append(alternative); - return alternative; - } - - Vector m_alternatives; - PatternAlternative* m_parent; - unsigned m_minimumSize; - unsigned m_callFrameSize; - bool m_hasFixedSize; -}; - -// You probably don't want to be calling these functions directly -// (please to be calling newlineCharacterClass() et al on your -// friendly neighborhood YarrPattern instance to get nicely -// cached copies). -CharacterClass* newlineCreate(); -CharacterClass* digitsCreate(); -CharacterClass* spacesCreate(); -CharacterClass* wordcharCreate(); -CharacterClass* nondigitsCreate(); -CharacterClass* nonspacesCreate(); -CharacterClass* nonwordcharCreate(); - -struct TermChain { - TermChain(PatternTerm term) - : term(term) - {} - - PatternTerm term; - Vector hotTerms; -}; - -struct YarrPattern { - YarrPattern(const String& pattern, bool ignoreCase, bool multiline, ErrorCode* error); - - ~YarrPattern() - { - deleteAllValues(m_disjunctions); - deleteAllValues(m_userCharacterClasses); - } - - void reset() - { - m_numSubpatterns = 0; - m_maxBackReference = 0; - - m_containsBackreferences = false; - m_containsBOL = false; - - newlineCached = 0; - digitsCached = 0; - spacesCached = 0; - wordcharCached = 0; - nondigitsCached = 0; - nonspacesCached = 0; - nonwordcharCached = 0; - - deleteAllValues(m_disjunctions); - m_disjunctions.clear(); - deleteAllValues(m_userCharacterClasses); - m_userCharacterClasses.clear(); - } - - bool containsIllegalBackReference() - { - return m_maxBackReference > m_numSubpatterns; - } - - CharacterClass* newlineCharacterClass() - { - if (!newlineCached) - m_userCharacterClasses.append(newlineCached = newlineCreate()); - return newlineCached; - } - CharacterClass* digitsCharacterClass() - { - if (!digitsCached) - m_userCharacterClasses.append(digitsCached = digitsCreate()); - return digitsCached; - } - CharacterClass* spacesCharacterClass() - { - if (!spacesCached) - m_userCharacterClasses.append(spacesCached = spacesCreate()); - return spacesCached; - } - CharacterClass* wordcharCharacterClass() - { - if (!wordcharCached) - m_userCharacterClasses.append(wordcharCached = wordcharCreate()); - return wordcharCached; - } - CharacterClass* nondigitsCharacterClass() - { - if (!nondigitsCached) - m_userCharacterClasses.append(nondigitsCached = nondigitsCreate()); - return nondigitsCached; - } - CharacterClass* nonspacesCharacterClass() - { - if (!nonspacesCached) - m_userCharacterClasses.append(nonspacesCached = nonspacesCreate()); - return nonspacesCached; - } - CharacterClass* nonwordcharCharacterClass() - { - if (!nonwordcharCached) - m_userCharacterClasses.append(nonwordcharCached = nonwordcharCreate()); - return nonwordcharCached; - } - - bool m_ignoreCase : 1; - bool m_multiline : 1; - bool m_containsBackreferences : 1; - bool m_containsBOL : 1; - unsigned m_numSubpatterns; - unsigned m_maxBackReference; - PatternDisjunction* m_body; - Vector m_disjunctions; - Vector m_userCharacterClasses; - -private: - ErrorCode compile(const String& patternString); - - CharacterClass* newlineCached; - CharacterClass* digitsCached; - CharacterClass* spacesCached; - CharacterClass* wordcharCached; - CharacterClass* nondigitsCached; - CharacterClass* nonspacesCached; - CharacterClass* nonwordcharCached; -}; - -} } // namespace JSC::Yarr - -#endif /* yarr_YarrPattern_h */ diff --git a/js/src/yarr/YarrSyntaxChecker.cpp b/js/src/yarr/YarrSyntaxChecker.cpp deleted file mode 100644 index 00fbf6e1f207..000000000000 --- a/js/src/yarr/YarrSyntaxChecker.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "yarr/YarrSyntaxChecker.h" - -#include "yarr/YarrParser.h" - -namespace JSC { namespace Yarr { - -class SyntaxChecker { -public: - void assertionBOL() {} - void assertionEOL() {} - void assertionWordBoundary(bool) {} - void atomPatternCharacter(UChar) {} - void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {} - void atomCharacterClassBegin(bool = false) {} - void atomCharacterClassAtom(UChar) {} - void atomCharacterClassRange(UChar, UChar) {} - void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {} - void atomCharacterClassEnd() {} - void atomParenthesesSubpatternBegin(bool = true) {} - void atomParentheticalAssertionBegin(bool = false) {} - void atomParenthesesEnd() {} - void atomBackReference(unsigned) {} - void quantifyAtom(unsigned, unsigned, bool) {} - void disjunction() {} -}; - -ErrorCode checkSyntax(const String& pattern) -{ - SyntaxChecker syntaxChecker; - return parse(syntaxChecker, pattern); -} - -}} // JSC::YARR diff --git a/js/src/yarr/YarrSyntaxChecker.h b/js/src/yarr/YarrSyntaxChecker.h deleted file mode 100644 index 42925826e366..000000000000 --- a/js/src/yarr/YarrSyntaxChecker.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef yarr_YarrSyntaxChecker_h -#define yarr_YarrSyntaxChecker_h - -#include "yarr/wtfbridge.h" -#include "yarr/YarrParser.h" - -namespace JSC { namespace Yarr { - -ErrorCode checkSyntax(const String& pattern); - -}} // JSC::YARR - -#endif /* yarr_YarrSyntaxChecker_h */ diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h deleted file mode 100644 index fe2a5f65f31f..000000000000 --- a/js/src/yarr/wtfbridge.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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 yarr_wtfbridge_h -#define yarr_wtfbridge_h - -/* - * WTF compatibility layer. This file provides various type and data - * definitions for use by Yarr. - */ - -#include -#include -#include "jscntxt.h" -#include "jsstr.h" -#include "vm/String.h" -#include "assembler/wtf/Platform.h" -#include "assembler/jit/ExecutableAllocator.h" -#include "yarr/CheckedArithmetic.h" - -namespace JSC { namespace Yarr { - -/* - * Basic type definitions. - */ - -typedef char LChar; -typedef jschar UChar; -typedef JSLinearString UString; -typedef JSLinearString String; - - -class Unicode { - public: - static UChar toUpper(UChar c) { return js::unicode::ToUpperCase(c); } - static UChar toLower(UChar c) { return js::unicode::ToLowerCase(c); } -}; - -/* - * Do-nothing smart pointer classes. These have a compatible interface - * with the smart pointers used by Yarr, but they don't actually do - * reference counting. - */ -template -class RefCounted { -}; - -template -class RefPtr { - T *ptr; - public: - RefPtr(T *p) { ptr = p; } - operator bool() const { return ptr != NULL; } - const T *operator ->() const { return ptr; } - T *get() { return ptr; } -}; - -template -class PassRefPtr { - T *ptr; - public: - PassRefPtr(T *p) { ptr = p; } - operator T*() { return ptr; } -}; - -template -class PassOwnPtr { - T *ptr; - public: - PassOwnPtr(T *p) { ptr = p; } - - T *get() { return ptr; } -}; - -template -class OwnPtr { - T *ptr; - public: - OwnPtr() : ptr(NULL) { } - OwnPtr(PassOwnPtr p) : ptr(p.get()) { } - - ~OwnPtr() { - js_delete(ptr); - } - - OwnPtr &operator=(PassOwnPtr p) { - ptr = p.get(); - return *this; - } - - T *operator ->() { return ptr; } - - T *get() { return ptr; } - - T *release() { - T *result = ptr; - ptr = NULL; - return result; - } -}; - -template -PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } - -template -PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } - -// Dummy wrapper. -#define WTF_MAKE_FAST_ALLOCATED void make_fast_allocated_() - -template -class Ref { - T &val; - public: - Ref(T &val) : val(val) { } - operator T&() const { return val; } -}; - -/* - * Vector class for Yarr. This wraps js::Vector and provides all - * the API method signatures used by Yarr. - */ -template -class Vector { - public: - js::Vector impl; - public: - Vector() {} - - Vector(const Vector &v) { - append(v); - } - - size_t size() const { - return impl.length(); - } - - T &operator[](size_t i) { - return impl[i]; - } - - const T &operator[](size_t i) const { - return impl[i]; - } - - T &at(size_t i) { - return impl[i]; - } - - const T *begin() const { - return impl.begin(); - } - - T &last() { - return impl.back(); - } - - bool isEmpty() const { - return impl.empty(); - } - - template - void append(const U &u) { - if (!impl.append(static_cast(u))) - js::CrashAtUnhandlableOOM("Yarr"); - } - - template - void append(const Vector &v) { - if (!impl.appendAll(v.impl)) - js::CrashAtUnhandlableOOM("Yarr"); - } - - void insert(size_t i, const T& t) { - if (!impl.insert(&impl[i], t)) - js::CrashAtUnhandlableOOM("Yarr"); - } - - void remove(size_t i) { - impl.erase(&impl[i]); - } - - void clear() { - return impl.clear(); - } - - void shrink(size_t newLength) { - JS_ASSERT(newLength <= impl.length()); - if (!impl.resize(newLength)) - js::CrashAtUnhandlableOOM("Yarr"); - } - - void swap(Vector &other) { - impl.swap(other.impl); - } - - void deleteAllValues() { - for (T *p = impl.begin(); p != impl.end(); ++p) - js_delete(*p); - } - - bool reserve(size_t capacity) { - return impl.reserve(capacity); - } -}; - -template -class Vector > { - public: - js::Vector impl; - public: - Vector() {} - - size_t size() const { - return impl.length(); - } - - void append(T *t) { - if (!impl.append(t)) - js::CrashAtUnhandlableOOM("Yarr"); - } - - PassOwnPtr operator[](size_t i) { - return PassOwnPtr(impl[i]); - } - - void clear() { - for (T **p = impl.begin(); p != impl.end(); ++p) - delete_(*p); - return impl.clear(); - } - - void reserve(size_t capacity) { - if (!impl.reserve(capacity)) - js::CrashAtUnhandlableOOM("Yarr"); - } -}; - -template -inline void -deleteAllValues(Vector &v) { - v.deleteAllValues(); -} - -static inline void -dataLogF(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -#if JS_ION - -/* - * Minimal JSGlobalData. This used by Yarr to get the allocator. - */ -class JSGlobalData { - public: - ExecutableAllocator *regexAllocator; - - JSGlobalData(ExecutableAllocator *regexAllocator) - : regexAllocator(regexAllocator) { } -}; - -#endif - - /* - * Do-nothing version of a macro used by WTF to avoid unused - * parameter warnings. - */ -#define UNUSED_PARAM(e) - -/* - * Like SpiderMonkey's allocation templates, but with more crashing. - */ -template -T *newOrCrash() -{ - T *t = js_new(); - if (!t) - js::CrashAtUnhandlableOOM("Yarr"); - return t; -} - -template -T *newOrCrash(P1 &&p1) -{ - T *t = js_new(mozilla::Forward(p1)); - if (!t) - js::CrashAtUnhandlableOOM("Yarr"); - return t; -} - -template -T *newOrCrash(P1 &&p1, P2 &&p2) -{ - T *t = js_new(mozilla::Forward(p1), mozilla::Forward(p2)); - if (!t) - js::CrashAtUnhandlableOOM("Yarr"); - return t; -} - -template -T *newOrCrash(P1 &&p1, P2 &&p2, P3 &&p3) -{ - T *t = js_new(mozilla::Forward(p1), mozilla::Forward(p2), mozilla::Forward(p3)); - if (!t) - js::CrashAtUnhandlableOOM("Yarr"); - return t; -} - -template -T *newOrCrash(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) -{ - T *t = js_new(mozilla::Forward(p1), - mozilla::Forward(p2), - mozilla::Forward(p3), - mozilla::Forward(p4)); - if (!t) - js::CrashAtUnhandlableOOM("Yarr"); - return t; -} - -} /* namespace Yarr */ - -/* - * Replacements for std:: functions used in Yarr. We put them in - * namespace JSC::std so that they can still be called as std::X - * in Yarr. - */ -namespace std { - -/* - * windows.h defines a 'min' macro that would mangle the function - * name. - */ -#if WTF_COMPILER_MSVC -# undef min -# undef max -#endif - -#define NO_RETURN_DUE_TO_ASSERT - -template -inline T -min(T t1, T t2) -{ - return js::Min(t1, t2); -} - -template -inline T -max(T t1, T t2) -{ - return js::Max(t1, t2); -} - -template -inline void -swap(T &t1, T &t2) -{ - T tmp = t1; - t1 = t2; - t2 = tmp; -} -} /* namespace std */ - -} /* namespace JSC */ - -namespace WTF { - -/* - * Sentinel value used in Yarr. - */ -const size_t notFound = size_t(-1); - -} - -#define JS_EXPORT_PRIVATE - -#endif /* yarr_wtfbridge_h */ diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 6a00e3816877..9f151e2e75fa 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2323,12 +2323,6 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats, "Transient data (mostly parse nodes) held by the JSRuntime during " "compilation."); -#ifdef JS_YARR - RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-data"), - KIND_NONHEAP, rtStats.runtime.regexpData, - "Regexp JIT data."); -#endif - RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/interpreter-stack"), KIND_HEAP, rtStats.runtime.interpreterStack, "JS interpreter frames."); From 601136f84653f38836ab55b01d9f23a4746a7c78 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Mon, 16 Jun 2014 18:50:15 -0400 Subject: [PATCH 41/64] Bug 1015637 - Clean up HTMLTableAccessible::HasDescendant r=tbsaunde --- accessible/src/html/HTMLTableAccessible.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/accessible/src/html/HTMLTableAccessible.cpp b/accessible/src/html/HTMLTableAccessible.cpp index 4322a58d7e84..f0b8b76d6930 100644 --- a/accessible/src/html/HTMLTableAccessible.cpp +++ b/accessible/src/html/HTMLTableAccessible.cpp @@ -38,6 +38,7 @@ #include "nsTableOuterFrame.h" using namespace mozilla; +using namespace mozilla::dom; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// @@ -869,15 +870,10 @@ HTMLTableAccessible::Description(nsString& aDescription) bool HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty) { - nsCOMPtr tableElt(do_QueryInterface(mContent)); - NS_ENSURE_TRUE(tableElt, false); + nsCOMPtr elements = + mContent->AsElement()->GetElementsByTagName(aTagName); - nsCOMPtr nodeList; - tableElt->GetElementsByTagName(aTagName, getter_AddRefs(nodeList)); - NS_ENSURE_TRUE(nodeList, false); - - nsCOMPtr foundItem; - nodeList->Item(0, getter_AddRefs(foundItem)); + Element* foundItem = elements->Item(0); if (!foundItem) return false; @@ -886,11 +882,10 @@ HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty) // Make sure that the item we found has contents and either has multiple // children or the found item is not a whitespace-only text node. - nsCOMPtr foundItemContent = do_QueryInterface(foundItem); - if (foundItemContent->GetChildCount() > 1) + if (foundItem->GetChildCount() > 1) return true; // Treat multiple child nodes as non-empty - nsIContent *innerItemContent = foundItemContent->GetFirstChild(); + nsIContent *innerItemContent = foundItem->GetFirstChild(); if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace()) return true; @@ -901,8 +896,7 @@ HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty) // caption element only. On another hand we create accessible object for // the first entry of caption element (see // HTMLTableAccessible::CacheChildren). - nodeList->Item(1, getter_AddRefs(foundItem)); - return !!foundItem; + return !!elements->Item(1); } bool From f3172735cb5d27bb452015f2a2a41e13cc3213c4 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Mon, 16 Jun 2014 18:50:16 -0400 Subject: [PATCH 42/64] Bug 1015644 - Clean up ActiveElementManager r=botond --- gfx/layers/apz/util/ActiveElementManager.cpp | 26 ++++++++------------ gfx/layers/apz/util/ActiveElementManager.h | 15 ++++++----- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/gfx/layers/apz/util/ActiveElementManager.cpp b/gfx/layers/apz/util/ActiveElementManager.cpp index 76a27e229c81..7cf5b970172b 100644 --- a/gfx/layers/apz/util/ActiveElementManager.cpp +++ b/gfx/layers/apz/util/ActiveElementManager.cpp @@ -8,11 +8,9 @@ #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "inIDOMUtils.h" -#include "nsIDOMDocument.h" -#include "nsIDOMElement.h" -#include "nsIDOMEventTarget.h" #include "base/message_loop.h" #include "base/task.h" +#include "mozilla/dom/Element.h" #define AEM_LOG(...) // #define AEM_LOG(...) printf_stderr("AEM: " __VA_ARGS__) @@ -40,7 +38,7 @@ ActiveElementManager::ActiveElementManager() ActiveElementManager::~ActiveElementManager() {} void -ActiveElementManager::SetTargetElement(nsIDOMEventTarget* aTarget) +ActiveElementManager::SetTargetElement(dom::EventTarget* aTarget) { if (mTarget) { // Multiple fingers on screen (since HandleTouchEnd clears mTarget). @@ -126,11 +124,12 @@ ActiveElementManager::HandleTouchEnd(bool aWasClick) } void -ActiveElementManager::SetActive(nsIDOMElement* aTarget) +ActiveElementManager::SetActive(dom::Element* aTarget) { AEM_LOG("Setting active %p\n", aTarget); if (mDomUtils) { - mDomUtils->SetContentState(aTarget, NS_EVENT_STATE_ACTIVE.GetInternalValue()); + nsCOMPtr target = do_QueryInterface(aTarget); + mDomUtils->SetContentState(target, NS_EVENT_STATE_ACTIVE.GetInternalValue()); } } @@ -141,15 +140,10 @@ ActiveElementManager::ResetActive() // Clear the :active flag from mTarget by setting it on the document root. if (mTarget) { - nsCOMPtr doc; - mTarget->GetOwnerDocument(getter_AddRefs(doc)); - if (doc) { - nsCOMPtr root; - doc->GetDocumentElement(getter_AddRefs(root)); - if (root) { - AEM_LOG("Found root %p, making active\n", root.get()); - SetActive(root); - } + dom::Element* root = mTarget->OwnerDoc()->GetDocumentElement(); + if (root) { + AEM_LOG("Found root %p, making active\n", root.get()); + SetActive(root); } } } @@ -162,7 +156,7 @@ ActiveElementManager::ResetTouchBlockState() } void -ActiveElementManager::SetActiveTask(nsIDOMElement* aTarget) +ActiveElementManager::SetActiveTask(dom::Element* aTarget) { AEM_LOG("mSetActiveTask %p running\n", mSetActiveTask); diff --git a/gfx/layers/apz/util/ActiveElementManager.h b/gfx/layers/apz/util/ActiveElementManager.h index a67d7b3124b9..e703927d5bd8 100644 --- a/gfx/layers/apz/util/ActiveElementManager.h +++ b/gfx/layers/apz/util/ActiveElementManager.h @@ -10,11 +10,14 @@ #include "nsISupportsImpl.h" class inIDOMUtils; -class nsIDOMEventTarget; -class nsIDOMElement; class CancelableTask; namespace mozilla { +namespace dom { +class Element; +class EventTarget; +} + namespace layers { /** @@ -35,7 +38,7 @@ public: * HandleTouchStart(). * |aTarget| may be nullptr. */ - void SetTargetElement(nsIDOMEventTarget* aTarget); + void SetTargetElement(dom::EventTarget* aTarget); /** * Handle a touch-start event. * @param aCanBePan whether the touch can be a pan @@ -55,7 +58,7 @@ private: /** * The target of the first touch point in the current touch block. */ - nsCOMPtr mTarget; + nsCOMPtr mTarget; /** * Whether the current touch block can be a pan. Set in HandleTouchStart(). */ @@ -73,10 +76,10 @@ private: // Helpers void TriggerElementActivation(); - void SetActive(nsIDOMElement* aTarget); + void SetActive(dom::Element* aTarget); void ResetActive(); void ResetTouchBlockState(); - void SetActiveTask(nsIDOMElement* aTarget); + void SetActiveTask(dom::Element* aTarget); void CancelTask(); }; From af1549a12d185a5d81b5858e9c765d85af1502e8 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 17 Jun 2014 01:59:54 +0300 Subject: [PATCH 43/64] Bug 998809 - WidgetEvent::typeString is not always set correctly , r=masayuki --- dom/events/Event.cpp | 1 + dom/events/test/mochitest.ini | 1 + dom/events/test/test_bug998809.html | 35 +++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 dom/events/test/test_bug998809.html diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index 0d8d1ea328f2..646dd88ae608 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -523,6 +523,7 @@ void Event::SetEventType(const nsAString& aEventTypeArg) { if (mIsMainThreadEvent) { + mEvent->typeString.Truncate(); mEvent->userType = nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType, &(mEvent->message)); diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini index 0b790b6e8675..4eeff715106e 100644 --- a/dom/events/test/mochitest.ini +++ b/dom/events/test/mochitest.ini @@ -157,3 +157,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM skip-if = buildapp == 'b2g' || e10s [test_bug985988.html] [test_dom_storage_event.html] +[test_bug998809.html] diff --git a/dom/events/test/test_bug998809.html b/dom/events/test/test_bug998809.html new file mode 100644 index 000000000000..08499d2c75af --- /dev/null +++ b/dom/events/test/test_bug998809.html @@ -0,0 +1,35 @@ + + + + + + Test for Bug 998809 + + + + + +Mozilla Bug 998809 +

+ +
+
+ + From 08774e4ba496f18f89fd5236e7645c99ca4c0e53 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 17 Jun 2014 02:01:22 +0300 Subject: [PATCH 44/64] Bug 902618 - Parser notifies about subtree roots, but not their descendants, r=hsivonen,bz --- content/base/public/nsINode.h | 4 + .../html/content/src/HTMLOutputElement.cpp | 14 ++- content/html/content/src/HTMLOutputElement.h | 6 +- parser/html/moz.build | 1 - parser/html/nsHtml5DocumentBuilder.h | 86 ++------------- parser/html/nsHtml5PendingNotification.h | 55 ---------- parser/html/nsHtml5TreeBuilder.cpp | 1 - parser/html/nsHtml5TreeBuilder.h | 1 - parser/html/nsHtml5TreeBuilderCppSupplement.h | 43 ++------ parser/html/nsHtml5TreeOpExecutor.cpp | 4 - parser/html/nsHtml5TreeOperation.cpp | 102 ++++++++---------- parser/html/nsHtml5TreeOperation.h | 4 +- 12 files changed, 79 insertions(+), 242 deletions(-) delete mode 100644 parser/html/nsHtml5PendingNotification.h diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index d2f225dae8f6..bc6c79b0bb79 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -1350,6 +1350,8 @@ private: // Set if the element has a parser insertion mode other than "in body", // per the HTML5 "Parse state" section. ElementHasWeirdParserInsertionMode, + // Parser sets this flag if it has notified about the node. + ParserHasNotified, // Guard value BooleanFlagCount }; @@ -1490,6 +1492,8 @@ public: bool IsScopedStyleRoot() { return GetBoolFlag(ElementIsScopedStyleRoot); } bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); } void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); } + void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); }; + bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); } protected: void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); } void SetInDocument() { SetBoolFlag(IsInDocument); } diff --git a/content/html/content/src/HTMLOutputElement.cpp b/content/html/content/src/HTMLOutputElement.cpp index 037236dab2eb..4c6fbc6f1610 100644 --- a/content/html/content/src/HTMLOutputElement.cpp +++ b/content/html/content/src/HTMLOutputElement.cpp @@ -13,14 +13,16 @@ #include "nsDOMSettableTokenList.h" #include "nsFormSubmission.h" -NS_IMPL_NS_NEW_HTML_ELEMENT(Output) +NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Output) namespace mozilla { namespace dom { -HTMLOutputElement::HTMLOutputElement(already_AddRefed& aNodeInfo) +HTMLOutputElement::HTMLOutputElement(already_AddRefed& aNodeInfo, + FromParser aFromParser) : nsGenericHTMLFormElement(aNodeInfo) , mValueModeFlag(eModeDefault) + , mIsDoneAddingChildren(!aFromParser) { AddMutationObserver(this); @@ -93,6 +95,12 @@ HTMLOutputElement::ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute, aValue, aResult); } +void +HTMLOutputElement::DoneAddingChildren(bool aHaveNotified) +{ + mIsDoneAddingChildren = true; +} + EventStates HTMLOutputElement::IntrinsicState() const { @@ -170,7 +178,7 @@ HTMLOutputElement::HtmlFor() void HTMLOutputElement::DescendantsChanged() { - if (mValueModeFlag == eModeDefault) { + if (mIsDoneAddingChildren && mValueModeFlag == eModeDefault) { if (!nsContentUtils::GetNodeTextContent(this, true, mDefaultValue)) { NS_RUNTIMEABORT("OOM"); } diff --git a/content/html/content/src/HTMLOutputElement.h b/content/html/content/src/HTMLOutputElement.h index 11041f9c4b4b..cf2617d0644e 100644 --- a/content/html/content/src/HTMLOutputElement.h +++ b/content/html/content/src/HTMLOutputElement.h @@ -21,7 +21,8 @@ class HTMLOutputElement MOZ_FINAL : public nsGenericHTMLFormElement, public: using nsIConstraintValidation::GetValidationMessage; - HTMLOutputElement(already_AddRefed& aNodeInfo); + HTMLOutputElement(already_AddRefed& aNodeInfo, + FromParser aFromParser = NOT_FROM_PARSER); virtual ~HTMLOutputElement(); // nsISupports @@ -39,6 +40,8 @@ public: bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult) MOZ_OVERRIDE; + virtual void DoneAddingChildren(bool aHaveNotified) MOZ_OVERRIDE; + EventStates IntrinsicState() const MOZ_OVERRIDE; virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, @@ -101,6 +104,7 @@ protected: }; ValueModeFlag mValueModeFlag; + bool mIsDoneAddingChildren; nsString mDefaultValue; nsRefPtr mTokenList; }; diff --git a/parser/html/moz.build b/parser/html/moz.build index 8a7e7eb5122a..f46a7b87c50f 100644 --- a/parser/html/moz.build +++ b/parser/html/moz.build @@ -33,7 +33,6 @@ EXPORTS += [ 'nsHtml5OplessBuilder.h', 'nsHtml5OwningUTF16Buffer.h', 'nsHtml5Parser.h', - 'nsHtml5PendingNotification.h', 'nsHtml5PlainTextUtils.h', 'nsHtml5RefPtr.h', 'nsHtml5Speculation.h', diff --git a/parser/html/nsHtml5DocumentBuilder.h b/parser/html/nsHtml5DocumentBuilder.h index d8fdcfe08f9c..1b20df133e34 100644 --- a/parser/html/nsHtml5DocumentBuilder.h +++ b/parser/html/nsHtml5DocumentBuilder.h @@ -7,10 +7,10 @@ #ifndef nsHtml5DocumentBuilder_h #define nsHtml5DocumentBuilder_h -#include "nsHtml5PendingNotification.h" #include "nsContentSink.h" #include "nsHtml5DocumentMode.h" #include "nsIDocument.h" +#include "nsIContent.h" typedef nsIContent* nsIContentPtr; @@ -29,74 +29,9 @@ public: NS_DECL_ISUPPORTS_INHERITED - inline void HoldElement(nsIContent* aContent) + inline void HoldElement(already_AddRefed aContent) { - mOwnedElements.AppendElement(aContent); - } - - inline bool HaveNotified(nsIContent* aNode) - { - NS_PRECONDITION(aNode, "HaveNotified called with null argument."); - const nsHtml5PendingNotification* start = mPendingNotifications.Elements(); - const nsHtml5PendingNotification* end = start + mPendingNotifications.Length(); - for (;;) { - nsIContent* parent = aNode->GetParent(); - if (!parent) { - return true; - } - for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) { - if (iter->Contains(parent)) { - return iter->HaveNotifiedIndex(parent->IndexOf(aNode)); - } - } - aNode = parent; - } - } - - void PostPendingAppendNotification(nsIContent* aParent, nsIContent* aChild) - { - bool newParent = true; - const nsIContentPtr* first = mElementsSeenInThisAppendBatch.Elements(); - const nsIContentPtr* last = first + mElementsSeenInThisAppendBatch.Length() - 1; - for (const nsIContentPtr* iter = last; iter >= first; --iter) { -#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH - sAppendBatchSlotsExamined++; -#endif - if (*iter == aParent) { - newParent = false; - break; - } - } - if (aChild->IsElement()) { - mElementsSeenInThisAppendBatch.AppendElement(aChild); - } - mElementsSeenInThisAppendBatch.AppendElement(aParent); - if (newParent) { - mPendingNotifications.AppendElement(aParent); - } -#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH - sAppendBatchExaminations++; -#endif - } - - void FlushPendingAppendNotifications() - { - NS_PRECONDITION(mFlushState == eInDocUpdate, "Notifications flushed outside update"); - mFlushState = eNotifying; - const nsHtml5PendingNotification* start = mPendingNotifications.Elements(); - const nsHtml5PendingNotification* end = start + mPendingNotifications.Length(); - for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) { - iter->Fire(); - } - mPendingNotifications.Clear(); -#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH - if (mElementsSeenInThisAppendBatch.Length() > sAppendBatchMaxSize) { - sAppendBatchMaxSize = mElementsSeenInThisAppendBatch.Length(); - } -#endif - mElementsSeenInThisAppendBatch.Clear(); - NS_ASSERTION(mFlushState == eNotifying, "mFlushState out of sync"); - mFlushState = eInDocUpdate; + *(mOwnedElements.AppendElement()) = aContent; } nsresult Init(nsIDocument* aDoc, nsIURI* aURI, @@ -142,12 +77,16 @@ public: { NS_PRECONDITION(mFlushState != eNotifying, "mFlushState out of sync"); if (mFlushState == eInDocUpdate) { - FlushPendingAppendNotifications(); mFlushState = eInFlush; mDocument->EndUpdate(UPDATE_CONTENT_MODEL); } } + bool IsInDocUpdate() + { + return mFlushState == eInDocUpdate; + } + void SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource); /** @@ -167,19 +106,12 @@ public: virtual nsresult FlushTags(); protected: - inline void SetAppendBatchCapacity(uint32_t aCapacity) - { - mElementsSeenInThisAppendBatch.SetCapacity(aCapacity); - } nsHtml5DocumentBuilder(bool aRunsToCompletion); virtual ~nsHtml5DocumentBuilder(); -private: - nsTArray mPendingNotifications; - nsTArray mElementsSeenInThisAppendBatch; protected: - nsTArray > mOwnedElements; + nsAutoTArray, 32> mOwnedElements; /** * Non-NS_OK if this parser should refuse to process any more input. * For example, the parser needs to be marked as broken if it drops some diff --git a/parser/html/nsHtml5PendingNotification.h b/parser/html/nsHtml5PendingNotification.h deleted file mode 100644 index b7205d8439fc..000000000000 --- a/parser/html/nsHtml5PendingNotification.h +++ /dev/null @@ -1,55 +0,0 @@ -/* 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 nsHtml5PendingNotification_h -#define nsHtml5PendingNotification_h - -#include "nsNodeUtils.h" - -class nsHtml5TreeBuilder; - -class nsHtml5PendingNotification { - public: - - nsHtml5PendingNotification(nsIContent* aParent) - : mParent(aParent), - mChildCount(aParent->GetChildCount() - 1) - { - MOZ_COUNT_CTOR(nsHtml5PendingNotification); - } - - ~nsHtml5PendingNotification() - { - MOZ_COUNT_DTOR(nsHtml5PendingNotification); - } - - inline void Fire() - { - nsNodeUtils::ContentAppended(mParent, mParent->GetChildAt(mChildCount), - mChildCount); - } - - inline bool Contains(nsIContent* aNode) - { - return !!(mParent == aNode); - } - - inline bool HaveNotifiedIndex(uint32_t index) - { - return index < mChildCount; - } - - private: - /** - * An element - */ - nsIContent* mParent; - - /** - * Child count at start of notification deferring - */ - uint32_t mChildCount; -}; - -#endif // nsHtml5PendingNotification_h diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp index 390ed92e2370..ca9736014b17 100644 --- a/parser/html/nsHtml5TreeBuilder.cpp +++ b/parser/html/nsHtml5TreeBuilder.cpp @@ -44,7 +44,6 @@ #include "nsHtml5Parser.h" #include "nsHtml5Atoms.h" #include "nsHtml5TreeOperation.h" -#include "nsHtml5PendingNotification.h" #include "nsHtml5StateSnapshot.h" #include "nsHtml5StackNode.h" #include "nsHtml5TreeOpExecutor.h" diff --git a/parser/html/nsHtml5TreeBuilder.h b/parser/html/nsHtml5TreeBuilder.h index ac5e55009e85..4297cbc0a976 100644 --- a/parser/html/nsHtml5TreeBuilder.h +++ b/parser/html/nsHtml5TreeBuilder.h @@ -45,7 +45,6 @@ #include "nsHtml5Parser.h" #include "nsHtml5Atoms.h" #include "nsHtml5TreeOperation.h" -#include "nsHtml5PendingNotification.h" #include "nsHtml5StateSnapshot.h" #include "nsHtml5StackNode.h" #include "nsHtml5TreeOpExecutor.h" diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index d52d1b951ab1..0f90e1d1705a 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -639,16 +639,6 @@ nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContent } if (aName == nsHtml5Atoms::input || aName == nsHtml5Atoms::button) { - if (!formPointer) { - // If form inputs don't belong to a form, their state preservation - // won't work right without an append notification flush at this - // point. See bug 497861. - if (mBuilder) { - mBuilder->FlushPendingAppendNotifications(); - } else { - mOpQueue.AppendElement()->Init(eTreeOpFlushPendingAppendNotifications); - } - } if (mBuilder) { nsHtml5TreeOperation::DoneCreatingElement(static_cast(aElement)); } else { @@ -710,7 +700,7 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent } if (aName == nsHtml5Atoms::title) { if (mBuilder) { - nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement), mBuilder); + nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement)); return; } nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); @@ -722,7 +712,6 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent if (mBuilder) { MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Scripts must be blocked."); - mBuilder->FlushPendingAppendNotifications(); mBuilder->UpdateStyleSheet(static_cast(aElement)); return; } @@ -748,32 +737,12 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent // properly (e.g. form state restoration). // XXX expose ElementName group here and do switch if (aName == nsHtml5Atoms::object || - aName == nsHtml5Atoms::applet) { + aName == nsHtml5Atoms::applet || + aName == nsHtml5Atoms::select || + aName == nsHtml5Atoms::textarea || + aName == nsHtml5Atoms::output) { if (mBuilder) { - nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement), mBuilder); - return; - } - nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); - NS_ASSERTION(treeOp, "Tree op allocation failed."); - treeOp->Init(eTreeOpDoneAddingChildren, aElement); - return; - } - if (aName == nsHtml5Atoms::select || - aName == nsHtml5Atoms::textarea) { - if (!formPointer) { - // If form inputs don't belong to a form, their state preservation - // won't work right without an append notification flush at this - // point. See bug 497861 and bug 539895. - if (mBuilder) { - mBuilder->FlushPendingAppendNotifications(); - } else { - nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); - NS_ASSERTION(treeOp, "Tree op allocation failed."); - treeOp->Init(eTreeOpFlushPendingAppendNotifications); - } - } - if (mBuilder) { - nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement), mBuilder); + nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement)); return; } nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 933cd8bf6799..75d5ff5c1111 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -430,8 +430,6 @@ nsHtml5TreeOpExecutor::RunFlushLoop() uint32_t numberOfOpsToFlush = mOpQueue.Length(); - SetAppendBatchCapacity(numberOfOpsToFlush * 2); - const nsHtml5TreeOperation* first = mOpQueue.Elements(); const nsHtml5TreeOperation* last = first + numberOfOpsToFlush - 1; for (nsHtml5TreeOperation* iter = const_cast(first);;) { @@ -534,8 +532,6 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite() uint32_t numberOfOpsToFlush = mOpQueue.Length(); - SetAppendBatchCapacity(numberOfOpsToFlush * 2); - const nsHtml5TreeOperation* start = mOpQueue.Elements(); const nsHtml5TreeOperation* end = start + numberOfOpsToFlush; for (nsHtml5TreeOperation* iter = const_cast(start); diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index c012a1d89171..ae5f75da63ba 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -71,7 +71,7 @@ class MOZ_STACK_CLASS nsHtml5OtherDocUpdate { } } private: - nsIDocument* mDocument; + nsCOMPtr mDocument; }; nsHtml5TreeOperation::nsHtml5TreeOperation() @@ -123,28 +123,23 @@ nsHtml5TreeOperation::AppendTextToTextNode(const char16_t* aBuffer, nsHtml5DocumentBuilder* aBuilder) { NS_PRECONDITION(aTextNode, "Got null text node."); + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->GetDocument() == aTextNode->OwnerDoc()); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); + uint32_t oldLength = aTextNode->TextLength(); + CharacterDataChangeInfo info = { + true, + oldLength, + oldLength, + aLength + }; + nsNodeUtils::CharacterDataWillChange(aTextNode, &info); - if (aBuilder->HaveNotified(aTextNode)) { - // This text node has already been notified on, so it's necessary to - // notify on the append - nsresult rv = NS_OK; - uint32_t oldLength = aTextNode->TextLength(); - CharacterDataChangeInfo info = { - true, - oldLength, - oldLength, - aLength - }; - nsNodeUtils::CharacterDataWillChange(aTextNode, &info); + nsresult rv = aTextNode->AppendText(aBuffer, aLength, false); + NS_ENSURE_SUCCESS(rv, rv); - rv = aTextNode->AppendText(aBuffer, aLength, false); - NS_ENSURE_SUCCESS(rv, rv); - - nsNodeUtils::CharacterDataChanged(aTextNode, &info); - return rv; - } - - return aTextNode->AppendText(aBuffer, aLength, false); + nsNodeUtils::CharacterDataChanged(aTextNode, &info); + return rv; } @@ -178,30 +173,17 @@ nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent, nsHtml5DocumentBuilder* aBuilder) { + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); nsresult rv = NS_OK; - nsIDocument* executorDoc = aBuilder->GetDocument(); - NS_ASSERTION(executorDoc, "Null doc on executor"); - nsIDocument* parentDoc = aParent->OwnerDoc(); - NS_ASSERTION(parentDoc, "Null owner doc on old node."); - - if (MOZ_LIKELY(executorDoc == parentDoc)) { - // the usual case. the parent is in the parser's doc - rv = aParent->AppendChildTo(aNode, false); - if (NS_SUCCEEDED(rv)) { - aBuilder->PostPendingAppendNotification(aParent, aNode); - } - return rv; - } - - // The parent has been moved to another doc - parentDoc->BeginUpdate(UPDATE_CONTENT_MODEL); - + nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), + aBuilder->GetDocument()); uint32_t childCount = aParent->GetChildCount(); rv = aParent->AppendChildTo(aNode, false); if (NS_SUCCEEDED(rv)) { + aNode->SetParserHasNotified(); nsNodeUtils::ContentAppended(aParent, aNode, childCount); } - parentDoc->EndUpdate(UPDATE_CONTENT_MODEL); return rv; } @@ -209,12 +191,16 @@ nsresult nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder) { + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc()); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); nsresult rv = NS_OK; - aBuilder->FlushPendingAppendNotifications(); + nsIDocument* doc = aBuilder->GetDocument(); uint32_t childCount = doc->GetChildCount(); rv = doc->AppendChildTo(aNode, false); NS_ENSURE_SUCCESS(rv, rv); + aNode->SetParserHasNotified(); nsNodeUtils::ContentInserted(doc, aNode, childCount); NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), @@ -247,7 +233,8 @@ IsElementOrTemplateContent(nsINode* aNode) { void nsHtml5TreeOperation::Detach(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder) { - aBuilder->FlushPendingAppendNotifications(); + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); nsCOMPtr parent = aNode->GetParentNode(); if (parent) { nsHtml5OtherDocUpdate update(parent->OwnerDoc(), @@ -263,8 +250,8 @@ nsHtml5TreeOperation::AppendChildrenToNewParent(nsIContent* aNode, nsIContent* aParent, nsHtml5DocumentBuilder* aBuilder) { - aBuilder->FlushPendingAppendNotifications(); - + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument()); @@ -290,10 +277,11 @@ nsHtml5TreeOperation::FosterParent(nsIContent* aNode, nsIContent* aTable, nsHtml5DocumentBuilder* aBuilder) { + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); nsIContent* foster = aTable->GetParent(); if (IsElementOrTemplateContent(foster)) { - aBuilder->FlushPendingAppendNotifications(); nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument()); @@ -352,16 +340,17 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs, aName = nsHtml5Atoms::select; } - nsCOMPtr newContent; + nsCOMPtr newElement; nsCOMPtr nodeInfo = aBuilder->GetNodeInfoManager()-> GetNodeInfo(aName, nullptr, aNs, nsIDOMNode::ELEMENT_NODE); NS_ASSERTION(nodeInfo, "Got null nodeinfo."); - NS_NewElement(getter_AddRefs(newContent), + NS_NewElement(getter_AddRefs(newElement), nodeInfo.forget(), aFromParser); - NS_ASSERTION(newContent, "Element creation created null pointer."); + NS_ASSERTION(newElement, "Element creation created null pointer."); - aBuilder->HoldElement(newContent); + dom::Element* newContent = newElement; + aBuilder->HoldElement(newElement.forget()); if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style || aName == nsHtml5Atoms::link)) { nsCOMPtr ssle(do_QueryInterface(newContent)); @@ -408,6 +397,7 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs, (void) optionText->SetText(theContent[i], false); optionElt->AppendChildTo(optionText, false); newContent->AppendChildTo(optionElt, false); + // XXXsmaug Shouldn't we call this after adding all the child nodes. newContent->DoneAddingChildren(false); } } @@ -506,12 +496,12 @@ nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent, nsIContent* aTable, nsHtml5DocumentBuilder* aBuilder) { + MOZ_ASSERT(aBuilder); + MOZ_ASSERT(aBuilder->IsInDocUpdate()); nsresult rv = NS_OK; nsIContent* foster = aTable->GetParent(); if (IsElementOrTemplateContent(foster)) { - aBuilder->FlushPendingAppendNotifications(); - nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument()); @@ -609,10 +599,9 @@ nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode) } void -nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode, - nsHtml5DocumentBuilder* aBuilder) +nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode) { - aNode->DoneAddingChildren(aBuilder->HaveNotified(aNode)); + aNode->DoneAddingChildren(aNode->HasParserNotified()); } void @@ -763,7 +752,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, } case eTreeOpDoneAddingChildren: { nsIContent* node = *(mOne.node); - node->DoneAddingChildren(aBuilder->HaveNotified(node)); + node->DoneAddingChildren(node->HasParserNotified()); return NS_OK; } case eTreeOpDoneCreatingElement: { @@ -771,10 +760,6 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, DoneCreatingElement(node); return NS_OK; } - case eTreeOpFlushPendingAppendNotifications: { - aBuilder->FlushPendingAppendNotifications(); - return NS_OK; - } case eTreeOpSetDocumentCharset: { char* str = mOne.charPtr; int32_t charsetSource = mFour.integer; @@ -791,7 +776,6 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, } case eTreeOpUpdateStyleSheet: { nsIContent* node = *(mOne.node); - aBuilder->FlushPendingAppendNotifications(); aBuilder->UpdateStyleSheet(node); return NS_OK; } diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h index 2727733fae92..f5e4e7f142b2 100644 --- a/parser/html/nsHtml5TreeOperation.h +++ b/parser/html/nsHtml5TreeOperation.h @@ -44,7 +44,6 @@ enum eHtml5TreeOperation { eTreeOpPreventScriptExecution, eTreeOpDoneAddingChildren, eTreeOpDoneCreatingElement, - eTreeOpFlushPendingAppendNotifications, eTreeOpSetDocumentCharset, eTreeOpNeedsCharsetSwitchTo, eTreeOpUpdateStyleSheet, @@ -182,8 +181,7 @@ class nsHtml5TreeOperation { static void PreventScriptExecution(nsIContent* aNode); - static void DoneAddingChildren(nsIContent* aNode, - nsHtml5DocumentBuilder* aBuilder); + static void DoneAddingChildren(nsIContent* aNode); static void DoneCreatingElement(nsIContent* aNode); From 2a126077132857a9d5c93d6fa091439294334c00 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Mon, 16 Jun 2014 16:47:28 -0700 Subject: [PATCH 45/64] Bug 1025781 - Add CreateDataSourceSurface() failure checks r=nical --- gfx/layers/GrallocImages.cpp | 4 ++++ gfx/layers/ImageContainer.cpp | 8 ++++++++ gfx/layers/YCbCrImageDataSerializer.cpp | 4 ++++ gfx/layers/composite/TextRenderer.cpp | 7 +++++++ gfx/layers/opengl/CompositorOGL.cpp | 4 ++++ 5 files changed, 27 insertions(+) diff --git a/gfx/layers/GrallocImages.cpp b/gfx/layers/GrallocImages.cpp index a5a01c4b441f..d06cbc8889ee 100644 --- a/gfx/layers/GrallocImages.cpp +++ b/gfx/layers/GrallocImages.cpp @@ -220,6 +220,10 @@ GrallocImage::GetAsSourceSurface() RefPtr surface = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5); + if (!surface) { + NS_WARNING("Failed to create SourceSurface."); + return nullptr; + } uint32_t width = GetSize().width; uint32_t height = GetSize().height; diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp index 13e59c5d29fc..b5ac61414dab 100644 --- a/gfx/layers/ImageContainer.cpp +++ b/gfx/layers/ImageContainer.cpp @@ -575,6 +575,10 @@ PlanarYCbCrImage::GetAsSourceSurface() } RefPtr surface = gfx::Factory::CreateDataSourceSurface(size, format); + if (!surface) { + NS_WARNING("Failed to create SourceSurface."); + return nullptr; + } gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride()); @@ -590,6 +594,10 @@ RemoteBitmapImage::GetAsSourceSurface() ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8; RefPtr newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt); + if (!newSurf) { + NS_WARNING("Failed to create SourceSurface."); + return nullptr; + } for (int y = 0; y < mSize.height; y++) { memcpy(newSurf->GetData() + newSurf->Stride() * y, diff --git a/gfx/layers/YCbCrImageDataSerializer.cpp b/gfx/layers/YCbCrImageDataSerializer.cpp index e16db18bae88..bd43e76b6a3a 100644 --- a/gfx/layers/YCbCrImageDataSerializer.cpp +++ b/gfx/layers/YCbCrImageDataSerializer.cpp @@ -276,6 +276,10 @@ YCbCrImageDataDeserializer::ToDataSourceSurface() { RefPtr result = Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8); + if (!result) { + NS_WARNING("Failed to create SourceSurface."); + return nullptr; + } DataSourceSurface::MappedSurface map; result->Map(DataSourceSurface::MapType::WRITE, &map); diff --git a/gfx/layers/composite/TextRenderer.cpp b/gfx/layers/composite/TextRenderer.cpp index 97553398e12c..3f7fd4ec911c 100644 --- a/gfx/layers/composite/TextRenderer.cpp +++ b/gfx/layers/composite/TextRenderer.cpp @@ -85,6 +85,9 @@ TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin, // Create a surface to draw our glyphs to. RefPtr textSurf = Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat); + if (!textSurf) { + return; + } DataSourceSurface::MappedSurface map; textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map); @@ -144,6 +147,10 @@ TextRenderer::EnsureInitialized() } mGlyphBitmaps = Factory::CreateDataSourceSurface(IntSize(sTextureWidth, sTextureHeight), sTextureFormat); + if (!mGlyphBitmaps) { + NS_WARNING("Failed to create SourceSurface."); + return; + } mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap); diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 6eb693edfcd1..f6e4b23b3946 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -1455,6 +1455,10 @@ CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, con RefPtr source = Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8); + if (!source) { + NS_WARNING("Failed to create SourceSurface."); + return; + } ReadPixelsIntoDataSurface(mGLContext, source); From c2735215c72649cb8b048a56f403245ad89dd3d8 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 16 Jun 2014 19:00:15 -0700 Subject: [PATCH 46/64] Backed out changeset 66f9a0038c67 (bug 774388) for various frequent intermittent failures including mochitest-2 on a CLOSED TREE --- gfx/layers/ipc/CompositorParent.cpp | 281 +++++++++------------------- gfx/layers/ipc/CompositorParent.h | 43 ++++- gfx/thebes/gfxPlatform.cpp | 4 +- xpcom/build/nsXPComInit.cpp | 8 +- 4 files changed, 128 insertions(+), 208 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index e23113ed9aec..b7828ee5e4d6 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -53,8 +53,6 @@ #include "mozilla/unused.h" #include "mozilla/Hal.h" #include "mozilla/HalTypes.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/Monitor.h" namespace mozilla { namespace layers { @@ -75,129 +73,64 @@ CompositorParent::LayerTreeState::LayerTreeState() typedef map LayerTreeMap; static LayerTreeMap sIndirectLayerTrees; -/** - * A global map referencing each compositor by ID. - * - * This map is used by the ImageBridge protocol to trigger - * compositions without having to keep references to the - * compositor - */ -typedef map CompositorMap; -static CompositorMap* sCompositorMap; - -static void CreateCompositorMap() -{ - MOZ_ASSERT(!sCompositorMap); - sCompositorMap = new CompositorMap; -} - -static void DestroyCompositorMap() -{ - MOZ_ASSERT(sCompositorMap); - MOZ_ASSERT(sCompositorMap->empty()); - delete sCompositorMap; - sCompositorMap = nullptr; -} +// FIXME/bug 774386: we're assuming that there's only one +// CompositorParent, but that's not always true. This assumption only +// affects CrossProcessCompositorParent below. +static Thread* sCompositorThread = nullptr; +// manual reference count of the compositor thread. +static int sCompositorThreadRefCount = 0; +static MessageLoop* sMainLoop = nullptr; // See ImageBridgeChild.cpp void ReleaseImageBridgeParentSingleton(); -/* - * CompositorThreadHolder is a singleton class that represents the lifetime - * of the compositor thread. Its constructor creates the compositor thread, - * and its destructor waits for CrossProcessCompositorParent's (CPCPs) to - * be destroyed and then destroys the compositor thread. - * - * The CompositorThreadHolder singleton must be created/destroyed on the main thread. - * CompositorParent's must hold a strong reference to it. - * CrossProcessCompositorParent's (CPCPs) must call - * AddCPCPReference/RemoveCPCPReference to ensure that the compositor thread - * destruction will wait for CPCPs to be destroyed first. - */ -class CompositorThreadHolder MOZ_FINAL +static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie) { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorThreadHolder) + aNowReadyToDie->Release(); +} -public: - CompositorThreadHolder() - : mCompositorThread(CreateCompositorThread()) - , mCPCPReferencesMonitor("CompositorThreadHolder CPCP references monitor") - , mCPCPRefCnt(0) - { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_COUNT_CTOR(CompositorThreadHolder); - } - - ~CompositorThreadHolder() - { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mCPCPRefCnt == 0, "You should have called WaitForCPCPs before!"); - - MOZ_COUNT_DTOR(CompositorThreadHolder); - - DestroyCompositorThread(mCompositorThread); - } - - Thread* GetCompositorThread() const { - return mCompositorThread; - } - - void WaitForCPCPs() - { - MOZ_ASSERT(NS_IsMainThread()); - MonitorAutoLock autoLock(mCPCPReferencesMonitor); - while(mCPCPRefCnt) { - mCPCPReferencesMonitor.Wait(); - } - } - - void AddCPCPReference() - { - MonitorAutoLock autoLock(mCPCPReferencesMonitor); - mCPCPRefCnt++; - } - - void ReleaseCPCPReference() - { - MOZ_ASSERT(!NS_IsMainThread()); - MonitorAutoLock autoLock(mCPCPReferencesMonitor); - MOZ_ASSERT(mCPCPRefCnt > 0, "dup release"); - mCPCPRefCnt--; - if (mCPCPRefCnt == 0) { - mCPCPReferencesMonitor.NotifyAll(); - } - } - -private: - - Thread* const mCompositorThread; - - /* Everywhere in this class, CPCP is short for CrossProcessCompositorParent. - * mCPCPRefCnt is the number of CPCPs referencing the compositor thread. - * It is not atomic because it is protected behind a monitor, mCPCPReferencesMonitor. - */ - Monitor mCPCPReferencesMonitor; - int mCPCPRefCnt; - - static Thread* CreateCompositorThread(); - static void DestroyCompositorThread(Thread* aCompositorThread); - - friend class CompositorParent; -}; - -static StaticRefPtr sCompositorThreadHolder; - -static MessageLoop* sMainLoop = nullptr; - -/* static */ Thread* -CompositorThreadHolder::CreateCompositorThread() +static void DeleteCompositorThread() { - MOZ_ASSERT(NS_IsMainThread()); + if (NS_IsMainThread()){ + ReleaseImageBridgeParentSingleton(); + delete sCompositorThread; + sCompositorThread = nullptr; + } else { + sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread)); + } +} + +static void ReleaseCompositorThread() +{ + if(--sCompositorThreadRefCount == 0) { + DeleteCompositorThread(); + } +} + +static void SetThreadPriority() +{ + hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); +} + +void CompositorParent::StartUp() +{ + CreateCompositorMap(); + CreateThread(); sMainLoop = MessageLoop::current(); +} - MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); +void CompositorParent::ShutDown() +{ + DestroyThread(); + DestroyCompositorMap(); +} - Thread* compositorThread = new Thread("Compositor"); +bool CompositorParent::CreateThread() +{ + NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(!sCompositorThread); + sCompositorThreadRefCount = 1; + sCompositorThread = new Thread("Compositor"); Thread::Options options; /* Timeout values are powers-of-two to enable us get better data. @@ -208,64 +141,24 @@ CompositorThreadHolder::CreateCompositorThread() than the default hang timeout on major platforms (about 5 seconds). */ options.permanent_hang_timeout = 8192; // milliseconds - if (!compositorThread->StartWithOptions(options)) { - delete compositorThread; - return nullptr; + if (!sCompositorThread->StartWithOptions(options)) { + delete sCompositorThread; + sCompositorThread = nullptr; + return false; } - CreateCompositorMap(); - - return compositorThread; + return true; } -/* static */ void -CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread) +void CompositorParent::DestroyThread() { - MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet."); - - if (NS_IsMainThread()) { - DestroyCompositorMap(); - ReleaseImageBridgeParentSingleton(); - delete aCompositorThread; - } else { - sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&CompositorThreadHolder::DestroyCompositorThread, aCompositorThread)); - } -} - -static Thread* CompositorThread() { - return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr; -} - -static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie) -{ - aNowReadyToDie->Release(); -} - -static void SetThreadPriority() -{ - hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); -} - -void CompositorParent::StartUpCompositorThread() -{ - MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); - MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); - - sCompositorThreadHolder = new CompositorThreadHolder(); -} - -void CompositorParent::ShutDownCompositorThreadWhenCompositorParentsGone() -{ - MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); - MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!"); - - sCompositorThreadHolder->WaitForCPCPs(); - sCompositorThreadHolder = nullptr; + NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); + ReleaseCompositorThread(); } MessageLoop* CompositorParent::CompositorLoop() { - return CompositorThread() ? CompositorThread()->message_loop() : nullptr; + return sCompositorThread ? sCompositorThread->message_loop() : nullptr; } CompositorParent::CompositorParent(nsIWidget* aWidget, @@ -282,10 +175,9 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, , mResumeCompositionMonitor("ResumeCompositionMonitor") , mOverrideComposeReadiness(false) , mForceCompositionTask(nullptr) - , mCompositorThreadHolder(sCompositorThreadHolder) { - MOZ_ASSERT(CompositorThread(), - "The compositor thread must be Initialized before instanciating a CompositorParent."); + MOZ_ASSERT(sCompositorThread != nullptr, + "The compositor thread must be Initialized before instanciating a CmpositorParent."); MOZ_COUNT_CTOR(CompositorParent); mCompositorID = 0; // FIXME: This holds on the the fact that right now the only thing that @@ -300,12 +192,13 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, sIndirectLayerTrees[mRootLayerTreeID].mParent = this; mApzcTreeManager = new APZCTreeManager(); + ++sCompositorThreadRefCount; } bool CompositorParent::IsInCompositorThread() { - return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId(); + return sCompositorThread && sCompositorThread->thread_id() == PlatformThread::CurrentId(); } uint64_t @@ -317,6 +210,8 @@ CompositorParent::RootLayerTreeId() CompositorParent::~CompositorParent() { MOZ_COUNT_DTOR(CompositorParent); + + ReleaseCompositorThread(); } void @@ -1026,6 +921,27 @@ CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor) return true; } + +typedef map CompositorMap; +static CompositorMap* sCompositorMap; + +void CompositorParent::CreateCompositorMap() +{ + if (sCompositorMap == nullptr) { + sCompositorMap = new CompositorMap; + } +} + +void CompositorParent::DestroyCompositorMap() +{ + if (sCompositorMap != nullptr) { + NS_ASSERTION(sCompositorMap->empty(), + "The Compositor map should be empty when destroyed>"); + delete sCompositorMap; + sCompositorMap = nullptr; + } +} + CompositorParent* CompositorParent::GetCompositor(uint64_t id) { CompositorMap::iterator it = sCompositorMap->find(id); @@ -1228,24 +1144,6 @@ private: Transport* mTransport; // Child side's process Id. base::ProcessId mChildProcessId; - - struct ScopedCompositorThreadReference - { - ScopedCompositorThreadReference() - { - MOZ_ASSERT(sCompositorThreadHolder); - sCompositorThreadHolder->AddCPCPReference(); - } - - ~ScopedCompositorThreadReference() - { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ASSERT(sCompositorThreadHolder); - sCompositorThreadHolder->ReleaseCPCPReference(); - } - }; - - ScopedCompositorThreadReference mCompositorThreadReference; }; void @@ -1277,8 +1175,6 @@ OpenCompositor(CrossProcessCompositorParent* aCompositor, /*static*/ PCompositorParent* CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess) { - gfxPlatform::InitLayersIPC(); - nsRefPtr cpcp = new CrossProcessCompositorParent(aTransport, aOtherProcess); ProcessHandle handle; @@ -1510,14 +1406,15 @@ CrossProcessCompositorParent::DeferredDestroy() CrossProcessCompositorParent* self; mSelfRef.forget(&self); - MOZ_ASSERT(XRE_GetIOMessageLoop()); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - NewRunnableMethod(self, &CrossProcessCompositorParent::Release)); + nsCOMPtr runnable = + NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); } CrossProcessCompositorParent::~CrossProcessCompositorParent() { - delete mTransport; + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, + new DeleteTask(mTransport)); } IToplevelProtocol* diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index c4189913edb9..de41299ef887 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -63,8 +63,6 @@ private: uint64_t mLayersId; }; -class CompositorThreadHolder; - class CompositorParent : public PCompositorParent, public ShadowLayersManager { @@ -165,15 +163,12 @@ public: /** * Creates the compositor thread and the global compositor map. */ - static void StartUpCompositorThread(); + static void StartUp(); /** - * Drops the static reference to the compositor thread holder, - * and wait for CrossProcessCompositorParent's to be gone, - * allowing the compositor thread shutdown to occur - * as soon as CompositorParent's will be gone. + * Destroys the compositor thread and the global compositor map. */ - static void ShutDownCompositorThreadWhenCompositorParentsGone(); + static void ShutDown(); /** * Allocate an ID that can be used to refer to a layer tree and @@ -264,6 +259,36 @@ protected: void ForceComposition(); void CancelCurrentCompositeTask(); + /** + * Creates a global map referencing each compositor by ID. + * + * This map is used by the ImageBridge protocol to trigger + * compositions without having to keep references to the + * compositor + */ + static void CreateCompositorMap(); + static void DestroyCompositorMap(); + + /** + * Creates the compositor thread. + * + * All compositors live on the same thread. + * The thread is not lazily created on first access to avoid dealing with + * thread safety. Therefore it's best to create and destroy the thread when + * we know we areb't using it (So creating/destroying along with gfxPlatform + * looks like a good place). + */ + static bool CreateThread(); + + /** + * Destroys the compositor thread. + * + * It is safe to call this fucntion more than once, although the second call + * will have no effect. + * This function is not thread-safe. + */ + static void DestroyThread(); + /** * Add a compositor to the global compositor map. */ @@ -311,8 +336,6 @@ protected: nsRefPtr mApzcTreeManager; - const nsRefPtr mCompositorThreadHolder; - DISALLOW_EVIL_CONSTRUCTORS(CompositorParent); }; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 3d1a24399c07..757e0390295c 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -512,7 +512,7 @@ gfxPlatform::InitLayersIPC() if (UsesOffMainThreadCompositing() && XRE_GetProcessType() == GeckoProcessType_Default) { - mozilla::layers::CompositorParent::StartUpCompositorThread(); + mozilla::layers::CompositorParent::StartUp(); if (gfxPrefs::AsyncVideoEnabled()) { mozilla::layers::ImageBridgeChild::StartUp(); } @@ -540,7 +540,7 @@ gfxPlatform::ShutdownLayersIPC() layers::SharedBufferManagerChild::ShutDown(); #endif - layers::CompositorParent::ShutDownCompositorThreadWhenCompositorParentsGone(); + layers::CompositorParent::ShutDown(); } } diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 05f6647a41bb..5e7f997e0ebe 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -799,17 +799,17 @@ ShutdownXPCOM(nsIServiceManager* servMgr) } } - // This must happen after the shutdown of media and widgets, which - // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. NS_ProcessPendingEvents(thread); - gfxPlatform::ShutdownLayersIPC(); - mozilla::scache::StartupCache::DeleteSingleton(); if (observerService) (void) observerService-> NotifyObservers(nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, nullptr); + // This must happen after the shutdown of media and widgets, which + // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. + gfxPlatform::ShutdownLayersIPC(); + gXPCOMThreadsShutDown = true; NS_ProcessPendingEvents(thread); From de07b6927f8ca534bb86177ed9bb5607bf5fca8e Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 16 Jun 2014 22:34:26 -0400 Subject: [PATCH 47/64] Bug 1025906 - Include intrin.h in jemalloc.c; r=glandium This fixes a linking error with clang-cl. --- memory/mozjemalloc/jemalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/memory/mozjemalloc/jemalloc.c b/memory/mozjemalloc/jemalloc.c index 469b2f3ae767..cc51be455a7c 100644 --- a/memory/mozjemalloc/jemalloc.c +++ b/memory/mozjemalloc/jemalloc.c @@ -247,6 +247,7 @@ #define __crtInitCritSecAndSpinCount InitializeCriticalSectionAndSpinCount #include #include +#include #pragma warning( disable: 4267 4996 4146 ) From f2dcba3d011853ea01f257a201230ef01da11e7e Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 16 Jun 2014 22:36:24 -0400 Subject: [PATCH 48/64] Bug 1025918 - Add support for the .cxx extension to mozbuild. r=ted --- config/rules.mk | 14 ++++++++++++-- python/mozbuild/mozbuild/frontend/emitter.py | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/config/rules.mk b/config/rules.mk index b7503a84122a..b958cccefe71 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1024,6 +1024,10 @@ $(filter %.s,$(CPPSRCS:%.cc=%.s)): %.s: %.cc $(call mkdir_deps,$(MDDEPDIR)) $(REPORT_BUILD) $(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS) +$(filter %.s,$(CPPSRCS:%.cxx=%.s)): %.s: %.cpp $(call mkdir_deps,$(MDDEPDIR)) + $(REPORT_BUILD) + $(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS) + $(filter %.s,$(CSRCS:%.c=%.s)): %.s: %.c $(call mkdir_deps,$(MDDEPDIR)) $(REPORT_BUILD) $(CC) -S $(COMPILE_CFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS) @@ -1039,6 +1043,7 @@ ifneq (,$(filter %.i,$(MAKECMDGOALS))) _group_srcs = $(sort $(patsubst %.$1,%.i,$(filter %.$1,$2 $(notdir $2)))) _PREPROCESSED_CPP_FILES := $(call _group_srcs,cpp,$(CPPSRCS)) _PREPROCESSED_CC_FILES := $(call _group_srcs,cc,$(CPPSRCS)) +_PREPROCESSED_CXX_FILES := $(call _group_srcs,cxx,$(CPPSRCS)) _PREPROCESSED_C_FILES := $(call _group_srcs,c,$(CSRCS)) _PREPROCESSED_CMM_FILES := $(call _group_srcs,mm,$(CMMSRCS)) @@ -1048,7 +1053,7 @@ VPATH += $(addprefix $(srcdir)/,$(sort $(dir $(CPPSRCS) $(CSRCS) $(CMMSRCS)))) # Make preprocessed files PHONY so they are always executed, since they are # manual targets and we don't necessarily write to $@. -.PHONY: $(_PREPROCESSED_CPP_FILES) $(_PREPROCESSED_CC_FILES) $(_PREPROCESSED_C_FILES) $(_PREPROCESSED_CMM_FILES) +.PHONY: $(_PREPROCESSED_CPP_FILES) $(_PREPROCESSED_CC_FILES) $(_PREPROCESSED_CXX_FILES) $(_PREPROCESSED_C_FILES) $(_PREPROCESSED_CMM_FILES) $(_PREPROCESSED_CPP_FILES): %.i: %.cpp $(call mkdir_deps,$(MDDEPDIR)) $(REPORT_BUILD) @@ -1060,6 +1065,11 @@ $(_PREPROCESSED_CC_FILES): %.i: %.cc $(call mkdir_deps,$(MDDEPDIR)) $(addprefix $(MKDIR) -p ,$(filter-out .,$(@D))) $(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS) +$(_PREPROCESSED_CXX_FILES): %.i: %.cxx $(call mkdir_deps,$(MDDEPDIR)) + $(REPORT_BUILD) + $(addprefix $(MKDIR) -p ,$(filter-out .,$(@D))) + $(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS) + $(_PREPROCESSED_C_FILES): %.i: %.c $(call mkdir_deps,$(MDDEPDIR)) $(REPORT_BUILD) $(addprefix $(MKDIR) -p ,$(filter-out .,$(@D))) @@ -1078,7 +1088,7 @@ PP_UNIFIED ?= 1 # infinite loop if the filename doesn't exist in the unified source files. ifndef PP_REINVOKE -MATCH_cpp = \(cpp\|cc\) +MATCH_cpp = \(cpp\|cc|cxx\) UPPER_c = C UPPER_cpp = CPP UPPER_mm = CMM diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index eb60dca362b7..6bc8106fdf1d 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -276,6 +276,7 @@ class TreeMetadataEmitter(LoggingMixin): '.mm': 'CMMSRCS', '.cc': 'CPPSRCS', '.cpp': 'CPPSRCS', + '.cxx': 'CPPSRCS', '.S': 'SSRCS', }, HOST_SOURCES={ @@ -283,12 +284,14 @@ class TreeMetadataEmitter(LoggingMixin): '.mm': 'HOST_CMMSRCS', '.cc': 'HOST_CPPSRCS', '.cpp': 'HOST_CPPSRCS', + '.cxx': 'HOST_CPPSRCS', }, UNIFIED_SOURCES={ '.c': 'UNIFIED_CSRCS', '.mm': 'UNIFIED_CMMSRCS', '.cc': 'UNIFIED_CPPSRCS', '.cpp': 'UNIFIED_CPPSRCS', + '.cxx': 'UNIFIED_CPPSRCS', } ) varmap.update(dict(('GENERATED_%s' % k, v) for k, v in varmap.items() From ddc9fe103df78839a231cc370f7d507483390d87 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 2 Jun 2014 18:41:00 -0400 Subject: [PATCH 49/64] Bug 1015547 - Prefer arc4random to generate UUIDs on BSDs. r=vlad, r=glandium --- configure.in | 2 +- xpcom/base/nsUUIDGenerator.cpp | 10 +++++----- xpcom/base/nsUUIDGenerator.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/configure.in b/configure.in index c7c400411247..98939cdc1e9a 100644 --- a/configure.in +++ b/configure.in @@ -2928,7 +2928,7 @@ dnl Checks for library functions. dnl ======================================================== AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP -AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r) +AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r arc4random) dnl check for clock_gettime(), the CLOCK_MONOTONIC clock AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), diff --git a/xpcom/base/nsUUIDGenerator.cpp b/xpcom/base/nsUUIDGenerator.cpp index 06873446d51a..28cf6985cff1 100644 --- a/xpcom/base/nsUUIDGenerator.cpp +++ b/xpcom/base/nsUUIDGenerator.cpp @@ -35,7 +35,7 @@ nsUUIDGenerator::Init() // We're a service, so we're guaranteed that Init() is not going // to be reentered while we're inside Init(). -#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(ANDROID) +#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM) /* initialize random number generator using NSPR random noise */ unsigned int seed; @@ -72,7 +72,7 @@ nsUUIDGenerator::Init() } #endif -#endif /* non XP_WIN and non XP_MACOSX */ +#endif /* non XP_WIN and non XP_MACOSX and non ARC4RANDOM */ return NS_OK; } @@ -122,13 +122,13 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) * back to it; instead, we use the value returned when we called * initstate, since older glibc's have broken setstate() return values */ -#ifndef ANDROID +#ifndef HAVE_ARC4RANDOM setstate(mState); #endif size_t bytesLeft = sizeof(nsID); while (bytesLeft > 0) { -#ifdef ANDROID +#ifdef HAVE_ARC4RANDOM long rval = arc4random(); const size_t mRBytes = 4; #else @@ -159,7 +159,7 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) aId->m3[0] &= 0x3f; aId->m3[0] |= 0x80; -#ifndef ANDROID +#ifndef HAVE_ARC4RANDOM /* Restore the previous RNG state */ setstate(mSavedState); #endif diff --git a/xpcom/base/nsUUIDGenerator.h b/xpcom/base/nsUUIDGenerator.h index 6a24212abf66..68ed6f2b954f 100644 --- a/xpcom/base/nsUUIDGenerator.h +++ b/xpcom/base/nsUUIDGenerator.h @@ -29,7 +29,7 @@ private: protected: mozilla::Mutex mLock; -#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(ANDROID) +#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM) char mState[128]; char* mSavedState; uint8_t mRBytes; From 1d8a86d41bf92a772ce0563ef29c3476cc318382 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 2 Jun 2014 18:42:00 -0400 Subject: [PATCH 50/64] Bug 1015547 - Fill |struct nsID| via arc4random_buf if available on Android and BSDs. r=vlad, r=glandium --- configure.in | 2 +- xpcom/base/nsUUIDGenerator.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 98939cdc1e9a..262eadc2d608 100644 --- a/configure.in +++ b/configure.in @@ -2928,7 +2928,7 @@ dnl Checks for library functions. dnl ======================================================== AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP -AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r arc4random) +AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r arc4random arc4random_buf) dnl check for clock_gettime(), the CLOCK_MONOTONIC clock AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), diff --git a/xpcom/base/nsUUIDGenerator.cpp b/xpcom/base/nsUUIDGenerator.cpp index 28cf6985cff1..516210ed61fb 100644 --- a/xpcom/base/nsUUIDGenerator.cpp +++ b/xpcom/base/nsUUIDGenerator.cpp @@ -16,6 +16,10 @@ #include "nsUUIDGenerator.h" +#ifdef ANDROID +extern "C" NS_EXPORT void arc4random_buf(void *, size_t); +#endif + using namespace mozilla; NS_IMPL_ISUPPORTS(nsUUIDGenerator, nsIUUIDGenerator) @@ -126,6 +130,9 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) setstate(mState); #endif +#ifdef HAVE_ARC4RANDOM_BUF + arc4random_buf(aId, sizeof(nsID)); +#else /* HAVE_ARC4RANDOM_BUF */ size_t bytesLeft = sizeof(nsID); while (bytesLeft > 0) { #ifdef HAVE_ARC4RANDOM @@ -150,6 +157,7 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) bytesLeft -= toWrite; } +#endif /* HAVE_ARC4RANDOM_BUF */ /* Put in the version */ aId->m2 &= 0x0fff; From 60c42c6d30a9d0b6c0c8ac46bd3cc00e9c7d0c31 Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Fri, 6 Jun 2014 16:19:29 +1200 Subject: [PATCH 51/64] Bug 1020679 - Fix MP4 demuxer duration. r=cpearce --- .../media/libstagefright/MPEG4Extractor.cpp | 22 ++++++++++++++++++- .../media/libstagefright/SampleIterator.cpp | 12 ++++++++++ .../av/media/libstagefright/SampleTable.cpp | 5 +++++ .../libstagefright/include/SampleIterator.h | 2 ++ .../libstagefright/include/SampleTable.h | 1 + 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp index 7bed94dcad76..379a5bf17f57 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp @@ -2774,6 +2774,14 @@ status_t MPEG4Source::parseTrackFragmentHeader(off64_t offset, off64_t size) { mTrackFragmentHeaderInfo.mFlags = flags; mTrackFragmentHeaderInfo.mTrackID = mLastParsedTrackId; + + mTrackFragmentHeaderInfo.mBaseDataOffset = 0; + mTrackFragmentHeaderInfo.mSampleDescriptionIndex = 0; + mTrackFragmentHeaderInfo.mDefaultSampleDuration = 0; + mTrackFragmentHeaderInfo.mDefaultSampleSize = 0; + mTrackFragmentHeaderInfo.mDefaultSampleFlags = 0; + mTrackFragmentHeaderInfo.mDataOffset = 0; + offset += 8; size -= 8; @@ -3130,6 +3138,7 @@ status_t MPEG4Source::read( off64_t offset; size_t size; uint32_t cts; + uint32_t duration; bool isSyncSample; bool newBuffer = false; if (mBuffer == NULL) { @@ -3137,7 +3146,8 @@ status_t MPEG4Source::read( status_t err = mSampleTable->getMetaDataForSample( - mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample); + mCurrentSampleIndex, &offset, &size, &cts, &duration, + &isSyncSample); if (err != OK) { return err; @@ -3169,6 +3179,8 @@ status_t MPEG4Source::read( mBuffer->meta_data()->setInt64(kKey64BitFileOffset, offset); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)duration * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -3292,6 +3304,8 @@ status_t MPEG4Source::read( mBuffer->meta_data()->setInt64(kKey64BitFileOffset, offset); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)duration * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -3365,6 +3379,7 @@ status_t MPEG4Source::fragmentedRead( off64_t offset = 0; size_t size; uint32_t cts = 0; + uint32_t duration = 0; bool isSyncSample = false; bool newBuffer = false; if (mBuffer == NULL) { @@ -3399,6 +3414,7 @@ status_t MPEG4Source::fragmentedRead( offset = smpl->offset; size = smpl->size; cts = mCurrentTime; + duration = smpl->duration; mCurrentTime += smpl->duration; isSyncSample = (mCurrentSampleIndex == 0); // XXX @@ -3443,6 +3459,8 @@ status_t MPEG4Source::fragmentedRead( mBuffer->set_range(0, size); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)duration * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -3566,6 +3584,8 @@ status_t MPEG4Source::fragmentedRead( mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); + mBuffer->meta_data()->setInt64( + kKeyDuration, ((int64_t)duration * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp index 767393a13c3d..c374eaef0e8b 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp @@ -139,6 +139,18 @@ status_t SampleIterator::seekTo(uint32_t sampleIndex) { return err; } + if (sampleIndex + 1 == mTable->mNumSampleSizes) { + mCurrentSampleDuration = 0; + } + else { + uint32_t nextSampleTime; + if ((err = findSampleTime(sampleIndex + 1, &nextSampleTime)) != OK ) { + ALOGE("findSampleTime return error"); + return err; + } + mCurrentSampleDuration = nextSampleTime - mCurrentSampleTime; + } + mCurrentSampleIndex = sampleIndex; mInitialized = true; diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp index d2099dff110a..4b185326e9fb 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp @@ -779,6 +779,7 @@ status_t SampleTable::getMetaDataForSample( off64_t *offset, size_t *size, uint32_t *compositionTime, + uint32_t *duration, bool *isSyncSample) { Mutex::Autolock autoLock(mLock); @@ -799,6 +800,10 @@ status_t SampleTable::getMetaDataForSample( *compositionTime = mSampleIterator->getSampleTime(); } + if (duration) { + *duration = mSampleIterator->getSampleDuration(); + } + if (isSyncSample) { *isSyncSample = false; if (mSyncSampleOffset < 0) { diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleIterator.h b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleIterator.h index a4d52feba0c7..7e8526d4a844 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleIterator.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleIterator.h @@ -33,6 +33,7 @@ struct SampleIterator { off64_t getSampleOffset() const { return mCurrentSampleOffset; } size_t getSampleSize() const { return mCurrentSampleSize; } uint32_t getSampleTime() const { return mCurrentSampleTime; } + uint32_t getSampleDuration() const { return mCurrentSampleDuration; } status_t getSampleSizeDirect( uint32_t sampleIndex, size_t *size); @@ -64,6 +65,7 @@ private: off64_t mCurrentSampleOffset; size_t mCurrentSampleSize; uint32_t mCurrentSampleTime; + uint32_t mCurrentSampleDuration; void reset(); status_t findChunkRange(uint32_t sampleIndex); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h index 2a8207769dd6..7434c4e9b56a 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h @@ -66,6 +66,7 @@ public: off64_t *offset, size_t *size, uint32_t *compositionTime, + uint32_t *duration = NULL, bool *isSyncSample = NULL); enum { From 37a9aa9902eb3d12c0e78e1a0304c20608b59fd5 Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Tue, 17 Jun 2014 13:52:03 +1200 Subject: [PATCH 52/64] Bug 1020679 - Guard against MP4 /0 for timescale. r=cpearce --- media/libstagefright/binding/mp4_demuxer.cpp | 3 ++- .../media/libstagefright/MPEG4Extractor.cpp | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/binding/mp4_demuxer.cpp b/media/libstagefright/binding/mp4_demuxer.cpp index bc32dd0fab03..f55fc7fd3a60 100644 --- a/media/libstagefright/binding/mp4_demuxer.cpp +++ b/media/libstagefright/binding/mp4_demuxer.cpp @@ -88,8 +88,9 @@ MP4Demuxer::Init() sp metaData = e->getTrackMetaData(i); const char* mimeType; - if (!metaData->findCString(kKeyMIMEType, &mimeType)) + if (metaData == nullptr || !metaData->findCString(kKeyMIMEType, &mimeType)) { continue; + } if (!mPrivate->mAudio.get() && !strncmp(mimeType, "audio/", 6)) { mPrivate->mAudio = e->getTrack(i); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp index 379a5bf17f57..cc600f698d9c 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp @@ -449,6 +449,9 @@ sp MPEG4Extractor::getTrackMetaData( && track->sampleTable->getMetaDataForSample( sampleIndex, NULL /* offset */, NULL /* size */, &sampleTime) == OK) { + if (!track->timescale) { + return NULL; + } track->meta->setInt64( kKeyThumbnailTime, ((int64_t)sampleTime * 1000000) / track->timescale); @@ -1137,6 +1140,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { duration = ntohl(duration32); } } + if (!mLastTrack->timescale) { + return ERROR_MALFORMED; + } mLastTrack->meta->setInt64( kKeyDuration, (duration * 1000000) / mLastTrack->timescale); @@ -1807,6 +1813,9 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { if (!mDataSource->getUInt32(offset + 8, &timeScale)) { return ERROR_MALFORMED; } + if (!timeScale) { + return ERROR_MALFORMED; + } ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale); uint64_t earliestPresentationTime; @@ -3111,6 +3120,9 @@ status_t MPEG4Source::read( } if (mode == ReadOptions::SEEK_CLOSEST) { + if (!mTimescale) { + return ERROR_MALFORMED; + } targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; } @@ -3177,6 +3189,9 @@ status_t MPEG4Source::read( mBuffer->set_range(0, size); mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64(kKey64BitFileOffset, offset); + if (!mTimescale) { + return ERROR_MALFORMED; + } mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); mBuffer->meta_data()->setInt64( @@ -3302,6 +3317,9 @@ status_t MPEG4Source::read( mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64(kKey64BitFileOffset, offset); + if (!mTimescale) { + return ERROR_MALFORMED; + } mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); mBuffer->meta_data()->setInt64( @@ -3457,6 +3475,9 @@ status_t MPEG4Source::fragmentedRead( CHECK(mBuffer != NULL); mBuffer->set_range(0, size); + if (!mTimescale) { + return ERROR_MALFORMED; + } mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); mBuffer->meta_data()->setInt64( @@ -3582,6 +3603,9 @@ status_t MPEG4Source::fragmentedRead( mBuffer->set_range(0, dstOffset); } + if (!mTimescale) { + return ERROR_MALFORMED; + } mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)cts * 1000000) / mTimescale); mBuffer->meta_data()->setInt64( From 01be5ccc3b479b268723fa179aa649c041d08a6b Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Tue, 17 Jun 2014 13:52:01 +1200 Subject: [PATCH 53/64] Bug 1020679 - Crash test for timescale /0. r=cpearce --- content/media/test/crashtests/0-timescale.html | 12 ++++++++++++ content/media/test/crashtests/0-timescale.mp4 | Bin 0 -> 14718 bytes content/media/test/crashtests/crashtests.list | 1 + 3 files changed, 13 insertions(+) create mode 100644 content/media/test/crashtests/0-timescale.html create mode 100644 content/media/test/crashtests/0-timescale.mp4 diff --git a/content/media/test/crashtests/0-timescale.html b/content/media/test/crashtests/0-timescale.html new file mode 100644 index 000000000000..72cb843d6e4f --- /dev/null +++ b/content/media/test/crashtests/0-timescale.html @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/content/media/test/crashtests/0-timescale.mp4 b/content/media/test/crashtests/0-timescale.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..32df5dc5a559a78bb28c76de5517862b987a1c7e GIT binary patch literal 14718 zcmZvD1yq~evS@I3_ds!XcWH5V4+PiZ?#11mQXGmEDehJrinq8s6sO1w|2gO0`|f+Q z*6i`wvt=b;@~r^?064W!8^{7QcXF`+a&U73T{yY;1%LuPyypC1 zeuzPq72?3Aq$=})g&QcLEd}ueTbM%(Qclj^_7;|IKu&gcE*4I9j<+<{Zf?$kY;2yM zo~#}=U<)UEkRz*;ixu13EUeaU4)zcqCucVsCr4L7pgG74WG=!1bg{4$;R1p!%*BL^hH#0BJNWg)`B3pBTOadH5eKtefyZY~z~_BO5%j^B$PZ0-hO z%s)DautQ1!fqk4DEkrmum^nCrmLOL*6K7XD8|OEVe1yF7!omr3vvz?* zKoW5R?VX(LK-Lh+l@FaE0uanTfMEgtq~Ua6)(x807r6 z3^Nlm8<6YUBsMM<|18YY!p6$l%?x65a<*_Zv2t>TSpTJThJ@N#ctdiFaPqMKn>BH; zafFCKS91$T3v+ij5pMRkGF?D#d+K80Y7Gf@F*o_I<-XZn%tg#yEP)PYkd1v?7DN!? zCrg zpL4u6K<@J+O#Qu`9r69C2$=0U**GiWQFJ9g>7L5p3Tu zKkB9Ubs9$wPYDWU3%CujfhRU;MbS{1v+cHyL63E26;O+G?amJ(=)mky4TaX{xfVSS zb!GZJpG|oz!6ls%HjRFwHa7x=E&Mu~bs}wt(f%g?qJ&dZIJ`%4r@PS$9zlL&5|?@O zlJHJ{zQP1I+aK_Bc~U`9&2hE_a9S;nqR}d}i<4Z1gBwymN`9Z&>rf}EfNLZ@wzcig z?DTpTOI`pvH&4HvP{4~Rs_c(9T4d}F-xxE;_@IO|u2V#<2(97b2w!BqZ?dUWE#Ag`c}Xe!HoDKK)jLV^mwt26 zn^?$SMW3L`7-eO8^hrj&FG9(?Wn7Po2v8FrT=6N@}Nd#ASv-=ql& ze)>(zc)x>>)z-V?&^bNiT%^4AS-d+sm~ZO*E@VjapD6XPMgyC9@lZ{Rt`!m$*qst9 zh16BMEIrc{?w!VFfftVZf!?oztWA-Dw^!`R<$Sf)47V9eo(diYuNa?KgB)>d?BT;B z?G4MPwhJUl92mWUX|+L;>A&oTlB5}n%zTD4UP^9DTP|zEZ2x-d6YW+wbAHfT__UBb zOMCrE&R`vZT9hJD&|!(bvz^HEJfM&}HaI+eYFP5_ra=??_n0gbwSo6hXHKjR-?66ImDY2Qw%4L8Rw*d-VCvL)S9E9dggEtNj_D&L+><<1szfy@ zSOZT&AIFPtM|?3a4HI)%8-71qY7dW^)!t6OtZUEtP8qjGO`<)2L{{fO_y#Mb=OzVE zin}OsD*HsOLPmQxK%A1M`&SB!1%qUeoSFnmJtyo?W}Wmo-0^d|dk|A!yO3+VeLHH< zheH*j8$w5*F5KQ!9qh;qnz(>-THRr%wUj@zBT*%@E%_}}v6qt_%5Tt`UfjApm+c)8 zA7$K7Se+E~FD67At?Z)lD7UP8fk$CZfU#&*| zOtE^vlw)lZsrL%A*w~t$S4&>_nN@UZ-fmz4%44?+t2S}bBW7b738fU?&N){!&7)6Vns?rS3T-N3@x*Duo3#>69&t z{Hg&vqqG;OCR;S!*zk*;szbt3&p8IZd?AykBF^)hk{?-dZ7KLjBqEA=Q=;eeHCt0s zeOv6bq$^f#5f$dAwrr~^(#>&K&vHK0G2$F}`cseJ!dMa@E6zs(u5*gnKK?1BxMNZD z71Bz2M}_yhE4W37*Ok-yWJ?bI&*A$jF0JoAd3Ybw7;bc+A9`^!WhM5%F>Yn$7KzEk z5r1}Py)YQIJ)iq~Y`@9BjGVLiSoKw9=xdnYf z_B|JC{jHdpGSJ_jM}L%h!ei5>6=VsS!g30oqBI}V&3&JA?yZiZJfNH$Ylo347Mu4HOHkNy-UWk$A~2R!x_Dv zZlpxYbgK;0gTLT}+9=C87>RD3IKf>rv1^{A_LF}?OnzBJJHNdi;T{zhZX_M;WlWZvz64AW;g6L8|CBKDKbug*4jE}q zdrBXVv>HP)=4UO~Z+{9A=L@T*5yjrgqjZYr+q==v6_JHCGh`J-{|RG6+k1|h2Q$UETNtD>a*6|JKXA*LnWJLGi=p=^@& z9?`lSTJCCjeKtZAK4Fw<krsrP(XD0)Pyz*klp)OVq`vDhCh)nU}CPVfq` zw&!w5_yL3hGiL=jN=qpe+_ML|iNTXtx-II8KdzF=>>wh+)c)>tX z*wR6J*r-~|81Z+~y=&#_*LJW7^1AP4s*@72HR(9lcRlBg?K00}{`&W6?~6<9X^2lR zup$F5X&)^&e|4}=R1HR#&_Dzme$qG7ErF)y^|LJIG+BDF zt6}58P^8QPEYg;)vI+Y=>q%U~vTrVy=SA~!zqYE{QmAnSF>IZ}xnLBda;NnthN-VZ zhB5CH9U7j?p(AB`ucN$*EBER-fZqNx5mL-N1XfjbmOZYC7Y|P2`rQHM0<9dy2!lNd z`s?($qRcqid`!jY1L;5lG)DE`Ni+l1x2|I4#-wydC&F`uTFCsH&>K5iV;Dh+oUfJK zl+a@8Dcoe&f9;b&=XulC3o#mNugH&J+BHk~N>L^q^&ixJ^J)Fh!#BQD)Y)F60(Zf1?G{uIpb7w%t05+}8L2FLC}Qba?6!$)yVh_|#M90*VHvRZ2Oy2L|? z87Eubw`-9sx4z~72db-*KO(J5cWcZINmOn(*1u&<0~LAZ5><#iPD^o2cJnuY#Sq4= zyT~#1ba#MHHnhu#pyEdxP_mohNuG(j_ufv^ZBlNvb}2H5IGJHfnz~&%oZMDCmE(DS zT7EKRvCn9%+*dmWzmv(!#(HQI%mu|j&4l#uDsM%mU0OcikGrU`x4W%*;hc5yIEiPn ze19K_PiEAbL0Gvy`Yar#PlMR4qm4*WjG;BdRL`5MZq-k6uJTa!6B`qo4p7=lK!2Q2 zFoyN1v5exp6I##=CAxW2d8F^FD8k(mVQ()dMtxskMV+=;=9kDOv=JH{ArY7(uH{7E zfR4~9G2T-6Y3E_6FaB|ZIbVIPtEz(dK4!U;D&KySRF|jT)DS@{fZFc?=5)hfb z=HBvd|9I|e7fu?Am|8pU$Gc(@YW|H~UFWTnsQR`XBinT)6deC<-c9Z?WTQVX`DxKk z)b^)v{UyzE!`;>mH9^H@GsE%us8ksb3jF~EMSkxnVT9p29zK*lFt*$ZWShqdeZlfO zVZjui*ff0TCF_GFTbUl~WO7_1H$9B$D)>4s?aYDDkt~&QxyY1f2$QkkFI2-J_}P+m z(-N7ZgREOE`HH{Ktg7gxkTxtXjVoirfFZ)zRiB!Cr9RcPq9`>aNg=ze;f1~V*h6Nq z-i^FCvuLTBG_kv^P>0smg!9jrehded;P5+-MbhP zK<(zzv)}*p3KeZ@+YY!pDf=+4q=x+&28+{l@6|owm9k(LIgsiYpa!3EHr#C+VOyr&Ye&j7LQmOLm?3Ja>xsZpNu_fsuWhUthp=PXMl~!Jg1>IEH(GsGY=t7y zwF`}Du9-LC1<7+0O-URLrlMaa57rC2=b_CpWKAPPYTr<9dC|pN8D>fDe=TiwFjV=K zu6>#-{_PH?pw^>nhv6#BUx9bIT zfwjnOBL0%5OYdZz0W#g(k;e!6Z7Dbg@j~BUWL0t$Yw%{wY3%vgC!pQ$-00h7J??)s zQ81vs>JcciN`I+wu0M%a#Rc9r48b?wNz-uEb~-4#OLSz}`hHg18b zBZcZ0ao3~6xH&#(hdJ1!;#R#KcA>!<{~W{wIu10SqKGS2c1mO?(v zW+SoV3e{=>CqhNBdif$Wu3jl;B@*GhQ6}g_Tur8lpn9>{(91_+5oI7xNCO+M=k5j7 z?biXHKZg`Vyx&$gi@_L8*B(2u?lObxY;Q<39n@&t>n3@YbYmpl=0=UPk(K5BgXi>2 zGTF66%6s>$;W@Fvw%8&5fQ(w+OY+g#{{HNe>QA&;sZQDl>lQGY{d_dDVjz(bPU`tP z*H36+AschqO=p;EEQXSQh^l^@_=lvU;Y4V-7wb4lCaZr;7w#I&+;x9dfr)hcIJ>_W zO_c@kVWhxoOTD$S%{H}L(JbGm+cO9ME+bpa*OLsVs(VkS6kN=8b&{+(-INemJODeb z1{bF$p3a!8!~0xYKR5S{Zz6r_3wMxowHoKCn?z3T@`B!N_-T0GXQOi@w9nQcW^X?k zosAZ-c2J2E3C)y6<&>6i+!x?@VRc8D-G(8@me>`q%i@|8^cLWO?*L6M7+mNQv&Q%r zMFa|IaAD8Wen(;c1Eavg&c3iGqS~R2jB$Tk1HD)H6^~qzYP{jmS=MA#k!XxUvwLy>n5{GyK>WY z8$TzHzSJ~ve_3oUAqj9-=k|+>IXjrI{%Ik`V9qP8TL&m}oK2a@tL(lEqhRtm<8@`( zA`ho>(*GW`q}gjj#YU^WjdDmZ&qV74-!>$}tl%e&kutqO+4>_ym7j zUkxlCx0i>8(&e;{P*R*XR|v@11(tvOp*)M_6;D_`Jw#xTQ*#!gtwR=4!ZD-x8sVnt z$y@Dqq@aK5xMy7{x2#@Dq{4;aGBU(`LC8G+S(q0_fJ%zh_ow+oD%fqx5XWV$qpBt7 z*n%@=WGuWw6V*lHJCm7@TT0j06CQl5=~zpKIFWO{KO4(8yIMpmk9sV;;I< z{AeOV8aa9`MoSTA489IO@CRRi6c>=E+zWD7QK^>P1mcN%6>`=-+a5umDRtpTZWhOR z?BYMJaL;h~=`}R|^rQVs4{l86FO~*V7;%C!mQFsrR$$6+zH<@N^4~W!i=+5!0{Vc& zT6TpA^~5=@TbC3(3RwKK%y`h-Gg}_AHT3j?)fKa{7qFy2p}?!AZgzRArAYWKuGaK` zvd@ozJaM7x>w83`V%G-^<<3@(isBTL)oy zBvjAcp%}EG2TzP~Z>La-?{5Mm9V&E!#_j%7tJ81&!4SoyniodfN|YJ%q392 z<R?4j9gePa{eDwZM#?q>ZGubAOl9vrB{xmqFpWPrB#Zb#hCee!)u zczuTT9wtU)`|iEK6<$VaVb>F?ADrdMvs9X$X#{=HUa_2CZ7sGtr+Wpm8+H#E(N&Mq zK{khi(%4kQW%va~4^2uO2du<%On&i`t+749cjRS~n2Z~jU9UCedJwKC`2N$pi7s>P zxLf7I7wYOyPr0ajm4!{4u=O;$i<4orr}&OFT`P%~K4|0O&laW~8M%Y@6=x48H|evk zUEjz;!PQZWX>ElrlKmbY$uA0W27}f#>PmHn^(cZ?r<)gfk_|=egUZZAIIZwsia9;l zh@S`*#IQbuT&Hr;caOd ze--wWujptF@$4*fYRWBmFk z>YuZO`*%clPRV)RYvxyP0`8Hqu-Tl~!V|-B4DBB;ej4r<%9TJje((AAle?4z+;n3R z2B&s-#{|Ctn?2>@{3o#k`x`eN9$`3rLk zpatzl%6DC6R;RXgE0qzmcrI1kIv2{n=G3vNKZMoX2d$nzJ{+BDy763X(&qql%DvG0qjEI-+~QS47dMtx1?FjJexS022U=SYptN+Mc*A;@8`@e=tM-8jpn zhe00@rU566k|QiEqw)T+%wdWE5D^aWHSkjoeJwyCghaaz7Fw< zZTY%JvDYzAO6!Fc7n|hqQD?YX-C9}5 zU4w+Z2xl`;t!AOc=+ou}&5t$4dhYLyyX=l+fmao^0%F>6Mn$s-(?G%x`u!(}R8<9x zN$^Y3xgSrvLhN6<6`dG2l?joFBZWn22n=){h3zHbkMRj;1o$~=;Qe^fZ`iprKGyv) zAb2hnYCW5?A;UJ(Un#5^it~+X1#WlTb2d`z6J~_!%N(|UbVgl9HvL5=Yltoh>$$5K zdQYUq<#2WBK$vBwhuiFN1k;@)z!Xy2B*6_-W7wuv!AE$>i|U26+A4Z}H4C0Ryw)RK|Awk0d zfgKZZGe5_~jF3l1=BqOTWhyo|+UqX8-1EIs;040q`50Eog=0-HqJTUa>#)*J14VsA zCDA54bWa#*X^|zOtxvbZFj|eY9m_gU)|-Df4Y+S&>iYD(SoS-s9q$cPb^Df4QA4m% z{h#lTFp82n=3lxIEaz>h_gxg7rQP7Bt)`i&kguc<9xoGuIsqf&JNSW~tVn0(?7xUe zH>I7?$`d}Ylzr-3W%|8P(A9W8@Gff3K6g!>w;yfxyMMDTey!M~)e8ZMKv6k7UnC1P z@{Qf2QQ|m@TC|#lf|a8q!rZks6W_so)vsDoS3f9z)8)iodo`2cyP=RRSg5XV!A!|s zoN*dL$q|<1typ<+mu9z0B!&xK!?MU9&$|6<>0-jRAJCPcnLk?aK>^3pw8C{qSCrJx=JbXE^DI)iY(KKE0@IH*45q!FIMl6}I(~9pita~v|0|zotmQHB5m{LpsfB5%MJVY()jpbQ)xr6@?tOE zSidCHe@$Z~{Ae3<^WMnWfus$hfrx^);x<9b|`pK@~w~uw3BN;k1A9$HaAN_d3 z6mz!qx9(Nbn1^Dt^!ioiy8_vq+H9RLCyD)X2-O!q=}QVcI1McXlPu9~C&JgndT$TK zf*v=Wm6HU5dT0)VRH1eazMTn2B78+VUuh=TW!Rv6axy(tXXzMJG6jF?EHTEfE`{WvpKLT{+jipr}ueHuQ{^wCj}GLrE9nA{58@$*l^!1Fv^ ztz8vIjIq83CP^^u0`GyVSy!`BjMQ#Sp_BI{=Y$@Z1L#+)C)_j7dt+1Q$wPCqq!|Vk z!R`~tFtaj+n(fTBrkvC_0<->@_u!_@t+4aCE3+08fE8?!8a*%zgaN}A4*poJj6lLZ)-~ zq#2`Y+B6BcVHcsK>xm3u4Q@U>bu8i!TjZ~u)P~Dy*wSB;;Na=iPb{UyOiWwNe>w5? zkxRq}iB7(WOf)&rV#ze7a`u;CvKduCMKjYwxxSyH{hYr@ zmW(UpPCP!%O&+b)pPFXPi}q2({WZ!eqC}wW8(5{s`_XQK7|EOiC#SqKu*fFHz+;*B zuGRMa`id3W6?DLgfKsalu9PvN!2?WQhd^s$1>6JAym1X#lBp8v`weO{ICEK)4F*s3 z^&;n{kHOM+F{?_wHsm8~!ko|ilh|mi{E6___%J$=jM-M%vJcFlik1;(&uW(dqkXIl z#-;NVw4e`l^8lS_MP1!2sOHuOc@q1rzs$+uSEfwf3f)CNCzO^raF3<}U$r($xb2=* z6xDu&QJVKY9%2nMb(5=8&zGU!EMu)Szl=25>;}hJ$}!+@GteGyx)G3SPYb92`YhQa z;%t^p6rUDNZF38XV~J4RW7Aas*0xdJFX2?pe_UF0EEA_vB@lD2u$Gj-M9`H@AHvX^6Z|NrZi#y7K6Q!tO3rRUVp$jSa7NL-yi+ z2}h<+^xuPLg9yd`!VfMj7i^$_DeRTB5qGE2h{o2@#S6m zqyW$e^bDM9wid=OmJ@E7ZO%x1apFd=YkCiF)Z)RGHmL8Fgw5hLhqqLS&uS=5+~{TB zjB?JLuLv#3b34Y4n%ZZo6rx>zMbKG!mH{xuq$E|Este=&4zhO=PEFSNc&sWws8GTj zjuJl_x1C_cL$h7h=`ua6&TE9Y{UX~eV7-RcD(S19EnCbkw+Hi3+2vt$*YVE`H=EL! zs{^PIxzpjYif365^M8Iv$^UYDe?6*j7as%mIXYL`iq%1t(Q4xb&k*4*oU5@aT#0|0 zwu1F(sa*Z(Y)dcb+5Vgn-lgLNz`LW#0wnk;#=`*agp#_1dueK&$<|>b2yp}}TCIqA z1b#61G(0hsb#J&Z&&8;=*YW}`eR_^#=s3REoBSy+k94E^Xxrx{ z6U)=%)RI}mXY?FKM0CpCl}hLm;?NxEYIgRiA>UO@aZob7Y44(OQ#xkRY0gEmqQ5F} zAZD+`ivAr$lc=p7NepfLUHOi(cD@ssKkN4~vMy&qHZC{QSL`=Iwm4^KR+6e20;jMi z-=Ny?VMw@5t@K@!UXQ)vlsgHS4Yt9DQ43@O`0f4Gn@YWXV;d;l<+|Wc8YF3#A?x`Y z-%DNQy9A)p%q`z#XwlO4SoYCn9BCT%i3=8*HLIvCQ>2uiiak>i&T+DO9e~8JKNzuI zX*Cpf7%}+q3Pk>;Z%B;E69b5iDzZ0z`hd`zFnfhIgPit?D{TvS(C){3-faPr*#&>n z37k#A{vMMpKT*{ZHz4!1hZH{)*Eq3&8biAR^ess7=Lz#dvQ_U2f9<#EP27!w8fgQu zDOlqLZBdQIa0*oRMv!kWdwI)r4q?lO~)i z%u%SDF8eRte`Jfy)Wky(E0?UCzky4tmBV0Cp;*T;M%dcFo@Lt+sn`;!HV&ihG1#5% z##~i;NbFil9kP5QWp~tn?)kCp%^sn5(>n6!A>GT+WaFBEac~(G{f=trguP11r#}-m zMZRotyQzDIk2!x{Bc<`yEH1=6y5uUOW}RSy@D>awMbPg_RJDg(eLlIjm`UeeU(m@B z+3octS`l1aCg^bafk8X&x=L7Z(U&^LREPPTGJ!lyew^Am`pSU@`)}y!@hi3BTJ?RT zTrApBA*D9TjP|xn*o&U$d=CO~S$~htsgqd%l+kO<4PTsenOrZ!bZ1H=4Lq^2hjsj{ zqwp;T8^-CB|F)4&JBliWb43}V#CN;zg~3imyrSJ7Zr)350s>Jbu-he(`wm`$41DZu&c{*vxW zR7c*qr5bU(oInNz+P`EZ+S0qKo+`lNsN!D#^mR(G3MzzKYx~@i6n0mB$Dkip+8#Ag zI{Jqs?$&it9GNV+(IRbXoZ!@>eylQ}?$GUpVh5VfHrlhGlc@lUoXyhMC~S%_ zm(Iko|MQ)p7MAhi=8i9~`Af&DG}cIX&uogrRV|vS?~PFqH3o)N4>Y{&A+dE-@v|N^ zt!t}t#01C zQAV5O(0MWeUhm$kzOw@4p#UVK5tL?a&il|-8T^g=-9I}AV|0r?onO~+Ji0Z>)2Tc; zuADTDo0K5HDy^$4+#txxWF=uYC)KGpELK=A>0J-8bhEoBNhD4^S1{EOpY2*}EMg_F z$J*RSs=CzNZ0pv4yQ|KQ_tDN;F4GSE5X;-?+&*DxJtqgfoX|v}Iaewj0`H@(mT)pS z%UXM54iM{NMs_=18_y(er`X0|uws%nl*2m+k_(Jr@(ZcH`ulAYwJAZkw#ckKeXR+z zlqB(Dw3`t#-!_^#JU{OXe>&cxFFvuB5Mgc{cJ$2fnF~t|JCBXn(WFQl+V9TPckLX+ z-pGB7XXAe0CtEQR-+V8o>ew$*>hUOMXmYQbQ1MdG)g-o^1E@#7INQ+&;o0f&3HTgM zJi?y_qqP8c0!vAO2}G03Kaf$*vT8?!NR3>ebmQx4nSRs`1_XfGD+vFharx@!oA|ZU zUcKWFz(#Z~=RKSrUL=M7%tD@y_g+!it*=~C*V5yA;DDjwKx%D@tJeex<_9}m#lcdB z-9{CEyaP@fq{`2s`>9F$3swgM9?hCX?s?yvar$?Pk}h)mw^VR*bC#`WyPr;o6Ivfz z>k0_a@gy?H7I$;B9V^lrvqy>|p*F-p z#(WVyty3RZsu^!Jl*HA)KV*RsT5{u5*t6lPwx)Wh9YqiGrZnW{~7nF@S!8DSyMn@dY*||1Y>{x&p)W_dz*Oi6Dg& zbkQR{@2MR1b6bXD)|tK5gh!>DH>BEZKK75`AA~k^cW!a5cD4QMN?<&3K3#@!-fwd2?X`shBQ8H=^C$OD}r!=E6=_b`{bTMa7rDIk!mdJ=O z-7q-9eOxjY9qwwzm@fM1%JO{^;R{Lw@tx@^zGv!%KZ6|82igz@HwMb#A$Lq{`;05} z`j$xs*T9m11MnyeW4}Z=5=#sJ!W{D%Sb=vx_=tc+%uDc&c|141fFYXl~;q^WTPq5ra%ve2jD|II00OQZ(c*i(|>KX0sN4B zYMuX-p5S9}qcLZ+(8khEqC=p>myJhxT@hRRt1?n2#2}fIj)0J*AtMt>ULB0*%pZ=Zn#nv#cyYpau{HL1!)1%d5G^9S<6$;TpqFWa-BL~! z%x`NCgV>ixq+g=ZzWE;6FFre5G(TE2^W`aO!(mY~8!?pMKz`!J z#RAKg?gY7ML@Nq9N0GXtV-*tQmKk(=EXf%$PzQRGl1?AeIRqSb<}?WDGi}P^kb2Si z0m{Hn4(~MOJwB5`;Jb+qwIvazWK`yI64_beZA+u#zFIvc!VA+Nm7LPE6qi z_E+#_c;dXO;UA*hPTUR*8Jm|*4i_5C+bGl)eRWK*!gVEiHp*ivmesFl#aq%P(|8vmt|9O zIvf9X#cre(zmovPY53cfhB*!uza!Zk4*YbEWAUhgj<2646-KFUFA65Z3w4%YZMOa- z$vx$O8|*$$&6R8Cb1#$lyf^HKU83Z5t4P!%f+Sn3*o>jkE$V>IcG*#Q}JCgl$?8Ns$qRwcZ)-NRL>@@k87tX@agKQe-hS)+^+l!#`x z5d&oWV!l@XWu=hIn?x`52%CRbA>n~WgNua%r)?2l=(0;AjPk7?EBnj}L@FsrZg6y^ z#;D|@zDz2LK`|Wl8}0X=#2l-P4&jBYa`bEQm2-1T$m^~>Xd@SHG-98c67knxA40Y9 z3YdndEXbelktYRIe_N%Es;Nc7bF&{?l~$?4kWlo)ak|ua&N^SeT%g@hZg0KIhF!nJ z>bFI>=WmN|c%-DR*05_5;c@u<;r&8Zb7Y#Nkv=t}-<|6nbaLpPJYy>5=#{vptD2xc zrOfhbc+6I)WrTZjgTeDL*88?*GLCJDk+{7mW)Y43nYx}2hYf&ZnSwR&1qym%>#Lh? zadbfm{!Lu@l$M+%yKa-Kv8jA(ID%PGBek;pxzCVF*pj$MP3>9TsFGOlXcgv%yJ*$} zG^Stx0BTYqo7!IC)tHUB%dEY3tw7sWfsye(itcy)Sxq{wW1;7mK#bAyVi=b4Q2G10 zyo#9+>7=w~&F)u)Z_hK@iW@u2^$3J9QeMGJDae0km8lN(8awJg0z`uQG%wDoCX$iQ z6Dt~Oqnvvr70Lloch^B!9Y+i_ZQ@zj4q}!$uYC$%IKCkGzk47 zO~+*#F;j;71Nt$`(BbdxDUw8^ZzsN*eq)K?`0?7kbLWZPiZa>Qpsb22B zAbvlWz?t9gQ>z9!__Ae!VRO)VwU~F-eQ$ayTfKxGP|4jE_+D$c2(jRq9n) zOSqekHbu0F?{i$@7-U^OYTu1xxbvoYCOF?MVJ#tELJ4O%xFZmh%?~a79N1)brOU8; zs$$$GV`9yA2pG=DW|8AYiQFx2Nd$ej!o`{K(fN_(a=I95wVG8$?#!&xGlj%UI+I~O z@6GI!-eM)w7Bg)|r(0Ib)%$Fa_YhNp9YenhFK>FH$Mo}w*IAvrPQC(GDwetyZOY(i znN@POhwAJO$IOL2z5G#ry`ECe_-6jD)Vx_|%VRSo>Rr2HaVIYPmp`)H?ugb?qC#Sb z7R}<2&YE6{d`Yj2*DGOy(B*3~D3kQb#C)EY1ynQ03o+>8!)-$R-QgJKPwDJ1OmbT| zM(pP>Rk-=a<`0_LFHPw>jN?XP8_mYtv}VPuMNDEW`LUkaGGFz(lG@mmw!#a3yxZAs z+~=!_kpJHIM@=R}=q7`s5DvhY8tmyL+0e@|X$%0P{E*Bs1Rhct2k zRG{+BZ37v?EBMnUL>8g;S#l}*38i4H+?DaglK`s8^ydVNPfsffqAOpKk^s+O1&f46 z#IyojIir`;xvb1PvzFdYFjr0|cpLphCP^U)lJZs}+d{5f!a7S4<5kjGJ8Vl`yK;o2 zR6m8IIE(-*oM+&)Cq#gw1XfbZ)~LBr{Er6@SfO4kABTdJQbc%S0pn_t13SgJAeg-t zBnh|{Qoi?>(eKP$eOI~#N2X?V&abB>Y(itK8ekv{O? zEaKQxxJZx8T0!~52{EQj@n?5AQdg(LR0??T6Mxa=ooivDmTL20Q7)=+XkFZ7F`HHB zj9Q?&@)fV(=E~8f3m@8kfB*oPPYzB_9*`Zdckr+VLnvTMXJYpaA+`gEI0ArzeC)g# z{saG)08#!gS^PhK|9=V%Q4`uYfnDFsm_b272mqDW*VmUl`@i6S&HrDX|8^3GP-u2YnQsgLKy3kbdz+io!rm3q$o3DsWq8XA{jXSP zEC;X+2qFU=!2f$s{_%&`8u*8@ScC0d{^20QTZ`I%_&2Kk*0LrGas=C3y!k+NKzf!e zAq=jE!#_#?XW7)?f7wXEkjALDU>+%ntDEaT2lX#KAo8tC z55m8}|IGQ10-7DNY*`5VhHvoyc>GKKKSsh=$WZ{^djF)LzyR{sO#qP2tqm> z0U8i|gdn}Eo4FH&zQJ1^kZZzG4ghdL; Date: Mon, 16 Jun 2014 20:32:11 +1000 Subject: [PATCH 54/64] Bug 1021754 - ARM Simulator: Avoid creating a Simulator for helper threads and reference the SimulatorRuntime via the PerThreadData. r=jandem --- js/src/jit/arm/Simulator-arm.cpp | 17 +++++++++-------- js/src/jit/mips/Simulator-mips.cpp | 17 +++++++++-------- js/src/vm/Runtime.h | 11 +++++++++++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp index c3fca102b604..49fcfe446680 100644 --- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -1109,7 +1109,7 @@ Simulator::FlushICache(void *start_addr, size_t size) IonSpewCont(IonSpew_CacheFlush, "[%p %zx]", start_addr, size); if (!Simulator::ICacheCheckingEnabled) return; - SimulatorRuntime *srt = Simulator::Current()->srt_; + SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime(); AutoLockSimulatorRuntime alsr(srt); js::jit::FlushICache(srt->icache(), start_addr, size); } @@ -1188,14 +1188,12 @@ class Redirection { friend class SimulatorRuntime; - Redirection(void *nativeFunction, ABIFunctionType type) + Redirection(void *nativeFunction, ABIFunctionType type, SimulatorRuntime *srt) : nativeFunction_(nativeFunction), swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected), type_(type), next_(nullptr) { - Simulator *sim = Simulator::Current(); - SimulatorRuntime *srt = sim->srt_; next_ = srt->redirection(); if (Simulator::ICacheCheckingEnabled) FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize); @@ -1208,10 +1206,13 @@ class Redirection ABIFunctionType type() const { return type_; } static Redirection *Get(void *nativeFunction, ABIFunctionType type) { - Simulator *sim = Simulator::Current(); - AutoLockSimulatorRuntime alsr(sim->srt_); + PerThreadData *pt = TlsPerThreadData.get(); + SimulatorRuntime *srt = pt->simulatorRuntime(); + AutoLockSimulatorRuntime alsr(srt); - Redirection *current = sim->srt_->redirection(); + JS_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt); + + Redirection *current = srt->redirection(); for (; current != nullptr; current = current->next_) { if (current->nativeFunction_ == nativeFunction) { MOZ_ASSERT(current->type() == type); @@ -1225,7 +1226,7 @@ class Redirection __FILE__, __LINE__); MOZ_CRASH(); } - new(redir) Redirection(nativeFunction, type); + new(redir) Redirection(nativeFunction, type, srt); return redir; } diff --git a/js/src/jit/mips/Simulator-mips.cpp b/js/src/jit/mips/Simulator-mips.cpp index 50bcc7185aa2..01759055b505 100644 --- a/js/src/jit/mips/Simulator-mips.cpp +++ b/js/src/jit/mips/Simulator-mips.cpp @@ -1278,7 +1278,7 @@ SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l) void Simulator::FlushICache(void *start_addr, size_t size) { - SimulatorRuntime *srt = Simulator::Current()->srt_; + SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime(); AutoLockSimulatorRuntime alsr(srt); js::jit::FlushICache(srt->icache(), start_addr, size); } @@ -1345,14 +1345,12 @@ class Redirection { friend class SimulatorRuntime; - Redirection(void* nativeFunction, ABIFunctionType type) + Redirection(void* nativeFunction, ABIFunctionType type, SimulatorRuntime *srt) : nativeFunction_(nativeFunction), swiInstruction_(kCallRedirInstr), type_(type), next_(nullptr) { - Simulator *sim = Simulator::Current(); - SimulatorRuntime *srt = sim->srt_; next_ = srt->redirection(); if (Simulator::ICacheCheckingEnabled) FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize); @@ -1365,10 +1363,13 @@ class Redirection ABIFunctionType type() const { return type_; } static Redirection *Get(void *nativeFunction, ABIFunctionType type) { - Simulator *sim = Simulator::Current(); - AutoLockSimulatorRuntime alsr(sim->srt_); + PerThreadData *pt = TlsPerThreadData.get(); + SimulatorRuntime *srt = pt->simulatorRuntime(); + AutoLockSimulatorRuntime alsr(srt); - Redirection *current = sim->srt_->redirection(); + JS_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt); + + Redirection *current = srt->redirection(); for (; current != nullptr; current = current->next_) { if (current->nativeFunction_ == nativeFunction) { MOZ_ASSERT(current->type() == type); @@ -1382,7 +1383,7 @@ class Redirection __FILE__, __LINE__); MOZ_CRASH(); } - new(redir) Redirection(nativeFunction, type); + new(redir) Redirection(nativeFunction, type, srt); return redir; } diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index d57322d4c6f9..3cfd11c932f7 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -602,10 +602,21 @@ class PerThreadData : public PerThreadDataFriendFields { JS_ASSERT(!pt->runtime_); pt->runtime_ = rt; +#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) + // The simulator has a pointer to its SimulatorRuntime, but helper threads + // don't have a simulator as they don't run JIT code so this pointer need not + // be updated. All the paths that the helper threads use access the + // SimulatorRuntime via the PerThreadData. + JS_ASSERT(!pt->simulator_); +#endif } ~AutoEnterRuntime() { pt->runtime_ = nullptr; +#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) + // Check that helper threads have not run JIT code and/or added a simulator. + JS_ASSERT(!pt->simulator_); +#endif } }; From 8bf2933ed23a23fd511d5e66d9e888214298665f Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 16 Jun 2014 14:08:00 -0400 Subject: [PATCH 55/64] Bug 1025973 - Part 1: Rename GlobalObject::GetContext() to Context(). r=bz --- content/base/src/WebSocket.cpp | 2 +- content/canvas/src/ImageData.cpp | 4 ++-- content/media/eme/MediaKeyMessageEvent.cpp | 4 ++-- content/media/eme/MediaKeyNeededEvent.cpp | 2 +- dom/bindings/BindingDeclarations.h | 2 +- dom/bindings/BindingUtils.cpp | 1 + dom/nfc/MozNDEFRecord.cpp | 2 +- dom/promise/Promise.cpp | 6 +++--- dom/src/notification/Notification.cpp | 2 +- dom/workers/RuntimeService.cpp | 2 +- dom/workers/URL.cpp | 8 ++++---- dom/workers/WorkerPrivate.cpp | 2 +- dom/workers/XMLHttpRequest.cpp | 2 +- dom/workers/XMLHttpRequest.h | 2 +- 14 files changed, 21 insertions(+), 20 deletions(-) diff --git a/content/base/src/WebSocket.cpp b/content/base/src/WebSocket.cpp index a6e06f7234c2..44d554306aec 100644 --- a/content/base/src/WebSocket.cpp +++ b/content/base/src/WebSocket.cpp @@ -559,7 +559,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal, } nsRefPtr webSocket = new WebSocket(ownerWindow); - nsresult rv = webSocket->Init(aGlobal.GetContext(), principal, + nsresult rv = webSocket->Init(aGlobal.Context(), principal, aUrl, protocolArray); if (NS_FAILED(rv)) { aRv.Throw(rv); diff --git a/content/canvas/src/ImageData.cpp b/content/canvas/src/ImageData.cpp index ebb10219a3d1..5c04a9231c15 100644 --- a/content/canvas/src/ImageData.cpp +++ b/content/canvas/src/ImageData.cpp @@ -52,8 +52,8 @@ ImageData::Constructor(const GlobalObject& aGlobal, aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return nullptr; } - js::AssertSameCompartment(aGlobal.GetContext(), aGlobal.Get()); - JSObject* data = Uint8ClampedArray::Create(aGlobal.GetContext(), + js::AssertSameCompartment(aGlobal.Context(), aGlobal.Get()); + JSObject* data = Uint8ClampedArray::Create(aGlobal.Context(), length.value()); if (!data) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); diff --git a/content/media/eme/MediaKeyMessageEvent.cpp b/content/media/eme/MediaKeyMessageEvent.cpp index 8af59724a12b..d5e2f4ebbab6 100644 --- a/content/media/eme/MediaKeyMessageEvent.cpp +++ b/content/media/eme/MediaKeyMessageEvent.cpp @@ -86,9 +86,9 @@ MediaKeyMessageEvent::Constructor(const GlobalObject& aGlobal, if (aEventInitDict.mMessage.WasPassed()) { const auto& a = aEventInitDict.mMessage.Value(); a.ComputeLengthAndData(); - e->mMessage = Uint8Array::Create(aGlobal.GetContext(), owner, a.Length(), a.Data()); + e->mMessage = Uint8Array::Create(aGlobal.Context(), owner, a.Length(), a.Data()); } else { - e->mMessage = Uint8Array::Create(aGlobal.GetContext(), owner, 0, nullptr); + e->mMessage = Uint8Array::Create(aGlobal.Context(), owner, 0, nullptr); } if (!e->mMessage) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); diff --git a/content/media/eme/MediaKeyNeededEvent.cpp b/content/media/eme/MediaKeyNeededEvent.cpp index 9305e8a90d4e..715e35a1d3b3 100644 --- a/content/media/eme/MediaKeyNeededEvent.cpp +++ b/content/media/eme/MediaKeyNeededEvent.cpp @@ -78,7 +78,7 @@ MediaKeyNeededEvent::Constructor(const GlobalObject& aGlobal, !aEventInitDict.mInitData.Value().IsNull()) { const auto& a = aEventInitDict.mInitData.Value().Value(); a.ComputeLengthAndData(); - e->mInitData = Uint8Array::Create(aGlobal.GetContext(), owner, a.Length(), a.Data()); + e->mInitData = Uint8Array::Create(aGlobal.Context(), owner, a.Length(), a.Data()); if (!e->mInitData) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; diff --git a/dom/bindings/BindingDeclarations.h b/dom/bindings/BindingDeclarations.h index c16c444d3414..51b6fa980b59 100644 --- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -70,7 +70,7 @@ public: // The context that this returns is not guaranteed to be in the compartment of // the object returned from Get(), in fact it's generally in the caller's // compartment. - JSContext* GetContext() const + JSContext* Context() const { return mCx; } diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index c423ab7f3a90..a66311e2cb30 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1835,6 +1835,7 @@ GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject) mCx(aCx), mGlobalObject(nullptr) { + MOZ_ASSERT(mCx); JS::Rooted obj(aCx, aObject); if (js::IsWrapper(obj)) { obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); diff --git a/dom/nfc/MozNDEFRecord.cpp b/dom/nfc/MozNDEFRecord.cpp index fbd87630e899..46da47b88752 100644 --- a/dom/nfc/MozNDEFRecord.cpp +++ b/dom/nfc/MozNDEFRecord.cpp @@ -79,7 +79,7 @@ MozNDEFRecord::Constructor(const GlobalObject& aGlobal, return nullptr; } - nsRefPtr ndefrecord = new MozNDEFRecord(aGlobal.GetContext(), + nsRefPtr ndefrecord = new MozNDEFRecord(aGlobal.Context(), win, aTnf, aType, aId, aPayload); if (!ndefrecord) { diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index aff7fd2247db..61c6f0ebab03 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -593,7 +593,7 @@ Promise::CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTas Promise::Constructor(const GlobalObject& aGlobal, PromiseInit& aInit, ErrorResult& aRv) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); nsCOMPtr global; global = do_QueryInterface(aGlobal.GetAsSupports()); @@ -744,9 +744,9 @@ public: : mPromise(aPromise), mCountdown(aCountdown) { MOZ_ASSERT(aCountdown != 0); - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); - // The only time aGlobal.GetContext() and aGlobal.Get() are not + // The only time aGlobal.Context() and aGlobal.Get() are not // same-compartment is when we're called via Xrays, and in that situation we // in fact want to create the array in the callee compartment diff --git a/dom/src/notification/Notification.cpp b/dom/src/notification/Notification.cpp index aa426569246e..f4e01de20a8c 100644 --- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -46,7 +46,7 @@ public: { MOZ_ASSERT(aWindow); MOZ_ASSERT(aPromise); - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); JSAutoCompartment ac(cx, mGlobal); mNotifications = JS_NewArrayObject(cx, 0); HoldData(); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 03c9083f8f00..c65784f63b04 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -2123,7 +2123,7 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal, nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); MOZ_ASSERT(window); - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); WorkerPrivate::LoadInfo loadInfo; nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL, diff --git a/dom/workers/URL.cpp b/dom/workers/URL.cpp index 0a9a3f741a7c..4e38dfffbb59 100644 --- a/dom/workers/URL.cpp +++ b/dom/workers/URL.cpp @@ -475,7 +475,7 @@ URL* URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, URL& aBase, ErrorResult& aRv) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); nsRefPtr runnable = @@ -499,7 +499,7 @@ URL* URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, const nsAString& aBase, ErrorResult& aRv) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); nsRefPtr runnable = @@ -844,7 +844,7 @@ URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject* aBlob, const mozilla::dom::objectURLOptions& aOptions, nsString& aResult, mozilla::ErrorResult& aRv) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); nsCOMPtr blob = file::GetDOMBlobFromJSObject(aBlob); @@ -878,7 +878,7 @@ URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject& aBlob, void URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); nsRefPtr runnable = diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index cc17effe5c2f..acd32a784ba7 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -3629,7 +3629,7 @@ WorkerPrivate::Constructor(const GlobalObject& aGlobal, const nsACString& aSharedWorkerName, LoadInfo* aLoadInfo, ErrorResult& aRv) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType, aSharedWorkerName, aLoadInfo, aRv); } diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index d8b54e42f011..0fdb8fcd2c51 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -1627,7 +1627,7 @@ XMLHttpRequest::Constructor(const GlobalObject& aGlobal, const MozXMLHttpRequestParameters& aParams, ErrorResult& aRv) { - JSContext* cx = aGlobal.GetContext(); + JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index e5ccfce0b501..bb8390dd22a8 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -88,7 +88,7 @@ public: { // Pretend like someone passed null, so we can pick up the default values MozXMLHttpRequestParameters params; - if (!params.Init(aGlobal.GetContext(), JS::NullHandleValue)) { + if (!params.Init(aGlobal.Context(), JS::NullHandleValue)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } From 85647df24bdb28ba4eabd271a75581f6c8d7a66b Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 16 Jun 2014 12:52:00 -0400 Subject: [PATCH 56/64] Bug 1025973 - Part 2: Do not pass JSContext to static webidl methods in non-worker case. r=bz --- dom/activities/src/Activity.h | 3 +-- dom/bindings/BindingUtils.cpp | 2 +- dom/bindings/Codegen.py | 18 ++++++++------ dom/bindings/test/TestBindingHeader.h | 4 +-- dom/events/MessageEvent.cpp | 2 +- dom/events/MessageEvent.h | 2 +- dom/indexedDB/IDBKeyRange.cpp | 18 +++++++------- dom/indexedDB/IDBKeyRange.h | 8 +++--- dom/promise/Promise.cpp | 36 +++++++++++++++------------ dom/promise/Promise.h | 8 +++--- dom/workers/WorkerPrivate.cpp | 2 +- js/xpconnect/src/event_impl_gen.py | 6 +---- 12 files changed, 54 insertions(+), 55 deletions(-) diff --git a/dom/activities/src/Activity.h b/dom/activities/src/Activity.h index 520f19b467bc..9a36bbce7db0 100644 --- a/dom/activities/src/Activity.h +++ b/dom/activities/src/Activity.h @@ -25,7 +25,6 @@ public: static already_AddRefed Constructor(const GlobalObject& aOwner, - JSContext* aCx, const ActivityOptions& aOptions, ErrorResult& aRv) { @@ -36,7 +35,7 @@ public: } nsRefPtr activity = new Activity(window); - aRv = activity->Initialize(window, aCx, aOptions); + aRv = activity->Initialize(window, aOwner.Context(), aOptions); return activity.forget(); } diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index a66311e2cb30..5135216f3ad4 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -2438,7 +2438,7 @@ ConvertExceptionToPromise(JSContext* cx, JS_ClearPendingException(cx); ErrorResult rv; - nsRefPtr promise = Promise::Reject(global, cx, exn, rv); + nsRefPtr promise = Promise::Reject(global, exn, rv); if (rv.Failed()) { // We just give up. Make sure to not leak memory on the // ErrorResult, but then just put the original exception back. diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 0ff25a7b6b67..af6145b000e9 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -5726,8 +5726,9 @@ def isResultAlreadyAddRefed(extendedAttributes): return 'resultNotAddRefed' not in extendedAttributes -def needCx(returnType, arguments, extendedAttributes, considerTypes): - return (considerTypes and +def needCx(returnType, arguments, extendedAttributes, considerTypes, + static=False): + return (not static and considerTypes and (typeNeedsCx(returnType, True) or any(typeNeedsCx(a.type) for a in arguments)) or 'implicitJSContext' in extendedAttributes) @@ -6057,10 +6058,11 @@ class CGPerSignatureCall(CGThing): # For JS-implemented interfaces we do not want to base the # needsCx decision on the types involved, just on our extended - # attributes. + # attributes. Also, JSContext is not needed for the static case + # since GlobalObject already contains the context. needsCx = needCx(returnType, arguments, self.extendedAttributes, - not descriptor.interface.isJSImplemented()) - if needsCx and not (static and descriptor.workers): + not descriptor.interface.isJSImplemented(), static) + if needsCx: argsPre.append("cx") needsUnwrap = False @@ -11708,7 +11710,7 @@ class CGNativeMember(ClassMethod): args.insert(0, Argument("JS::Value", "aThisVal")) # And jscontext bits. if needCx(returnType, argList, self.extendedAttrs, - self.passJSBitsAsNeeded): + self.passJSBitsAsNeeded, self.member.isStatic()): args.insert(0, Argument("JSContext*", "cx")) if needScopeObject(returnType, argList, self.extendedAttrs, self.descriptorProvider.wrapperCache, @@ -13647,7 +13649,7 @@ class CGEventMethod(CGNativeMember): self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner")) constructorForNativeCaller = CGNativeMember.declare(self, cgClass) self.args = list(self.originalArgs) - if needCx(None, self.arguments(), [], True): + if needCx(None, self.arguments(), [], considerTypes=True, static=True): self.args.insert(0, Argument("JSContext*", "aCx")) self.args.insert(0, Argument("const GlobalObject&", "aGlobal")) self.args.append(Argument('ErrorResult&', 'aRv')) @@ -13698,7 +13700,7 @@ class CGEventMethod(CGNativeMember): """, arg0=self.args[0].name, arg1=self.args[1].name) - if needCx(None, self.arguments(), [], True): + if needCx(None, self.arguments(), [], considerTypes=True, static=True): self.args.insert(0, Argument("JSContext*", "aCx")) self.args.insert(0, Argument("const GlobalObject&", "aGlobal")) self.args.append(Argument('ErrorResult&', 'aRv')) diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index c4def67e38e2..9ad7699036a7 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -151,7 +151,6 @@ public: static already_AddRefed Test2(const GlobalObject&, - JSContext*, const DictForConstructor&, JS::Handle, JS::Handle, @@ -682,8 +681,7 @@ public: // Static methods and attributes static void StaticMethod(const GlobalObject&, bool); - static void StaticMethodWithContext(const GlobalObject&, JSContext*, - JS::Value); + static void StaticMethodWithContext(const GlobalObject&, JS::Value); static bool StaticAttribute(const GlobalObject&); static void SetStaticAttribute(const GlobalObject&, bool); diff --git a/dom/events/MessageEvent.cpp b/dom/events/MessageEvent.cpp index 66e583658170..2d06aefb7a24 100644 --- a/dom/events/MessageEvent.cpp +++ b/dom/events/MessageEvent.cpp @@ -114,7 +114,7 @@ MessageEvent::GetSource(Nullable& aValue) const /* static */ already_AddRefed MessageEvent::Constructor(const GlobalObject& aGlobal, - JSContext* aCx, const nsAString& aType, + const nsAString& aType, const MessageEventInit& aParam, ErrorResult& aRv) { diff --git a/dom/events/MessageEvent.h b/dom/events/MessageEvent.h index fa403d622be6..2d45b4e08c3b 100644 --- a/dom/events/MessageEvent.h +++ b/dom/events/MessageEvent.h @@ -70,7 +70,7 @@ public: } static already_AddRefed - Constructor(const GlobalObject& aGlobal, JSContext* aCx, + Constructor(const GlobalObject& aGlobal, const nsAString& aType, const MessageEventInit& aEventInit, ErrorResult& aRv); diff --git a/dom/indexedDB/IDBKeyRange.cpp b/dom/indexedDB/IDBKeyRange.cpp index 370b44d15ea3..7c69077a01a6 100644 --- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -214,7 +214,7 @@ IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle aResult, // static already_AddRefed -IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx, +IDBKeyRange::Only(const GlobalObject& aGlobal, JS::Handle aValue, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); @@ -222,7 +222,7 @@ IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr keyRange = new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true); - aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower()); + aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower()); if (aRv.Failed()) { return nullptr; } @@ -232,7 +232,7 @@ IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx, // static already_AddRefed -IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx, +IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JS::Handle aValue, bool aOpen, ErrorResult& aRv) { @@ -241,7 +241,7 @@ IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr keyRange = new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false); - aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower()); + aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower()); if (aRv.Failed()) { return nullptr; } @@ -251,7 +251,7 @@ IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx, // static already_AddRefed -IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx, +IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JS::Handle aValue, bool aOpen, ErrorResult& aRv) { @@ -260,7 +260,7 @@ IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr keyRange = new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false); - aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Upper()); + aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Upper()); if (aRv.Failed()) { return nullptr; } @@ -270,7 +270,7 @@ IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx, // static already_AddRefed -IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx, +IDBKeyRange::Bound(const GlobalObject& aGlobal, JS::Handle aLower, JS::Handle aUpper, bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv) { @@ -279,12 +279,12 @@ IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr keyRange = new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false); - aRv = GetKeyFromJSVal(aCx, aLower, keyRange->Lower()); + aRv = GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower()); if (aRv.Failed()) { return nullptr; } - aRv = GetKeyFromJSVal(aCx, aUpper, keyRange->Upper()); + aRv = GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper()); if (aRv.Failed()) { return nullptr; } diff --git a/dom/indexedDB/IDBKeyRange.h b/dom/indexedDB/IDBKeyRange.h index 618a364c53b3..85ade2510917 100644 --- a/dom/indexedDB/IDBKeyRange.h +++ b/dom/indexedDB/IDBKeyRange.h @@ -177,19 +177,19 @@ public: } static already_AddRefed - Only(const GlobalObject& aGlobal, JSContext* aCx, + Only(const GlobalObject& aGlobal, JS::Handle aValue, ErrorResult& aRv); static already_AddRefed - LowerBound(const GlobalObject& aGlobal, JSContext* aCx, + LowerBound(const GlobalObject& aGlobal, JS::Handle aValue, bool aOpen, ErrorResult& aRv); static already_AddRefed - UpperBound(const GlobalObject& aGlobal, JSContext* aCx, + UpperBound(const GlobalObject& aGlobal, JS::Handle aValue, bool aOpen, ErrorResult& aRv); static already_AddRefed - Bound(const GlobalObject& aGlobal, JSContext* aCx, + Bound(const GlobalObject& aGlobal, JS::Handle aLower, JS::Handle aUpper, bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv); diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 61c6f0ebab03..117c7d029173 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -641,12 +641,12 @@ Promise::Constructor(const GlobalObject& aGlobal, } /* static */ already_AddRefed -Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx, +Promise::Resolve(const GlobalObject& aGlobal, JS::Handle aValue, ErrorResult& aRv) { // If a Promise was passed, just return it. if (aValue.isObject()) { - JS::Rooted valueObj(aCx, &aValue.toObject()); + JS::Rooted valueObj(aGlobal.Context(), &aValue.toObject()); Promise* nextPromise; nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise); @@ -663,7 +663,7 @@ Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx, return nullptr; } - return Resolve(global, aCx, aValue, aRv); + return Resolve(global, aGlobal.Context(), aValue, aRv); } /* static */ already_AddRefed @@ -677,7 +677,7 @@ Promise::Resolve(nsIGlobalObject* aGlobal, JSContext* aCx, } /* static */ already_AddRefed -Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx, +Promise::Reject(const GlobalObject& aGlobal, JS::Handle aValue, ErrorResult& aRv) { nsCOMPtr global = @@ -687,7 +687,7 @@ Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx, return nullptr; } - return Reject(global, aCx, aValue, aRv); + return Reject(global, aGlobal.Context(), aValue, aRv); } /* static */ already_AddRefed @@ -864,7 +864,7 @@ NS_INTERFACE_MAP_END_INHERITING(PromiseNativeHandler) NS_IMPL_CYCLE_COLLECTION(AllResolveHandler, mCountdownHolder) /* static */ already_AddRefed -Promise::All(const GlobalObject& aGlobal, JSContext* aCx, +Promise::All(const GlobalObject& aGlobal, const Sequence& aIterable, ErrorResult& aRv) { nsCOMPtr global = @@ -874,21 +874,23 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx, return nullptr; } + JSContext* cx = aGlobal.Context(); + if (aIterable.Length() == 0) { - JS::Rooted empty(aCx, JS_NewArrayObject(aCx, 0)); + JS::Rooted empty(cx, JS_NewArrayObject(cx, 0)); if (!empty) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; } - JS::Rooted value(aCx, JS::ObjectValue(*empty)); - return Promise::Resolve(aGlobal, aCx, value, aRv); + JS::Rooted value(cx, JS::ObjectValue(*empty)); + return Promise::Resolve(aGlobal, value, aRv); } nsRefPtr promise = new Promise(global); nsRefPtr holder = new CountdownHolder(aGlobal, promise, aIterable.Length()); - JS::Rooted obj(aCx, JS::CurrentGlobalOrNull(aCx)); + JS::Rooted obj(cx, JS::CurrentGlobalOrNull(cx)); if (!obj) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; @@ -897,8 +899,8 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr rejectCb = new RejectPromiseCallback(promise, obj); for (uint32_t i = 0; i < aIterable.Length(); ++i) { - JS::Rooted value(aCx, aIterable.ElementAt(i)); - nsRefPtr nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv); + JS::Rooted value(cx, aIterable.ElementAt(i)); + nsRefPtr nextPromise = Promise::Resolve(aGlobal, value, aRv); MOZ_ASSERT(!aRv.Failed()); @@ -916,7 +918,7 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx, } /* static */ already_AddRefed -Promise::Race(const GlobalObject& aGlobal, JSContext* aCx, +Promise::Race(const GlobalObject& aGlobal, const Sequence& aIterable, ErrorResult& aRv) { nsCOMPtr global = @@ -926,7 +928,9 @@ Promise::Race(const GlobalObject& aGlobal, JSContext* aCx, return nullptr; } - JS::Rooted obj(aCx, JS::CurrentGlobalOrNull(aCx)); + JSContext* cx = aGlobal.Context(); + + JS::Rooted obj(cx, JS::CurrentGlobalOrNull(cx)); if (!obj) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; @@ -940,8 +944,8 @@ Promise::Race(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr rejectCb = new RejectPromiseCallback(promise, obj); for (uint32_t i = 0; i < aIterable.Length(); ++i) { - JS::Rooted value(aCx, aIterable.ElementAt(i)); - nsRefPtr nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv); + JS::Rooted value(cx, aIterable.ElementAt(i)); + nsRefPtr nextPromise = Promise::Resolve(aGlobal, value, aRv); // According to spec, Resolve can throw, but our implementation never does. // Well it does when window isn't passed on the main thread, but that is an // implementation detail which should never be reached since we are checking diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index fb64c85f3e0e..60484c0b2426 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -121,7 +121,7 @@ public: ErrorResult& aRv); static already_AddRefed - Resolve(const GlobalObject& aGlobal, JSContext* aCx, + Resolve(const GlobalObject& aGlobal, JS::Handle aValue, ErrorResult& aRv); static already_AddRefed @@ -129,7 +129,7 @@ public: JS::Handle aValue, ErrorResult& aRv); static already_AddRefed - Reject(const GlobalObject& aGlobal, JSContext* aCx, + Reject(const GlobalObject& aGlobal, JS::Handle aValue, ErrorResult& aRv); static already_AddRefed @@ -144,11 +144,11 @@ public: Catch(JSContext* aCx, AnyCallback* aRejectCallback); static already_AddRefed - All(const GlobalObject& aGlobal, JSContext* aCx, + All(const GlobalObject& aGlobal, const Sequence& aIterable, ErrorResult& aRv); static already_AddRefed - Race(const GlobalObject& aGlobal, JSContext* aCx, + Race(const GlobalObject& aGlobal, const Sequence& aIterable, ErrorResult& aRv); void AppendNativeHandler(PromiseNativeHandler* aRunnable); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index acd32a784ba7..0dfd43e89788 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -5771,7 +5771,7 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial) ErrorResult rv; nsRefPtr event = - MessageEvent::Constructor(globalObject, aCx, + MessageEvent::Constructor(globalObject, NS_LITERAL_STRING("connect"), init, rv); event->SetTrusted(true); diff --git a/js/xpconnect/src/event_impl_gen.py b/js/xpconnect/src/event_impl_gen.py index be8f2a8403f7..d8176dd2ae88 100755 --- a/js/xpconnect/src/event_impl_gen.py +++ b/js/xpconnect/src/event_impl_gen.py @@ -165,8 +165,6 @@ def print_class_declaration(eventname, iface, fd, conf): hasVariant = True break; fd.write(" static already_AddRefed<%s> Constructor(const GlobalObject& aGlobal, " % eventname) - if hasVariant: - fd.write("JSContext* aCx, ") fd.write("const nsAString& aType, ") fd.write("const %sInit& aParam, " % eventname) fd.write("ErrorResult& aRv);\n\n") @@ -404,8 +402,6 @@ def write_cpp(eventname, iface, fd, conf): fd.write("already_AddRefed<%s>\n" % eventname) fd.write("%s::Constructor(const GlobalObject& aGlobal, " % eventname) - if hasVariant: - fd.write("JSContext* aCx, "); fd.write("const nsAString& aType, ") fd.write("const %sInit& aParam, " % eventname) fd.write("ErrorResult& aRv)\n") @@ -415,7 +411,7 @@ def write_cpp(eventname, iface, fd, conf): fd.write(" bool trusted = e->Init(t);\n") fd.write(" e->Init%s(" % eventname) if hasVariant: - fd.write("aCx, "); + fd.write("aGlobal.Context(), "); fd.write("aType, aParam.mBubbles, aParam.mCancelable") for a in allattributes: fd.write(", aParam.m%s" % firstCap(a.name)) From 80ad2a9bd1cb7f6dcb2c25d3e252d85192804b15 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 16 Jun 2014 11:47:05 -0400 Subject: [PATCH 57/64] Bug 1025959 - disable checks for webapp updates during tests; r=jmaher --- js/src/tests/user.js | 1 + layout/tools/reftest/runreftest.py | 2 ++ testing/profiles/prefs_general.js | 3 +++ 3 files changed, 6 insertions(+) diff --git a/js/src/tests/user.js b/js/src/tests/user.js index aeaedc3b3f5b..1947058e55b7 100755 --- a/js/src/tests/user.js +++ b/js/src/tests/user.js @@ -28,3 +28,4 @@ user_pref("browser.safebrowsing.malware.enabled", false); user_pref("browser.snippets.enabled", false); user_pref("browser.snippets.syncPromo.enabled", false); user_pref("general.useragent.updates.enabled", false); +user_pref("browser.webapps.checkForUpdates", 0); diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index ba95025c63e9..f325e2452c54 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -176,6 +176,8 @@ class RefTest(object): prefs['browser.snippets.syncPromo.enabled'] = False # And for useragent updates. prefs['general.useragent.updates.enabled'] = False + # And for webapp updates. Yes, it is supposed to be an integer. + prefs['browser.webapps.checkForUpdates'] = 0 if options.e10s: prefs['browser.tabs.remote.autostart'] = True diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js index b1d5443f21af..8cbae8b3bb48 100644 --- a/testing/profiles/prefs_general.js +++ b/testing/profiles/prefs_general.js @@ -175,6 +175,9 @@ user_pref("browser.snippets.syncPromo.enabled", false); // Disable useragent updates. user_pref("general.useragent.updates.enabled", false); +// Disable webapp updates. Yes, it is supposed to be an integer. +user_pref("browser.webapps.checkForUpdates", 0); + // Do not turn HTTP cache v2 for our infra tests (some tests are failing) user_pref("browser.cache.use_new_backend_temp", false); From c13f1df2a8444cbdbeced9714ce051aba671d584 Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Wed, 4 Jun 2014 18:09:37 +1000 Subject: [PATCH 58/64] Bug 1020141 - IonMonkey: (ARM) Remove the unused 'offset' field from RelativePatch. r=mjrosenb --- js/src/jit/arm/Assembler-arm.cpp | 3 --- js/src/jit/arm/Assembler-arm.h | 14 +++----------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index dea8ee777186..36d9f5bb3883 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -541,9 +541,6 @@ Assembler::finish() JS_ASSERT(!isFinished); isFinished = true; - for (size_t i = 0; i < jumps_.length(); i++) - jumps_[i].fixOffset(m_buffer); - for (unsigned int i = 0; i < tmpDataRelocations_.length(); i++) { int offset = tmpDataRelocations_[i].getOffset(); int real_offset = offset + m_buffer.poolSizeBefore(offset); diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 36d41106a6cc..c041e2d40215 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1242,18 +1242,10 @@ class Assembler : public AssemblerShared // gets moved (executable copy, gc, etc.) struct RelativePatch { - // the offset within the code buffer where the value is loaded that - // we want to fix-up - BufferOffset offset; void *target; Relocation::Kind kind; - void fixOffset(ARMBuffer &m_buffer) { - offset = BufferOffset(offset.getOffset() + m_buffer.poolSizeBefore(offset.getOffset())); - } - RelativePatch(BufferOffset offset, void *target, Relocation::Kind kind) - : offset(offset), - target(target), - kind(kind) + RelativePatch(void *target, Relocation::Kind kind) + : target(target), kind(kind) { } }; @@ -1652,7 +1644,7 @@ class Assembler : public AssemblerShared protected: void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { - enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); + enoughMemory_ &= jumps_.append(RelativePatch(target.value, kind)); if (kind == Relocation::JITCODE) writeRelocation(src); } From 64b0116f8ba612eb4f1dcf8c3ac7d0c7a9cc0270 Mon Sep 17 00:00:00 2001 From: Susanna Bowen Date: Mon, 16 Jun 2014 09:55:00 -0400 Subject: [PATCH 59/64] Bug 1025308 - Rename the variables associated with skipping style fixups for children element's based on parent display value. r=mats --- layout/base/RestyleManager.cpp | 6 +++--- layout/base/nsCSSFrameConstructor.cpp | 11 ++++++----- layout/style/nsRuleProcessorData.h | 28 ++++++++++++++------------- layout/style/nsStyleContext.cpp | 12 ++++++------ layout/style/nsStyleContext.h | 14 ++++++++------ layout/style/nsStyleSet.cpp | 14 +++++++------- layout/style/nsStyleSet.h | 2 +- 7 files changed, 46 insertions(+), 41 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 883186dc348b..40145baa5e46 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -2455,9 +2455,9 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint) else { NS_ASSERTION(aSelf->GetContent(), "non pseudo-element frame without content node"); - // Skip flex-item style fixup for anonymous subtrees: - TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper - flexOrGridFixupSkipper(mTreeMatchContext, + // Skip parent display based style fixup for anonymous subtrees: + TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper + parentDisplayBasedFixupSkipper(mTreeMatchContext, element->IsRootOfNativeAnonymousSubtree()); newContext = styleSet->ResolveStyleFor(element, parentContext, mTreeMatchContext); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 085408a128b7..6711320dac42 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -3963,9 +3963,10 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, } else { FrameConstructionItemList items; { - // Skip flex item style-fixup during our AddFrameConstructionItems() call: - TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper - flexOrGridItemStyleFixupSkipper(aState.mTreeMatchContext); + // Skip parent display based style-fixup during our + // AddFrameConstructionItems() call: + TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper + parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext); AddFrameConstructionItems(aState, content, true, aParentFrame, items); } @@ -9355,8 +9356,8 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent( "Why is someone creating garbage anonymous content"); nsRefPtr styleContext; - TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper - flexOrGridItemStyleFixupSkipper(aState.mTreeMatchContext); + TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper + parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext); if (aAnonymousItems[i].mStyleContext) { styleContext = aAnonymousItems[i].mStyleContext.forget(); } else { diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index a1e9b954440f..02793831d826 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -289,23 +289,24 @@ struct MOZ_STACK_CLASS TreeMatchContext { }; /* Helper class for tracking whether we're skipping the ApplyStyleFixups - * code for flex/grid items. + * code for special cases where child element style is modified based on + * parent display value. * - * The optional second parameter aSkipFlexOrGridItemStyleFixup allows + * The optional second parameter aSkipParentDisplayBasedStyleFixup allows * this class to be instantiated but only conditionally activated (e.g. * in cases where we may or may not want to be skipping flex/grid-item * style fixup for a particular chunk of code). */ - class MOZ_STACK_CLASS AutoFlexOrGridItemStyleFixupSkipper { + class MOZ_STACK_CLASS AutoParentDisplayBasedStyleFixupSkipper { public: - AutoFlexOrGridItemStyleFixupSkipper(TreeMatchContext& aTreeMatchContext, - bool aSkipFlexOrGridItemStyleFixup = true + AutoParentDisplayBasedStyleFixupSkipper(TreeMatchContext& aTreeMatchContext, + bool aSkipParentDisplayBasedStyleFixup = true MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mAutoRestorer(aTreeMatchContext.mSkippingFlexOrGridItemStyleFixup) + : mAutoRestorer(aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - if (aSkipFlexOrGridItemStyleFixup) { - aTreeMatchContext.mSkippingFlexOrGridItemStyleFixup = true; + if (aSkipParentDisplayBasedStyleFixup) { + aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup = true; } } @@ -363,10 +364,11 @@ struct MOZ_STACK_CLASS TreeMatchContext { // Whether this document is using PB mode bool mUsingPrivateBrowsing; - // Whether we're currently skipping the flex/grid item chunk of - // ApplyStyleFixups when resolving style (e.g. for children of elements that - // have a mandatory frame-type for which we ignore "display:flex/grid"). - bool mSkippingFlexOrGridItemStyleFixup; + // Whether we're currently skipping the part of ApplyStyleFixups that changes + // style of child elements based on their parent's display value + // (e.g. for children of elements that have a mandatory frame-type for which + // we ignore "display:flex/grid"). + bool mSkippingParentDisplayBasedStyleFixup; // Whether this TreeMatchContext is being used with an nsCSSRuleProcessor // for an HTML5 scoped style sheet. @@ -398,7 +400,7 @@ struct MOZ_STACK_CLASS TreeMatchContext { , mIsHTMLDocument(aDocument->IsHTML()) , mCompatMode(aDocument->GetCompatibilityMode()) , mUsingPrivateBrowsing(false) - , mSkippingFlexOrGridItemStyleFixup(false) + , mSkippingParentDisplayBasedStyleFixup(false) , mForScopedStyle(false) , mCurrentStyleScope(nullptr) { diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index 7327c95b5b7e..ce3fd58fa50b 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -35,7 +35,7 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag, nsCSSPseudoElements::Type aPseudoType, nsRuleNode* aRuleNode, - bool aSkipFlexOrGridItemStyleFixup) + bool aSkipParentDisplayBasedStyleFixup) : mParent(aParent), mChild(nullptr), mEmptyChild(nullptr), @@ -71,7 +71,7 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent, mRuleNode->AddRef(); mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()! - ApplyStyleFixups(aSkipFlexOrGridItemStyleFixup); + ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup); #define eStyleStruct_LastItem (nsStyleStructID_Length - 1) NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem), @@ -294,7 +294,7 @@ nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct) } void -nsStyleContext::ApplyStyleFixups(bool aSkipFlexOrGridItemStyleFixup) +nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup) { // See if we have any text decorations. // First see if our parent has text decorations. If our parent does, then we inherit the bit. @@ -359,7 +359,7 @@ nsStyleContext::ApplyStyleFixups(bool aSkipFlexOrGridItemStyleFixup) // # The computed 'display' of a flex item is determined // # by applying the table in CSS 2.1 Chapter 9.7. // ...which converts inline-level elements to their block-level equivalents. - if (!aSkipFlexOrGridItemStyleFixup && mParent) { + if (!aSkipParentDisplayBasedStyleFixup && mParent) { const nsStyleDisplay* parentDisp = mParent->StyleDisplay(); if ((parentDisp->mDisplay == NS_STYLE_DISPLAY_FLEX || parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX || @@ -737,12 +737,12 @@ NS_NewStyleContext(nsStyleContext* aParentContext, nsIAtom* aPseudoTag, nsCSSPseudoElements::Type aPseudoType, nsRuleNode* aRuleNode, - bool aSkipFlexOrGridItemStyleFixup) + bool aSkipParentDisplayBasedStyleFixup) { nsRefPtr context = new (aRuleNode->PresContext()) nsStyleContext(aParentContext, aPseudoTag, aPseudoType, aRuleNode, - aSkipFlexOrGridItemStyleFixup); + aSkipParentDisplayBasedStyleFixup); return context.forget(); } diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h index d6ed0e8372e7..cf7cf046eab0 100644 --- a/layout/style/nsStyleContext.h +++ b/layout/style/nsStyleContext.h @@ -56,15 +56,17 @@ public: * rules that any element, pseudo-element, or * anonymous box that this style context is for * matches. See |nsRuleNode| and |nsIStyleRule|. - * @param aSkipFlexOrGridItemStyleFixup + * @param aSkipParentDisplayBasedStyleFixup * If set, this flag indicates that we should skip - * the chunk of ApplyStyleFixups() that modifies flex - * and grid items' display values. + * the chunk of ApplyStyleFixups() that applies to + * special cases where a child element's style may + * need to be modified based on its parent's display + * value. */ nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag, nsCSSPseudoElements::Type aPseudoType, nsRuleNode* aRuleNode, - bool aSkipFlexOrGridItemStyleFixup); + bool aSkipParentDisplayBasedStyleFixup); ~nsStyleContext(); void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW; @@ -348,7 +350,7 @@ protected: void AddChild(nsStyleContext* aChild); void RemoveChild(nsStyleContext* aChild); - void ApplyStyleFixups(bool aSkipFlexOrGridItemStyleFixup); + void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup); void FreeAllocations(nsPresContext* aPresContext); @@ -442,5 +444,5 @@ NS_NewStyleContext(nsStyleContext* aParentContext, nsIAtom* aPseudoTag, nsCSSPseudoElements::Type aPseudoType, nsRuleNode* aRuleNode, - bool aSkipFlexOrGridItemStyleFixup); + bool aSkipParentDisplayBasedStyleFixup); #endif diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index c72bb74d1679..69c2a1459ccd 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -804,12 +804,12 @@ nsStyleSet::GetContext(nsStyleContext* aParentContext, if (!result) { result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType, aRuleNode, - aFlags & eSkipFlexOrGridItemStyleFixup); + aFlags & eSkipParentDisplayBasedStyleFixup); if (aVisitedRuleNode) { nsRefPtr resultIfVisited = NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType, aVisitedRuleNode, - aFlags & eSkipFlexOrGridItemStyleFixup); + aFlags & eSkipParentDisplayBasedStyleFixup); if (!parentIfVisited) { mRoots.AppendElement(resultIfVisited); } @@ -1225,8 +1225,8 @@ nsStyleSet::ResolveStyleFor(Element* aElement, HasState(NS_EVENT_STATE_VISITED)) { flags |= eIsVisitedLink; } - if (aTreeMatchContext.mSkippingFlexOrGridItemStyleFixup) { - flags |= eSkipFlexOrGridItemStyleFixup; + if (aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup) { + flags |= eSkipParentDisplayBasedStyleFixup; } return GetContext(aParentContext, ruleNode, visitedRuleNode, @@ -1393,7 +1393,7 @@ nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement, // aside from ::before and ::after. So if we have such a child, we're not // actually in a flex/grid container, and we should skip flex/grid item // style fixup. - flags |= eSkipFlexOrGridItemStyleFixup; + flags |= eSkipParentDisplayBasedStyleFixup; } return GetContext(aParentContext, ruleNode, visitedRuleNode, @@ -1465,7 +1465,7 @@ nsStyleSet::ProbePseudoElementStyle(Element* aParentElement, // aside from ::before and ::after. So if we have such a child, we're not // actually in a flex/grid container, and we should skip flex/grid item // style fixup. - flags |= eSkipFlexOrGridItemStyleFixup; + flags |= eSkipParentDisplayBasedStyleFixup; } nsRefPtr result = @@ -1893,7 +1893,7 @@ nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext, // or not the parent is styled as a flex/grid container. (If the parent // has anonymous-subtree kids, then we know it's not actually going to get // a flex/grid container frame, anyway.) - flags |= eSkipFlexOrGridItemStyleFixup; + flags |= eSkipParentDisplayBasedStyleFixup; } return GetContext(aNewParentContext, ruleNode, visitedRuleNode, diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 30a52cd7c5a1..837831ee1c23 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -407,7 +407,7 @@ class nsStyleSet // or "display: grid" but we can tell we're not going to honor that (e.g. if // it's the outer frame of a button widget, and we're the inline frame for // the button's label). - eSkipFlexOrGridItemStyleFixup = 1 << 3 + eSkipParentDisplayBasedStyleFixup = 1 << 3 }; already_AddRefed From 5de925be636a9552a04fdffe5a78cc0905b87056 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Tue, 17 Jun 2014 15:27:46 +1200 Subject: [PATCH 60/64] Bug 1022913 - Ensure that fastSeek() doesn't skip behind the current playback position if we're seeking forwards. r=cajbir --- content/media/MediaDecoderStateMachine.cpp | 19 +++++ content/media/test/mochitest.ini | 1 + .../media/test/test_fastSeek-forwards.html | 74 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 content/media/test/test_fastSeek-forwards.html diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp index f448a9fb713b..665e48c485fc 100644 --- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -1966,6 +1966,25 @@ void MediaDecoderStateMachine::DecodeSeek() video = mReader->FindStartTime(nextSampleStartTime); } + if (seekTime > mediaTime && + nextSampleStartTime < mediaTime && + mSeekTarget.mType == SeekTarget::PrevSyncPoint) { + // We are doing a fastSeek, but we ended up *before* the previous + // playback position. This is surprising UX, so switch to an accurate + // seek and decode to the seek target. This is not conformant to the + // spec, fastSeek should always be fast, but until we get the time to + // change all Readers to seek to the keyframe after the currentTime + // in this case, we'll just decode forward. Bug 1026330. + ResetPlayback(); + { + ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); + res = mReader->DecodeToTarget(seekTime); + if (NS_SUCCEEDED(res)) { + video = mReader->FindStartTime(nextSampleStartTime); + } + } + } + // Setup timestamp state. if (seekTime == mEndTime) { newCurrentTime = mAudioStartTime = seekTime; diff --git a/content/media/test/mochitest.ini b/content/media/test/mochitest.ini index a75c74487d7e..37219e5ea3fb 100644 --- a/content/media/test/mochitest.ini +++ b/content/media/test/mochitest.ini @@ -347,6 +347,7 @@ skip-if = buildapp == 'b2g' # bug 1021676 [test_error_in_video_document.html] [test_error_on_404.html] [test_fastSeek.html] +[test_fastSeek-forwards.html] [test_info_leak.html] [test_invalid_reject.html] [test_load.html] diff --git a/content/media/test/test_fastSeek-forwards.html b/content/media/test/test_fastSeek-forwards.html new file mode 100644 index 000000000000..a7258ddf71c5 --- /dev/null +++ b/content/media/test/test_fastSeek-forwards.html @@ -0,0 +1,74 @@ + + + + + + Test for Bug 1022913 + + + + + + +Mozilla Bug 1022913 +

+ +
+
+ + From c371700a13d19f0ac62063ca0229d3e36e4cd4dd Mon Sep 17 00:00:00 2001 From: George Wright Date: Fri, 6 Jun 2014 14:26:21 -0400 Subject: [PATCH 61/64] Bug 913805 - Hold a lock on the RasterImage in ScaleRequest so that the srcFrame doesn't go away if we need to discard images to free up memory r=seth --- image/src/RasterImage.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index d2ebf5c03cd7..6d19e49ca270 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -211,13 +211,16 @@ public: bool success = false; if (!dstLocked) { + // We need to hold a lock onto the RasterImage object itself so that + // it (and its associated imgFrames) aren't marked as discardable. + bool imgLocked = NS_SUCCEEDED(image->LockImage()); bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData()); srcSurface = srcFrame->GetSurface(); dstLocked = NS_SUCCEEDED(dstFrame->LockImageData()); dstSurface = dstFrame->GetSurface(); - success = srcLocked && dstLocked && srcSurface && dstSurface; + success = imgLocked && srcLocked && dstLocked && srcSurface && dstSurface; if (success) { srcData = srcFrame->GetImageData(); @@ -253,6 +256,7 @@ public: if (DiscardingEnabled()) dstFrame->SetDiscardable(); success = NS_SUCCEEDED(dstFrame->UnlockImageData()); + success = success && NS_SUCCEEDED(image->UnlockImage()); dstLocked = false; srcData = nullptr; From 6c21b7c10e86c86c800776a6f5c36f6fdd94380e Mon Sep 17 00:00:00 2001 From: Harsh Pathak Date: Mon, 16 Jun 2014 20:27:00 +0200 Subject: [PATCH 62/64] Bug 1017826 - prevent a potential memory leak in OCSPCache::Put. r=keeler --- security/certverifier/OCSPCache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/security/certverifier/OCSPCache.cpp b/security/certverifier/OCSPCache.cpp index 3e5a4631aa6a..06c424b315a0 100644 --- a/security/certverifier/OCSPCache.cpp +++ b/security/certverifier/OCSPCache.cpp @@ -286,6 +286,7 @@ OCSPCache::Put(const CERTCertificate* aCert, SECStatus rv = newEntry->Init(aCert, aIssuerCert, aErrorCode, aThisUpdate, aValidThrough); if (rv != SECSuccess) { + delete newEntry; return rv; } mEntries.append(newEntry); From d40092c02c926c5007baeb0aa66a19ca43abc593 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Wed, 11 Jun 2014 05:03:00 +0200 Subject: [PATCH 63/64] Bug 957396 - Enlarge container constraints when MinSize is bigger than MaxSize. r=enndeakin --- layout/generic/nsContainerFrame.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 37983b651a73..116d40b0d50b 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -675,6 +675,13 @@ void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext, aPresContext->AppUnitsToDevPixels(aMaxSize.width), aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE : aPresContext->AppUnitsToDevPixels(aMaxSize.height)); + + // MinSize has a priority over MaxSize + if (devMinSize.width > devMaxSize.width) + devMaxSize.width = devMinSize.width; + if (devMinSize.height > devMaxSize.height) + devMaxSize.height = devMinSize.height; + widget::SizeConstraints constraints(devMinSize, devMaxSize); // The sizes are in inner window sizes, so convert them into outer window sizes. From 9c7515313cd250e453aaa6b4f35bc7c821f62d1d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 17 Jun 2014 08:26:23 +0100 Subject: [PATCH 64/64] Bug 1025741 - Null-check for GetPerfomance in Console API, r=bz --- dom/base/Console.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 7bae4c87b126..c70b62faa32c 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -910,7 +910,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName, ErrorResult rv; nsRefPtr performance = win->GetPerformance(rv); - if (rv.Failed()) { + if (rv.Failed() || !performance) { return; }